实施咖喱功能

时间:2014-08-28 17:58:18

标签: haskell composition currying

我目前正在阅读Graham Hutton撰写的“haskell编程”,并且刚刚达到了currying和函数组合。在练习部分,有从头开始实现curry函数的任务,该函数已经存在于prelude模块中。 / p>

这是我的实现,但它不起作用。任何人都可以解释(我是函数编程的新手)为什么它不能正常工作

my_curry :: ((a ,b) -> c) -> (a -> b -> c)
my_curry origFunc = origFunc.combine
                    where
                         combine e f = (e, f)

这是错误[已添加]

[1 of 1] Compiling Main             ( higher_order.hs, interpreted )

  higher_order.hs:92:30:
      Couldn't match type `t0 -> (a, t0)' with `(a, b)'
      Expected type: a -> (a, b)
        Actual type: a -> t0 -> (a, t0)
      In the second argument of `(.)', namely `combine'
      In the expression: origFunc . combine
      In an equation for `my_curry':
          my_curry origFunc
            = origFunc . combine
            where
                combine e f = (e, f)

2 个答案:

答案 0 :(得分:5)

问题是.意味着采用单个参数函数并将它们粘合在一起,

在这种情况下,combine的类型为a -> b -> (a, b)。所以它的第一个参数是a,它的返回类型是b -> (a, b)(请记住->组在右边)。所以.的类型为

(.) :: (b -> c) -> (a -> b) -> a  -> c

由于combine是第二个参数,因此haskell将统一.类型变量,如

(.).a ~ combine.a
(.).b ~ (combine.b -> (combine.a, combine.b))

我使用foo.bar来表示bar定义中的类型变量foo。接下来,我们将其作为origFunc类型提供给(a, b) -> c。现在,当我们尝试将其纳入.时,我们得到

(.).b ~ my_curry.(a, b)
(.).c ~ my_curry.c

但是等等! b不能(a, b)b -> (a, b),因此类型错误。

相反,我们有两个选择,我们可以创建一种新的合成类型

(..) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
f .. g = \a b -> f (g a b)

注意这允许g采用两个参数,并且您的函数变为

 my_curry origFunc = combine .. origFunc

或者我们可以使用currying

 my_curry origFunc x y = origFunc (x, y)

答案 1 :(得分:3)

jozefg的回答解释了为什么你的代码不起作用,我认为我可以为你提供相当直接的实现。

请注意my_curry的函数签名是((a, b) -> c) -> (a -> b -> c)。它接受一个函数,并返回一个函数作为结果。我们可以捕捉到"返回一个函数"很容易用lambda表达式:

my_curry func = \x y -> func (x, y)

所有这些代码都是在等号的左侧接受一个函数,并在右侧返回一个新函数。它返回的函数一次接受一个参数,将它们组合起来并将它们发送到我们传入的任何函数。

我们可以通过删除类型签名中的括号来另一种方法。由于类型签名中的箭头是右关联的,因此my_curry的类型也可以写为((a, b) -> c) -> a -> b -> c。在这种形式中,我们可以看到我们也可以将my_curry实现为一个带有三个参数的函数:输入函数,x和y到元组并通过该函数发送。因此,编写函数的另一种有效方法是

my_curry func x y = func (x, y)