lambda之路...

DMD最近的版本号加入了闭包,感觉非常有用,虽然有些背后动作,不过我是实用派不介意这个。玩的时候忽然想到为什么没有lambda呢?AST还没影,不过可以利用D强大的模板可以使用字符串来先模拟一下。

我假想的语法是这样的:

int[] arr = [1,2,3];
int[] arr1 = arr.map(lambda!("int x -> x * x"));


上面执行的arr1结果将会是[1,4,9]。

在编写过程中发现匿名委托不能够使用模板来这样生成:

template labmda(string expr)
{
auto lambda = mixin("(int x){return (x);}");
}

所以必须在使用的地方去mixin(如果你可以避免这个请告诉我),像这样的:


int[] arr1 = arr.map(mixin("(int x){return (x);}"));

测试很长时间没有找到突破方法去掉这个mixin,所以就在这个起点上向目标前进了。

测试过程中也发现现在的模板对于字符串参数似乎不像以前那么友好了,编译期执行函数则得到了加强,所以使用它来实现:

int indexof(string s, char ch)
{
foreach(i, c; s)
if(c == ch)
return i;
return -1;
}

int indexof(string s, string sub)
{
for(int i=0; i<s.length-sub.length; i++)
{
if (s[i..i+sub.length] == sub)
return i;
}
return -1;
}

string _RetType(string expr)
{
int end = indexof(expr, '|');
if (end == -1)
return "";
else
{
int end1 = indexof(expr, "->");
assert(end1 > 0, "'->' not found in lambda expression: " ~ expr);

if (end > end1) return "";

return expr[0..end];
}
}

string _ArgTypes(string expr)
{
int start = indexof(expr, '|');

int end = indexof(expr, "->");
assert(end > 0, "'->' not found in lambda expression: " ~ expr);

if (start > end) start = -1;

return expr[start+1 .. end];
}

string _Body(string expr)
{
int start = indexof(expr, "->");
assert(start > 0 && start<expr.length-1, "'->' not found in lambda expression: " ~ expr);

return expr[start+2 .. $];
}

string lambda(string expr)
{
return
"delegate " ~ _RetType(expr) ~
"(" ~ _ArgTypes(expr) ~ "){return (" ~
_Body(expr) ~ ");}";
}

它支持的lambda语法是这样的:

//参数列表 -> 表达式:
int x -> x
int x, int y -> x * y

//返回值 | 参数列表 -> 表达式:
string | int x -> toString(x)

测试:

T[] map(T,T1)(T1[] arr, T delegate(T1) dg)
{
T[] result;
result.length = arr.length;
foreach(i, v; arr)
result[i] = dg(v);
return result;
}

void main()
{
int[] arr = [1,2,3];
// int[] arr1 = arr.map(int x -> x * x);
int[] arr1 = arr.map(mixin(lambda("int x -> x * x")));
writefln(arr1);

string sep = ";\n";
string[] arr2 = arr.map(mixin(lambda("string | int x -> toString(x) ~ sep")));
writefln(arr2);
}

运行结果:
[quote]
[3 6 9]
[1;
2;
3;
]
[/quote]
语法罗嗦了一些,要是有AST宏不知道是否能简化一些。。

加一个例子:

T1 inject(T,T1)(T[] arr, T1 init, T1 delegate(T1, T) dg)
{
T1 value = init;
foreach(e; arr)
value = dg(value, e);
return value;
}

void main()
{
int[] arr = [1,2,3];

// int total = arr.inject(0, (int sum, int elem) -> sum + elem);
int total = arr.inject(0, mixin(lambda("int sum, int elem -> sum + elem")));
writefln(total);
}


运行得到的结果是6.

对应的ruby代码:

total = [1,2,3].inject(0){|sum, elem| sum + elem}


从这个例子的注释中可以看到,lambda的参数应该用括号包起来,和参数加以区别;而单参数的lambda则应该省掉括号让它更美观,我上面的解析部分还不包括括号的解析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值