Created
February 7, 2020 23:08
-
-
Save 71/8e4f0798137862a07b37e4e080be0ab7 to your computer and use it in GitHub Desktop.
Trying to implement algebraic effects in Go.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Inspired by https://github.com/ocamllabs/ocaml-effects-tutorial | |
// | |
// Goroutines can be implemented using effects, and, as it turns | |
// out, effects can be implemented using Goroutines. | |
// It does require an explicit `context.Context` argument, though. | |
// | |
// Note: The following code is a quick and dirty experiment. It | |
// is not efficient, and probably leaks memory. | |
package main | |
import ( | |
"fmt" | |
"context" | |
) | |
type Continuation func(x interface{}) | |
type Handler func(k Continuation, args ...interface{}) | |
type eff struct { | |
ch chan interface{} | |
handler Handler | |
} | |
func Perform(ctx context.Context, effectType interface{}, values ...interface{}) interface{} { | |
effectObj := ctx.Value(effectType).(eff) | |
go func() { | |
effectObj.handler(func(x interface{}) { | |
effectObj.ch <- x | |
}, values...) | |
}() | |
return <-effectObj.ch | |
} | |
func WithHandler(ctx context.Context, effectType interface{}, handler Handler) context.Context { | |
ch := make(chan interface{}) | |
return context.WithValue(ctx, effectType, eff{ch, handler}) | |
} | |
type get struct {} | |
type put struct {} | |
var ( | |
getEffect = &get{} | |
putEffect = &put{} | |
) | |
func GetState(ctx context.Context) interface{} { | |
return Perform(ctx, getEffect) | |
} | |
func PutState(ctx context.Context, x interface{}) { | |
Perform(ctx, putEffect, x) | |
} | |
func WithState(ctx context.Context, state interface{}) context.Context { | |
ctx = WithHandler(ctx, getEffect, func(k Continuation, _ ...interface{}) { | |
k(state) | |
}) | |
ctx = WithHandler(ctx, putEffect, func(k Continuation, args ...interface{}) { | |
state = args[0] | |
k(nil) | |
}) | |
return ctx | |
} | |
func main() { | |
ctx := WithState(context.Background(), 5) | |
fmt.Println("State:", GetState(ctx)) | |
PutState(ctx, 10) | |
fmt.Println("State:", GetState(ctx)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment