uncurry f=\(a,b)->f a b
Run Code Online (Sandbox Code Playgroud)
uncurry将curried函数转换为对上的函数,但上面的函数只是将它转换为curried函数f a b.这与uncurry函数的定义是否相矛盾?
Zac*_*h L 14
什么样的人和Chuck说的是100%正确的.我认为你在某些方面对咖喱与不良和功能定义有点混淆.
我们知道一个curried函数是这样的:
add x y = x + y
它的定义是:
add :: (Num a) => a -> a -> a
添加需要Num,并返回一个函数,需要一个Num和返回Num.
通过这种方式,我们可以得到一个部分应用的功能,如
add3 = add 3
由于add被curry,当我们只传递一个参数(在这种情况下,3)时,我们可以返回一个带a Num并返回a 的函数Num.
>add3 5
8
Run Code Online (Sandbox Code Playgroud)
未计算的函数采用元组,或将值组合在一起,如(1,2).(注意,元组不需要配对.你可以有一个(1,2,3,4,5)形式的元组.只是常规的旧的uncurry处理特定的对).如果我们改变了我们的添加不被证实,它将是:
add :: (Num t) => (t, t) -> t
add (x, y) = x + y
Run Code Online (Sandbox Code Playgroud)
它取两个元组Num并返回一个Num.我们不能像使用添加作为curried函数那样部分地应用它.它需要两个参数,在元组中传递.
现在,进入uncurry功能!(如果您想知道函数的类型,请:t <some function>在GHCi中使用,或使用Hoogle).
uncurry :: (a -> b -> c) -> ((a, b) -> c)
uncurry f=\(a,b)->f a b
Run Code Online (Sandbox Code Playgroud)
那么我们从中得知什么呢?这需要˚F,这是我们从定义注意到是咖喱从(A-> B-> C)的功能,并返回一个uncurried函数((A,B) - > C).
如果我们提供不合理的添加(记住:) add x y,我们会得到什么?
我们得到一个匿名函数,或lambda函数,这需要一个元组,并应用元组的值,a并且b,我们的功能add.
f a b并不意味着我们得到一个功能 - 你会看到一个->是否是这种情况.我们刚刚得到的值的f同a和b.
这有点像我们手工做到这一点:
tupleAdd (a,b) = add a b
但这uncurry一切对我们来说都是如此,我们可以继续使用我们最初的咖喱功能的全新形式.
很酷,嗯?
编写这个定义的另一种方式是使得更清楚的是:
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f = \(a, b) -> (f a) b
Run Code Online (Sandbox Code Playgroud)
变量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函数,这正是uncurrying的过程!
您可以编写一个函数,其行为方式相同(并且具有相同的签名),而不使用lambda:
uncurry' :: (a -> b -> c) -> ((a, b) -> c)
uncurry' f (a,b) = f a b
Run Code Online (Sandbox Code Playgroud)
我认为这个版本更容易阅读.如果你有一个tupel和一个函数,它接受两个单独的值(或者更确切地说,它取一个值并返回一个接受下一个值的函数),那么uncurry'函数会为我们"解包"元组.
一般来说,如果你看到像
f x y z = x + y + z
Run Code Online (Sandbox Code Playgroud)
它是一样的
f = \x y z -> x + y + z
Run Code Online (Sandbox Code Playgroud)
要么
f x = \y -> (\z -> x + y + z)
Run Code Online (Sandbox Code Playgroud)