Haskell使用特定数据构造函数过滤嵌套列表

时间:2018-02-12 03:07:39

标签: list haskell recursion functional-programming

假设我有数据类型

data Joke = Funny String | Lame String

并说我有以下嵌套列表

[[Funny "Haha", Lame "boo"], [Funny "Haha"], [Lame "BOO"]]

如何过滤这样的嵌套列表,以便删除包含Funny "Haha"的嵌套列表中的任何列表?换句话说,我正在尝试过滤列表,以便收到以下结果:

[[Lame "BOO"]] 

删除包含Funny "Haha"的所有列表。

感谢任何帮助,我在学习Haskell以及如何使用列表和自定义数据类型时遇到了很多困难。

1 个答案:

答案 0 :(得分:2)

作为初步步骤,让我们为您的类型派生EqShow个实例:

data Joke = Funny String | Lame String
    deriving (Eq, Show)

Eq可以测试Joke s的(in)相等性,而Show则可以在GHCi中显示测试结果。

filter是正确的工具:

excludeHaha :: [[Joke]] -> [[Joke]]
excludeHaha = filter (notElem (Funny "Haha"))

这会过滤(外部)列表,以便只保留包含与Funny "Haha"不同的所有元素的内部列表。

尝试一下:

GHCi> excludeHaha [[Funny "Haha", Lame "boo"], [Funny "Haha"], [Lame "BOO"]]
[[Lame "BOO"]]

如果您不想硬编码"Haha",请添加参数并将其传递给测试:

excludeAFunnyJoke :: String -> [[Joke]] -> [[Joke]]
excludeAFunnyJoke s = filter (notElem (Funny s))
GHCi> excludeAFunnyJoke "LOL" [[Funny "LOL", Lame "boo"], [Funny "Haha"], [Lame "BOO"]]
[[Funny "Haha"],[Lame "BOO"]]

如果您想要排除所有Funny个笑话,无论包含的String是什么,您都可以使用模式匹配来定义适当的测试:

excludeFunny :: [[Joke]] -> [[Joke]]
excludeFunny = filter (all (not . isFunny))
    where
    isFunny :: Joke -> Bool
    isFunny joke = case joke of
        Funny _ -> True
        _ -> False

此处的过滤测试使用all,它将自己的测试(此处为(/= Funny "Haha"))应用于(内部)列表的元素,然后将结果[Bool]折叠为{{ 1}}。

(您也可以定义(&&)并使用它而不是isLame - 请注意,这只会起作用,因为您碰巧只有两个构造函数。)

not . isFunny

P.S。:GHCi> excludeFunny [[Funny "LOL", Lame "boo"], [Funny "Haha"], [Lame "BOO"]] [[Lame "BOO"]] 实例的手动实现如下所示:

Eq

你可以用catch-all(instance Eq Joke where Funny x == Funny y = x == y Lame x == Lame y = x == y Funny _ == Lame _ = False Lame _ == Funny _ = False )替换最后两种情况,保存一行代价是为了让你更容易忘记更新实例,如果你有更多的构造函数添加到{{1 }}。在任何情况下,这样的定义都很繁琐,所以我们用_ == _ = False来避免它,除非需要进行非显而易见的相等测试。