我正在學習Haskell Book,並在第10章(摺疊列表)中,我試圖解決有關從包含不同類型的元素的列表中僅獲取一種特定類型的元素的練習。如何僅從Haskell的列表中獲取特定類型的元素?
作者給出了下面的代碼:
import Data.Time
data DatabaseItem = DbString String
| DbNumber Integer
| DbDate UTCTime
deriving (Eq, Ord, Show)
theDatabase :: [DatabaseItem]
theDatabase = [ DbDate (UTCTime
(fromGregorian 1911 5 1)
(secondsToDiffTime 34123))
, DbNumber 9001
, DbString "Hello, world!"
, DbDate (UTCTime
(fromGregorian 1921 5 1)
(secondsToDiffTime 34123))
]
和第一個問題是:
編寫過濾器DBDATE值和返回的 列表裏面他們UTCTime值的功能。
filterDbDate :: [DatabaseItem] -> [UTCTime]
filterDbDate = undefined
因爲章是關於摺疊名單,我認爲它可以使用,例如,foldr
來完成。
我最初的嘗試是先寫一些輔助功能,並在foldr
使用它們,如:
getDbDate1 :: DatabaseItem -> UTCTime
getDbDate1 (DbDate utcTime) = utcTime
isDbDate :: DatabaseItem -> Bool
isDbDate (DbDate _) = True
isDbDate _ = False
filterDbDate1 :: [DatabaseItem] -> [UTCTime]
filterDbDate1 database = foldr ((:) . getDbDate1) [] (filter isDbDate database)
這似乎做的工作,這是因爲:
λ> filterDbDate1 theDatabase
[1911-05-01 09:28:43 UTC,1921-05-01 09:28:43 UTC]
但我對此解決方案並不舒服,因爲首先它給出以下警告:
/Users/emre/code/haskell/chapter10_folding_lists/database.hs:36:1: Warning: …
Pattern match(es) are non-exhaustive
In an equation for ‘getDbDate1’:
Patterns not matched:
DbString _
DbNumber _
而且我使用了兩個輔助函數,一個幫助濾除不是DbDate的值,另一個幫助處理UTCTime
組件。
因此,擺脫非詳盡的模式匹配的警告,並使用一個輔助函數,我決定把它寫這樣的:
getDbDate2 :: DatabaseItem -> Maybe UTCTime
getDbDate2 (DbDate utcTime) = Just utcTime
getDbDate2 _ = Nothing
filterDbDate2 :: [DatabaseItem] -> [UTCTime]
filterDbDate2 database = foldr ((:) . getDbDate2) [] database
但是,當然,上面沒有編譯,因爲它沒有類型檢查,因爲,例如:
λ> foldr ((:) . getDbDate2) [] theDatabase
[Just 1911-05-01 09:28:43 UTC,Nothing,Nothing,Just 1921-05-01 09:28:43 UTC]
換句話說,它可以與Nothing
值返回Just UTCTime
值的列表,在一起,不僅UTCTime
值的列表。
所以我的問題是:如何編寫一個(幫助器?)函數,以便我不必使用filter
),檢查其值是否爲DbNumber
,如果是,則返回UTCTime
組件? (如果不是......它也有返回的東西(如Nothing
?),而這正是我有麻煩,那就是使用Maybe UTCTime
,然後讓Just UTCTime
值等)
['catMaybes :: [也許] - >並[a]'](https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Maybe.html#v :catMaybes)可以在這裏幫忙。 – ErikR
函數'f = maybe [](:[])。 getDbDate2'返回一個單獨列表,其中有一個列表,否則返回一個空列表。 'filterDbDate'就是'foldMap f'。 – user2407038