0

I have two functions that I would like to combine to use with filter to filter a list of Items.

Here's a minimal example of what I'm trying to achieve:

data Item = Item { itemName :: String, itemSize :: Int }

hasName :: String -> Item -> Bool
hasName name i
  | itemName i == name = True
  | otherwise = False

hasSize :: Int -> Item -> Bool
hasSize size i
  | itemSize i == size = True
  | otherwise = False

The only solution I know to filter items that have "This" name and size 42 is to call filter twice:

items = [Item "This" 2, Item "That" 42, Item "This" 42, Item "No" 9]
filter (hasName "This") $ filter (hasSize 42) items

However, I was wondering if there's some way to "combine" those two together and call filter just once.

Jir
  • 2,985
  • 8
  • 44
  • 66

1 Answers1

1

You can use a lambda:

filter (\i -> hasName "This" i && hasSize 42 i) items

Alternatively, you can define your own auxiliary predicate function:

let condition i = hasName "This" i && hasSize 42 i
in filter condition items

More advanced alternatives exist, but (IMO) are less readable:

filter (and . sequence [hasName "This", hasSize 42]) items

Also see: Elegant way to combine multiple filtering functions in Haskell

chi
  • 111,837
  • 3
  • 133
  • 218
  • 1
    (I realized that this might be an almost duplicate after I wrote my answer. At this point I think I'll leave it there anyway, but feel free to argue otherwise.) – chi Nov 08 '22 at 10:41