简体   繁体   English

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

[英]Haskell filtering a nested list with specific data constructors

Suppose I have the data type假设我有数据类型

data Joke = Funny String | Lame String

and say I have the following nested list并说我有以下嵌套列表

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

How would I go about filtering such a nested list so that any list within the nested list that contains Funny "Haha" is removed?我将如何过滤这样的嵌套列表,以便删除嵌套列表中包含Funny "Haha"任何列表? In other words, I'm trying to filter the list so that I receive the following result:换句话说,我正在尝试过滤列表,以便收到以下结果:

[[Lame "BOO"]] 

Any list that contains Funny "Haha" is removed.任何包含Funny "Haha"列表都将被删除。

Would appreciate any help, I'm having a terrible time learning Haskell and how to do things with lists and custom data types.非常感谢任何帮助,我在学习 Haskell 以及如何使用列表和自定义数据类型做事的过程中度过了一段糟糕的时光。

As a preliminary step, let's derive Eq and Show instances for your type:作为初步步骤,让我们为您的类型派生EqShow实例:

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

Eq makes it possible to test the (in)equality of Joke s, while Show makes it possible to display the results of your tests in GHCi. Eq可以测试Joke的(不)等式,而Show可以在 GHCi 中显示测试结果。

filter is the right tool here: filter是正确的工具:

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

This filters the (outer) list so that only inner lists with all elements different from Funny "Haha" are kept.这会过滤(外部)列表,以便只保留所有元素与Funny "Haha"不同的内部列表。

Trying it out:尝试一下:

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

If you don't want to hardcode "Haha" , add a parameter and pass it on to the test:如果您不想硬编码"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"]]

If you wanted instead to exclude all Funny jokes, regardless of what the contained String is, you could use pattern matching to define an appropriate test:如果您想排除所有Funny笑话,无论包含的String是什么,您都可以使用模式匹配来定义适当的测试:

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

The filtering test here uses all , which applies its own test (here, (/= Funny "Haha") ) to the elements of the (inner) list and then folds the resulting [Bool] with (&&) .此处的过滤测试使用all ,它将自己的测试(此处为(/= Funny "Haha") )应用于(内部)列表的元素,然后将结果[Bool](&&)折叠起来。

(You might as well define isLame and use it instead of not . isFunny -- note, though, that that would only work because you happen to have just two constructors.) (您也可以定义isLame并使用它而不是not . isFunny但是请注意,这只会起作用,因为您碰巧只有两个构造函数。)

GHCi> excludeFunny [[Funny "LOL", Lame "boo"], [Funny "Haha"], [Lame "BOO"]]
[[Lame "BOO"]]

PS: A manual implementation of the Eq instance would look like this: PS: Eq实例的手动实现如下所示:

instance Eq Joke where
    Funny x == Funny y = x == y
    Lame x == Lame y = x == y
    Funny _ == Lame _ = False
    Lame _ == Funny _ = False

You might replace the last two cases by a catch-all ( _ == _ = False ), saving one line at the cost of making it a little easier to forget updating the instance if you ever add more constructors to Joke .您可能会用一个包罗万象( _ == _ = False )替换最后两个案例,以节省一行为代价,如果您向Joke添加更多构造函数,则更容易忘记更新实例。 In any case, such definitions are boring busywork, so we avoid it with deriving unless there is a need for a non-obvious equality test.在任何情况下,这样的定义都是枯燥乏味的工作,所以我们通过deriving避免它,除非需要一个不明显的相等性测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM