我正在阅读真实世界的哈斯克尔书,它更有意义 . 我已经完成了这个功能,并想知道我对它正在做什么的解释是否正确 . 功能是
oddList :: [Int] -> [Int]
oddList (x:xs) | odd x = x : oddList xs
| otherwise = oddList xs
oddList _ = []
我读过那个
定义函数oddList,它接受一个int列表并返回一个int列表 .
模式匹配:当参数是列表时 .
取第一项,将其绑定到x,将余数元素保留为xs .
如果x是奇数,则将x应用于将oddList应用于剩余元素xs并返回该结果的结果 . 重复...
当x不是奇数时,只返回将oddList应用于xs的结果
在所有其他情况下,返回一个空列表 .
1)这是一种合适/正确的阅读方式吗?
2)即使我认为我理解它,我也不相信我已经将(x:xs)位缩小了 . 应该如何阅读,它实际上在做什么?
3)是| ... |否则语法与语法的case expr相似/相同
4 回答
你做对了 .
(x:xs)
部分说:如果列表包含至少一个元素,则将第一个元素绑定到x
,将列表的其余部分绑定到xs
代码也可以写成
在这个特定的情况下,守卫(
|
)只是一种更好的方式来写下来 . 请注意,otherwise
只是True
的同义词,这通常使代码更易于阅读 .@DanielWagner指出的是,在某些情况下,我们使用警卫可以实现更复杂的行为 .
考虑这个功能(仅用于说明原理)
这个函数将通过这些子句,直到其中一个为真:
如果至少有两个元素(
x1
和x2
) and 它们都是偶数,那么结果是:将第一个元素(
x1
)添加到处理列表其余部分的结果中(不包括x1
或x2
)如果列表中至少有一个元素(
x
),则 and 为奇数,则结果为:将第一个元素(
x
)添加到处理列表其余部分的结果中(不包括x
)无论列表如何,结果如下:
一个空列表
[]
因此
funnyList [1,3,4,5] == [1,3]
和funnyList [1,2,4,5,6] == [1,2,5]
您还应该查看免费在线图书Learn You a Haskell for Great Good
1我只对您的描述进行了2次更改:
当参数是非空列表时 .
f x是将奇数列表应用于剩余元素xs并返回该结果的奇数前缀x . [删除“重复...”“]
请注意,对于“_”,“在所有其他情况下”实际上意味着“当参数是空列表时”,因为这是唯一的其他情况 .
2
(x:xs)
是一个引入两个变量的模式 . 该模式匹配非空列表,并将x
变量绑定到列表的第一个项目(头部),并将xs
绑定到列表的余数(尾部) .3是的 . 编写相同函数的等效方法是
oddList :: [Int] - > [Int]
注意
otherwise
与True
相同,因此这里可以省略| otherwise
.你已经正确地理解它在低级别上做了什么 .
但是,根据一些经验,您应该能够立即在"big picture"中解释它:当您有两个案例
(x:xs)
和_
,并且xs
再次仅作为函数的参数再次出现时,这意味着这是一个列表使用者 . 实际上,这样的函数总是等于foldr
. 你的功能有表格同
因此可以将该定义压缩为
oddList' = foldr g q
.虽然你可能现在对折叠不比使用显式递归更舒服,但实际上,一旦你看过它几次就会更简单 .
实际上,这个例子当然可以做得更简单:
oddList'' = filter odd
.将
(x:xs)
读为:使用(x:xs)
形式的表达式构造的列表然后,确保您了解每个非空列表 must 都是使用(:)构造函数构造的 .
当您考虑列表类型只有2个构造函数时,这是显而易见的:[]构造空列表,而(a:xs)构造头部为a且尾部为xs的列表 .
你还需要在心理上去除像糖这样的表达
和
这种语法糖是列表和其他类型如Maybe,Either之间的唯一区别或者你自己的类型 . 例如,当你写作
我们也在考虑Maybe的两个基本案例:
它是用
Just
构建的它是用
Nothing
构建的