好吧,让我们看一下curried 函数 foldr
的类型签名:
>:t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
所以foldr
接受一个二进制函数(即a->b->b
)、一个b
值、一个值列表a
,并返回一个b
值。
让我们也看看文档以foldr
获得更清晰的定义:
foldr,应用于二元运算符、起始值(通常是运算符的右标识)和列表,使用二元运算符从右到左减少列表:
现在,让我们看一下类型签名myConcat xs = foldr (++) []
> :t myConcat
myConcat :: t -> [[a]] -> [a]
嗯……这不是我们想要的……
问题是您从未提供foldr
type 的值[a]
。所以现在,myConcat
需要一些任何类型的值来满足xs
和类型的值[a]
来完成foldr (++) []
,比如:
> myConcat 2 [[1,2],[3,4]]
[1,2,3,4]
> myConcat Nothing [[1,2],[3,4]]
[1,2,3,4]
这行得通,但第一个论点只是浪费。
但是,如果我们将该xs
值传递给foldr (++) []
,例如:
myConcat xs = foldr (++) [] xs
并检查其类型签名
> :t myConcat
myConcat :: [[a]] -> [a]
啊,好多了。现在 myConcat 使用xs
来完成该foldr
功能。
此外,myConcat = foldr (++) []
也有效,实际上是无点式编程的一个示例。如果我们检查 的类型签名foldr (++) []
,
> :t foldr (++) []
foldr (++) [] :: [[a]] -> [a]
由于我们已经通过部分应用foldr
提供了它的前两个参数,我们得到了一个函数,它将接受一个值并执行我们想要的操作!所以我们只是将它分配给一个名字,它就像上面的例子一样工作,但我们不需要显式传递参数![[a]]
> let myConcat = foldr (++) []
> :t myConcat
myConcat :: [[a]] -> [a]
> myConcat [[1,2],[3,4]]
[1,2,3,4]