Reputation: 1582
I've been doing some Haskell exercises from a Haskell book, and one of the tasks is for me to filter for values of a certain type and return them as a list.
import Data.Time
data Item = DbString String
| DbNumber Integer
| DbDate UTCTime
deriving (Eq, Ord, Show)
database :: [Item]
database =
[
DbDate (UTCTime (fromGregorian 1911 5 1) (secondsToDiffTime 34123)),
DbNumber 9001,
DbString "Hello World!",
DbDate (UTCTime (fromGregorian 1921 5 1) (secondsToDiffTime 34123))
]
That's the code I am given to work with, and for my first task:
Write a function that filters for DbDate values and returns a list of the UTCTime values inside them.
The template for the function is:
filterDate :: [Item] -> [UTCTime]
filterDate = undefined
What I have to use here are folds since that is the matter concerned here.
I looked up the Data.Time
module on Hoogle and that didn't really help since I couldn't understand how to interact with the module. Maybe I'm looking at this from a wrong perspective because I don't think it has something to do with the filter
function, and I don't think it has something to do with type-casting neither ::
.
How do I get UTCTime values, and how do I filter for them?
Upvotes: 0
Views: 775
Reputation: 2894
OK, my Haskell-fu is extremely weak but I'm going to have a stab at an answer. You're looking to define a function that walks across a list and filters it. If the value is a DbDate
then you return <that value> : <output list>
, otherwise you return <output list>
. By folding over the input you produce a filtered output. There's a relevant question at How would you define map and filter using foldr in Haskell? which might explain this better.
This breaks down to something like:
filterFn :: Item -> [UTCTime] -> [UTCTime]
filterFn (DbDate x) xs = x:xs
filterFn _ xs = xs
(this might be a syntax fail). This function takes an item off our [Item]
and pattern matches.
DbDate x
then x
is a UTCTime
and we append it to our input list.We can then fold:
filterDate = foldr filterFn []
Does that get you to an answer?
Upvotes: 5
Reputation: 5543
Item is defined as a union type, which means it can be a DbString
, a DbNumber
or a DbDate
.
data Item = DbString String
| DbNumber Integer
| DbDate UTCTime
deriving (Eq, Ord, Show)
You can use pattern matching to get only the value you're interested in. You need to match on an item, check whether it is a DbDate
and if that's the case extract the UTCTime
instance it holds.
You said you want to use a fold so you need an accumulator where you can put the values you want to keep and a function to populate it.
filterDate items = foldl accumulate [] items
where extractTime item = case item of DbDate time -> [time]
_ -> []
accumulate item accumulator = accumulator ++ (extractTime item)
In the code above you have extractTime
that pattern matches over an item and either returns a list containing the time or it returns an empty list. The accumulate
function just puts together the values you got from the previous steps (they're stored in accumulator
) and the value you got applying extractTime
to the current item.
Upvotes: 0