Created
April 29, 2017 22:28
-
-
Save bkase/064f3a72eb4d6a11d8e723edc6b6157d to your computer and use it in GitHub Desktop.
Effectful programming with callbacks
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
/* | |
* 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 | |
* see http://swift.sandbox.bluemix.net/#/repl/5905133f4ee0cd258050b0a4 | |
* 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