relude-1.2.0.0: Safe, performant, user-friendly and lightweight Haskell Standard Library
Copyright(c) 2012-2016 Edward Kmett
(c) 2019-2023 Kowainik
LicenseMIT
MaintainerKowainik <xrom.xkov@gmail.com>
StabilityStable
PortabilityPortable
Safe HaskellSafe
LanguageHaskell2010

Relude.Extra.Lens

Description

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

Synopsis

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 structure
  • s 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

view :: Lens' s a -> s -> a Source #

Gets a value out of a structure using a getter.

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

(^.) :: s -> Lens' s a -> a infixl 8 Source #

The operator form of view with the arguments flipped.

Since: 0.5.0

(.~) :: Lens' s a -> a -> s -> s infixr 4 Source #

The operator form of set.

Since: 0.5.0

(%~) :: Lens' s a -> (a -> a) -> s -> s infixr 4 Source #

The operator form of over.

Since: 0.5.0