How to define a lambda function that filters list based on subtype of a sum type?

  • A+
Category:Languages

The example is taken from a "Haskell programming from first principles" The goal of filter function is get rid of all the objects except those of 'DbDate' type.

On somone's github I found a way to filter sum types with list comprehension and pattern matching(1). Now I am trying to find a way to redefine this filter with a lambda function(2) or normal "case of" of "if then" function. I do not know how to properly check the type of arguments of a function when I deal with custom data type.

Book doesn't introduce the reader to any super specific library functions, just standard maps, folds, filters and other stuff you'd find in prelude.

import Data.Time  data DatabaseItem = DbString String                   | DbNumber Integer                   | DbDate   UTCTime                   deriving (Eq, Ord, Show)  --List that needs to be filtered theDatabase :: [DatabaseItem] theDatabase =   [ DbDate (UTCTime (fromGregorian 1911 5 1)                     (secondsToDiffTime 34123))   , DbNumber 9001   , DbString "Hello, world!"   , DbDate (UTCTime (fromGregorian 1921 5 1)                     (secondsToDiffTime 34123))   ]    --1 works fine, found on someone's git hub filterDbDate :: [DatabaseItem] -> [UTCTime] filterDbDate dbes = [x | (DbDate x) <- dbes]  --2 Looking for the eqivalents with lambda or "case" or "if then" --pattern is not satisfactory  filterDbDate :: [DatabaseItem] -> [UTCTime] filterDbDate dbes = filter (/(DbDate x) -> True) theDatabase 

 


You were indeed on the right track, as pattern matching is an easy way of solving this, however you will get error as your pattern-matching is not comprehensive. Also, note that if you use filter, you will still get a list of [DatabaseItem] as filter never changes the type. You can however use map to do it. So:

Case Of

You can have a case .. of inside your lambda function:

filterDbDate' :: [DatabaseItem] -> [UTCTime] filterDbDate' = map (/(DbDate x) -> x) .filter (/x ->   case x of     DbDate x -> True     _        -> False) 

Recursion + Pattern Matching

However I think it's more clear using a recursion:

filterDbDate'' :: [DatabaseItem] -> [UTCTime] filterDbDate'' [] = [] filterDbDate'' ((DbDate d):ds) = d : filterDbDate ds filterDbDate'' (_:ds)          =     filterDbDate ds 

Best Way

To be honest, when you have to mix up filter and map, and your lambdas are easy like this one, list comprehensions like yours are the cleanest way:

filterDbDate ds = [d | (DbDate d) <- ds] 

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: