0 | module Monocle.Setter
 1 |
 2 | import Control.Monad.State
 3 | import Data.Contravariant
 4 | import Data.SnocList
 5 | import Monocle.Fold
 6 |
 7 | %default total
 8 |
 9 | ||| A Setter allows us to update zero or more values in a
10 | ||| larger data type.
11 | |||
12 | ||| Possible examples include updating single record fields, mapping
13 | ||| a function over the values in a `List` (or any other `Functor`),
14 | ||| or converting the characters in a string.
15 | |||
16 | ||| A Setter is parameterized over four parameters, because in general
17 | ||| we could not only update a value but also its type with an updating
18 | ||| function. Consider Setter `io`, where `s` corresponds to `IO a` and
19 | ||| `t` corresponds to `IO b`. Accordingly, if we have a function from
20 | ||| `a` to `b`, we can convert an `IO a` to an `IO b`.
21 | public export
22 | record Setter s t a b where
23 |   constructor S
24 |   over_ : (a -> b) -> s -> t
25 |
26 | ||| Convenience alias for monomorphic setters, which do not allow
27 | ||| us to change the value and source types.
28 | public export
29 | 0 Setter' : (s,a : Type) -> Type
30 | Setter' s a = Setter s s a a
31 |
32 | --------------------------------------------------------------------------------
33 | --          Interface
34 | --------------------------------------------------------------------------------
35 |
36 | ||| Interface for converting other optics to setters. With the exception
37 | ||| of Fold and Getter, all optics in this library have an implementation
38 | ||| of `ToSetter`.
39 | public export
40 | interface ToSetter (0 o : Type -> Type -> Type -> Type -> Type) where
41 |   toSetter : o s t a b -> Setter s t a b
42 |
43 | public export %inline
44 | ToSetter Setter where toSetter = id
45 |
46 | --------------------------------------------------------------------------------
47 | --          Utilities
48 | --------------------------------------------------------------------------------
49 |
50 | ||| Use a Setter to update the data stored in a source value.
51 | public export %inline
52 | over : ToSetter o => o s t a b -> (a -> b) -> s -> t
53 | over f = over_ (toSetter f)
54 |
55 | ||| Use a Setter to set the data stored in a source value.
56 | public export %inline
57 | set : ToSetter o => o s t a b -> b -> s -> t
58 | set f = over (toSetter f) . const
59 |
60 | ||| Sequential composition of setters.
61 | public export %inline
62 | (~>) : Setter s t a b -> Setter a b c d -> Setter s t c d
63 | S f ~> S g = S $ f . g
64 |
65 | --------------------------------------------------------------------------------
66 | --          Predefined Setters
67 | --------------------------------------------------------------------------------
68 |
69 | ||| Every `Functor` gives rise to a polymorphic Setter via `map`.
70 | public export %inline
71 | map_ : Functor f => Setter (f a) (f b) a b
72 | map_ = S map
73 |
74 | ||| Every contravariant functor gives rise to a polymorphic Setter via
75 | ||| `contramap`.
76 | public export %inline
77 | contramap_ : Contravariant f => Setter (f a) (f b) b a
78 | contramap_ = S contramap
79 |
80 | --------------------------------------------------------------------------------
81 | --          State
82 | --------------------------------------------------------------------------------
83 |
84 | ||| Modify the current state with a setter
85 | export %inline
86 | overST : Monad m => ToSetter o => o s s a a -> (a -> a) -> StateT s m ()
87 | overST s f = modify (over s f)
88 |
89 | ||| Modify the current state with a setter
90 | export %inline
91 | setST : Monad m => ToSetter o => o s s a a -> a -> StateT s m ()
92 | setST s = overST s . const
93 |