簡體   English   中英

如何評估Clojure表單的第一步?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM