一直以来对Lisp语言怀有很崇敬的内心,《黑客与画家》对Lisp更是推崇备至,虽然看了很多有关Lisp的介绍但都没有机会去写段程序试试,就像我对C++同样,多少有点敬畏。这个周末花了很多时间来研究Lisp。
Lisp是古老的函数式语言,跟C,C++等命令式语言彻底不同的编程风格,但Lisp的方言不少,最后Lisp标准委员制定了Common Lisp,但内容很长,有1000多页,所以功能比较强大;而Lisp的另一个主要分支就是Scheme,它的标准内容只有不到100页,因此很是简单,适合学术研究和大学计算机语言教学以及通常的工程应用。目前Lisp有在JVM上的实现,在.NET上的实现就是 IronScheme,因而我便开始选择了IronScheme做为Lisp研究的第一站。html
IronScheme在Codeplex上有开源项目, https://ironscheme.codeplex.com/ ,能够下载它的源码和编译好的程序,在 https://ironscheme.codeplex.com/SourceControl/latest 能够下载源码,我下载时候的文件名是 ironscheme-103684,下载的源码能够用VS2008打开。若是没有开发环境,直接用 debugbuild.bat 也就能够直接编译。另外还能够直接运行测试 r6rstest.batlinux
在网站上下载IronScheme的应用程序后,能够直接看到它已经提供了不一样环境下的控制台程序,分别有64位与32位,.NET 2.0与4.0的程序: IronScheme.Console32-v2.exe IronScheme.Console32-v4.exe IronScheme.Console-v2.exe IronScheme.Console-v4.exesql
找一个合适的控制台运行下,输入几个Lisp表达式看看: 编程
Lisp程序有一个自然的执行多个参数运算的特色,因此咱们能够执行多个数字相加。也可使用 display 函数显示一个字符串。架构
写一个简单的Hello 程序文件来加载 试试:框架
执行这个程序,成功 ,可是乱码,不论是存储成 ANSI格式仍是UTF8格式均乱码:函数
无奈,只有打开IronScheme源码进行分析,分析了好久好久....学习
最后干脆直接搜索编码格式 Encoding...,好歹涉及这个关键词的地方只有3个:测试
在 IronScheme.Console 项目下的 Program 文件中,找到下面的代码:字体
Encoding oo = Console.OutputEncoding; EnableMulticoreJIT(); try { //Console.OutputEncoding = Encoding.UTF8; return IronSchemeConsoleHost.Execute(args); } finally { Console.OutputEncoding = oo; }
将原来的 Console.OutputEncoding = Encoding.UTF8 注释便可,因为个人电脑是中文环境,这样程序便以GBK的编码运行了,此时便可正常显示Scheme 程序中的 汉字。可是,若是要加载的文件名有汉字,则悲剧了,控制台没法输入汉字...
再次检查程序中全部跟控制台有关的编码的地方,发现除了前面检查过的编码问题,再也没有其它地方,最后跟踪调试代码,发现程序使用
Console.ReadKey()
方法来获取屏幕输入的,而这个方法,是没法得到中文输入的...%&*....
既然是截获了键盘敲击,那么我就顶一个特殊的键,按下它在弹窗出来一个窗口,在里面输入中文就能够了吧,因而找到文件 SuperConsole.cs ,找到 Insert(ConsoleKeyInfo key) 方法,修改为下面的代码:
private void Insert(ConsoleKeyInfo key) { char c; if (key.Key == ConsoleKey.F6) { Debug.Assert(FinalLineText.Length == 1); c = FinalLineText[0]; } else if (key.Modifiers == ConsoleModifiers.Alt && (key.Key >= ConsoleKey.NumPad0 && key.Key <= ConsoleKey.NumPad9)) { c = '?'; } else { c = key.KeyChar; } //Ctrl+Z 输入汉字 if (key.Key == ConsoleKey.Z && key.Modifiers == ConsoleModifiers.Control) { frmInputString frm = new frmInputString(); frm.Activate(); frm.ShowDialog(); //Console.Write(frm.Text); string s = frm.Text; _input.Append(s); Output.Write(s); _rendered += s.Length; _current += s.Length; } else { Insert(c); } }
这样就能够在Scheme控制台弹窗输入中文了,顺便加入文件选择功能,方便加载程序文件,如图:
控制台默认的字体是 “点阵字体”,这种字体在输入中文后,Scheme 定位字符位置会有问题,应该使用非点阵字体,例如以下图的设置(控制台窗口标题--属性--字体):
按照 做者官方的说法,IronScheme是能够签入在.NET应用程序里面的,可是单独执行Scheme程序的时候,是否能够调用 .net已有的程序呢?这个IronScheme也提供了,下面是 https://ironscheme.codeplex.com/wikipage?title=clr-syntax&referringTitle=Documentation 页面的内容:
These macro's are exported from the (ironscheme clr) library.
type is either:
(clr-namespaces) Returns all the imported at the lexical scope
(clr-reference reference) reference can be a symbol for the assembly short name (ie System.Web) or a string containing the fully qualified assembly name.
(clr-using namespace) namespace is a symbol. Eg System.IO .
(clr-call type method instance arg ...) method is a symbol for a simple name, eg ToInt32 or a string to resolve specific methods, eg "ToInt32(Object)" . instance is a reference to the object of type . Can be null ('()) for static methods. arg ... is the arguments passed to the method.
(clr-cast type expr) expr is the instance to be cast.
(clr-is type expr) expr is the instance to be tested.
(clr-new type arg ...) arg ... is the arguments passed to the constructor.
(clr-new-array type size) size is the size of the array. Must be an integer.
(clr-event-add! type event instance handler) event is a symbol for the name of the event. Eg Click . instance is a reference to the object of type . Can be null ('()) for static events. handler is a procedure taking the same number of arguments as the event's delegate.
(clr-event-remove! type event instance handler) event is a symbol for the name of the event. Eg Click . instance is a reference to the object of type . Can be null ('()) for static events. handler is a procedure taking the same number of arguments as the event's delegate.
(clr-field-get type field instance) field is a symbol for the name of the field. Eg m_foo . instance is a reference to the object of type . Can be null ('()) for static fields.
(clr-field-set! type field instance expr) field is a symbol for the name of the field. Eg m_foo . instance is a reference to the object of type . Can be null ('()) for static fields. expr is the value to set the field.
(pinvoke-call library method arg ...) arg ... is the arguments passed to the method.
(clr-indexer-get type instance arg ...) instance is a reference to the object of type . arg ... is the arguments passed to the indexer.
(clr-indexer-set! type instance arg ... expr) instance is a reference to the object of type . arg ... is the arguments passed to the indexer. expr is the value to set the indexer.
(clr-prop-get type property instance) property is the name of the property. Eg Height . instance is a reference to the object of type . Can be null ('()) for static properties.
(clr-prop-set! type property instance expr) property is the name of the property. Eg Height . instance is a reference to the object of type . Can be null ('()) for static properties. expr is the value to set the property.
(clr-static-call type method arg ...) method is a symbol for a simple name, eg ToInt32 or a string to resolve specific methods, eg "ToInt32(Object)" . arg ... is the arguments passed to the method.
(clr-static-event-add! type event handler) event is a symbol for the name of the event. Eg Click . handler is a procedure taking the same number of arguments as the event's delegate.
(clr-static-event-remove! type event handler) event is a symbol for the name of the event. Eg Click . handler is a procedure taking the same number of arguments as the event's delegate.
(clr-static-field-get type field) field is a symbol for the name of the field. Eg m_foo .
(clr-static-field-set! type field expr) field is a symbol for the name of the field. Eg m_foo . expr is the value to set the field.
(clr-static-prop-get type property) property is the name of the property. Eg Height .
(clr-static-prop-set! type property expr) property is the name of the property. Eg Height . expr is the value to set the property.
看来支持得还挺全面,立刻写个程序试试看:
(import (rnrs) (ironscheme clr)) ;Define a function write-ln (define (write-ln fmt . args) (clr-static-call System.Console WriteLine (clr-cast System.String fmt) (clr-cast System.Object[] (list->vector args)))) ; And invoke it! (write-ln "{0}" "Hello World!") (write-ln "1:{0}" "aaa") (write-ln "1:{0} 2:{1}" "张三" "李四")
这个程序是调用 .net的 Console.WriteLine 方法的,运行这个程序试试:
注意程序文件须要保存为 UTF8格式的,IronScheme 才能够正常显示中文。
利用 Lisp的强大表达能力,调用.net强大的类库
Scheme能够看成脚本语言,能够.net程序动态生成一个 Scheme程序,Scheme程序再调用.net。。。。 这个过程的用途,明白了吧?
好比工做流程序,调用一个Scheme 脚本..
更多的 Lisp,Scheme学习资源,能够参考下面的连接 :
Lisp 的永恒之道
http://www.oschina.net/question/28_57183
Scheme语言--简介
http://blog.csdn.net/zzulp/article/details/5547729
学习Scheme
http://blog.csdn.net/ramacess/article/details/570769
Scheme 语言概要
http://www.ibm.com/developerworks/cn/linux/l-schm/index1.html
Read access to a .NET Assembly
https://ironscheme.codeplex.com/discussions/60977
Playing with IronScheme
http://www.codeproject.com/Articles/33050/Playing-with-IronScheme
尾递归
http://blog.sina.com.cn/s/blog_3e5694650100tzqq.html
本文程序下载 “IronScheme中文版”
http://pwmis.codeplex.com/releases/view/117822
---------分界线 ----------------
欢迎使用 PDF.NET SOD 开源框架,框架追求的目标是简单与效率的平衡,体如今:代码的精简,开发、维护的简单与追求极致的运行效率。
做者简介:
本人现任职架构师,求伯乐,联系方式:http://www.pwmis.com/sqlmap