uncurry f=\(a,b)->f a b
uncurry
将curried函数转换为对上的函数,但上面的函数只是将它转换为curried函数f a b
。这与uncurry
函数的定义是否相矛盾?
答案 0 :(得分:14)
什么样的人和Chuck说100%是正确的。我认为你在某些方面对咖喱与不良和功能定义有点混淆。
我们知道一个curried函数是这样的:
add x y = x + y
它的定义是:
add :: (Num a) => a -> a -> a
添加需要Num
,并返回函数,其中Num
并返回Num
。
通过这种方式,我们可以获得部分应用功能,例如
add3 = add 3
感谢add
被curry,当我们只传递一个参数(在本例中为3)时,我们可以返回一个带Num
并返回Num
的函数
>add3 5
8
未经验证的函数采用元组,或将值组合在一起,如(1,2)。 (注意,元组不需要配对。你可以有一个(1,2,3,4,5)形式的元组。只是常规的旧的uncurry处理特定的对)。如果我们改变了我们的添加,那就是:
add :: (Num t) => (t, t) -> t
add (x, y) = x + y
它取两个Num
的元组并返回一个Num。我们不能像使用添加作为curried函数那样部分地应用它。它需要两个参数,在元组中传递。
现在,进入uncurry功能! (如果您想知道函数的类型,请在GHCi中使用:t <some function>
,或使用Hoogle)。
uncurry :: (a -> b -> c) -> ((a, b) -> c)
uncurry f=\(a,b)->f a b
那么我们从中知道什么呢?需要 f ,我们从定义中注意到(a-&gt; b-&gt; c)中的 curried 函数,并返回未发送的函数((a,b) - &gt; c)。
如果我们提供不合格的添加(记住:add x y
),我们会得到什么?
我们得到一个匿名函数或lambda函数,它接受一个元组,并将元组a
和b
的值应用于我们的函数{ {1}}。
add
并不意味着我们获得了一项功能 - 如果是这种情况,您会看到f a b
。我们只使用->
和f
得到a
的值。
如果我们手工做到这一点有点像:
b
但是tupleAdd (a,b) = add a b
为我们做了这一切,我们可以继续使用我们最初的咖喱功能的全新形式。
酷,嗯?
答案 1 :(得分:6)
另一种编写这个定义的方法,以便更清楚地发生了什么:
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f = \(a, b) -> (f a) b
变量f
的类型为a -> b -> c
,即它是一个curried函数,而uncurry g
对于某些curried函数g
的类型为(a, b) -> c
,即一个未经证实的功能。
请注意,当x
和y
为字词时,x y
表示将函数x
应用于y
。 f a b
(或(f a) b
)表示将函数f
应用于参数a
,生成类型为b -> c
的函数,然后立即应用此函数函数b
,生成c
类型的结果。所以这个定义的右边只是展示了如何解包元组参数的组件并将它们应用于curry函数,这正是一个不发生的过程!
答案 2 :(得分:5)
你可以编写一个行为相同但具有相同签名的函数而不使用lambda:
uncurry' :: (a -> b -> c) -> ((a, b) -> c)
uncurry' f (a,b) = f a b
我认为这个版本更容易阅读。如果你有一个tupel和一个函数,它接受两个单独的值(或者更确切地说,它取一个值并返回一个接受下一个值的函数),那么uncurry'函数会为我们“解包”元组。
通常,如果您看到类似
的内容f x y z = x + y + z
与
相同f = \x y z -> x + y + z
或
f x = \y -> (\z -> x + y + z)
答案 3 :(得分:3)
我觉得你误读了。它确实在对上返回一个函数。这就是\(a,b)->
部分的含义 - 它定义了一个匿名函数,该函数接受一对并对该对中的值执行给定函数。