[英]Haskell function definition syntax
我正在通过以下方式进行列表连接(例如,使用 GHC):
myConcat :: [[a]] -> [a]
myConcat xs = foldr (++) [] xs
myConcat = foldr (++) []
有人可以向我解释一下上述定义为什么以及如何工作,而这个没有:
myConcat xs = foldr (++) []
是故意不允许最后一行代码(由于结构可能会变得混乱,它无用等原因)还是更深层次的东西,可能与currying有关......
我希望我能对此有所了解,这真的让我很困惑:/
后期编辑:除了下面给出的解释之外,我发现关于此事的一个很好的信息来源是章节“部分 function 应用程序和柯里化”部分。 4 来自“Real World Haskell”一书的“函数式编程” 。 该书可在线免费获取。
让我们回顾一下不同的版本:
myConcat xs = foldr (++) [] xs
这是通常的方式,提供一个由foldr
使用的参数。 类型是[[a]] -> [a]
,因为我们在左侧有一个[[a]]
类型的参数,当输入到右侧时会产生[a]
。
myConcat = foldr (++) []
这里foldr
被部分应用,所以我们返回一个 function ,它可以接受一个额外的参数,一个列表列表。 所以我们从右边得到的已经是我们需要的了,它不是“句法糖”,而是和第一个版本一样的另一种表达方式。 类型再次为[[a]] -> [a]
:左侧没有任何内容,但在右侧返回该签名的 function。
myConcat xs = foldr (++) []
这里foldr
也被部分应用了,我们返回一个 function ,它可以像以前一样接受一个参数,但是我们的定义有一个额外的参数xs
,它没有在右侧使用。 编译器不“知道”我们想要将这个参数应用于右侧。 类型是t -> [[a]] -> [a]
。 为什么?
假设你有一个正方形 function:
sqr :: Int -> Int
sqr x = x*x
您所做的基本上与提供一个未使用的附加参数相同:
sqr:: Int -> t -> Int
sqr x y = x*x
function 仍然“有效”,例如sqr 3 "bla"
产生 9,但类型签名已关闭,未使用的参数是......呃,未使用。 未使用的参数没有固定类型,因为它实际上可以是“任何东西”,没关系。 所以它在签名中获取类型变量( t
)。
好吧,让我们看一下curried function foldr
的类型签名:
>:t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
因此foldr
采用二进制 function (即a->b->b
)、一个b
值、一个a
值列表,并返回一个b
值。
让我们也看看foldr
的文档以获得更清晰的定义:
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
function。
另外, myConcat = foldr (++) []
也可以,实际上是无点编程的一个例子。 如果我们检查foldr (++) []
的类型签名,
> :t foldr (++) []
foldr (++) [] :: [[a]] -> [a]
由于我们已经通过部分应用程序为foldr
提供了它的前两个 arguments ,我们得到一个 function 返回,它将采用[[a]]
值并执行我们想要的操作,所以我们只需将其分配给一个名称,它就像示例一样工作上面,但我们不需要显式传递参数!
> let myConcat = foldr (++) []
> :t myConcat
myConcat :: [[a]] -> [a]
> myConcat [[1,2],[3,4]]
[1,2,3,4]
myConcat xs = foldr (++) []
具有类型t -> [[a]] -> [a]
与其他两个[[a]] -> [a]
的类型不同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.