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
stop
oeiuwq.com
10 months ago
f017f47f
d6811eb4
+33
-23
1 changed file
expand all
collapse all
unified
split
fx.go
+33
-23
fx.go
···
1
1
package fx
2
2
3
3
type Fx[S, V any] struct {
4
4
+
// an immediate value
4
5
imm func() V
6
6
+
// the continuation of a suspended effect
5
7
sus func(S) Fx[S, V]
6
6
-
stp func() Fx[S, V]
8
8
+
// the resume function of an stopped effect
9
9
+
res func() Fx[S, V]
7
10
}
8
11
9
12
type FxPure[V any] = Fx[Nil, V]
···
29
32
30
33
func Ctx[V any]() Fx[V, V] { return Func(identity[V]) }
31
34
32
32
-
// An stopped effect that panics if restarted
35
35
+
// An stopped effect that panics if resumed
33
36
func Halt[S, V any]() Fx[S, V] {
34
37
return Stop(func() Fx[S, V] {
35
35
-
panic("tried to restart halted effect. try using fx.Replace instead")
38
38
+
return Fx[S, V]{
39
39
+
imm: func() V {
40
40
+
panic("tried to Resume a halted effect. try using Replace instead")
41
41
+
},
42
42
+
}
36
43
})
37
44
}
38
45
39
39
-
func Stop[S, V any](f func() Fx[S, V]) Fx[S, V] { return Fx[S, V]{stp: f} }
46
46
+
// Creates an stopped effect from a resume function
47
47
+
func Stop[S, V any](e func() Fx[S, V]) Fx[S, V] {
48
48
+
return Fx[S, V]{res: e}
49
49
+
}
40
50
41
41
-
// Replace with y if x is already stopped. Otherwise x continues.
51
51
+
// Resume an effect if it was previously stopped.
52
52
+
func Resume[S, V any](e Fx[S, V]) Fx[S, V] {
53
53
+
if e.res != nil {
54
54
+
return e.res()
55
55
+
}
56
56
+
return e
57
57
+
}
58
58
+
59
59
+
// Replace with y if x is already Halted. Otherwise x continues.
42
60
func Replace[S, V any](y func() Fx[S, V]) func(Fx[S, V]) Fx[S, V] {
43
61
return func(x Fx[S, V]) Fx[S, V] {
44
44
-
if x.stp != nil {
62
62
+
if x.res != nil {
45
63
return y()
46
64
}
47
65
if x.imm != nil {
···
54
72
// Continue an effect by transforming its immediate value into another effect.
55
73
func Then[T, U, S, V any](cmap func(T) S, fmap func(V) Fx[T, U]) func(Fx[S, V]) Fx[T, U] {
56
74
return func(e Fx[S, V]) Fx[T, U] {
57
57
-
if e.stp != nil {
58
58
-
return Stop(func() Fx[T, U] {
59
59
-
return Then(cmap, fmap)(e.stp())
60
60
-
})
75
75
+
if e.res != nil {
76
76
+
return Stop(func() Fx[T, U] { return Then(cmap, fmap)(e.res()) })
61
77
}
62
78
if e.imm != nil {
63
79
return fmap(e.imm())
···
88
104
89
105
func ContraMap[V, S, R any](f func(R) S) func(Fx[S, V]) Fx[R, V] {
90
106
return func(e Fx[S, V]) Fx[R, V] {
91
91
-
if e.stp != nil {
92
92
-
return Stop(func() Fx[R, V] {
93
93
-
return ContraMap[V](f)(e.stp())
94
94
-
})
107
107
+
if e.res != nil {
108
108
+
return Stop(func() Fx[R, V] { return ContraMap[V](f)(e.res()) })
95
109
}
96
110
if e.imm != nil {
97
111
return Const[R](e.imm())
···
171
185
}
172
186
173
187
func ProvideLeft[A, B, V any](e Fx[And[A, B], V], a A) Fx[B, V] {
174
174
-
if e.stp != nil {
175
175
-
return Stop(func() Fx[B, V] {
176
176
-
return ProvideLeft(e.stp(), a)
177
177
-
})
188
188
+
if e.res != nil {
189
189
+
return Stop(func() Fx[B, V] { return ProvideLeft(e.res(), a) })
178
190
}
179
191
if e.imm != nil {
180
192
return Const[B](e.imm())
···
185
197
loop = func(e Fx[And[A, B], V]) Fx[B, V] {
186
198
for {
187
199
e = e.sus(ab)
188
188
-
if e.stp != nil {
189
189
-
return Stop(func() Fx[B, V] {
190
190
-
return loop(e.stp())
191
191
-
})
200
200
+
if e.res != nil {
201
201
+
return Stop(func() Fx[B, V] { return loop(e.res()) })
192
202
}
193
203
if e.imm != nil {
194
204
return Const[B](e.imm())
···
217
227
218
228
func Eval[V any](e Fx[Nil, V]) V {
219
229
for {
220
220
-
if e.stp != nil {
230
230
+
if e.res != nil {
221
231
panic("tried to evaluate halted effect. try using fx.Replace with another effect.")
222
232
}
223
233
if e.imm != nil {