[英]How do I evaluate the first step of a Clojure form?
如果我的以下字符串包含有效的Clojure / ClojureScript形式:
"(+ 1 (+ 2 (/ 6 3)))"
我將如何評估此表單的第一個“步驟”? 換句話說,我如何將以上表格轉換為:
"(+ 1 (+ 2 2))"
然后將相應的表格轉換為:
"(+ 1 4)"
您使用遞歸。
您需要具有一個對數字求值的函數,但是如果不是數字,則需要對參數的求值應用運算。
(evaluate '(+ 1 (+ 2 (/ 6 3))))
這應視為:
(+ (evaluate '1) (evaluate '(+ 2 (/ 6 3))))
當它開始執行您的第一步時,幾個步驟也正在等待結果完成。
注意我使用的是列表結構而不是字符串。 對於字符串,您將需要使用一些函數來對其進行解析。
如果您想分步執行代碼,其他答案也不錯,但是我想提一下,也可以使用調試器來可視化此評估。 參見下面的Cider調試器 :
通過使用cider-debug-defun-at-point
我們在evaluate
上添加了一個斷點。 然后,在evaluate
定義時,將命中斷點,然后通過重復按next
逐步瀏覽代碼。
當您要評估表單的“步驟”時,調試器非常方便。
下面是一個非常基本的實現,它可以滿足您的需求。 評估整個表單會更常見,但是由於您只想簡化最里面的表達式,因此可以這樣做:
(defn leaf?
[x]
(and (list? x)
(symbol? (first x))
(not-any? list? (rest x))))
(defn eval-one
[expr]
(cond
(leaf? expr) (apply (-> (first expr) resolve var-get)
(rest expr))
(list? expr) (apply list (map eval-one expr))
:default expr
))
(read-string "(+ 1 (+ 2 (/ 6 3)))")
=> (+ 1 (+ 2 (/ 6 3)))
(eval-one *1)
=> (+ 1 (+ 2 2))
(eval-one *1)
=> (+ 1 4)
(eval-one *1)
=> 5
這是幼稚的,僅出於說明目的,因此請不要以為真正的評估會以這種方式起作用。
我們將葉子定義為列表,其第一個元素是符號,並且不包含任何其他可以評估的列表。 然后,我們處理表單,評估葉子表達式,遞歸地評估列表中的非葉子表達式,對於其他任何東西,我們只需將其插入到結果表達式中即可。 結果是,根據我們的定義,所有可以求值的最里面的表達式都被求值。
為了增加其他好的答案,下面是一個簡單的函數,該函數應返回第一個形式以給定的字符串求值:
(defn first-eval [form-str]
(let [form (read-string form-str)
tree-s (tree-seq sequential? identity form)]
(first (filter #(= % (flatten %)) tree-s))))
用法:
(first-eval "(+ 1 (+ 2 (/ 6 3)))") ;; returns (/ 6 3)
tree-seq
評估所有形式的能力受到很大限制,但這只是一個開始。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.