tangled
alpha
login
or
join now
oeiuwq.com
/
fx.go
0
fork
atom
An Algebraic Effect System for Golang.
0
fork
atom
overview
issues
pulls
pipelines
More functional
oeiuwq.com
10 months ago
29fe1ff8
3f1c2003
+92
-135
1 changed file
expand all
collapse all
unified
split
fx.go
+92
-135
fx.go
···
1
1
package fx
2
2
3
3
-
type immediate[V any] func() V
4
4
-
type suspended[S, V any] func(S) Fx[S, V]
5
5
-
type Fx[S, V any] func() (immediate[V], suspended[S, V])
3
3
+
type Fx[S, V any] struct {
4
4
+
imm func() V
5
5
+
sus func(S) Fx[S, V]
6
6
+
hlt func()
7
7
+
}
6
8
7
9
type FxPure[V any] = Fx[Nil, V]
8
10
type FxNil = FxPure[Nil]
···
17
19
return Const[Nil](v)
18
20
}
19
21
22
22
+
func identity[V any](v V) V { return v }
23
23
+
24
24
+
func Const[S, V any](v V) Fx[S, V] {
25
25
+
return Fx[S, V]{imm: func() V { return v }}
26
26
+
}
27
27
+
28
28
+
func Pending[S, V any](f func(S) Fx[S, V]) Fx[S, V] {
29
29
+
return Fx[S, V]{sus: f}
30
30
+
}
31
31
+
20
32
func Func[S, V any](f func(S) V) Fx[S, V] {
21
21
-
return func() (immediate[V], suspended[S, V]) {
22
22
-
return nil, func(s S) Fx[S, V] {
23
23
-
return func() (immediate[V], suspended[S, V]) {
24
24
-
v := func() V { return f(s) }
25
25
-
return v, nil
26
26
-
}
27
27
-
}
28
28
-
}
33
33
+
return Pending(func(s S) Fx[S, V] { return Const[S](f(s)) })
34
34
+
}
35
35
+
36
36
+
func Apply[F ~func(I) O, I, O any](i I) Fx[F, O] {
37
37
+
return Map(Ctx[F](), func(f F) O { return f(i) })
29
38
}
30
39
31
40
func Ctx[V any]() Fx[V, V] {
32
32
-
return Func(func(v V) V { return v })
41
41
+
return Func(identity[V])
33
42
}
34
43
35
44
// An effect that will never be continued.
36
45
func Halt[S, V any]() Fx[S, V] {
37
37
-
return nil
46
46
+
return Fx[S, V]{hlt: func() {}}
38
47
}
39
48
40
49
// Replace with y if x is already Halted. Otherwise x continues.
41
50
func Replace[S, V any](y func() Fx[S, V]) func(Fx[S, V]) Fx[S, V] {
42
51
return func(x Fx[S, V]) Fx[S, V] {
43
43
-
if x == nil {
52
52
+
if x.hlt != nil {
44
53
return y()
45
54
}
46
46
-
imm, sus := x()
47
47
-
if imm != nil {
48
48
-
return Const[S](imm())
49
49
-
}
50
50
-
return func() (immediate[V], suspended[S, V]) {
51
51
-
return nil, func(s S) Fx[S, V] {
52
52
-
return Replace(y)(sus(s))
53
53
-
}
55
55
+
if x.imm != nil {
56
56
+
return Const[S](x.imm())
54
57
}
58
58
+
return Pending(func(s S) Fx[S, V] { return Replace(y)(x.sus(s)) })
55
59
}
56
60
}
57
61
58
58
-
func cont[T, U, S, V any](r func(T) S, f func(immediate[V]) Fx[T, U]) func(Fx[S, V]) Fx[T, U] {
62
62
+
// Continue an effect by transforming its immediate value into another effect.
63
63
+
func Cont[T, U, S, V any](cmap func(T) S, fmap func(V) Fx[T, U]) func(Fx[S, V]) Fx[T, U] {
59
64
return func(e Fx[S, V]) Fx[T, U] {
60
60
-
if e == nil {
61
61
-
return nil
62
62
-
}
63
63
-
imm, sus := e()
64
64
-
if imm != nil {
65
65
-
return f(imm)
65
65
+
if e.hlt != nil {
66
66
+
return Halt[T, U]()
66
67
}
67
67
-
return func() (immediate[U], suspended[T, U]) {
68
68
-
return nil, func(t T) Fx[T, U] {
69
69
-
return cont(r, f)(sus(r(t)))
70
70
-
}
68
68
+
if e.imm != nil {
69
69
+
return fmap(e.imm())
71
70
}
71
71
+
return Pending(func(t T) Fx[T, U] { return Cont(cmap, fmap)(e.sus(cmap(t))) })
72
72
}
73
73
}
74
74
75
75
type And[A, B any] func() (A, B)
76
76
77
77
+
func rswap[A, B any](ba And[B, A]) And[A, B] {
78
78
+
var ab And[A, B] = func() (A, B) {
79
79
+
b, a := ba()
80
80
+
return a, b
81
81
+
}
82
82
+
return ab
83
83
+
}
84
84
+
85
85
+
func left[A, B any](ab And[A, B]) A {
86
86
+
a, _ := ab()
87
87
+
return a
88
88
+
}
89
89
+
90
90
+
func right[A, B any](ab And[A, B]) B {
91
91
+
_, b := ab()
92
92
+
return b
93
93
+
}
94
94
+
77
95
func ContraMap[V, S, R any](f func(R) S) func(Fx[S, V]) Fx[R, V] {
78
96
return func(e Fx[S, V]) Fx[R, V] {
79
79
-
if e == nil {
80
80
-
return nil
97
97
+
if e.hlt != nil {
98
98
+
return Halt[R, V]()
81
99
}
82
82
-
imm, sus := e()
83
83
-
if imm != nil {
84
84
-
return Const[R](imm())
85
85
-
}
86
86
-
return func() (immediate[V], suspended[R, V]) {
87
87
-
return nil, func(r R) Fx[R, V] {
88
88
-
s := f(r)
89
89
-
return ContraMap[V](f)(sus(s))
90
90
-
}
100
100
+
if e.imm != nil {
101
101
+
return Const[R](e.imm())
91
102
}
103
103
+
return Pending(func(r R) Fx[R, V] {
104
104
+
return ContraMap[V](f)(e.sus(f(r)))
105
105
+
})
92
106
}
93
107
}
94
108
95
109
func MapM[S, U, V any](f func(U) Fx[S, V]) func(Fx[S, U]) Fx[S, V] {
96
96
-
id := func(s S) S { return s }
97
97
-
return cont(id, func(u immediate[U]) Fx[S, V] {
98
98
-
v := f(u())
99
99
-
return cont(id, func(v immediate[V]) Fx[S, V] {
100
100
-
return Const[S](v())
101
101
-
})(v)
102
102
-
})
110
110
+
return FlatCont(identity, identity, f)
103
111
}
104
112
105
105
-
func MapT[S, V, U any](f func(V) U) func(Fx[S, V]) Fx[S, U] {
106
106
-
return MapM(func(v V) Fx[S, U] {
107
107
-
u := f(v)
108
108
-
return Const[S](u)
109
109
-
})
113
113
+
func MapH[S, V, U any](f func(V) U) func(Fx[S, V]) Fx[S, U] {
114
114
+
return MapM(func(v V) Fx[S, U] { return Const[S](f(v)) })
110
115
}
111
116
112
117
func Map[S, V, U any](e Fx[S, V], f func(V) U) Fx[S, U] {
113
113
-
return MapT[S](f)(e)
118
118
+
return MapH[S](f)(e)
114
119
}
115
120
116
121
func FlatMap[A, U, B, V any](e Fx[A, U], f func(U) Fx[B, V]) Fx[And[A, B], V] {
117
117
-
return FlatMapT[A](f)(e)
122
122
+
return FlatMapH[A](f)(e)
123
123
+
}
124
124
+
125
125
+
func FlatMapH[A, U, B, V any](f func(U) Fx[B, V]) func(Fx[A, U]) Fx[And[A, B], V] {
126
126
+
return FlatCont[And[A, B]](left, right, f)
118
127
}
119
128
120
120
-
func FlatMapT[A, U, B, V any](f func(U) Fx[B, V]) func(Fx[A, U]) Fx[And[A, B], V] {
121
121
-
a := func(ab And[A, B]) A {
122
122
-
a, _ := ab()
123
123
-
return a
124
124
-
}
125
125
-
b := func(ab And[A, B]) B {
126
126
-
_, b := ab()
127
127
-
return b
128
128
-
}
129
129
-
return cont(a, func(u immediate[U]) Fx[And[A, B], V] {
130
130
-
return cont(b, func(v immediate[V]) Fx[And[A, B], V] {
131
131
-
return Const[And[A, B]](v())
132
132
-
})(f(u()))
133
133
-
})
129
129
+
func FlatCont[N, A, U, B, V any](amap func(N) A, bmap func(N) B, fmap func(U) Fx[B, V]) func(Fx[A, U]) Fx[N, V] {
130
130
+
return Cont(amap, func(u U) Fx[N, V] { return Cont(bmap, Const[N, V])(fmap(u)) })
134
131
}
135
132
136
133
func AndNil[S, V any](e Fx[S, V]) Fx[And[S, Nil], V] {
137
137
-
fst := func(n And[S, Nil]) S {
138
138
-
s, _ := n()
139
139
-
return s
140
140
-
}
141
141
-
return cont(fst, func(v immediate[V]) Fx[And[S, Nil], V] {
142
142
-
return Const[And[S, Nil]](v())
143
143
-
})(e)
134
134
+
return Cont[And[S, Nil], V](left, Const)(e)
144
135
}
145
136
146
137
func AndSwap[A, B, V any](e Fx[And[A, B], V]) Fx[And[B, A], V] {
147
147
-
swp := func(ba And[B, A]) And[A, B] {
148
148
-
var ab And[A, B] = func() (A, B) {
149
149
-
b, a := ba()
150
150
-
return a, b
151
151
-
}
152
152
-
return ab
153
153
-
}
154
154
-
return cont(swp, func(v immediate[V]) Fx[And[B, A], V] {
155
155
-
return Const[And[B, A]](v())
156
156
-
})(e)
138
138
+
return Cont[And[B, A], V](rswap, Const)(e)
157
139
}
158
140
159
141
func AndJoin[A, B, V any](e Fx[A, Fx[B, V]]) Fx[And[A, B], V] {
160
160
-
return FlatMap(e, func(f Fx[B, V]) Fx[B, V] { return f })
142
142
+
return FlatMap(e, identity)
161
143
}
162
144
163
145
func AndDisjoin[A, B, V any](e Fx[And[A, B], V]) Fx[A, Fx[B, V]] {
164
164
-
return func() (immediate[Fx[B, V]], suspended[A, Fx[B, V]]) {
165
165
-
return nil, func(a A) Fx[A, Fx[B, V]] {
166
166
-
x := ProvideLeft(e, a)
167
167
-
return Const[A](x)
168
168
-
}
169
169
-
}
146
146
+
return Pending(func(a A) Fx[A, Fx[B, V]] { return Const[A](ProvideLeft(e, a)) })
170
147
}
171
148
172
149
func AndCollapse[A, V any](e Fx[And[A, A], V]) Fx[A, V] {
173
173
-
return func() (immediate[V], suspended[A, V]) {
174
174
-
return nil, func(a A) Fx[A, V] {
175
175
-
return ProvideLeft(e, a)
176
176
-
}
177
177
-
}
150
150
+
return Pending(func(a A) Fx[A, V] { return ProvideLeft(e, a) })
178
151
}
179
152
180
153
func ProvideFirstLeft[A, B, C, V any](e Fx[And[And[A, C], B], V], a A) Fx[And[C, B], V] {
···
202
175
}
203
176
204
177
func ProvideLeft[A, B, V any](e Fx[And[A, B], V], a A) Fx[B, V] {
205
205
-
if e == nil {
206
206
-
return nil
178
178
+
if e.hlt != nil {
179
179
+
return Halt[B, V]()
207
180
}
208
208
-
imm, sus := e()
209
209
-
if imm != nil {
210
210
-
return Const[B](imm())
181
181
+
if e.imm != nil {
182
182
+
return Const[B](e.imm())
211
183
}
212
212
-
return func() (immediate[V], suspended[B, V]) {
213
213
-
return nil, func(b B) Fx[B, V] {
214
214
-
var ab And[A, B] = func() (A, B) { return a, b }
215
215
-
for {
216
216
-
e = sus(ab)
217
217
-
if e == nil {
218
218
-
return nil
219
219
-
}
220
220
-
imm, sus = e()
221
221
-
if imm != nil {
222
222
-
return Const[B](imm())
223
223
-
}
184
184
+
return Pending(func(b B) Fx[B, V] {
185
185
+
var ab And[A, B] = func() (A, B) { return a, b }
186
186
+
for {
187
187
+
e = e.sus(ab)
188
188
+
if e.hlt != nil {
189
189
+
return Halt[B, V]()
190
190
+
}
191
191
+
if e.imm != nil {
192
192
+
return Const[B](e.imm())
224
193
}
225
194
}
226
226
-
}
227
227
-
}
228
228
-
229
229
-
func Apply[F ~func(I) O, I, O any](i I) Fx[F, O] {
230
230
-
return Map(Ctx[F](), func(f F) O { return f(i) })
231
231
-
}
232
232
-
233
233
-
func Const[S, V any](v V) Fx[S, V] {
234
234
-
return func() (immediate[V], suspended[S, V]) {
235
235
-
return func() V { return v }, nil
236
236
-
}
195
195
+
})
237
196
}
238
197
239
198
func Suspend[A ~func(I) Fx[B, O], B, I, O any](i I) Fx[And[A, B], O] {
···
250
209
251
210
func Eval[V any](e Fx[Nil, V]) V {
252
211
for {
253
253
-
if e == nil {
212
212
+
if e.hlt != nil {
254
213
panic("tried to evaluate halted effect. try using fx.Replace with another effect.")
255
214
}
256
256
-
imm, sus := e()
257
257
-
if imm != nil {
258
258
-
v := imm()
259
259
-
return v
215
215
+
if e.imm != nil {
216
216
+
return e.imm()
260
217
}
261
261
-
e = sus(PNil)
218
218
+
e = e.sus(PNil)
262
219
}
263
220
}