Created
August 5, 2012 16:32
-
-
Save frabbit/3265763 to your computer and use it in GitHub Desktop.
This file contains 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
// two special types to fake type constructor ploymorphism. | |
@:native('Dynamic') | |
class Of<M,A> {} | |
class In {} | |
interface Functor<F> | |
{ | |
public function map<A,B>(val:Of<F,A>, f:A->B):Of<F,B>; | |
} | |
class ArrayFunctor implements Functor<Array<In>> | |
{ | |
public function new () {} | |
override public function map<A,B>(of:Of<Array<In>,A>, f:A->B):Of<Array<In>,B> { | |
//... | |
} | |
} | |
// special types for imclit conversions and implicit objects | |
typedef IConv<A,B> = { implicitFrom : A, implicitTo : B->Void }; | |
typedef IObj<A> = A->Void; | |
class ArrayMonadImplicitObj | |
{ | |
public static var monad(default, null) = new ArrayOfMonad(); | |
// imnplicitObj is by convention and used in the macro | |
public static inline function implicitObj <T>(_:IObj<Monad<Array<T>>>):Monad<Array<In>> | |
{ | |
return monad; | |
} | |
} | |
class ArrayToArrayOfConv | |
{ | |
public static inline function implicit <T>(_:IConv<Array<T>, ArrayOf<T>>, a:Array<T>) | |
{ | |
return cast a; | |
} | |
} | |
class Functors { | |
public static function map<B,C>(of:Of<M, B>, f:B->C, functor:Functor<M>):Of<M,B> { | |
return functor.map(of, f); | |
} | |
} | |
// this is where the magic happens | |
class Implicits { | |
public static function apply (f:Expr, params:Array<Expr>) { | |
var c = macro f.curry(); // we have a function from the first to the second type | |
for (p in numArgsOfF) | |
{ | |
if (we have a param at this position) | |
{ | |
var needed = macro c.thunk() // we now have a function of type Of<F,A> -> Void | |
var check = Context.typeof( macro needed($p) ); // check if it can be applied directly to the param | |
var resultingExpr = null; // the resulting expr | |
if (check) resultingExpr = p; // it doesn't, we need a conversion | |
else | |
{ | |
// search implicit conversion | |
var conversionTuple = macro { implicitFrom : param[0], implicitTo : needed }; // generated a special type, faking a little bit of multiple dispatch | |
var convExpr = macro conversionTuple.implicit(); | |
if (Context.typeof(convExpr)) resultingExpr = convExpr; // it works | |
else throw "cannot find a conversion" | |
} | |
} else { | |
// search implicit object | |
// same as conversion tuple with one difference | |
// if there is an implicit object it may need dependecies and as such it's a function | |
// how do we get these dependencies | |
// ah i see, we have this function already ;) | |
resultingExpr = ... | |
} | |
res.push(resultingExpr); | |
c = macro $c($resultingExpr).curry(); // apply the current expression and move on | |
} | |
return macro $f($[res]); | |
} | |
} | |
class Identity | |
{ | |
@:macro public static function map <M,A,B>(e:Expr, f:Expr):Expr | |
{ | |
return Implicits.apply(macro Functors.map, [e,f]); | |
} | |
} | |
using ArrayToArrayOfConv; | |
using ArrayMonadImplicitObj; | |
using Identity; | |
class MyClass { | |
public function main () { | |
[1,2,3].map(function (x) return x + 1); | |
// becomes Identity.map([1,2,3], function (x) return x+1); | |
// becomes Functors.map(ArrayToArrayOfConv.implicit([1,2,3]), ArrayMonadImplicitObj.implicitObj()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment