簡體   English   中英

Haskell 使用特定的數據構造函數過濾嵌套列表

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

假設我有數據類型

data Joke = Funny String | Lame String

並說我有以下嵌套列表

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

我將如何過濾這樣的嵌套列表,以便刪除嵌套列表中包含Funny "Haha"任何列表? 換句話說,我正在嘗試過濾列表,以便收到以下結果:

[[Lame "BOO"]] 

任何包含Funny "Haha"列表都將被刪除。

非常感謝任何幫助,我在學習 Haskell 以及如何使用列表和自定義數據類型做事的過程中度過了一段糟糕的時光。

作為初步步驟,讓我們為您的類型派生EqShow實例:

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

Eq可以測試Joke的(不)等式,而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](&&)折疊起來。

(您也可以定義isLame並使用它而不是not . isFunny但是請注意,這只會起作用,因為您碰巧只有兩個構造函數。)

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

PS: Eq實例的手動實現如下所示:

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

您可能會用一個包羅萬象( _ == _ = False )替換最后兩個案例,以節省一行為代價,如果您向Joke添加更多構造函數,則更容易忘記更新實例。 在任何情況下,這樣的定義都是枯燥乏味的工作,所以我們通過deriving避免它,除非需要一個不明顯的相等性測試。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM