Haskell 未成熟函数的类型签名
Haskell 未成熟函数的类型签名,haskell,Haskell,uncurry将当前函数转换为成对函数,但上面的函数仅将其转换为当前函数f a b。这是否与uncurry函数的定义相矛盾?我认为你误读了。它确实会返回成对的函数。这就是\(a,b)->部分的意思-它定义了一个匿名函数,它接受一对值,并对该对中的值执行给定的函数。编写此定义的另一种方法,以便更清楚地了解发生了什么: uncurry f=\(a,b)->f a b 变量f的类型为a->b->c,即它是一个curried函数,而uncurry g对于某些curried函数g的类型为(a,b)
uncurry
将当前函数转换为成对函数,但上面的函数仅将其转换为当前函数f a b
。这是否与uncurry
函数的定义相矛盾?我认为你误读了。它确实会返回成对的函数。这就是\(a,b)->
部分的意思-它定义了一个匿名函数,它接受一对值,并对该对中的值执行给定的函数。编写此定义的另一种方法,以便更清楚地了解发生了什么:
uncurry f=\(a,b)->f a b
变量f
的类型为a->b->c
,即它是一个curried函数,而uncurry g
对于某些curried函数g
的类型为(a,b)->c
,即一个uncurried函数
请记住,当
x
和y
是术语时,xy
表示将函数x
应用于y
。而fab
(或(fa)b
)意味着将函数f
应用于参数a
,生成类型为b->c
的函数,然后立即将此函数应用于b
,生成类型为c
的结果。因此,这个定义的右侧只是展示了如何解包元组参数的组件,并将它们应用到一个curry函数,这正是一个不修剪的过程 pelotom和Chuck所说的百分之百正确。我想你只是在某些时候对curry vs uncurry和函数定义有点困惑
我们知道,curried函数类似于:
addxy=x+y
它的定义是:
uncurry f=\(a,b)->f a b
add::(Num a)=>a->a->a
Add接受一个Num
,并返回一个函数,该函数接受一个Num
并返回一个Num
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f = \(a, b) -> (f a) b
通过这种方式,我们可以得到一个部分应用的函数,如
add3=add3
由于使用了add
,当我们只传递一个参数(在本例中为3)时,我们可以返回一个函数,该函数接受Num
并返回Num
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f = \(a, b) -> (f a) b
未传递的函数接受元组,或将值分组在一起,如(1,2)。(注意,元组不必成对。您可以有一个(1,2,3,4,5)形式的元组。只有常规的old uncurry处理特定的成对)。如果我们将add更改为uncarried,则会是:
>add3 5
8
它接受两个Num
s的元组并返回一个Num。我们不能像将add作为curried函数那样部分应用它。它需要两个参数,以元组形式传递
现在,转到uncurry函数!(如果您想知道函数的类型,请在GHCi中使用:t
,或使用)
那么我们从中了解到了什么?它采用f,我们从定义中注意到,它是(a->b->c)中的curried函数,并且它返回未加载波的函数((a,b)->c)
如果我们不加修改地输入我们的咖喱add(记住:addxy
),我们会得到什么
我们得到一个匿名函数,或lambda函数,它接受一个元组,并将元组a
和b
的值应用到我们的函数add
fab
并不意味着我们得到一个函数——如果是这样的话,你会看到一个->
。我们只需通过a
和b
获得f
的值
这有点像是我们用手做的:
tupleAdd(a,b)=添加b
但是,uncurry
为我们做了这一切,我们可以继续使用我们最初使用的函数的全新uncurry形式
酷毙了,嗯?您可以编写一个没有lambda的函数,其行为方式相同(并且具有相同的签名):
uncurry :: (a -> b -> c) -> ((a, b) -> c)
uncurry f=\(a,b)->f a b
我认为这个版本更容易阅读。如果您有一个元组和一个接受两个单一值的函数(或者更确切地说,它接受一个值并返回一个接受下一个值的函数),uncurry'函数为我们执行元组的“展开”
一般来说,如果你看到
uncurry' :: (a -> b -> c) -> ((a, b) -> c)
uncurry' f (a,b) = f a b
这和
f x y z = x + y + z
或
f x = \y -> (\z -> x + y + z)