Copyright | (c) 2013-2016 Edward Kmett (c) 2019-2020 Kowainik |
---|---|
License | MIT |
Maintainer | Kowainik <xrom.xkov@gmail.com> |
Stability | Experimental |
Portability | Portable |
Safe Haskell | Safe |
Language | Haskell2010 |
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'
UserText
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'
UserInt
addressL ::Lens'
User Address countryL ::Lens'
UserText
cityL ::Lens'
UserText
indexL ::Lens'
UserText
Note: here we are using composition of the lenses for userAddress
field. If we have
addressCityL ::Lens'
AddressText
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
ageLsucc
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
Synopsis
- type Lens' s a = forall f. Functor f => (a -> f a) -> s -> f s
- lens :: (s -> a) -> (s -> a -> s) -> Lens' s a
- view :: Lens' s a -> s -> a
- set :: Lens' s a -> a -> s -> s
- over :: Lens' s a -> (a -> a) -> s -> s
- (^.) :: s -> Lens' s a -> a
- (.~) :: Lens' s a -> a -> s -> s
- (%~) :: Lens' s a -> (a -> a) -> s -> s
Documentation
type Lens' s a = forall f. Functor f => (a -> f a) -> s -> f s Source #
The monomorphic lenses which don't change the type of the container (or of
the value inside). It has a Functor
constraint, and since both Const
and
Identity
are functors, it can be used whenever a getter or a setter is needed.
a
is the type of the value inside of structures
is the type of the whole structure
Since: 0.5.0
lens :: (s -> a) -> (s -> a -> s) -> Lens' s a Source #
Creates Lens'
from the getter and setter.
Since: 0.5.0
set :: Lens' s a -> a -> s -> s Source #
Sets the given value to the structure using a setter.
Since: 0.5.0
over :: Lens' s a -> (a -> a) -> s -> s Source #
Applies the given function to the target.
Since: 0.5.0