[英]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 以及如何使用列表和自定義數據類型做事的過程中度過了一段糟糕的時光。
作為初步步驟,讓我們為您的類型派生Eq
和Show
實例:
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.