Shawn Zhang
Shawn Zhang

Reputation: 1852

lens to access fields in sum type

For example, here is the sum type

 data Fruit = Apple Int Color Date
            | Banana Color Date

The Date is purchase date but it sits in different location for Apple and Banana. I'm able to make Prism via makePrisms ''Fruit

Is it possible to create a Lens like:

purchaseDate :: Lens Fruit Date

Then I can easily get/set/modify on purchase date for all fruits ( both Apple and Banana)?

I think it is different with How can I write a lens for a sum type as the field location is different ¨Date" is in different locations of value constructors

Upvotes: 0

Views: 83

Answers (2)

Daniel Wagner
Daniel Wagner

Reputation: 152682

It's pretty mechanical to write lenses; that's why makeLenses exists. But if makeLenses doesn't quite do the thing you want, then of course you're free to write your favorite variation by hand!

purchaseDate :: Lens' Fruit Date
purchaseDate f = \case
    Apple i c d -> Apple i c <$> f d
    Banana c d -> Banana c <$> f d

The lens for extracting the color is extremely similar, though slightly syntactically noisier for fairly uninteresting reasons.

fruitColor :: Lens' Fruit Color
fruitColor f = \case
    Apple i c d -> f c <&> \c' -> Apple i c' d
    Banana c d -> f c <&> \c' -> Banana c' d

Upvotes: 4

K. A. Buhr
K. A. Buhr

Reputation: 50819

If you give the fields common names, then makeLenses will generate appropriate lenses. That is, after:

data Color = Red | Yellow deriving (Show)
newtype Date = Date Int deriving (Show)

data Fruit = Apple { _tree :: Int
                   , _color :: Color
                   , _date :: Date }
           | Banana { _color :: Color
                    , _date :: Date }
           deriving (Show)

makeLenses ''Fruit

there will be color and date lenses:

λ> :t date
date :: Lens' Fruit Date
λ> Apple 1 Red (Date 20241217) ^. date
Date 20241217
λ> Banana Yellow (Date 20250101) ^. date
Date 20250101

For fields that aren't in common, like tree, they'll be made traversals instead:

λ> :t tree
tree :: Traversal' Fruit Int

Upvotes: 4

Related Questions