3

我有一个名为“人”的班级

Person :: String -> String -> Int -> Gender -> Person

目标: 通过将 Gender 分配给 Female 来制作更通用的 Person 版本,即 femalePerson。

什么有效: 绑定前 N 个元素有效:

let personsWithNameAlice = Person "Alice"
let personsWithNameAliceMcGee = Person "Alice" "McGee"

什么不起作用:

let femalePerson = Person {gender = Female}

问题:

  • 我该怎么做呢?
  • 如何将值绑定到 n != 0 的任何函数的第 n 个元素?

只是我知道我可以用数学写 f(x,y,z) = g(x,y,z,5) 用 C++ 写 std::bind2nd(f, 8) 所以在 Haskell 中不应该?

4

2 回答 2

13

使用语义编辑器组合器。例如,假设您有一个函数:

foo :: Int -> String -> Bool -> Char -> Float
foo = undefined

我已将示例更改为涉及所有不同的类型,因此类型检查将确保我们的定义正确。我们想要以下四种特化,每一种都是由填写一个参数产生的:

foo0 ::        String -> Bool -> Char -> Float  -- 3
foo1 :: Int ->           Bool -> Char -> Float  -- "hey"
foo2 :: Int -> String ->         Char -> Float  -- True
foo3 :: Int -> String -> Bool ->         Float  -- 'x'

第一个很简单,直接部分应用:

foo0 = foo 3

但是,让我们以一种奇怪的方式来写它(为了与其他方式保持一致):

foo0 = ($ 3) foo

对于其他人,使用result,这是组合的同义词:

result :: (b -> b') -> ((a -> b) -> (a -> b'))
result = (.)

应用程序result将给定函数瞄准另一个函数的“结果”(因此直接类似于 的firstsecond函数Control.Arrow)。然后重复应用程序瞄准多个结果,跳过连续的柯里化参数,完全符合我们的需要:

foo1 = result ($ "hey") foo
foo2 = (result.result) ($ True) foo
foo3 = (result.result.result) ($ 'x') foo

请注意,第 n 个特化使用result了与自身组成的 n 次。

于 2012-07-25T17:39:14.877 回答
7

您可以使用 lambda 表达式来做到这一点,给定

Person :: String -> String -> Int -> Gender -> Person

你会定义

femalePerson = \fn ln a -> Person fn ln a Female

或者,在绑定中使用参数:

femalePerson fn ln a = Person fn ln a Female

如果要专门绑定第二个参数,flip就是你要的函数

third = flip (/) 3

您可以使用flip将参数绑定在任意位置,但这很快就会变得麻烦且难以理解:

femalePerson = curry . curry $ flip (uncurry (uncurry Person)) Female
于 2012-07-25T12:23:46.430 回答