Skip to content

Instantly share code, notes, and snippets.

@devboy
Created November 28, 2011 01:02
Show Gist options
  • Save devboy/1398638 to your computer and use it in GitHub Desktop.
Save devboy/1398638 to your computer and use it in GitHub Desktop.
package org.devboy;
import haxe.macro.Type;
import neko.Lib;
import haxe.macro.Expr;
import haxe.macro.Context;
class Funk
{
@:macro public static function partial( expressions: Array<Expr> ): Expr
{
var pos = Context.currentPos();
function mk(e:ExprDef) return { expr: e, pos: pos };
var methodExpression = expressions.shift();
var methArgs = extractArgumentsOfMethodType( Context.typeof( methodExpression ) );
var argumentExpressions: Array<Expr> = [];
var args: Array<FunctionArg> = [];
var expression: Expr;
for ( i in 0...methArgs.length )
{
expression = (expressions.length - 1) >= i ? expressions[i] : null;
if ( expression != null && isWildcard(expression) )
{
args.push( { name: methArgs[i].name, opt: false, type: null, value: null } );
argumentExpressions.push( mk( EConst( CIdent( methArgs[i].name ) ) ) );
}
else if( expression != null && !isWildcard(expression) )
{
argumentExpressions.push( expression );
}
else
{
args.push( { name: methArgs[i].name, opt: false, type: null, value: null } );
argumentExpressions.push( mk( EConst( CIdent( methArgs[i].name ) ) ) );
}
}
return mk( EFunction( null,
{
ret: null, params: [], args: args,
expr: mk( EReturn( mk( ECall( methodExpression, argumentExpressions ))))
}
));
}
@:macro public static function curry( expressions: Array<Expr> ): Expr
{
var pos = Context.currentPos();
function mk(e:ExprDef) return { expr: e, pos: pos };
var methodExpression = expressions.length > 1 ? partial(expressions) : expressions.shift();
var methArgs = extractArgumentsOfMethodType( Context.typeof( methodExpression ) );
var lastMethodArgumentExpressions: Array<Expr> = [];
for ( arg in methArgs)
lastMethodArgumentExpressions.push( mk( EConst( CIdent( arg.name ) ) ) );
var lastMethodArgs: Array<FunctionArg> = methArgs.length > 0 ? [{ name: methArgs[methArgs.length-1].name, opt: false, type: null, value: null }] : [];
var lastMethodExpression = mk( EFunction( null,
{
ret: null, params: [], args: lastMethodArgs,
expr: mk( EReturn( mk( ECall( methodExpression, lastMethodArgumentExpressions ))))
}
));
methArgs.pop();
var chainedExpression: Expr = lastMethodExpression;
var currentArg = methArgs.pop();
while (currentArg != null)
{
chainedExpression = mk( EFunction( null,
{
ret: null, params: [], args: [{ name: currentArg.name, opt: false, type: null, value: null }],
expr: mk( EReturn( chainedExpression ))
}));
currentArg = methArgs.pop();
}
return chainedExpression;
}
private inline static function isWildcard( expression:Expr ): Bool
{
switch( expression.expr )
{
case EConst( c ):
switch( c )
{
case CIdent(s):
return s == "_";
default:
return false;
}
default:
return false;
}
}
private inline static function extractArgumentsOfMethodType( methodExpression: haxe.macro.Type ): Array<{ name : String, opt : Bool, t : Type }>
{
return switch( methodExpression )
{
case TFun(args, ret): args;
default: null;
}
}
private inline static function createExpressionDefinition( pos: Position, expressionDefinition: ExprDef )
{
return { expr: expressionDefinition, pos: pos };
}
}
package org.devboy.hxTask;
import neko.Lib;
import org.devboy.Funk;
class Main
{
static function main()
{
var func = function( x: Float, y: Float, z: Float ): Float
{
return x * y * z;
}
var curried = function(x: Float)
{
return function(y: Float)
{
return function(z: Float)
{
return func(x, y, z);
}
}
}
Lib.println( curried(2)(2)(2) ); // returns 8
var funkCurried = Funk.curry( func );
type( funkCurried );
Lib.println( funkCurried(2)(2)(2) ); // returns 8
}
}
package org.devboy.hxTask;
import neko.Lib;
import org.devboy.Funk;
class Main
{
static function main()
{
var abc = function( a, b, c ) return a + b + c;
var ac = Funk.partial( abc, _, 10, _ );
Lib.println(ac(5,15)); // returns 30
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment