我正在阅读真实世界的哈斯克尔书,这更有意义。我已经完成了这个功能,并想知道我对它正在做什么的解释是否正确。功能是
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相似/相同答案 0 :(得分:3)
1我只对您的描述进行了2次更改:
当参数是非空列表时。
f x是奇数,它是将oddList应用于剩余元素xs并返回该结果的结果。 [删除"重复......""]
请注意,对于" _","在所有其他情况下"实际上意味着"当参数是一个空列表"时,因为这是唯一的另一种情况。
2 (x:xs)
是一种引入两个变量的模式。该模式匹配非空列表,并将x
变量绑定到列表的第一个项目(头部),并将xs
绑定到列表的剩余部分(尾部)。
3是的。编写相同函数的等效方法是
oddList :: [Int] - > [Int]
oddList ys = case ys of { (x:xs) | odd x -> x : oddList xs ;
(x:xs) | otherwise -> oddList xs ;
_ -> [] }
请注意otherwise
与True
相同,因此| otherwise
可以省略。
答案 1 :(得分:2)
你做得对。
(x:xs)
部分说:如果列表包含至少一个元素,请将第一个元素绑定到x
,将列表的其余部分绑定到xs
代码也可以写成
oddList :: [Int] -> [Int]
oddList (x:xs) = case (odd x) of
True -> x : oddList xs
False -> oddList xs
oddList _ = []
在这种特定情况下,守卫(|
)只是一种更好的方式来写下来。请注意,otherwise
只是True
的同义词,通常会使代码更易于阅读。
@DanielWagner指出的是,在某些情况下,我们使用警卫会导致更复杂的行为。
考虑这个功能(仅用于说明原理)
funnyList :: [Int] -> [Int]
funnyList (x1:x2:xs)
| even x1 && even x2 = x1 : funnyList xs
| odd x1 && odd x2 = x2 : funnyList xs
funnyList (x:xs)
| odd x = x : funnyList xs
funnyList _ = []
这个函数将通过这些子句,直到其中一个为真:
如果至少有两个元素(x1
和x2
)和它们都是偶数,则结果为:
x1
)添加到处理列表其余部分的结果中(不包括x1
或x2
)如果列表中至少有一个元素(x
),和它是奇数,则结果为:
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
答案 2 :(得分:2)
你已经正确地理解它在低级别上的作用。
但是,根据一些经验,您应该能够立即在“大图”中解释它:当您有两个案例(x:xs)
和_
时,xs
只会出现再次作为该函数的参数,这意味着这是一个列表消费者。实际上,这样的函数总是等于foldr
。您的函数的格式为
oddList' (x:xs) = g x $ oddList' xs
oddList' [] = q
与
g :: Int -> [Int] -> [Int]
g x qs | odd x = x : qs
| otherwise = qs
q = [] :: [Int]
因此可以将定义压缩为oddList' = foldr g q
。
虽然你可能现在对折叠感觉不是比使用显式递归更舒服,但是一旦看到它几次就会更容易阅读。
当然,实际上可以更简单地完成示例:oddList'' = filter odd
。
答案 3 :(得分:1)
将(x:xs)
读取为:使用(x:xs)
然后,请确保您了解每个非空列表必须已使用(:)构造函数构建。
当您考虑列表类型只有2个构造函数时,这很明显:[]构造空列表,而(a:xs)构造头部为a且尾部为xs的列表。
你还需要精神上消除像
这样的表达[a,b,c] = a : b : c : []
和
"foo" = 'f' : 'o' : 'o' : []
这种语法糖是列表与其他类型(如Maybe,Either或您自己的类型)之间的唯一区别。例如,当你写
foo (Just x) = ....
foo Nothing = .....
我们也在考虑Maybe的两个基本案例:
Just
Nothing