2010-07-06 35 views
11

所有的,我開始看看Clojure語言,並且對我正在嘗試做的事情有幾個問題。廣泛的目標是將序列功能every?別名至all?。我確定有一個函數或者宏可以混合(或者沿着這些線),但是我想看看到目前爲止我所知道的一些基本構造是否可行。我的方法是定義一個名爲all?的函數,它將參數應用於every?實現。我很好奇,看看這是否可以不可知,所以我想參數我的別名函數採取兩個參數,新名稱(作爲關鍵字)和舊名稱(作爲函數參考)。爲了實現這一目標,我遇到了兩個問題。Clojure元編程問題(適合初學者!)

1)使用關鍵字定義命名函數會引發錯誤。顯然它想要clojure.lang.IObj

user=> (defn :foo "bar")  
java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to clojure.lang.IObj (NO_SOURCE_FILE:0) 

有蒙上了關鍵字到IObj,或其他手段來參數與一些提供價值新定義的函數的名稱的功能? (在Ruby,define_method除其他技術執行此)

irb(main)> self.class.instance_eval do 
irb(main)* define_method(:foo) { "bar" } 
irb(main)> end 
=> #<Proc> 
irb(main)> foo 
=> "bar" 

2)收集所有參數的函數成一個單一的變量。即使是基本功能,如(+ 1 2 3 4)也會帶來可變數量的參數。到目前爲止,我所見過的所有函數定義技術都需要一定數量的參數,但沒有辦法將列表中的所有內容都彙總在函數體中進行處理。再次,我要做的是在紅寶石這樣做:

irb(main)> def foo(*args) 
irb(main)> p args 
irb(main)> end 
=> nil 
irb(main)> foo(1, 2, 3) 
[1, 2, 3] 
=> nil 

感謝您的任何幫助,您可以提供我!

回答

17

我會要點回答,因爲這些問題可以被整齊地分成若干不同的問題。這是隱含在什麼是跟隨,但可能保證其自身的子彈

  • 東西:由def &有限公司創建頂級對象(尤其是defn)是瓦爾。所以你真正想要做的是別名Var;函數只是一些常規值,它們並沒有真正的名稱(除了它們可能有一個名稱綁定到自己的本體內部;這與手邊的問題無關)。

  • 的確存在「混疊的宏」可用Clojure中 - clojure.contrib.def/defalias

    (use '[clojure.contrib.def :only [defalias]]) 
    (defalias foo bar) 
    ; => foo can now be used in place of bar 
    

    的這種過度(def foo bar)的優點是,則複製的元數據(如文檔字符串);它甚至似乎可以在當前HEAD中使用宏,但我記得一個在早期版本中阻止的錯誤。

  • 變量是用符號來命名的,而不是關鍵字。Clojure(和其他Lisp)中的符號文字不以冒號開頭(:foo是關鍵字,而不是符號)。因此,要定義一個名爲foo功能,你應該寫

    (defn foo [...] ...) 
    
  • defn是一個輔助宏觀寬鬆的創作功能保持瓦爾通過允許程序員使用def & fn語法的組合。所以defn對於創建具有預先存在的值(可能是函數)的Vars來說是不容置疑的,正如創建別名所需的那樣;改爲使用defalias或簡單地使用def

  • 要創建一個可變參數函數,使用以下語法:

    (fn [x y & args] ...) 
    

    xy將被要求位置參數;傳遞給函數的其餘參數(其中任意數量)將被收集到一個seq中,並以名稱args提供。如果不需要,您不必指定任何「所需位置參數」:(fn [& args] ...)

    要創建一個VAR拿着可變參數函數,使用

    (defn foo [x y & args] ...) 
    
  • 要應用功能,你已經有了組裝成一個seqable對象一些參數(如上面的例子或者可能args以次矢量& C),使用apply

    (defn all? [& args] 
        (apply every? args)) 
    
  • 如果你想編寫一個函數創建別名 - 而不是。一個宏 - 您需要調查函數intern,with-meta,meta - 可能還有resolve/ns-resolve,這取決於函數是接受符號還是變量。我會留下填充細節作爲練習給讀者。 :-)

+1

剛剛發佈了一個帶有「intern-alias」功能的Gist,實現了最後一段中暗示的設計。我會在一秒鐘內添加一個文檔字符串。它將原始元素複製到別名,支持在除當前名稱空間以外的名稱空間中創建別名,同時接受符號和變量作爲原始&c。見http://gist.github.com/464970 – 2010-07-06 03:55:17

+0

來吧,夥計。至少給別人一個機會!是否有某種藥物可以降低智力水平回到正常水平?回到我們身邊,兄弟,我們想念你。 :p – Rayne 2010-07-06 09:48:51

+0

感謝您的深入評論。它絕對照亮了我所尋找的大部分。關於第3點(變量是用符號命名的,而不是關鍵字),有沒有辦法將關鍵字變成符號?比如說,爲了練習,我想寫一個包裝def的函數,並且帶了兩個參數,一個關鍵字和一個值,然後在內部調用def並將變量命名爲關鍵字的名稱。可能? – 2010-07-06 22:23:13

6

你需要做的就是綁定每一個?函數的全部?符號,它是通過DEF完成:

(def all? every?) 

對於多一點關於這個,看到Clojure macro to create a synonym for a function

+0

我正在探索這樣的功能的實施,但我很高興知道快速的方式來做到這一點,謝謝! – 2010-07-06 22:24:05

3

不要以爲我可以添加多少現有的解釋這裏,也許除了填寫一對夫婦在Ruby旅客的字典空白對參數的收集和拆解:

(defn foo [& args]     ; Ruby: def foo(*args) 
    (println args))  
user=> (foo 1 2 3) 
(1 2 3) 

(defn foo [& args] 
    (+ args)) 
user=> (foo 1 2 3) 
java.lang.ClassCastException  ; + takes numbers, not a list 

(defn foo [& args] 
    (apply + args))     ; apply: as Ruby proc.call(*args) 
user=> (foo 1 2 3) 
6 

(defn foo [& args] 
    (let [[a b & other] args]  ; Ruby: a, b, *other = args 
    (println a b other))) 
user=> (foo 1 2 3) 
1 2 (3) 
+0

感謝您的同義詞。 :] – 2010-07-06 22:25:48