How to avoid getter function in list comprehension

Beginner’s question: I have defined these data types:

data State = InStock | BackOrder | Removed
data Part = Part String State

Now I have a large list of parts [parts]and want to know all parts in this list which are in a particular state:

partsInState :: [Part] -> State -> [Part]
partsInState parts state = 
  [ p| p <- parts, getState p == state ]
  where
    getState (Part _ s) = s   

That works, but the use of an “getter” function getState doesn’t look very Haskell-ish.

Is there a better way to do this (maybe without the getter function)?

1 Like

Haskell has (optional) field labels:

data Foo = Foo { fName :: String,
                 fLength :: Int }
λ> a = Foo "baz" 10
λ> fLength a
10
1 Like

Notice you can pattern match directly, without autilixiar function.

partsInState :: [Part] -> State -> [Part]
partsInState parts state = [ p | p@(Part _ s) <- parts, s == state ]
1 Like

I wouldn’t write an extra function for this. Instead use the builtin filter function and use a named field pState like @f-a suggested.

filter (\p -> pState p == state) parts

If you still want to have a partsInState function, you should flip the arguments of this function, so you can do things like:

partsList = undefined :: [[Part]]
map (partsInState state) partsList

Also derive Eq for your State type.

1 Like

Wow, the “@” operation looks pretty cool! Or is the @ just part of the name p@? – Then the magic is in the bracketing (...).

Haven’t come across this construct, I think. Any idea where can I read up on it?

2 Likes

The pattern matching syntax in Haskell includes as-patterns, which allow one to simultaneously destructure a value and bind the entire value to a name.

2 Likes

Thanks @jhenahan. This is super cool!

2 Likes