- 浏览: 491498 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
hypercube:
markin'
配置D语言编程环境 -
qiezi:
qiezi 写道yangyang_08 写道1 ...
我的编程语言学习经历 -
qiezi:
yangyang_08 写道1、现在如果做并发服务器,楼主选用 ...
我的编程语言学习经历 -
yangyang_08:
1、现在如果做并发服务器,楼主选用什么样的语言架构?2、lua ...
我的编程语言学习经历 -
dearplain:
我也是语言爱好者,不过我一直坚持使用c。
我的编程语言学习经历
DMD最近的版本号加入了闭包,感觉非常有用,虽然有些背后动作,不过我是实用派不介意这个。玩的时候忽然想到为什么没有lambda呢?AST还没影,不过可以利用D强大的模板可以使用字符串来先模拟一下。
我假想的语法是这样的:
上面执行的arr1结果将会是[1,4,9]。
在编写过程中发现匿名委托不能够使用模板来这样生成:
所以必须在使用的地方去mixin(如果你可以避免这个请告诉我),像这样的:
测试很长时间没有找到突破方法去掉这个mixin,所以就在这个起点上向目标前进了。
测试过程中也发现现在的模板对于字符串参数似乎不像以前那么友好了,编译期执行函数则得到了加强,所以使用它来实现:
它支持的lambda语法是这样的:
测试:
运行结果:
[3 6 9]
[1;
2;
3;
]
语法罗嗦了一些,要是有AST宏不知道是否能简化一些。。
加一个例子:
运行得到的结果是6.
对应的ruby代码:
从这个例子的注释中可以看到,lambda的参数应该用括号包起来,和参数加以区别;而单参数的lambda则应该省掉括号让它更美观,我上面的解析部分还不包括括号的解析。
这个好像是类型反推了,估计有点困难。
仔细想了一下,确实是不行,不过返回值类型确实是可以省略的。
返回值是可以省略,现在也支持,不过在D这种强类型系统里面,有时候需要明确指定返回类型来进行精确匹配,减少程序员犯错误的机会,比如:
新手很容易认为i是个char类型,实际上却是个int,所以可选的返回值类型我感觉是必要的。
这个好像是类型反推了,估计有点困难。
仔细想了一下,确实是不行,不过返回值类型确实是可以省略的。
从函数里面返回delegate在D1。0上应该也是不安全的吧。
因为这个 delegate 无法触及任何作用域以外的东西,就跟递归调用一样。
qiezi
对了,你上面这种消除mixin的手法也只有在最新的DMD上才能进行吧,这是一个闭包而不是内嵌函数或委托量。
另外改用你这个版本以后,前两个用法都能通过,第三个有点问题:
代码
1. string sep = ";\n";
2. string[] arr2 = arr.map(lambda!("string | int x -> toString(x) ~ sep"));
3. writefln(arr2);
编译无法通过,因为返回的闭包被包裹了一层,上下文已经不对了。
我的办法在 D 1.0 上也是可行的(GDC 0.24测试),附带的好处是可以防止1.0 的闭包问题,当然,定义处上下文是不能处理了。
D的delegate字面值允许省略返回值类型,所以 _RetType 也可以省掉了。
从函数里面返回delegate在D1。0上应该也是不安全的吧。
这个好像是类型反推了,估计有点困难。如何从这个委托所处的上下文获得它应该成为的类型?
qiezi
对了,你上面这种消除mixin的手法也只有在最新的DMD上才能进行吧,这是一个闭包而不是内嵌函数或委托量。
另外改用你这个版本以后,前两个用法都能通过,第三个有点问题:
代码
1. string sep = ";\n";
2. string[] arr2 = arr.map(lambda!("string | int x -> toString(x) ~ sep"));
3. writefln(arr2);
编译无法通过,因为返回的闭包被包裹了一层,上下文已经不对了。
我的办法在 D 1.0 上也是可行的(GDC 0.24测试),附带的好处是可以防止1.0 的闭包问题,当然,定义处上下文是不能处理了。
D的delegate字面值允许省略返回值类型,所以 _RetType 也可以省掉了。
这估计是不行的,语法分析阶段无法识别类型
这个是很有必要,不知道Walter打算如何实现。另外对于一些常用的匹配应该提供一些内置的名称,类似下面的TYPE/PARAM_LIST/EXPR:
还有变长部分的匹配,最好与可变参数一致。
我假想的语法是这样的:
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); }
运行结果:
引用
[3 6 9]
[1;
2;
3;
]
语法罗嗦了一些,要是有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则应该省掉括号让它更美观,我上面的解析部分还不包括括号的解析。
评论
15 楼
qiezi
2007-11-10
oldrev 写道
引用
这个好像是类型反推了,估计有点困难。
仔细想了一下,确实是不行,不过返回值类型确实是可以省略的。
返回值是可以省略,现在也支持,不过在D这种强类型系统里面,有时候需要明确指定返回类型来进行精确匹配,减少程序员犯错误的机会,比如:
char c = 'a'; auto i = c & 0xff; writefln(typeid(typeof(i)));
新手很容易认为i是个char类型,实际上却是个int,所以可选的返回值类型我感觉是必要的。
14 楼
oldrev
2007-11-10
引用
这个好像是类型反推了,估计有点困难。
仔细想了一下,确实是不行,不过返回值类型确实是可以省略的。
引用
从函数里面返回delegate在D1。0上应该也是不安全的吧。
因为这个 delegate 无法触及任何作用域以外的东西,就跟递归调用一样。
13 楼
qiezi
2007-11-10
oldrev 写道
引用
qiezi
对了,你上面这种消除mixin的手法也只有在最新的DMD上才能进行吧,这是一个闭包而不是内嵌函数或委托量。
另外改用你这个版本以后,前两个用法都能通过,第三个有点问题:
代码
1. string sep = ";\n";
2. string[] arr2 = arr.map(lambda!("string | int x -> toString(x) ~ sep"));
3. writefln(arr2);
编译无法通过,因为返回的闭包被包裹了一层,上下文已经不对了。
我的办法在 D 1.0 上也是可行的(GDC 0.24测试),附带的好处是可以防止1.0 的闭包问题,当然,定义处上下文是不能处理了。
D的delegate字面值允许省略返回值类型,所以 _RetType 也可以省掉了。
从函数里面返回delegate在D1。0上应该也是不安全的吧。
12 楼
qiezi
2007-11-10
oldrev 写道
可不可以再改进一下,允许省略参数类型和返回值类型,做到:
"x -> x*x"
"x -> x*x"
这个好像是类型反推了,估计有点困难。如何从这个委托所处的上下文获得它应该成为的类型?
11 楼
oldrev
2007-11-10
引用
qiezi
对了,你上面这种消除mixin的手法也只有在最新的DMD上才能进行吧,这是一个闭包而不是内嵌函数或委托量。
另外改用你这个版本以后,前两个用法都能通过,第三个有点问题:
代码
1. string sep = ";\n";
2. string[] arr2 = arr.map(lambda!("string | int x -> toString(x) ~ sep"));
3. writefln(arr2);
编译无法通过,因为返回的闭包被包裹了一层,上下文已经不对了。
我的办法在 D 1.0 上也是可行的(GDC 0.24测试),附带的好处是可以防止1.0 的闭包问题,当然,定义处上下文是不能处理了。
D的delegate字面值允许省略返回值类型,所以 _RetType 也可以省掉了。
10 楼
oldrev
2007-11-10
可不可以再改进一下,允许省略参数类型和返回值类型,做到:
"x -> x*x"
"x -> x*x"
9 楼
qiezi
2007-11-10
修改了一下,现在支持这种用法:
"|" 在 "->" 后面。
int[] arr = [1,2,3]; int result = arr.inject(0, mixin(lambda("int r, int c -> r | c"))); writefln(result);
"|" 在 "->" 后面。
8 楼
oldrev
2007-11-10
引用
# // 匹配 int | int x, int y -> x * y
# macro(TYPE, "|", PARAM_LIST, "->", EXPR)
# macro(TYPE, "|", PARAM_LIST, "->", EXPR)
这估计是不行的,语法分析阶段无法识别类型
7 楼
qiezi
2007-11-10
对了,你上面这种消除mixin的手法也只有在最新的DMD上才能进行吧,这是一个闭包而不是内嵌函数或委托量。
另外改用你这个版本以后,前两个用法都能通过,第三个有点问题:
编译无法通过,因为返回的闭包被包裹了一层,上下文已经不对了。
另外改用你这个版本以后,前两个用法都能通过,第三个有点问题:
string sep = ";\n"; string[] arr2 = arr.map(lambda!("string | int x -> toString(x) ~ sep")); writefln(arr2);
编译无法通过,因为返回的闭包被包裹了一层,上下文已经不对了。
6 楼
qiezi
2007-11-10
对了,这个实验的初衷是看到邮件列表中有人对比D的闭包和其它语言的闭包语法,D虽然语法也够简炼了,不过比起来还是显得罗嗦,比如:
主要是丑在大括号这部分,小括号里面包着大括号感觉很怪。
// ruby: arr = [1,2,3] total = arr.inject(0){|sum, elem| sum + elem} // D: int[] arr = [1,2,3] int total = arr.inject(0, (int sum, int elem){return sum + elem;});
主要是丑在大括号这部分,小括号里面包着大括号感觉很怪。
5 楼
qiezi
2007-11-10
oldrev 写道
貌似 AST 宏也不是很难实现,我的设想是编译器遇到 AST 宏就把它记录到一张表里,并为宏里的代码生存一棵单独的 AST。当整个程序的代码都生成 AST 以后,再对代码 AST 进行模式匹配,然后把宏体内的 AST 嫁接上去就行了。
除了 The Future of D 里的演示外,应该再往前走一步,允许无名宏:
除了 The Future of D 里的演示外,应该再往前走一步,允许无名宏:
macro("for_each", "(", value, "in", container, ")", body) { auto iter = container.begin(); for(; iter != container.end(); ++iter) { auto value = iter.value(); body; } } int[] array = [1,2,3,4,5,6]; for_each(i in array) writefln(i);
这个是很有必要,不知道Walter打算如何实现。另外对于一些常用的匹配应该提供一些内置的名称,类似下面的TYPE/PARAM_LIST/EXPR:
// 匹配 int | int x, int y -> x * y macro(TYPE, "|", PARAM_LIST, "->", EXPR) // 匹配 (int x, int y) -> x * y macro("(", PARAM_LIST, ")", "->", EXPR) // 匹配 int x -> x * x macro(PARAM_LIST, "->", EXPR)
还有变长部分的匹配,最好与可变参数一致。
4 楼
qiezi
2007-11-10
哈哈,不错!这么曲溜拐弯的。。往前走了一步。
在没有AST macro的情况下,估计也只能写成这样了。
在没有AST macro的情况下,估计也只能写成这样了。
3 楼
oldrev
2007-11-10
程序里有个错误,请把第11行的 size_t 改成 int
2 楼
oldrev
2007-11-10
当当当,经过一个半小时的努力,终于去除了 mixin!
输出:
缺点是错误检测还没做,不过这是小问题。
import std.stdio; int indexof(string s, char ch) { foreach(int i, c; s) if(c == ch) return i; return -1; } size_t 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; } template _RetType(string expr) { static if (indexof(expr, '|') == -1) const string _RetType = ""; else const string _RetType = expr[0..indexof(expr, '|')]; } template _ArgTypes(string expr) { const string _ArgTypes = expr[indexof(expr, '|') + 1 .. indexof(expr, "->")]; } template _Body(string expr) { const string _Body = expr[indexof(expr, "->") + 2 .. $]; } template _LambdaLiteral(string expr) { const string _LambdaLiteral = "delegate " ~ _RetType!(expr) ~ "(" ~ _ArgTypes!(expr) ~ "){return (" ~ _Body!(expr) ~ ");}"; } template lambda(string expr) { typeof(mixin(_LambdaLiteral!(expr))) lambda() { return mixin(_LambdaLiteral!(expr)); } } 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, lambda!("int sum, int elem -> sum + elem")); writefln(total); }
输出:
6
缺点是错误检测还没做,不过这是小问题。
1 楼
oldrev
2007-11-10
貌似 AST 宏也不是很难实现,我的设想是编译器遇到 AST 宏就把它记录到一张表里,并为宏里的代码生存一棵单独的 AST。当整个程序的代码都生成 AST 以后,再对代码 AST 进行模式匹配,然后把宏体内的 AST 嫁接上去就行了。
除了 The Future of D 里的演示外,应该再往前走一步,允许无名宏:
除了 The Future of D 里的演示外,应该再往前走一步,允许无名宏:
macro("for_each", "(", value, "in", container, ")", body) { auto iter = container.begin(); for(; iter != container.end(); ++iter) { auto value = iter.value(); body; } } int[] array = [1,2,3,4,5,6]; for_each(i in array) writefln(i);
发表评论
-
D语言模板和编译期执行
2012-07-29 00:15 0D语言模板继承了C++模板的基本用法,在其上做了相当多扩充,近 ... -
Generator
2008-04-09 13:46 1974几种并发编程模型开销(从大到小): Process > ... -
像Erlang一样写D程序
2007-09-15 10:23 6696琢磨了好久,一直没时间来做它。在讨论这个问题的时候就已经有这想 ... -
[D语言] qsort的尴尬
2007-05-06 21:31 5039phobos里面在stc.c.stdlib里提供了qsort, ... -
强类型数值计算
2007-04-10 21:45 4669以前曾经讨论过使用typedef来完成强类型的数值计算,最终遇 ... -
简单的单元测试框架
2007-04-10 21:20 3114做了个简单的单元测试框架,只算个毛坯,遇到一些问题。 1、由 ... -
仿STL的vector,写了一组array操作方法。
2007-04-05 23:55 11941文档从MSDN抄过来的,稍稍改了一下。 module ar ... -
编译期执行的效率
2007-03-15 15:58 4180写了一个编译期执行的fibonacci模板: templ ... -
D语言编译期生成和编译期执行技术
2007-02-24 14:35 4092借助D语言新的mixin表达式,可以完成一些代码生成功能,比如 ... -
如何获得一个方法的名字?
2007-01-15 19:24 3455在D语言中,一个方法你可以得到它的指针(函数指针或委托),但不 ... -
D语言的函数编程
2007-01-07 11:17 3816前阵子论坛上有人问我D语言做函数编程怎样,老实说我没怎么想过这 ... -
D语言和python的差异
2007-01-07 10:12 6509这2个语言的比较怪怪的,我最近转换了一些twisted的源文件 ... -
从简单测试看D数组内存分配策略
2007-01-07 09:43 3196D语言动态数组可以在运行期改变大小,这和C++的vector相 ... -
DMD 0.178发布
2006-12-24 15:32 4559What's New for D 0.178 ... -
GDC 0.20发布
2006-12-17 14:35 2759引用 * Updated to DMD 0.177 * Fix ... -
DMD 0.177发布
2006-12-09 18:47 2240没什么亮点,BUG修复得也不多,BUG数量始终保持在250-2 ... -
DMD 0.176发布
2006-12-03 14:22 3027引用 What's New for D 0.176 Dec ... -
D语言的成员函数模板
2006-12-02 20:29 3039DMD 0.166 特性列表中有一条: * ncorp ... -
D语言 在栈上分配对象 以及 无需GC拖管对象
2006-11-28 13:18 2763一、栈上分配对象 C++可以轻易实现在栈上和堆上分配对象,例 ... -
打算把twisted移植到D语言上
2006-11-26 20:14 4173twisted是一个优秀的python网络开发库,以前用它做过 ...
相关推荐
Stream、Lambda表达式练习.doc
AWS Lambda开发指南,由亚马逊提供,提供基本Lambda的开发教程以及对AWS的详细讲解。2018年版。
通过多个示例详细演示了.Net中C#语言lambda表达式的基本用法,主要包括三个方面内容: 1.什么是lambda表达式 2.理解lambda表达式 3.使用lambda表达式
lambda-filter.html
资源分类:Python库 所属语言:Python 资源全名:mypy-boto3-lambda-1.17.104.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
c++ C++_lambda闭包函数.pdf
python库。 资源全名:aws-cdk.aws-lambda-1.32.2.tar.gz
api-lambda-app.iml
python库。 资源全名:mini_lambda-1.2.1.tar.gz
开源项目-aws-aws-lambda-go.zip,aws/aws-lambda-go
python库。 资源全名:aws-cdk.aws-lambda-1.6.1.tar.gz
python库。 资源全名:aws-cdk.aws-lambda-1.1.0.tar.gz
python库。 资源全名:aws-cdk.aws-lambda-1.25.0.tar.gz
python库。 资源全名:mypy-boto3-lambda-1.17.58.0.tar.gz
python库。 资源全名:mypy-boto3-lambda-1.17.72.tar.gz
资源来自pypi官网。 资源全名:aws_lambda-1.0.0.tar.gz
2_Lambda表达式.zip2_Lambda表达式.zip2_Lambda表达式.zip
内部类&Lambda&API.md