Shawn Zhang
Shawn Zhang

Reputation: 1852

How to remove speicific value constructor in a list using traversal

data Fruit = Apple Int
           | Banana Color Int
           
data Color = Red
           | Green
           
let basket = [Apple 3,Banana Red 30,Apple 6]

The goal is to keep Banana only

How to remove all Apple {} in the list basket ? using traversal (https://hackage.haskell.org/package/lens-5.3.2/docs/Control-Lens-Traversal.html) ?

Once the traversal is built then I can remove them , modify them (over) , change them (set)

Thank you !

Upvotes: 0

Views: 118

Answers (1)

danidiaz
danidiaz

Reputation: 27771

It can't be done using Traversals. Neither traverse from base nor the traversals from lens allow for that.

The reason is that traversals have the important property that they don't change the overall "shape" of the container. They can't add or remove elements. As the docs for Traversable say:

Functors representing data structures that can be transformed to structures of the same shape

It's true that the lens documentation says that traversals let you "focus" on certain elements of a structure. But what is meant is that you can set those elements, or modify them. You can't delete them.


If you are looking for a Traversable-like class for containers that allow (potentially effectful) filtering operations, there's Filterable and Witherable from the witherable package.


But in your case, I would simply do something like

removeApples :: [Fruit] -> [Fruit]
removeApples = mapMaybe (\f -> case f of
   Apple {} -> Nothing
   other -> Just other)

removeApples2 :: [Fruit] -> [Fruit]
removeApples2 = foldMap (\f -> case f of
   Apple {} -> []
   other -> [other])

removeApples3 :: [Fruit] -> [Fruit]
removeApples3 fruits = do -- list monad
   fruit <- fruits
   case fruit of 
    Apple {} -> []
    other -> [other]

removeApples4 :: [Fruit] -> [Fruit]
removeApples4 = filter (\f -> case f of
   Apple {} -> False
   other -> True)

Upvotes: 5

Related Questions