2017-08-25 117 views
1

我試圖使用引用將seq-exprs傳遞給for,但是我的兩次嘗試均導致CompilerException java.lang.IllegalArgumentException: for requires a vector for its binding。我顯然誤解了引用和評估(以及相關概念)如何工作。將seq-exprs傳遞給使用引用

(let [v ['b (range 2)]] 
    (for v b)) 

(let [v '[b (range 2)]] 
    (for v b)) 

什麼是做了正確的方式,你會如何解釋begineer沒有上述工作的實現,爲什麼?謝謝!

編輯:
我知道我可以做

(let [] 
    (for [b (range 2)] b)) 

我想要實現的是能夠通過綁定的載體(如另一個函數的輸出)

編輯2 ,動機/背景:
我正在構建一個轉譯器[repo],我正在嘗試翻譯和展開一個for循環(包括嵌套循環,example),所以我認爲我可以追加要迭代的範圍變量seq-exprs通過嵌套循環更深入地遍歷AST(抽象語法樹),然後評估在給定由clojure for生成的'綁定'的每個原始塊中包含的翻譯關係(關係總是可以逐個翻譯)。如果有更好的方法可以做到,你有什麼建議嗎?

+0

最後你想有這樣的事情:(for [i(0 1)])?你想實現什麼?你可以這樣使用:(對於[我(範圍2)](println「我是:」我)),也需要像這樣的矢量綁定 - > [<你的表達式] –

+0

這是一個最小的例子 - 我希望能夠將矢量'seq-exprs'作爲變量傳遞給'for'。 – tales

+2

因爲'for'是一個宏,它在編譯時被擴展,這意味着綁定向量應該是一個文字向量,而不是一個var,你試圖做的事情是完全不可能的(編譯器只是不知道運行時值'v')。你可以做的是使用另一個返回'for'宏的宏(它仍然不能在'v'的運行時值上操作)或者你可以使用'eval',這是不好的。爲什麼你甚至想這樣做? – leetwinski

回答

0

['b (range 2)] => ['b (0 1)]這個例子中,你有一個名爲b符號,你也正在調用哪一個evals (0 1)

'[b (range 2)] => [b (range)]在這個例子中,所以你最終有符號brange symbol within a list data structure你引用的所有表達的功能(range 2)

關於你的for循環,你會得到這個異常,因爲你沒有正確使用它(缺少矢量綁定)。

這是你應該怎麼寫一個for循環:

(for [i (range 5)] ;;you need to define vector in here 
    (do 
     (println "I: " i) 
     i));;let's return i here 

結果:

I: 0 
I: 1 
I: 2 
I: 3 
I: 4 
=> (0 1 2 3 4) 
3

這正是宏和函數之間的區別。函數在運行時獲取並返回數據。然而,宏取並返回代碼編譯時

考慮以下幾點:

(defn foo [arg] 
    (str arg)) 

(let [x (dec 10)] 
    (foo x)) ;=> "9" 

foo看到整數9作爲參數,因爲x當前運行值爲9。然而,foo無法知道該值9由下式表示符號x,因爲符號x是代碼。

(defmacro bar [arg] 
    (str arg)) 

(let [x 9] 
    (bar x)) ;=> "x" 

(str 'x) => "x" 

因此,如果我們將其更改爲一個宏,我們得到的x編譯時間值,這僅僅是象徵x

(我們將其更改爲一個字符串,那麼它的返回代碼,並作爲串碼"x"只是計算結果爲"x"。)

這裏最重要的外賣是,以同樣的方式foo無法知道它傳遞了一個叫做x的東西,它只知道運行時間值是9,bar只有知道它傳遞了一個叫做x的東西,它無法知道x的運行時值是什麼。

這就是爲什麼宏具有傳染性。

所以在你的例子中,v運行'[b (range 2)],但你傳遞給for編譯時值只是象徵v本身。

解決您的眼前的問題,你可以做這樣的事情:

(let [v '[b (range 2)]] 
    (eval `(for ~v ~'b))) 

但這只是...太可怕了。你可能想要的是編寫一個宏。

我不確定這個宏是什麼樣子的,因爲我必須瞭解你想解決的實際問題,但這裏是一個宏的例子,它將seq-exprs傳遞給for

;; Minimal example of a macro that takes seq-exprs as code 
;; and returns code with a for that uses them. 
(defmacro forv [seq-exprs body] 
    `(vec (for ~seq-exprs ~body))) 
+2

我不知道「可能」。詢問這個問題的人通常實際上想要像笛卡爾產品這樣的東西,這更好地做爲一個函數來獲取列表並返回元組列表。 – amalloy

+0

這是有道理的。 – madstap

+0

@madstap我想弄清楚如何使用你提供的宏來解決問題,但是我不能,你能給我一個例子嗎?我嘗試了下面的方式 '(let [v'[b(range 2)] body'b] (macroexpand'(forv v body)))' and got '(clojure.core/vec(clojure.core/for v body))' 。正如你已經解釋過的,宏不會評估參數的運行時間值,所以我不知道如何通過編寫宏來解決它。 – tales