This module aims to provide a minimal implementation of
lens
package required for basic usage. All functions are compatible with
the real
lens package therefore if you need to expand to the
full version the process should be straightforward.
Main ideas implemented in this module are described in the following
blog post:
Usage
To use lenses in your project, you don't need to add any other
dependency rather than
relude. You should add the import of
this module in the place of lenses usage:
import Relude.Extra.Lens
Example
To understand better how to use this module lets look at some simple
example. Let's say we have the user data type in our system:
data User = User
{ userName :: Text
, userAge :: Int
, userAddress :: Address
} deriving (Show)
data Address = Address
{ addressCountry :: Text
, addressCity :: Text
, addressIndex :: Text
} deriving (Show)
To create the lens for the
userName field we can use
lens function and manually writing getter and setter function:
nameL :: Lens' User Text
nameL = lens getter setter
where
getter :: User -> Text
getter = userName
setter :: User -> Text -> User
setter user newName = user {userName = newName}
In this manner, we can create other lenses for our User data type.
ageL :: Lens' User Int
addressL :: Lens' User Address
countryL :: Lens' User Text
cityL :: Lens' User Text
indexL :: Lens' User Text
Note: here we are using composition of the lenses for
userAddress field. If we have
addressCityL :: Lens' Address Text
then
cityL = addressL . addressCityL
Let's say we have some sample user
user :: User
user = User
{ userName = "John"
, userAge = 42
, userAddress = Address
{ addressCountry = "UK"
, addressCity = "London"
, addressIndex = "XXX"
}
}
To view the fields of the User data type we can use
view or
^.
>>> view ageL user
42
>>> user ^. cityL
"London"
If we want to change any of the user's data, we should use
set
or
.~
>>> set nameL "Johnny" user
>>> user & indexL .~ "YYY"
over or
%~ operator could be useful when, for example,
you want to increase the age by one on the user's birthday:
>>> over ageL succ user
>>> user & ageL %~ succ
Migration
This module is not supposed to be the replacement for the
lens package. One of the reasons why one would want to
migrate to
lens or
microlens is that the functional
in
relude is limited to just vital lens functions.
To migrate to
lens or
microlens package add the
required library to the dependencies list in the
.cabal file
and replace the import from
relude library
import Relude.Extra.Lens
to the one of this correspondingly:
- lens:
import Control.Lens
- microlens:
import Lens.Micro
And that's all! No need to change the types or implementation of the
functions you used
Relude.Extra.Lens in.
Links