我目前正在阅读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)
答案 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)
请注意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)