我希望在Newick format中打印一棵二叉樹,顯示每個節點與其父節點的距離。目前我沒有遇到下面的代碼使用正則遞歸的問題,但是太深的樹可能會產生堆棧溢出。以紐尼克格式懶洋洋地打印一棵樹
(defn tree->newick
[tree]
(let [{:keys [id children to-parent]} tree
dist (double to-parent)] ; to-parent may be a rational
(if children
(str "(" (tree->newick (first children))
"," (tree->newick (second children))
"):" dist)
(str (name id) ":" dist))))
(def example {:id nil :to-parent 0.0
:children [{:id nil :to-parent 0.5
:children [{:id "A" :to-parent 0.3 :children nil}
{:id "B" :to-parent 0.2 :children nil}]}
{:id "C" :to-parent 0.8 :children nil}]})
(tree->newick example)
;=> "((A:0.3,B:0.2):0.5,C:0.8):0.0"
(def linear-tree (->> {:id "bottom" :to-parent 0.1 :children nil}
(iterate #(hash-map :id nil :to-parent 0.1
:children [% {:id "side" :to-parent 0.1 :children nil}]))
(take 10000)
last))
(tree->newick linear-tree)
;=> StackOverflowError
我已經與當前的工具,如tree-seq
和clojure.walk
發現的問題,是我要拜訪的內部節點不止一次,以夾着逗號和關閉支架。我用clojure.zip
,但沒有設法寫一個懶/尾遞歸實現,因爲我需要爲每個內部節點存儲它們已經訪問了多少次。
雖然我不能夠維護它,但令人印象深刻!要在面向對象的範例中編寫更好的代碼,你必須學習模式;要在功能範例中更好地編寫代碼,您必須學習計算機科學。 –
@BrunoKim:如果可以的話,看一看The Little Schemer一書。第8章(Lambda the Ultimate)的結尾處理了延續傳球的風格。爲了給出一個簡短的解釋,它基本上用包裝其他閉包的閉包代替了調用堆棧。而蹦牀只是一個巧妙的小訣竅,可以在「recur」支持的特殊情況之外進行尾遞歸:只要返回值是一個函數,蹦牀就會調用它。 –