-----------------------------------------------------------------------------
-- |
-- Module      :  Miso.Lens
-- Copyright   :  (C) 2016-2025 David M. Johnson
-- License     :  BSD3-style (see the file LICENSE)
-- Maintainer  :  David M. Johnson <code@dmj.io>
-- Stability   :  experimental
-- Portability :  non-portable
--
-- This modules exposes a very simple 'Lens' formulation that is compatible with other lens libraries.
--
-- For state management of miso applications, this module should meet all of your needs. It also
-- ensures a smaller payload size during compilation.
--
-- @
-- data Lens record field
--  = Lens
--  { _get :: record -> field
--  , _set :: record -> field -> record
--  }
-- @
--
-- The goal is to provide users with an out-of-the box lens experience without the large
-- dependency footprint and cognitive load. This module also aims to preserve semantics of
-- existing lens combinators using a simple formulation (not the Van Laarhoven). It must be imported
-- separately (@import Miso.Lens@) and can be used with the @Effect@ Monad inside of a miso
-- application (as described below).
--
-- This module is at fixity and interface parity with @lens@ and @microlens@ and can therefore
-- be used interchangeably with them. Simply replace the @Miso.Lens@ import with @Control.Lens@.
-- For convenience we re-export the 'Lens'' synonym to ease the transition into @lens@ or
-- @microlens@.
--
-- For the curious reader, if you'd like more information on @lens@ and the Van Laarhoven
-- formulation, we recommend the @lens@ library <https://hackage.haskell.org/package/lens>.
--
-- @
-- -- Person type
-- data Person = Person
--   { _name :: String
--   , _address :: Address
--   , _age  :: Int
--   } deriving (Show, Eq, Generic)
--
-- -- Address type
-- newtype Address
--   = Address
--   { _zipCode :: Zip
--   } deriving (Show, Eq)
--
-- -- | Zip code type synonym
-- type Zip = String
--
-- -- | Name Lens
-- name :: Lens Person String
-- name = 'lens' _name $ \\record x -> record { _name = x }
--
-- -- | Address Lens
-- address :: Lens Person Address
-- address = 'lens' _address $ \\record x -> record { _address = x }
--
-- -- | Zip Code Lens
-- zipCode :: Lens Address Zip
-- zipCode = 'lens' _zipCode $ \\record x -> record { _zipCode = x }
--
-- -- | Lens Composition example
-- personZip :: Lens Person Zip
-- personZip = zipCode . address
--
-- -- | Person example
-- person :: Person
-- person = Person "john" (Address "90210") 33
--
-- main :: IO ()
-- main = print $ john '&' address '.~' Address "10012"
--
-- > Person
-- >  { _name = "john"
-- >  , _age = 33
-- >  , _address = Address {_zipCode = "10012"}
-- >  }
-- @
--
-- Example usage with miso's @Effect@ @Monad@
--
-- @
-- newtype Model = Model { _value :: Int }
--
-- value :: Lens Model Int
-- value = 'lens' _value $ \\model v -> model { _value = v }
--
-- data Action = AddOne | SubtractOne
--
-- updateModel :: Action -> 'Effect' Model Action
-- updateModel AddOne      = value '+=' 1
-- updateModel SubtractOne = value '-=' 1
-- @
----------------------------------------------------------------------------
module Miso.Lens
  ( -- ** Types
    Lens (..)
  , Lens'
    -- ** Smart constructor
  , lens
    -- ** Re-exports
  , (&)
  , (<&>)
    -- ** Combinators
  , (.~)
  , (?~)
  , set
  , (%~)
  , over
  , (^.)
  , (+~)
  , (*~)
  , (//~)
  , (-~)
  , (%=)
  , modifying
  , (+=)
  , (*=)
  , (//=)
  , (-=)
  , (.=)
  , (<~)
  , (<%=)
  , (<.=)
  , (<?=)
  , (<<.=)
  , (<<%=)
  , assign
  , use
  , (?=)
  , (<>~)
  ) where
----------------------------------------------------------------------------
import Control.Monad.State (MonadState, modify, gets)
import Control.Category (Category (..))
import Control.Arrow ((<<<))
import Data.Function ((&))
import Data.Functor((<&>))
----------------------------------------------------------------------------
-- | A @Lens@ is a generalized getter and setter.
--
-- Lenses allow both the retrieval of values from fields in a record and the
-- assignment of values to fields in a record. The power of a @Lens@ comes
-- from its ability to be composed with other lenses.
--
-- In the context of building applications with miso, the @model@ is
-- often a deeply nested product type. This makes it highly conducive
-- to @Lens@ operations (as defined below).
--
data Lens record field
  = Lens
  { forall record field. Lens record field -> record -> field
_get :: record -> field
    -- ^ Retrieves a field from a record
  , forall record field. Lens record field -> record -> field -> record
_set :: record -> field -> record
    -- ^ Sets a field on a record
  }
----------------------------------------------------------------------------
-- | Type synonym re-export for @lens@ / @microlens@ compatability.
-- Note: use this if you plan on migrating to lens or microlens eventually.
-- Just use @Lens@ otherwise (as examples show).
type Lens' record field = Lens record field
----------------------------------------------------------------------------
-- | Lens are Categories, and can therefore be composed.
instance Category Lens where
  id :: forall a. Lens a a
id = (a -> a) -> (a -> a -> a) -> Lens a a
forall record field.
(record -> field)
-> (record -> field -> record) -> Lens record field
Lens (\a
x -> a
x) (\a
x a
_ -> a
x)
  Lens b -> c
g1 b -> c -> b
s1 . :: forall b c a. Lens b c -> Lens a b -> Lens a c
. Lens a -> b
g2 a -> b -> a
s2 = Lens
    { _get :: a -> c
_get = b -> c
g1 (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
<<< a -> b
g2
    , _set :: a -> c -> a
_set = \a
r c
f -> a -> b -> a
s2 a
r (b -> c -> b
s1 (a -> b
g2 a
r) c
f)
    }
----------------------------------------------------------------------------
-- | Set a field on a record
--
-- @
-- newtype Person = Person { _name :: String }
--
-- name :: Lens Person String
-- name = lens _name $ \\person n -> person { _name = n }
--
-- setName :: Person -> String -> Person
-- setName person newName = person & name .~ newName
-- @
infixr 4 .~
(.~) :: Lens record field -> field -> record -> record
.~ :: forall record field. Lens record field -> field -> record -> record
(.~) Lens record field
_lens = (record -> field -> record) -> field -> record -> record
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Lens record field -> record -> field -> record
forall record field. Lens record field -> record -> field -> record
_set Lens record field
_lens)
----------------------------------------------------------------------------
-- | Synonym for '(.~)'
--
set :: Lens record field -> field -> record -> record
set :: forall record field. Lens record field -> field -> record -> record
set = Lens record field -> field -> record -> record
forall record field. Lens record field -> field -> record -> record
(.~)
----------------------------------------------------------------------------
-- | Set an options field on a record
--
-- @
-- newtype Person = Person { _name :: Maybe String }
--
-- name :: Lens Person (Maybe String)
-- name = lens _name $ \\person n -> person { _name = n }
--
-- setName :: Person -> String -> Person
-- setName person newName = person & name ?~ newName
-- @
infixr 4 ?~
(?~) :: Lens record (Maybe field) -> field -> record -> record
?~ :: forall record field.
Lens record (Maybe field) -> field -> record -> record
(?~) Lens record (Maybe field)
_lens field
f record
r = record
r record -> (record -> record) -> record
forall a b. a -> (a -> b) -> b
& Lens record (Maybe field)
_lens Lens record (Maybe field) -> Maybe field -> record -> record
forall record field. Lens record field -> field -> record -> record
.~ field -> Maybe field
forall a. a -> Maybe a
Just field
f
----------------------------------------------------------------------------
-- | Modify a field on a record by applying a function to it.
--
-- @
-- newtype Counter = Counter { _value :: Int }
--
-- value :: Lens Counter Int
-- value = lens _value $ \\counter v -> counter { _value = v }
--
-- increment :: Counter -> Counter
-- increment counter = counter & value %~ (+1)
-- @
infixr 4 %~
(%~) :: Lens record field -> (field -> field) -> record -> record
%~ :: forall record field.
Lens record field -> (field -> field) -> record -> record
(%~) Lens record field
_lens field -> field
f record
record = Lens record field -> record -> field -> record
forall record field. Lens record field -> record -> field -> record
_set Lens record field
_lens record
record (field -> record) -> field -> record
forall a b. (a -> b) -> a -> b
$ field -> field
f (record
record record -> Lens record field -> field
forall record field. record -> Lens record field -> field
^. Lens record field
_lens)
----------------------------------------------------------------------------
-- | Synonym for '(%~)'
over :: Lens record field -> (field -> field) -> record -> record
over :: forall record field.
Lens record field -> (field -> field) -> record -> record
over = Lens record field -> (field -> field) -> record -> record
forall record field.
Lens record field -> (field -> field) -> record -> record
(%~)
----------------------------------------------------------------------------
-- | Read a field from a record using a 'Lens'
--
-- @
-- newtype Person = Person { _name :: String }
--   deriving (Show, Eq)
--
-- name :: Lens Person String
-- name = lens _name $ \person n -> person { _name = n }
--
-- getName :: Person -> String
-- getName = person ^. name
-- @
infixl 8 ^.
(^.) :: record -> Lens record field -> field
^. :: forall record field. record -> Lens record field -> field
(^.) = (Lens record field -> record -> field)
-> record -> Lens record field -> field
forall a b c. (a -> b -> c) -> b -> a -> c
flip Lens record field -> record -> field
forall record field. Lens record field -> record -> field
_get
----------------------------------------------------------------------------
-- | Increment a @Num@eric field on a record using a @Lens@
--
-- @
-- newtype Person = Person { _age :: Int }
--
-- age :: Lens Person Int
-- age = lens _age $ \\person a -> person { _age = a }
--
-- birthday :: Person -> Person
-- birthday person = person & age +~ 1
-- @
infixr 4 +~
(+~) :: Num field => Lens record field -> field -> record -> record
+~ :: forall field record.
Num field =>
Lens record field -> field -> record -> record
(+~) Lens record field
_lens field
x record
record = record
record record -> (record -> record) -> record
forall a b. a -> (a -> b) -> b
& Lens record field
_lens Lens record field -> (field -> field) -> record -> record
forall record field.
Lens record field -> (field -> field) -> record -> record
%~ (field -> field -> field
forall a. Num a => a -> a -> a
+field
x)
----------------------------------------------------------------------------
-- | Multiply a @Num@eric field on a record using a @Lens@
--
-- @
-- newtype Circle = Circle { _radius :: Int }
--
-- radius :: Lens Circle Int
-- radius = lens _radius $ \\circle r -> circle { _radius = r }
--
-- expand :: Circle -> Circle
-- expand circle = circle & radius *~ 10
-- @
infixr 4 *~
(*~) :: Num field => Lens record field -> field -> record -> record
*~ :: forall field record.
Num field =>
Lens record field -> field -> record -> record
(*~) Lens record field
_lens field
x record
record = record
record record -> (record -> record) -> record
forall a b. a -> (a -> b) -> b
& Lens record field
_lens Lens record field -> (field -> field) -> record -> record
forall record field.
Lens record field -> (field -> field) -> record -> record
%~ (field -> field -> field
forall a. Num a => a -> a -> a
*field
x)
----------------------------------------------------------------------------
-- | Divide a @Fractional@ field on a record using a @Lens@
--
-- @
-- newtype Circle = Circle { _radius :: Int }
--
-- radius :: Lens Circle Int
-- radius = lens _radius $ \\circle r -> circle { _radius = r }
--
-- expand :: Circle -> Circle
-- expand circle = circle & radius *~ 10
-- @
infixr 4 //~
(//~) :: Fractional field => Lens record field -> field -> record -> record
//~ :: forall field record.
Fractional field =>
Lens record field -> field -> record -> record
(//~) Lens record field
_lens field
x record
record = record
record record -> (record -> record) -> record
forall a b. a -> (a -> b) -> b
& Lens record field
_lens Lens record field -> (field -> field) -> record -> record
forall record field.
Lens record field -> (field -> field) -> record -> record
%~ (field -> field -> field
forall a. Fractional a => a -> a -> a
/field
x)
----------------------------------------------------------------------------
-- | Increment a @Num@eric field on a record using a @Lens@
--
-- @
-- newtype Person = Person { _age :: Int }
--
-- age :: Lens Person Int
-- age = lens _age $ \\person a -> person { _age = a }
--
-- timeTravel :: Person -> Person
-- timeTravel person = person & age -~ 1
-- @
infixr 4 -~
(-~) :: Num field => Lens record field -> field -> record -> record
-~ :: forall field record.
Num field =>
Lens record field -> field -> record -> record
(-~) Lens record field
_lens field
x record
record = record
record record -> (record -> record) -> record
forall a b. a -> (a -> b) -> b
& Lens record field
_lens Lens record field -> (field -> field) -> record -> record
forall record field.
Lens record field -> (field -> field) -> record -> record
%~ field -> field -> field
forall a. Num a => a -> a -> a
subtract field
x
----------------------------------------------------------------------------
-- | Monoidally append a field in a record using a @Lens@
--
-- @
-- newtype List = List { _values :: [Int] }
--
-- values :: Lens List [Int]
-- values = lens _values $ \\l vs -> l { _values = vs }
--
-- addElement :: List -> List
-- addElement list = list & values <>~ [2]
--
-- addElement (List [])
-- -- List [2]
-- @
--
infixr 4 <>~
(<>~) :: Monoid field => Lens record field -> field -> record -> record
<>~ :: forall field record.
Monoid field =>
Lens record field -> field -> record -> record
(<>~) Lens record field
_lens field
x record
record = record
record record -> (record -> record) -> record
forall a b. a -> (a -> b) -> b
& Lens record field
_lens Lens record field -> (field -> field) -> record -> record
forall record field.
Lens record field -> (field -> field) -> record -> record
%~ (field -> field -> field
forall a. Semigroup a => a -> a -> a
<> field
x)
----------------------------------------------------------------------------
-- | Execute a monadic action in @MonadState@ that returns a field. Sets the
-- return value equal to the field in the record.
--
-- @
-- newtype List = List { _values :: [Int] }
--
-- values :: Lens List [Int]
-- values = lens _values $ \\l vs -> l { _values = vs }
--
-- addElement :: List -> List
-- addElement list = list & values <>~ [2]
-- @
infixr 2 <~
(<~) :: MonadState record m => Lens record field -> m field -> m ()
Lens record field
l <~ :: forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> m field -> m ()
<~ m field
mb = do
  b <- m field
mb
  l .= b
----------------------------------------------------------------------------
-- | Modify a record in @MonadState@ monad at a field using a @Lens@
--
-- @
-- newtype Model = Model { _value :: Int }
--
-- data Action = AddOne | SubtractOne
--
-- value :: Lens Model Int
-- value = lens _value $ \\p x -> p { _value = x }
--
-- update :: Action -> Effect Model Action
-- update AddOne = do
--   value %= (+1)
-- @
infix 4 %=
(%=) :: MonadState record m => Lens record field -> (field -> field) -> m ()
%= :: forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> (field -> field) -> m ()
(%=) Lens record field
_lens field -> field
f = (record -> record) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\record
r -> record
r record -> (record -> record) -> record
forall a b. a -> (a -> b) -> b
& Lens record field
_lens Lens record field -> (field -> field) -> record -> record
forall record field.
Lens record field -> (field -> field) -> record -> record
%~ field -> field
f)
----------------------------------------------------------------------------
-- | Synonym for '(%=)'
modifying :: MonadState record m => Lens record field -> (field -> field) -> m ()
modifying :: forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> (field -> field) -> m ()
modifying = Lens record field -> (field -> field) -> m ()
forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> (field -> field) -> m ()
(%=)
----------------------------------------------------------------------------
-- | Modify the field of a record in @MonadState@ using a @Lens@, then
-- return the newly modified field from the updated record.
--
-- @
-- import Miso.String (ms)
--
-- newtype Model = Model { _value :: Int }
--   deriving (Show)
--
-- data Action = AddOne
--
-- value :: Lens Model Int
-- value = lens _value $ \\p x -> p { _value = x }
--
-- update :: Action -> Effect Model Action
-- update AddOne = do
--   result <- value <%= (+1)
--   io $ consoleLog (ms result)
-- @
infix 4 <%=
(<%=) :: MonadState record m => Lens record field -> (field -> field) -> m field
Lens record field
l <%= :: forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> (field -> field) -> m field
<%= field -> field
f = do
  Lens record field
l Lens record field -> (field -> field) -> m ()
forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> (field -> field) -> m ()
%= field -> field
f
  Lens record field -> m field
forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> m field
use Lens record field
l
----------------------------------------------------------------------------
-- | Assign the field of a record in @MonadState@ to a value using a @Lens@
-- Return the value after assignment.
--
-- @
-- import Miso.String (ms)
--
-- newtype Model = Model { _value :: Int }
--
-- data Action = Assign Int
--
-- value :: Lens Model Int
-- value = lens _value $ \\p x -> p { _value = x }
--
-- update :: Action -> Effect Model Action
-- update (Assign x) = do
--   result <- value <.= x
--   io $ consoleLog (ms result) -- x
-- @
infix 4 <.=
(<.=) :: MonadState record m => Lens record field -> field -> m field
Lens record field
l <.= :: forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> field -> m field
<.= field
b = do
  Lens record field
l Lens record field -> field -> m ()
forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> field -> m ()
.= field
b
  field -> m field
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return field
b
----------------------------------------------------------------------------
-- | Assign the field of a record in a @MonadState@ to a value (wrapped in a 'Just')
-- using a @Lens@. Return the value after assignment.
--
-- @
-- import Miso.String (ms)
--
-- newtype Model = Model { _value :: Maybe Int }
--
-- data Action = SetValue Int
--
-- value :: Lens Model (Maybe Int)
-- value = lens _value $ \\p x -> p { _value = x }
--
-- update :: Action -> Effect Model Action
-- update (SetValue x) = do
--   result <- value <?= x
--   io $ consoleLog (ms result) -- Just 1
-- @
infix 4 <?=
(<?=) :: MonadState record m => Lens record (Maybe field) -> field -> m field
Lens record (Maybe field)
l <?= :: forall record (m :: * -> *) field.
MonadState record m =>
Lens record (Maybe field) -> field -> m field
<?= field
b = do
  Lens record (Maybe field)
l Lens record (Maybe field) -> Maybe field -> m ()
forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> field -> m ()
.= field -> Maybe field
forall a. a -> Maybe a
Just field
b
  field -> m field
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return field
b
----------------------------------------------------------------------------
-- | Assign the field of a record in a @MonadState@ to a value using a @Lens@.
-- Returns the /previous/ value, before assignment.
--
-- @
-- import Miso.String (ms)
--
-- newtype Model = Model { _value :: Int }
--   deriving (Show, Eq)
--
-- data Action = Assign Int
--   deriving (Show, Eq)
--
-- value :: Lens Model Int
-- value = lens _value $ \\p x -> p { _value = x }
--
-- update :: Action -> Effect Model Action
-- update (Assign x) = do
--   value .= x
--   previousValue <- value <<.= 1
--   io $ consoleLog $ ms previousValue -- prints value at x
-- @
infix 4 <<.=
(<<.=) :: MonadState record m => Lens record field -> field -> m field
Lens record field
l <<.= :: forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> field -> m field
<<.= field
b = do
  old <- Lens record field -> m field
forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> m field
use Lens record field
l
  l .= b
  return old
----------------------------------------------------------------------------
-- | Modifies the field of a record in @MonadState@ using a @Lens@.
-- Returns the /previous/ value, before modification.
--
-- @
-- import Miso.String (ms)
--
-- newtype Model = Model { _value :: Int }
--   deriving (Show, Eq)
--
-- data Action = Modify (Int -> Int)
--
-- value :: Lens Model Int
-- value = lens _value $ \p x -> p { _value = x }
--
-- update :: Action -> Effect Model Action
-- update (Modify f) = do
--   value .= 2
--   result <- value <<%= f
--   io $ consoleLog (ms result) -- prints previous value of 2
-- @
infix 4 <<%=
(<<%=) :: MonadState record m => Lens record field -> (field -> field) -> m field
Lens record field
l <<%= :: forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> (field -> field) -> m field
<<%= field -> field
f = do
  old <- Lens record field -> m field
forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> m field
use Lens record field
l
  l %= f
  return old
----------------------------------------------------------------------------
-- | Sets the value of a field in a record using @MonadState@ and a @Lens@
--
-- @
-- newtype Model = Model { _value :: Int }
--   deriving (Show, Eq)
--
-- data Action = SetValue Int
--
-- value :: Lens Model Int
-- value = lens _value $ \\p x -> p { _value = x }
--
-- update' :: Action -> Effect Model Action
-- update' (SetValue v) = value .= v
-- @
infix 4 .=
(.=) :: MonadState record m => Lens record field -> field -> m ()
.= :: forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> field -> m ()
(.=) Lens record field
_lens field
f = (record -> record) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\record
r -> record
r record -> (record -> record) -> record
forall a b. a -> (a -> b) -> b
& Lens record field
_lens Lens record field -> field -> record -> record
forall record field. Lens record field -> field -> record -> record
.~ field
f)
----------------------------------------------------------------------------
-- | Synonym for '(.=)'
assign :: MonadState record m => Lens record field -> field -> m ()
assign :: forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> field -> m ()
assign = Lens record field -> field -> m ()
forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> field -> m ()
(.=)
----------------------------------------------------------------------------
-- | Retrieves the value of a field in a record using a @Lens@ inside @MonadState@
--
-- @
-- import Miso.String (ms)
--
-- newtype Model = Model { _value :: Int }
--   deriving (Show, Eq)
--
-- data Action = SetValue Int
--
-- value :: Lens Model Int
-- value = lens _value $ \p x -> p { _value = x }
--
-- update :: Action -> Effect Model Action
-- update (SetValue x) = do
--   value .= x
--   result <- use value
--   io $ consoleLog (ms result) -- prints the value of 'x'
-- @
use :: MonadState record m => Lens record field -> m field
use :: forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> m field
use Lens record field
_lens = (record -> field) -> m field
forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets (record -> Lens record field -> field
forall record field. record -> Lens record field -> field
^. Lens record field
_lens)
----------------------------------------------------------------------------
-- | Sets the value of a field in a record using a @Lens@ inside a @MonadState@
-- The value is wrapped in a @Just@ before being assigned.
--
-- @
-- newtype Model = Model { _value :: Maybe Int }
--   deriving (Show, Eq)
--
-- data Action = AssignValue Int
--
-- value :: Lens Model (Maybe Int)
-- value = lens _value $ \\p x -> p { _value = x }
--
-- update :: Action -> Effect Model Action
-- update (AssignValue x) = value ?= x
-- @
infix 4 ?=
(?=) :: MonadState record m => Lens record (Maybe field) -> field -> m ()
?= :: forall record (m :: * -> *) field.
MonadState record m =>
Lens record (Maybe field) -> field -> m ()
(?=) Lens record (Maybe field)
_lens field
value = Lens record (Maybe field)
_lens Lens record (Maybe field) -> Maybe field -> m ()
forall record (m :: * -> *) field.
MonadState record m =>
Lens record field -> field -> m ()
.= field -> Maybe field
forall a. a -> Maybe a
Just field
value
----------------------------------------------------------------------------
-- | Increments the value of a @Num@eric field of a record using a @Lens@
-- inside a @State@ Monad.
--
-- @
-- newtype Model = Model { _value :: Int }
--   deriving (Show, Eq)
--
-- data Action = IncrementBy Int
--
-- value :: Lens Model Int
-- value = lens _value $ \\p x -> p { _value = x }
--
-- update :: Action -> Effect Model Action
-- update (IncrementBy x) = value += x
--
infix 4 +=
(+=) :: (MonadState record m, Num field)  => Lens record field -> field -> m ()
+= :: forall record (m :: * -> *) field.
(MonadState record m, Num field) =>
Lens record field -> field -> m ()
(+=) Lens record field
_lens field
f = (record -> record) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\record
r -> record
r record -> (record -> record) -> record
forall a b. a -> (a -> b) -> b
& Lens record field
_lens Lens record field -> field -> record -> record
forall field record.
Num field =>
Lens record field -> field -> record -> record
+~ field
f)
----------------------------------------------------------------------------
-- | Multiplies the value of a @Num@eric field of a record using a @Lens@
-- inside a @State@ Monad.
--
-- @
-- newtype Model = Model { _value :: Int }
--   deriving (Show, Eq)
--
-- data Action = MultiplyBy Int
--
-- value :: Lens Model Int
-- value = lens _value $ \\p x -> p { _value = x }
--
-- update :: Action -> Effect Model Action
-- update (MultiplyBy x) = value *= x
-- @
infix 4 *=
(*=) :: (MonadState record m, Num field)  => Lens record field -> field -> m ()
*= :: forall record (m :: * -> *) field.
(MonadState record m, Num field) =>
Lens record field -> field -> m ()
(*=) Lens record field
_lens field
f = (record -> record) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\record
r -> record
r record -> (record -> record) -> record
forall a b. a -> (a -> b) -> b
& Lens record field
_lens Lens record field -> field -> record -> record
forall field record.
Num field =>
Lens record field -> field -> record -> record
*~ field
f)
----------------------------------------------------------------------------
-- | Divides the value of a @Fractional@ field of a record using a @Lens@
-- inside a @State@ Monad.
--
-- @
-- newtype Model = Model { _value :: Double }
--   deriving (Show, Eq)
--
-- data Action = DivideBy Double
--
-- value :: Lens Model Double
-- value = lens _value $ \\p x -> p { _value = x }
--
-- update :: Action -> Effect Model Action
-- update (DivideBy x) = value //= x
-- @
infix 4 //=
(//=) :: (MonadState record m, Fractional field)  => Lens record field -> field -> m ()
//= :: forall record (m :: * -> *) field.
(MonadState record m, Fractional field) =>
Lens record field -> field -> m ()
(//=) Lens record field
_lens field
f = (record -> record) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\record
r -> record
r record -> (record -> record) -> record
forall a b. a -> (a -> b) -> b
& Lens record field
_lens Lens record field -> (field -> field) -> record -> record
forall record field.
Lens record field -> (field -> field) -> record -> record
%~ (field -> field -> field
forall a. Fractional a => a -> a -> a
/ field
f))
----------------------------------------------------------------------------
-- | Subtracts the value of a @Num@eric field of a record using a @Lens@
-- inside of a @State@ Monad.
--
-- @
-- newtype Model = Model { _value :: Double }
--   deriving (Show, Eq)
--
-- data Action = SubtractBy Double
--
-- value :: Lens Model Double
-- value = lens _value $ \\p x -> p { _value = x }
--
-- update :: Action -> Effect Model Action
-- update (SubtractBy x) = value -= x
-- @
infix 4 -=
(-=) :: (MonadState record m, Num field) => Lens record field -> field -> m ()
-= :: forall record (m :: * -> *) field.
(MonadState record m, Num field) =>
Lens record field -> field -> m ()
(-=) Lens record field
_lens field
f = (record -> record) -> m ()
forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (\record
r -> record
r record -> (record -> record) -> record
forall a b. a -> (a -> b) -> b
& Lens record field
_lens Lens record field -> field -> record -> record
forall field record.
Num field =>
Lens record field -> field -> record -> record
-~ field
f)
---------------------------------------------------------------------------------
-- | Smart constructor @lens@ function. Used to easily construct a @Lens@
--
-- > name :: Lens Person String
-- > name = lens _name $ \p n -> p { _name = n }
--
lens
  :: (record -> field)
  -> (record -> field -> record)
  -> Lens record field
lens :: forall record field.
(record -> field)
-> (record -> field -> record) -> Lens record field
lens = (record -> field)
-> (record -> field -> record) -> Lens record field
forall record field.
(record -> field)
-> (record -> field -> record) -> Lens record field
Lens
----------------------------------------------------------------------------