IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    [原]Clojure CLR 入门

    ligaorenvip发表于 2014-01-01 16:21:05
    love 0

    看过"黑客与画家"之后,你是不是对Lisp心动不已?然后翻了几页ACL(Ansi Common Lisp)又望而却步?叹息:如果有一天可以再.Net CLR 上写Lisp代码那就好了!这一天已经来了,这就是Clojure CLR.看语言转换矩阵, Clojure的寄生能力超强,这方面甚至超过javascript.在CLR上有一席之地不足为怪.

    既然是入门,就必须回答下面几个问题:
    • 怎么安装?怎么运行REPL?
    • 使用什么IDE编写Clojure?
    • 如何编译clj文件?
    • Clojure CLR 与 Clojure JVM 有什么区别?
    • Clojure 如何调用 C#?
    • C# 如何调用Clojure?
    • Clojure如何调用.net WinForm ?

    安装

    这第一步就不是太顺利,如果你从Github上( https://github.com/clojure/clojure-clr ) 下载了代码编译的时候,你可能遇到特别多的问题,比如一开始你会发现lib文件夹中并没有项目依赖的Microsoft.Dynamic.dll和Microsoft.Scripting.dll.这个问题不大,只要到 http://dlr.codeplex.com/ 下载一份就可以了(下载解压拷贝等若干步骤省略),通过这个问题其实也可以知道Clojure CLR是构建在Microsoft's Dynamic Language Runtime (DLR)之上的.
    解决了引用的问题,紧接着就是编译项目,你可能会看到下面这个错误信息:
    Error 16 The command ""D:\Code\clojure-clr-master\bin\4.0\Debug\Clojure.Compile.exe" clojure.core clojure.core.protocols clojure.main clojure.set clojure.zip clojure.walk clojure.stacktrace clojure.template clojure.test clojure.test.tap clojure.test.junit clojure.pprint clojure.clr.io clojure.repl clojure.clr.shell clojure.string clojure.data clojure.reflect" exited with code 1. Clojure.Compile

    与其这样,我的选择是:直接用编译好的二进制包,不要在Clojure的门口逡巡太久.下载地址: https://github.com/clojure/clojure-clr/wiki/Getting-binaries http://sourceforge.net/projects/clojureclr/files/

    运行REPL

    解压之后的目录里面只有一个带Clojure图标的Clojure.Main.exe,双击它,一个崭新的世界就来了:
    复制代码
    Clojure 1.4.1
    user=> (+ 1 2)
    3
    user=> (println "hello world")
    hello world
    nil
    user=>
    复制代码

      

    如果你真的按照我上面一步一步来操作了,走到这里你可能会问:你是怎么把上面的文字拷贝出来的?Clojure.Main.exe是一个.net的Console Application,在界面鼠标上选中操作是不能直接使用的,我们可以先单击应用左上角的图标,出来编辑菜单,可以选择"select all",然后回车即可完成复制.还是截图来看看这个略显扯淡的操作方式:

    Clojure IDE

    不必专门找Clojure CLR的IDE,只要是Clojure的IDE都可以拿来用.备选方案有:Eclipse插件,Light Table,Vim插件,Emac 等等,按照自己的口味自己选吧,下面Stackoverflow上的讨论基本上包含了呼声比较高的几个Clojure IDE:
    http://stackoverflow.com/questions/463776/clojure-ide-on-windows

    编译

    编写下面的文件hello.clj
    (ns hello)
    (println "hello world" 2013)
    命令行完成编译:
    C:\Clojure-CLR 1.4>Clojure.Compile.exe hello
    Compiling hello to .hello world 2013
    -- 415 milliseconds.
    编译完成之后就会生成hello.clj.dll文件,拖入Reflector里面看看生成的代码是什么样子,注意下面的0x7ddL就是常量2013:
    复制代码
    public class __Init__
    {
        // Fields
        protected internal static Var const__0;
        protected internal static AFn const__1;
        protected internal static Var const__2;
        protected internal static object const__3;
    
        // Methods
        static __Init__()
        {
            try
            {
                Compiler.PushNS();
                __static_ctor_helper_constants();
            }
            finally
            {
                Var.popThreadBindings();
            }
        }
    
        private static void __static_ctor_helper_constants()
        {
            const__0 = RT.var("clojure.core", "in-ns");
            const__1 = Symbol.intern(null, "hello");
            const__2 = RT.var("clojure.core", "println");
            const__3 = 0x7ddL;
        }
    
        public static void Initialize()
        {
            ((IFn) const__0.getRawRoot()).invoke(const__1);
            ((IFn) new hello$loading__16463__auto____5()).invoke();
            ((IFn) const__2.getRawRoot()).invoke("hello world", const__3);
        }
    }
    复制代码

      


    Clojure CLR 与 Clojure JVM 有什么区别?

    Clojure CLR项目的目标:

    -- Implement a feature-complete Clojure on top of CLR/DLR.
    -- Stay as close as possible to the JVM implementation.
    -- Have some fun.
    基础不同必然有差异,比如 https://github.com/richhickey/clojure-clr/wiki/Completing-CLR-interop

    Clojure 调用 C#

    CLR interop is essentially the same as JVM interop. However, we have to make a number of extensions to allow for parts of the CLR object model that are not in the JVM.
    https://github.com/richhickey/clojure-clr/wiki/CLR-Interop
    复制代码
    user=> (System.Console/WriteLine "Now we use Console Writeline")
    Now we use Console Writeline
    nil
     
     ;;读写文件
    user=> (def file (System.IO.StreamWriter. "test.txt"))
    #'user/file
    user=> (.WriteLine file "===Hello Clojure ===")
    nil
    user=> (.Close file)
    nil
    user=> (println (slurp "test.txt"))
    WARNING: (slurp f enc) is deprecated, use (slurp f :encoding enc).
    ===Hello Clojure ===
    
    nil
    user=>
    复制代码

      

    我们把抓取Web页面的代码翻译成Clojure:
    C#:
    System.Net.WebClient webClient= new System.Net.WebClient();
    byte[] bResponse = webClient.DownloadData("http://www.baidu.com");
    Console.WriteLine(Encoding.UTF8.GetString(bResponse));

      

    Clojure:
    (import (System.Net WebClient))
    (import (System.Text Encoding))
    
      (.GetString Encoding/UTF8 
           (.DownloadData (WebClient.) "http://www.baidu.com"))

    我们继续在这个代码上做点文章,我们把它修改成一下放在hello.clj文件里面编译出来:

     

    复制代码
    (ns hello)
     
    (import (System.Net WebClient))
    (import (System.Text Encoding))
    
    (defn getbaidu []
      (.GetString Encoding/UTF8 
           (.DownloadData (WebClient.) "http://www.baidu.com"))
    )
    复制代码

     

    再一次把hello.clj.dll拖入Reflector,看生成的代码:
    复制代码
    [Serializable]
    public class hello$getbaidu__11 : AFunction
    {
        // Methods
        public override bool HasArity(int num1)
        {
            if (num1 != 0)
            {
                return false;
            }
            return true;
        }
     
        public override object invoke()
        {
            return Encoding.UTF8.GetString(new WebClient().DownloadData("http://www.baidu.com"));
        }
    }
    复制代码

      

    是不是上面有一个问题已经在不知不觉之间解决了?(如何在C#中调用Clj代码)
    Clojure 调用.net Winform 当然也不是问题
    只要加载System.Windows.Forms程序集导入对应的类即可,示例代码如下:
    复制代码
    user=> (System.Reflection.Assembly/Load "System.Windows.Forms,
    Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
    #4.0.0.0, Culture=neutral, Public
    KeyToken=b77a5c561934e089>
    user=> (import (System.Windows.Forms MessageBox))
    System.Windows.Forms.MessageBox
    user=> (MessageBox/Show "Hello world from clojure-clr!" "Clojure-CLR DialogBox")
    
    OK
    user=>
    复制代码

     
    Clojure CLR 旅行愉快 !
    [0] http://www.myclojureadventure.com/2011/10/getting-started-with-clojure-clr.html
    [1] http://www.4clojure.com/
    [2] http://clojure-doc.org/
    [3] http://try-clojure.org/
    [4] http://dev.clojure.org/display/doc/Getting+Started
    [5] https://github.com/rippinrobr/clojure-clr-intro
    最后小图一张:


沪ICP备19023445号-2号
友情链接