An Algebraic Effect System for Golang.

More functional

+92 -135
+92 -135
fx.go
··· 1 1 package fx 2 2 3 - type immediate[V any] func() V 4 - type suspended[S, V any] func(S) Fx[S, V] 5 - type Fx[S, V any] func() (immediate[V], suspended[S, V]) 3 + type Fx[S, V any] struct { 4 + imm func() V 5 + sus func(S) Fx[S, V] 6 + hlt func() 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 + func identity[V any](v V) V { return v } 23 + 24 + func Const[S, V any](v V) Fx[S, V] { 25 + return Fx[S, V]{imm: func() V { return v }} 26 + } 27 + 28 + func Pending[S, V any](f func(S) Fx[S, V]) Fx[S, V] { 29 + return Fx[S, V]{sus: f} 30 + } 31 + 20 32 func Func[S, V any](f func(S) V) Fx[S, V] { 21 - return func() (immediate[V], suspended[S, V]) { 22 - return nil, func(s S) Fx[S, V] { 23 - return func() (immediate[V], suspended[S, V]) { 24 - v := func() V { return f(s) } 25 - return v, nil 26 - } 27 - } 28 - } 33 + return Pending(func(s S) Fx[S, V] { return Const[S](f(s)) }) 34 + } 35 + 36 + func Apply[F ~func(I) O, I, O any](i I) Fx[F, O] { 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 - return Func(func(v V) V { return v }) 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 - return nil 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 - if x == nil { 52 + if x.hlt != nil { 44 53 return y() 45 54 } 46 - imm, sus := x() 47 - if imm != nil { 48 - return Const[S](imm()) 49 - } 50 - return func() (immediate[V], suspended[S, V]) { 51 - return nil, func(s S) Fx[S, V] { 52 - return Replace(y)(sus(s)) 53 - } 55 + if x.imm != nil { 56 + return Const[S](x.imm()) 54 57 } 58 + return Pending(func(s S) Fx[S, V] { return Replace(y)(x.sus(s)) }) 55 59 } 56 60 } 57 61 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 + // Continue an effect by transforming its immediate value into another effect. 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 - if e == nil { 61 - return nil 62 - } 63 - imm, sus := e() 64 - if imm != nil { 65 - return f(imm) 65 + if e.hlt != nil { 66 + return Halt[T, U]() 66 67 } 67 - return func() (immediate[U], suspended[T, U]) { 68 - return nil, func(t T) Fx[T, U] { 69 - return cont(r, f)(sus(r(t))) 70 - } 68 + if e.imm != nil { 69 + return fmap(e.imm()) 71 70 } 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 + func rswap[A, B any](ba And[B, A]) And[A, B] { 78 + var ab And[A, B] = func() (A, B) { 79 + b, a := ba() 80 + return a, b 81 + } 82 + return ab 83 + } 84 + 85 + func left[A, B any](ab And[A, B]) A { 86 + a, _ := ab() 87 + return a 88 + } 89 + 90 + func right[A, B any](ab And[A, B]) B { 91 + _, b := ab() 92 + return b 93 + } 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 - if e == nil { 80 - return nil 97 + if e.hlt != nil { 98 + return Halt[R, V]() 81 99 } 82 - imm, sus := e() 83 - if imm != nil { 84 - return Const[R](imm()) 85 - } 86 - return func() (immediate[V], suspended[R, V]) { 87 - return nil, func(r R) Fx[R, V] { 88 - s := f(r) 89 - return ContraMap[V](f)(sus(s)) 90 - } 100 + if e.imm != nil { 101 + return Const[R](e.imm()) 91 102 } 103 + return Pending(func(r R) Fx[R, V] { 104 + return ContraMap[V](f)(e.sus(f(r))) 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 - id := func(s S) S { return s } 97 - return cont(id, func(u immediate[U]) Fx[S, V] { 98 - v := f(u()) 99 - return cont(id, func(v immediate[V]) Fx[S, V] { 100 - return Const[S](v()) 101 - })(v) 102 - }) 110 + return FlatCont(identity, identity, f) 103 111 } 104 112 105 - func MapT[S, V, U any](f func(V) U) func(Fx[S, V]) Fx[S, U] { 106 - return MapM(func(v V) Fx[S, U] { 107 - u := f(v) 108 - return Const[S](u) 109 - }) 113 + func MapH[S, V, U any](f func(V) U) func(Fx[S, V]) Fx[S, U] { 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 - return MapT[S](f)(e) 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 - return FlatMapT[A](f)(e) 122 + return FlatMapH[A](f)(e) 123 + } 124 + 125 + func FlatMapH[A, U, B, V any](f func(U) Fx[B, V]) func(Fx[A, U]) Fx[And[A, B], V] { 126 + return FlatCont[And[A, B]](left, right, f) 118 127 } 119 128 120 - func FlatMapT[A, U, B, V any](f func(U) Fx[B, V]) func(Fx[A, U]) Fx[And[A, B], V] { 121 - a := func(ab And[A, B]) A { 122 - a, _ := ab() 123 - return a 124 - } 125 - b := func(ab And[A, B]) B { 126 - _, b := ab() 127 - return b 128 - } 129 - return cont(a, func(u immediate[U]) Fx[And[A, B], V] { 130 - return cont(b, func(v immediate[V]) Fx[And[A, B], V] { 131 - return Const[And[A, B]](v()) 132 - })(f(u())) 133 - }) 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 + 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 - fst := func(n And[S, Nil]) S { 138 - s, _ := n() 139 - return s 140 - } 141 - return cont(fst, func(v immediate[V]) Fx[And[S, Nil], V] { 142 - return Const[And[S, Nil]](v()) 143 - })(e) 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 - swp := func(ba And[B, A]) And[A, B] { 148 - var ab And[A, B] = func() (A, B) { 149 - b, a := ba() 150 - return a, b 151 - } 152 - return ab 153 - } 154 - return cont(swp, func(v immediate[V]) Fx[And[B, A], V] { 155 - return Const[And[B, A]](v()) 156 - })(e) 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 - return FlatMap(e, func(f Fx[B, V]) Fx[B, V] { return f }) 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 - return func() (immediate[Fx[B, V]], suspended[A, Fx[B, V]]) { 165 - return nil, func(a A) Fx[A, Fx[B, V]] { 166 - x := ProvideLeft(e, a) 167 - return Const[A](x) 168 - } 169 - } 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 - return func() (immediate[V], suspended[A, V]) { 174 - return nil, func(a A) Fx[A, V] { 175 - return ProvideLeft(e, a) 176 - } 177 - } 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 - if e == nil { 206 - return nil 178 + if e.hlt != nil { 179 + return Halt[B, V]() 207 180 } 208 - imm, sus := e() 209 - if imm != nil { 210 - return Const[B](imm()) 181 + if e.imm != nil { 182 + return Const[B](e.imm()) 211 183 } 212 - return func() (immediate[V], suspended[B, V]) { 213 - return nil, func(b B) Fx[B, V] { 214 - var ab And[A, B] = func() (A, B) { return a, b } 215 - for { 216 - e = sus(ab) 217 - if e == nil { 218 - return nil 219 - } 220 - imm, sus = e() 221 - if imm != nil { 222 - return Const[B](imm()) 223 - } 184 + return Pending(func(b B) Fx[B, V] { 185 + var ab And[A, B] = func() (A, B) { return a, b } 186 + for { 187 + e = e.sus(ab) 188 + if e.hlt != nil { 189 + return Halt[B, V]() 190 + } 191 + if e.imm != nil { 192 + return Const[B](e.imm()) 224 193 } 225 194 } 226 - } 227 - } 228 - 229 - func Apply[F ~func(I) O, I, O any](i I) Fx[F, O] { 230 - return Map(Ctx[F](), func(f F) O { return f(i) }) 231 - } 232 - 233 - func Const[S, V any](v V) Fx[S, V] { 234 - return func() (immediate[V], suspended[S, V]) { 235 - return func() V { return v }, nil 236 - } 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 - if e == nil { 212 + if e.hlt != nil { 254 213 panic("tried to evaluate halted effect. try using fx.Replace with another effect.") 255 214 } 256 - imm, sus := e() 257 - if imm != nil { 258 - v := imm() 259 - return v 215 + if e.imm != nil { 216 + return e.imm() 260 217 } 261 - e = sus(PNil) 218 + e = e.sus(PNil) 262 219 } 263 220 }