Some experimentation with .NET 4.0 dynamic keyword in C#.
using System;
using System.Dynamic;
using System.Linq.Expressions;
using IronScheme.Runtime;
namespace IronScheme.Dynamic
{
static class DynamicExtensions
{
public static dynamic EvalDynamic(this string expr)
{
var r = expr.Replace("_", "-").Eval();
if (r is Callable)
{
return new SchemeProcedure { Value = r };
}
else
{
return r;
}
}
}
public sealed class SchemeEnvironment : IDynamicMetaObjectProvider
{
public DynamicMetaObject GetMetaObject(Expression expr)
{
return new SchemeEnvironmentMetaObject(expr, this);
}
}
class SchemeEnvironmentMetaObject : DynamicMetaObject
{
public SchemeEnvironmentMetaObject(Expression expr, SchemeEnvironment value)
: base(expr, BindingRestrictions.Empty, value)
{
}
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
var expr = Expression.Call(typeof(DynamicExtensions),
"EvalDynamic", null, Expression.Constant(binder.Name));
return new DynamicMetaObject(expr,
BindingRestrictions.GetTypeRestriction(Expression, typeof(SchemeEnvironment)));
}
}
class SchemeProcedure : IDynamicMetaObjectProvider
{
public DynamicMetaObject GetMetaObject(Expression expr)
{
return new SchemeProcedureMetaObject(expr, Value);
}
public object Value { get; set; }
}
class SchemeProcedureMetaObject : DynamicMetaObject
{
public SchemeProcedureMetaObject(Expression expr, object value)
: base(expr, BindingRestrictions.Empty, value)
{
}
public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args)
{
var meth = typeof(Callable).GetMethod("Call", Array.ConvertAll(args, x => typeof(object)));
var nargs = Array.ConvertAll(args,
x => Expression.Convert(
Expression.Constant(
x.Value is Delegate ?
((Delegate)x.Value).ToSchemeProcedure() :
x.Value),
typeof(object)));
var call = Expression.Call(Expression.Constant(Value), meth, nargs);
return new DynamicMetaObject(call,
BindingRestrictions.GetTypeRestriction(Expression, typeof(SchemeProcedure)), Value);
}
}
}
class Program
{
static dynamic Scheme = new SchemeEnvironment();
static void Main(string[] args)
{
var list = Scheme.list;
var map = Scheme.map;
var reverse = Scheme.reverse;
Func<int, int> f = x => x * x;
var r = map(f, reverse(map(f, list(1, 2, 3))));
Console.WriteLine(r.car); // prints 81
}
}