Clojure CLR 入門


  看過"黑客與畫家"之后,你是不是對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:
 
 
 

編譯

 
  編寫下面的文件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. 
 
 
 
 

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.
 
 
 
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")
#<RuntimeAssembly System.Windows.Forms, Version=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 旅行愉快 !
 
     
 
 最后小圖一張:
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM