有人可以向我解释这些Haskell函数吗?
我在过去曾经涉足过Haskell,最近又重新回到了Haskell,我正在阅读真实世界中的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'
是如何工作的,什么是预先真正被连接呢?我不明白案例表达式的结果是如何与pre连接的。也许我只需要有人详细解释这些功能的评估。我必须错过一些非常重要的事情。
在此先感谢!
编辑:我知道,这是一个复制粘贴失败。抱歉。编辑2:看来我的困惑是这些功能实际上是什么/返回/我现在已经全部解决了。感谢答案的人,它终于点击了!我很感激!
至于第一个,它是一个非常基本的递归方式。但是,它似乎缺少一个部分:
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或\ r或\ r \ n开头。我们想要删除这些。所以我们使用模式匹配。看看其余变量是如何基本上是suf变量减去初始换行符(s)。
所以我们有pre,这是第一行,休息,这是文本的其余部分。因此,为了继续将休息分割成行,我们将递归调用splitLines并将结果连接到pre。
可视化,假设你有字符串“foo \ nbar \ r \ 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
这是最终结果。
我认为myLength
定义错过在列表为空的情况下:
myLength [] = 0
myLength (x:xs) = 1 + myLength (xs)
根据这个定义,一个空列表的myLength
为0。(x:xs)
彭定康解包列表到的第一个项目, a
,以及其余项目列表xs
。如果列表中有一个项目,那么xs
是一个空列表,所以结果是1 + 0.依此类推。
递归最容易理解,首先查看基本情况,然后查看每个递归级别如何构建结果。 (基体的情况是,该函数不会调用自身的情况下,如果一个递归函数不具有基的情况下,输出将是无限的。)
在第二示例中,基座壳体(最后一种情况下在case-statment中)也是一个空的列表。所以pre会永远被添加到列表中,这将产生一个新的,更长的列表。
回复:myLength (x:xs) = 1 + myLength (xs)
- 这是myLength
定义的“半壁江山”,它说,通过模式匹配,即如果的说法有头有尾,那么结果是比递归尾部多了一个呼吁尾巴 - 需要有另一半说,结果是0时,该参数无法比拟x:xs
,即当参数是一个空列表。
在第二种情况下,不同的图案匹配的可能性就只是通过case
制成多一点epxlicit。
BTW,懒惰是不是一个关键的问题在这里 - ML,充满渴望的评估,但模式匹配很像Haskell中,将工作非常相似。貌似模式匹配是你真正需要刷一下。所有的第一个例子中的
首先应该是这样的(编辑:它看起来像你现在修好了):
myLength [] = 0
myLength (x:xs) = 1 + myLength (xs)
它的工作原理是这样的:说我给它有三个项目的名单,它返回一个加上尾巴的长度(这是一个加上尾巴的长度(这是一个加上尾巴的长度,这是[]
在这一点上),这是1),这是W),其中是3(最终答案)。也许嵌套括号会帮助你理解它。 ;-)
看看函数的类型签名是什么会很有意义。他们可能是:
myLength :: [a] -> Int
在myLength
,1被添加到递归调用的结果myLength
,这是一个Int
,这在一个Int
反过来结果。
splitLines :: [Char] -> [[Char]]
在splitLines
,pre
(一个[Char]
)被预先考虑的情况下语句,该语句,从看的情况下,可以是一个递归调用splitLines
,这是[[Char]]
的结果的结果;或一个空的列表。在两种情况下,预先输入pre
(a [Char]
)将导致[[Char]]
轮流。
感谢您的回答。我有模式匹配下来压缩,我递归很好。我的错误在于这些函数实际上是/返回/。 – Rayne 2009-05-26 02:43:42