運行Clojure中下面的代碼給出了一個StackOverflow的錯誤:COND Clojure中與成千上萬的條款
(cond
(= 1 2) 1
(= 2 3) 2
(= 3 4) 3
...
(= 1022 1023) 1022
(= 1023 1024) 1023
:else 1024)
我想創建一個函數/宏,可以處理條款的數量巨大,而無需創建一個堆棧溢出。
請告訴我如何嘗試這個。
運行Clojure中下面的代碼給出了一個StackOverflow的錯誤:COND Clojure中與成千上萬的條款
(cond
(= 1 2) 1
(= 2 3) 2
(= 3 4) 3
...
(= 1022 1023) 1022
(= 1023 1024) 1023
:else 1024)
我想創建一個函數/宏,可以處理條款的數量巨大,而無需創建一個堆棧溢出。
請告訴我如何嘗試這個。
如果你看完整的堆棧跟蹤,你會發現cond
發出一個嵌套深的if
結構;當編譯器試圖解析這個結構時,就會發生異常。這個問題可能更多的是與編譯深度嵌套的Clojure代碼相比,具體使用cond
。
我能夠拿出下面這個宏,它接受一個子句列表,將它們包裝在thunk中,以提供使用if
獲得的延期評估,然後使用some
查找第一個邏輯真實測試表達式。由於創建了這麼多的匿名函數,它的性能可能並不是很好,但它會繞過堆棧溢出異常。
(defmacro cond' [& clauses]
`(:result
(some (fn [[pred-thunk# val-thunk#]]
(if (pred-thunk#) {:result (val-thunk#)}))
(partition 2 (list [email protected](map (fn [c] `(fn [] ~c)) clauses))))))
注意包裝,並在地圖返回值的展開,以確保some
正確處理計算結果爲零值條款。
A cond
與513條款不太可能在實踐中使用。
這是您的示例的功能實現。
(or (some identity (map #(if (= %1 %2) %1)
(range 1 1024)
(range 2 1025)))
1024)
的要求是這樣的:
給定的條件和結果的映射,例如列表
[ [cond1 r1] [cond2 r2] ...]
,其中
COND1:(= 1 1)
,
R1:1
rn
- 在condn
計算結果爲true解決方案使用some
是完美的這裏如此存在這個問題,但我認爲我們可以通過避免使用宏。
(defn match [[condition result]]
(when condition result))
(some match [[(= 1 2) 100] [(= 2 3) 200] [(= 3 3) 300]]) ;; => 300
你能解釋一下你試圖用'cond'解決的問題嗎?它可以幫助我們回答你的問題。 – Kyle
Clojure沒有tail調用優化,但是你可以[使用recur](http://clojure.org/functional_programming#Functional%20Programming--Recursive%20Looping)來避免堆棧問題。 –
感謝您的評論。 @Kyle:當我將一個巨大的SQL case語句翻譯成clojure時遇到了這個問題。實際上,sql語句會被更好地編碼爲連接。所以,說實話我主要是問,因爲認爲這是一個有趣的編碼問題。 – user2179977