An Algebraic Effect System for Golang.

stop

+33 -23
+33 -23
fx.go
··· 1 1 package fx 2 2 3 3 type Fx[S, V any] struct { 4 + // an immediate value 4 5 imm func() V 6 + // the continuation of a suspended effect 5 7 sus func(S) Fx[S, V] 6 - stp func() Fx[S, V] 8 + // the resume function of an stopped effect 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 - // An stopped effect that panics if restarted 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 - panic("tried to restart halted effect. try using fx.Replace instead") 38 + return Fx[S, V]{ 39 + imm: func() V { 40 + panic("tried to Resume a halted effect. try using Replace instead") 41 + }, 42 + } 36 43 }) 37 44 } 38 45 39 - func Stop[S, V any](f func() Fx[S, V]) Fx[S, V] { return Fx[S, V]{stp: f} } 46 + // Creates an stopped effect from a resume function 47 + func Stop[S, V any](e func() Fx[S, V]) Fx[S, V] { 48 + return Fx[S, V]{res: e} 49 + } 40 50 41 - // Replace with y if x is already stopped. Otherwise x continues. 51 + // Resume an effect if it was previously stopped. 52 + func Resume[S, V any](e Fx[S, V]) Fx[S, V] { 53 + if e.res != nil { 54 + return e.res() 55 + } 56 + return e 57 + } 58 + 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 - if x.stp != nil { 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 - if e.stp != nil { 58 - return Stop(func() Fx[T, U] { 59 - return Then(cmap, fmap)(e.stp()) 60 - }) 75 + if e.res != nil { 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 - if e.stp != nil { 92 - return Stop(func() Fx[R, V] { 93 - return ContraMap[V](f)(e.stp()) 94 - }) 107 + if e.res != nil { 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 - if e.stp != nil { 175 - return Stop(func() Fx[B, V] { 176 - return ProvideLeft(e.stp(), a) 177 - }) 188 + if e.res != nil { 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 - if e.stp != nil { 189 - return Stop(func() Fx[B, V] { 190 - return loop(e.stp()) 191 - }) 200 + if e.res != nil { 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 - if e.stp != nil { 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 {