purescript-barlow-lens ๐Ÿ”ญ

June 5, 2023 ยท View on GitHub

Barlow lens increases your magnification and let's you see the stars โœจ

In other words, barlow lens makes creating complex lenses such as record lenses super simple.

Installation

Note: Version v1.0.0 requires Purescript > v0.15.10. If you are on an older version, use v0.9.0 instead or upgrade your Purescript version.

spago install barlow-lens

tl;dr

import Data.Lens 
import Data.Lens.Barlow
import Data.String (toUpper)

sky = { zodiac: { virgo: { alpha: "Spica" } } }

spica = view (barlow @"zodiac.virgo.alpha") sky
-- "Spica"
upped = over (barlow @"zodiac.virgo.alpha") toUpper sky
-- { zodiac: { virgo: { alpha: "SPICA" } } }
    
-- alfa = view (barlow @"zodiac.virgo.alfa") sky 
-- doesn't compile

or use the barlow helpers to make it even shorter:

import Data.Lens.Barlow
import Data.Lens.Barlow.Helpers
import Data.String (toUpper)

sky = { zodiac: { virgo: { alpha: "Spica" } } }

spica = view @"zodiac.virgo.alpha" sky
-- "Spica"
upped = over @"zodiac.virgo.alpha" toUpper sky
-- { zodiac: { virgo: { alpha: "SPICA" } } }

Features

Barlow supports lens creation for the following types:

Deep sky ๐ŸŒŒ

Maybe

Use ? to zoom into a Maybe.

import Data.Maybe (Maybe(..))
import Data.Lens.Barlow
import Data.Lens.Barlow.Helpers

sky =
  { zodiac:
      Just
        { virgo:
            Just
              { alpha: Just "Spica"
              }
        }
  }

spica = preview @"zodiac?.virgo?.alpha?" sky

Either

Use < for Left and > for Right to zoom into an Either.

import Data.Either (Either(..))
import Data.Maybe (Maybe(..))
import Data.Lens.Barlow
import Data.Lens.Barlow.Helpers
import Data.String (toUpper)

sky =
  { zodiac:
      Right
        { virgo:
            Just
              { alpha: Left "Spica"
              }
        }
  }

spica = preview @"zodiac>.virgo?.alpha<" sky

Array and other Traversables

Use + to zoom into Traversables like Array.

import Data.Maybe (Maybe(..))
import Data.Lens.Barlow
import Data.Lens.Barlow.Helpers
import Data.String (toUpper)

sky =
  { zodiac:
      [ { virgo:
            Just
              { star: "Spica"
              }
        }
      , { virgo:
            Just
              { star: "Serpentis"
              }
        }
      ]
  }

upped = over @"zodiac+.virgo?.star" toUpper sky

Newtype

Use ! to zoom into a Newtype.

import Data.Lens.Barlow
import Data.Lens.Barlow.Helpers
import Data.Maybe (Maybe(..))
import Data.Newtype (class Newtype)

newtype Alpha = Alpha { alpha :: String }
instance Newtype Alpha { alpha :: String }

sky =
  { zodiac:
      Just
        { virgo:
            Alpha { alpha: "Spica"
            }
        }
  }

spica = preview @"zodiac?.virgo!.alpha" sky

Data types

Barlow supports zooming into arbitrary sum and product types as long as there is a Generic instance.

Use %<NAME> to zoom into sum types, where <NAME> is the name of your data constructor. E.g. %Virgo for the data constructor Virgo.

Use %<INDEX> to zoom into product types, where <INDEX> is an integer between 1 and 9. Note that counting for product types and tuples usually starts with 1 and not 0. So the first element of a product is %1.

It is more readable if you separate your sum lens from your product lens with a . dot.

import Data.Lens.Barlow
import Data.Lens.Barlow.Helpers
import Data.Generic.Rep (class Generic)
import Data.Show.Generic (genericShow)
import Data.String.Common (toUpper)

data Zodiac
  = Carina { alpha :: String } 
  | Virgo { alpha :: String } { beta :: String } { gamma :: String } { delta :: String } 
  | CanisMaior String 

derive instance Generic Zodiac _

-- Optionally derive a show instance
instance Show Zodiac where
  show = genericShow

sky =
  { zodiac:
      Virgo { alpha : "Spica"} { beta: "ฮฒ Vir"} { gamma: "ฮณ Vir B"} { delta: "ฮด Vir"}
  }

upped = over @"zodiac.%Virgo.%4.delta" toUpper sky
-- { zodiac: Virgo { alpha : "Spica"} { beta: "ฮฒ Vir"} { gamma: "ฮณ Vir B"} { delta: "ฮ” VIR"} }

Credits

This lib was heavily inspired by this incredible blog post. Thanks also to @i-am-the-slime for pushing me to go further and for reviewing my PRs.