好的,让我们来看一下柯里化函数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]
嗯...这不是我们想要的...
问题在于您从未提供类型为[a]
的值给foldr
。因此,现在myConcat
需要一些值(任何类型),以满足xs
并完成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]