Skip to content

Instantly share code, notes, and snippets.

@fponticelli
Last active April 11, 2017 02:34
Show Gist options
  • Save fponticelli/1c6530f1b853ba9f44e12ce29463417c to your computer and use it in GitHub Desktop.
Save fponticelli/1c6530f1b853ba9f44e12ce29463417c to your computer and use it in GitHub Desktop.
Free Monad in Haxe
using thx.Functions;
import thx.Unit;
import thx.promise.Promise;
using Actions;
enum Action<A> {
Move(x: Float, y: Float): Action<Unit>; // output
Feed(x: Float, y: Float): Action<Unit>;
ReadPosition: Action<Position>;
PromptPosition: Action<Position>; // input
Home: Action<Unit>;
}
typedef Position = { x: Float, y: Float }
class Actions {
public static function move(x: Float, y: Float): ActionFree<Unit>
return coyo(Move(x, y));
public static function feed(x: Float, y: Float): ActionFree<Unit>
return coyo(Feed(x, y));
public static function home(): ActionFree<Unit>
return coyo(Home);
public static function readPosition<A>(): ActionFree<Position>
return coyo(ReadPosition);
public static function promptPosition<A>(): ActionFree<Position>
return coyo(PromptPosition);
public static function map<A, B>(act: CoyoAction<A>, f: A -> B): CoyoAction<B>
return switch act {
case Coyoneda(m, ff): Coyoneda(m, f.compose(ff));
};
public static function flatMap<A, B>(actf: ActionFree<A>, f: A -> ActionFree<B>): ActionFree<B> {
return switch actf {
case Pure(a):
f(a);
case Free(act):
Free(map(act, function(actf: ActionFree<A>): ActionFree<B> return flatMap(actf, f)));
}
};
static function coyo<A>(v: Action<A>): ActionFree<A>
return Free(Coyoneda(v, Pure));
static function main() {
var move110 =
home()
.flatMap(function(_) return feed(5, 8))
.flatMap(function(_) return readPosition())
.flatMap(function(p: Position) return move(p.x * 2, p.y * 3))
.flatMap(function(_) return promptPosition())
.flatMap(function(p: Position) return move(p.x + 1, p.y + 10))
.flatMap(function(_) return home());
Interpreter.run(move110, { x: 0.0, y: 0.0, last: "nops" });
}
}
class Interpreter {
public static function run<T>(prog: ActionFree<T>, curPosition: { x: Float, y: Float, last: String }): Promise<T> {
trace(curPosition);
function go<A, B>(action: Action<A>, f: A -> ActionFree<B>): Promise<B> {
return switch action {
case Move(x, y):
run(f(unit), { x: curPosition.x + x, y: curPosition.y + y, last: "move" });
case Feed(x, y):
run(f(unit), { x: curPosition.x + x, y: curPosition.y + y, last: "feed" });
case ReadPosition:
run(f(curPosition), { x: curPosition.x, y: curPosition.y, last: "read"});
case PromptPosition:
Promise.create(function(resolve, reject) {
var rl = js.node.Readline.createInterface({
input: js.Node.process.stdin,
output: js.Node.process.stdout
});
rl.question("type a couple of numbers\n> ", function(d) {
var p = d.split(",").map(StringTools.trim).map(Std.parseFloat);
resolve(p);
rl.close();
});
}).flatMap(function(xs: Array<Float>) {
var newpos = { x: xs[0], y: xs[1] };
return run(f(newpos), { x: curPosition.x, y: curPosition.y, last: "prompt"});
});
case Home:
run(f(unit), {x: 0, y: 0, last: "home"});
};
}
return switch prog {
case Pure(v):
Promise.value(v);
case Free(cont):
switch cont {
case Coyoneda(base, f):
go(base, f);
}
};
}
}
enum CoyoAction<A> {
Coyoneda<B>(base: Action<B>, f: B -> A): CoyoAction<A>;
}
enum ActionFree<A> {
Pure(a: A);
Free(act: CoyoAction<ActionFree<A>>);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment