我正在通过以下方式进行列表连接(例如,使用GHC):
myConcat :: [[a]] -> [a]
myConcat xs = foldr (++) [] xs
myConcat = foldr (++) []
有人可以向我解释一下上述定义为何以及如何运作,而且这个定义没有:
myConcat xs = foldr (++) []
有意不允许最后一行代码(由于构造可能会变得令人困惑,它没用,等等)或者它是更深层次的东西,可能与currying相关......
我希望我能对此有所了解,这真让我感到困惑:/
后期编辑:除了下面给出的解释之外,我已经找到了关于这个问题的一个很好的信息来源,来自Chap的"Partial function application and currying"部分。 4 {4}中的“功能编程”。这本书可以在线免费获得。
答案 0 :(得分:7)
让我们回顾一下不同的版本:
myConcat xs = foldr (++) [] xs
这是通常的方式,提供由foldr
消耗的参数。类型为[[a]] -> [a]
,因为我们在左侧有一个类型为[[a]]
的参数,当输入到右侧时会产生[a]
。
myConcat = foldr (++) []
这里部分应用了foldr
,所以我们返回一个函数,它可以带一个额外的参数,一个列表列表。所以我们从正确的方面回来的已经是我们需要的,它不是一种“语法上的混乱”,而是表达与第一个版本相同的另一种方式。类型再次为[[a]] -> [a]
:我们左侧没有任何内容,但在右侧返回该签名的功能。
myConcat xs = foldr (++) []
这里foldr
也被部分应用了,我们返回一个可以像以前一样接受参数的函数,但是我们的定义有一个额外的参数xs
,它在右侧没有使用。编译器不“知道”我们想要应用于右侧的这个参数。类型为t -> [[a]] -> [a]
。为什么呢?
假设你有一个方形函数:
sqr :: Int -> Int
sqr x = x*x
您正在做的与提供一个未使用的附加参数基本相同:
sqr:: Int -> t -> Int
sqr x y = x*x
该功能仍然“有效”,例如sqr 3 "bla"
产生9,但类型签名关闭,未使用的参数是...... erm,未使用。未使用的参数没有固定类型,因为它实际上可以是“任何东西”,这无关紧要。因此它在签名中获得了类型变量(t
)。
答案 1 :(得分:3)
好吧,我们来看看curried function foldr
的类型签名:
>:t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
因此foldr
采用二元函数(即a->b->b
),b
值,a
值列表,并返回b
值。
让我们看一下foldr
的{{3}}以获得更明确的定义:
foldr,应用于二元运算符,一个起始值(通常为 运算符的右侧标识)和列表,使用减少列表 二元运算符,从右到左:
现在,我们来看看myConcat xs = foldr (++) []
> :t myConcat
myConcat :: t -> [[a]] -> [a]
嗯......那不是我们想要的......
问题是您从未向foldr
提供[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 (++) []
也有效,实际上是documentation的一个示例。如果我们检查foldr (++) []
的类型签名,
> :t foldr (++) []
foldr (++) [] :: [[a]] -> [a]
由于我们已经通过point-free style programming提供了foldr
前两个参数,因此我们得到一个返回的函数,它将获得[[a]]
值并执行我们想要的操作!所以我们只是将它分配给一个名称,它就像上面的例子一样工作,但我们不需要显式传递参数!
> let myConcat = foldr (++) []
> :t myConcat
myConcat :: [[a]] -> [a]
> myConcat [[1,2],[3,4]]
[1,2,3,4]
答案 2 :(得分:2)
myConcat xs = foldr (++) []
的类型t -> [[a]] -> [a]
与其他两个[[a]] -> [a]
的类型不同。