aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/function/state.lux
blob: edca1d81bca921087782520d7be97b61c58ed2ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
(;module:
  lux
  (lux (control functor
                ["A" applicative #*]
                ["M" monad #*])))

## [Types]
(type: #export (State s a)
  {#;doc "Stateful computations."}
  (-> s [s a]))

## [Structures]
(struct: #export Functor<State> (All [s] (Functor (State s)))
  (def: (map f ma)
    (lambda [state]
      (let [[state' a] (ma state)]
        [state' (f a)]))))

(struct: #export Applicative<State> (All [s] (Applicative (State s)))
  (def: functor Functor<State>)

  (def: (wrap a)
    (lambda [state]
      [state a]))

  (def: (apply ff fa)
    (lambda [state]
      (let [[state' f] (ff state)
            [state'' a] (fa state')]
        [state'' (f a)]))))

(struct: #export Monad<State> (All [s] (Monad (State s)))
  (def: applicative Applicative<State>)

  (def: (join mma)
    (lambda [state]
      (let [[state' ma] (mma state)]
        (ma state')))))

## [Values]
(def: #export get
  {#;doc "Read the current state."}
  (All [s] (State s s))
  (lambda [state]
    [state state]))

(def: #export (put new-state)
  {#;doc "Set the new state."}
  (All [s] (-> s (State s Unit)))
  (lambda [state]
    [new-state []]))

(def: #export (update change)
  {#;doc "Compute the new state."}
  (All [s] (-> (-> s s) (State s Unit)))
  (lambda [state]
    [(change state) []]))

(def: #export (use user)
  {#;doc "Run function on current state."}
  (All [s a] (-> (-> s a) (State s a)))
  (lambda [state]
    [state (user state)]))

(def: #export (local change action)
  {#;doc "Run computation with a locally-modified state."}
  (All [s a] (-> (-> s s) (State s a) (State s a)))
  (lambda [state]
    (let [[state' output] (action (change state))]
      [state output])))

(def: #export (run state action)
  {#;doc "Run a stateful computation."}
  (All [s a] (-> s (State s a) [s a]))
  (action state))

(struct: (Functor<StateT> Functor<M>)
  (All [M s] (-> (Functor M) (Functor (All [a] (-> s (M [s a]))))))
  (def: (map f sfa)
    (lambda [state]
      (:: Functor<M> map (lambda [[s a]] [s (f a)])
          (sfa state)))))

(struct: (Applicative<StateT> Monad<M>)
  (All [M s] (-> (Monad M) (Applicative (All [a] (-> s (M [s a]))))))
  (def: functor (Functor<StateT> (:: Monad<M> functor)))

  (def: (wrap a)
    (lambda [state]
      (:: Monad<M> wrap [state a])))

  (def: (apply sFf sFa)
    (lambda [state]
      (do Monad<M>
        [[state f] (sFf state)
         [state a] (sFa state)]
        (wrap [state (f a)])))))

(type: #export (State' M s a)
  {#;doc "Stateful computations decorated by a monad."}
  (-> s (M [s a])))

(def: #export (run' state action)
  {#;doc "Run a stateful computation decorated by a monad."}
  (All [M s a] (-> s (State' M s a) (M [s a])))
  (action state))

(struct: #export (StateT Monad<M>)
  {#;doc "A monad transformer to create composite stateful computations."}
  (All [M s] (-> (Monad M) (Monad (State' M s))))
  (def: applicative (Applicative<StateT> Monad<M>))
  (def: (join sMsMa)
    (lambda [state]
      (do Monad<M>
        [[state' sMa] (sMsMa state)]
        (sMa state')))))

(def: #export (lift-state Monad<M> ma)
  {#;doc "Lift monadic values to the State' wrapper."}
  (All [M s a] (-> (Monad M) (M a) (State' M s a)))
  (lambda [state]
    (do Monad<M>
      [a ma]
      (wrap [state a]))))