Skip to content

Instantly share code, notes, and snippets.

@bkase
Created January 5, 2018 06:06
Show Gist options
  • Save bkase/5563d09841b0b236ce645543929f50d2 to your computer and use it in GitHub Desktop.
Save bkase/5563d09841b0b236ce645543929f50d2 to your computer and use it in GitHub Desktop.
Callback-based Effects (ported from Swift Sandbox)
/*
* A callback-base implementation of effectful computation that defers interpretation
* until after computation is expressed (so you can inject different interpreters
* onto the same computation).
*
* The downside is the results aren't expressed as values. They are callback calls.
* You probably don't actually want to use this, but it seems interesting to think about.
*
* Inspired by "Programming with Algebraic Effects and Handlers" by
* Andrej Bauer and Matija Pretnar 2012
*
* Tested on Swift 3.1.1
* bkase @ 2017
*/
// An effectful computation
// An effect handler takes some input and a sink and performs some effect to feed the sink some output based on the input zero or more times
typealias EffectHandler<I,O> = (I, (O) -> ()) -> ()
// A callback
typealias Callback<O> = (O) -> ()
// An effectful computation needs a handler and a sink to feed output
// By binding the handler later, we can reuse the same effectful computation
// but interpret the effects differently.
struct Effectful<EffIn,EffOut,Out> {
let handle: (@escaping EffectHandler<EffIn, EffOut>) -> (Callback<Out>) -> ()
}
// Nondeterministic choice as an effect
let effectful = Effectful<[Int],Int,Int> { decide in { next in
decide([0,5,8]) { y in
decide([10,20]) { x in
next(x - y)
}
}
} }
// Choose interpreter later
let chooseFirst = effectful.handle { choices, k in k(choices[0]) }
let chooseAll = effectful.handle { choices, k in
choices.forEach{ k($0) }
}
func toStdout<T>(t: T) -> () { print("\(t)") }
print("Choose first")
chooseFirst(toStdout)
print("Choose all")
chooseAll(toStdout)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment