我过去曾经涉足过Haskell,最近又认真地回到了它,我正在阅读现实世界的haskell。他们已经发光的一些例子,我还没有理解。就在这一点:
myLength [] = 0
myLength (x:xs) = 1 + myLength (xs)
我不知道这是如何工作的,真正添加的是什么?递归如何返回可以添加的内容?我不明白。
我们在这里有一个:
splitLines [] = []
splitLines cs =
let (pre, suf) = break isLineTerminator cs
in pre : case suf of
('\r':'\n':rest) -> splitLines rest
('\r':rest) -> splitLines rest
('\n':rest) -> splitLines rest
_ -> []
isLineTerminator c = c == '\r' || c == '\n'
这是如何工作的,什么是真正的附加?我没有看到case表达式的结果是如何预先连接到的。也许我只需要有人详细解释这些功能的评估。我必须遗漏一些非常重要的东西。
提前致谢!
编辑:我知道,这是一个复制粘贴失败。遗憾。 编辑2:看来我的困惑在于这些功能实际/返回/我现在已经解决了。谢谢你们的答案,终于点击了!我很感激!答案 0 :(得分:10)
至于第一个,它是一种非常基本的递归方式。但是,似乎缺少了一部分:
myLength [] = 0
它的工作原理是从列表中缩小一个元素并将一个元素添加到结果中。要想象,请考虑调用
myLength [1,2,3]
将评估为:
1 + myLength [2,3]
1 + 1 + myLength [3]
1 + 1 + 1 + myLength []
1 + 1 + 1 + 0
是3。
至于第二个,嗯,你已经把下一个换行符的字符串分成两个部分:pre和suf。现在,suf将以\ n,\ n或\ r或\ r \ n开头。我们想删除这些。所以我们使用模式匹配。看看rest变量本质上是suf变量减去初始换行符。
所以我们有pre,这是第一行,而rest,这是文本的其余部分。因此,为了继续将休息分成行,我们以递归方式调用splitLines并将结果连接到pre。
要想象,请说你有字符串“foo \ nbar \ r \ n \ nbaz”。
因此,在致电时,结果将是:
[ pre => foo, suf => \nbar\r\nbaz, rest => bar\r\n\baz ]
foo : splitLines bar\r\nbaz
然后再次调用splitLines,结果扩展为:
[ pre => bar, suf => \r\nbaz, rest = baz ]
foo : bar : splitLines baz
然后再一次:
[ pre => baz, suf => [], rest = [] ]
foo : bar : baz
这是最终结果。
答案 1 :(得分:4)
我认为myLength
的定义错过了列表为空的情况:
myLength [] = 0
myLength (x:xs) = 1 + myLength (xs)
使用此定义,空列表的myLength
为0. (x:xs)
模式将列表解压缩到第一个项a
中,以及包含其余项的列表,xs
。如果列表中有一个项目,则xs
是一个空列表,因此结果为1 + 0.依此类推。
当您首先查看基本案例时,最容易理解递归,然后查看每个递归级别如何构建在结果上。 (基本情况是函数不调用自身的情况。如果递归函数没有基本情况,则输出将是无限的。)
在第二个示例中,基本案例(案例陈述中的最后一个案例)也是一个空列表。所以pre将始终附加到列表中,这将产生一个新的,更长的列表。
答案 2 :(得分:2)
Re:myLength (x:xs) = 1 + myLength (xs)
- 这是myLength
定义的“一半”,它通过模式匹配说明,如果参数有一个头和一个tail,那么结果比尾部的递归尾调用更多 - 当参数不匹配x:xs
时,需要另外一半说结果是0,即,当参数为空时列表。
在第二种情况下,通过case
进行不同模式匹配的可能性更加明显。
答案 3 :(得分:2)
首先,第一个例子应该是这样的(编辑:,看起来你现在修好了):
myLength [] = 0
myLength (x:xs) = 1 + myLength (xs)
它的工作原理如下:说我给它一个包含三个项目的列表,它返回一个加上尾部的长度(这是一个加上尾部的长度(这是一个加上尾部的长度,(此时为[]
,即1),即w),即3(最终答案)。也许嵌套的括号将帮助您理解它。 ; - )
答案 4 :(得分:1)
查看函数的类型签名是有益的。他们可能是:
myLength :: [a] -> Int
在myLength
中,正在向myLength
的递归调用的结果中添加1,这是Int
,这反过来导致Int
。< / p>
splitLines :: [Char] -> [[Char]]
在splitLines
中,pre
(一个[Char]
)被置于case语句的结果之前,从查看案例中,它是递归调用的结果至splitLines
,[[Char]]
;或一个空列表。在这两种情况下,预先pre
(一个[Char]
)将依次产生[[Char]]
。