打破haskell功能

时间:2013-12-01 13:33:20

标签: haskell

我正在阅读真实世界的哈斯克尔书,这更有意义。我已经完成了这个功能,并想知道我对它正在做什么的解释是否正确。功能是

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 个答案:

答案 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 ;
                           _                  -> [] }

请注意otherwiseTrue相同,因此| 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 _ = []

这个函数将通过这些子句,直到其中一个为真:

  • 如果至少有两个元素(x1x2它们都是偶数,则结果为:

    • 将第一个元素(x1)添加到处理列表其余部分的结果中(不包括x1x2
  • 如果列表中至少有一个元素(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的两个基本案例:

  1. 它是使用Just
  2. 构建的
  3. 它是使用Nothing
  4. 构建的