SICP, Continuation Passing Style and Clojure's trampoline

╄→гoц情女王★ 提交于 2020-01-01 19:19:09

问题


I am working with SICP and exercise 2.29-b gave me the opportunity to have fun with the Continuation Passing Style while traversing mobiles and branches.

To make the story short, each mobile has left and right branch, which are composed by a length and either a numeric weight or another mobile. The question asks to find the total weight given a mobile.

After the first mutually recursive solution, quite simple, I tried and successfully implemented a cps' one:

(defn total-weight-cps [mobile]
  (letfn 
    [(branch-weight-cps
      [branch kont]
      (let [structure (branch-structure branch)]
        (if (mobile? (branch-structure branch))
          (do (println "then " structure) (kont (traverse-mobile-cps structure identity)))
          (do (println "else " structure) (kont structure)))))

     (traverse-mobile-cps
      [mobile kont]
      (branch-weight-cps (left-branch mobile)
                         (fn [left-weight]
                           (branch-weight-cps (right-branch mobile)
                                              (fn [right-weight] (kont (+ left-weight right-weight)))))))]

    (traverse-mobile-cps mobile identity)))

At this point, I have tried to apply the trampoline in order to preserve my stack. But it blows with the following exception:

java.lang.ClassCastException: sicp_clojure.2_1_exercises_2_24_2_32$total_weight_STAR_$traverse_mobile_cps__6694$fn__6695$fn__6696$fn__6697 cannot be cast to java.lang.Number
Numbers.java:126 clojure.lang.Numbers.add
.../git/sicp-clojure/src/sicp_clojure/2_1_exercises_2_24_2_32.clj:185 sicp-clojure.2-1-exercises-2-24-2-32/total-weight*[fn]
core.clj:5801 clojure.core/trampoline
core.clj:5806 clojure.core/trampoline
RestFn.java:439 clojure.lang.RestFn.invoke
.../git/sicp-clojure/src/sicp_clojure/2_1_exercises_2_24_2_32.clj:186 sicp-clojure.2-1-exercises-2-24-2-32/total-weight*

The code using trampoline, following the excellent link, is:

(defn total-weight* [mobile]
  (letfn 
    [(branch-weight-cps
      [branch kont]
      (let [structure (branch-structure branch)]
        (if (mobile? (branch-structure branch))
          (do (println "then " structure) (kont (traverse-mobile-cps structure identity)))
          (do (println "else " structure) (kont structure)))))

     (traverse-mobile-cps
      [mobile kont]
      (branch-weight-cps (left-branch mobile)
                         (fn [left-weight]
                           (branch-weight-cps (right-branch mobile)
                                              (fn [right-weight] #(kont (+ left-weight right-weight)))))))]
    (trampoline traverse-mobile-cps mobile identity)))

And finally some sample data:

(def branch11 (make-branch 1 1))
(def branch22 (make-branch 2 2))
(def branch36 (make-branch 3 6))
(def branch43 (make-branch 4 3))

(def mobile11-43 (make-mobile branch11 branch43))
(def mobile36-22 (make-mobile branch36 branch22))

(def branch5m1143 (make-branch 5 mobile11-43))
(def branch7m3622 (make-branch 7 mobile36-22))
(def mobile5m1143-7m3622 (make-mobile branch5m1143 branch7m3622))

(total-weight* mobile5m1143-7m3622)

Why does it blow up?


回答1:


Following the same link in my post, I have solved turning my implementation in:

(defn total-weight* [mobile]
  (letfn
    [(branch-weight-cps
      [branch kont]
      (let [structure (branch-structure branch)]
        (if (mobile? (branch-structure branch))
          (fn [] (traverse-mobile-cps structure kont))
          (fn [] (kont structure)))))

     (traverse-mobile-cps
      [mobile kont]
      (branch-weight-cps (left-branch mobile)
                         (fn [left-weight]
                           (branch-weight-cps (right-branch mobile)
                                              (fn [right-weight] #(kont (+ left-weight right-weight)))))))]
    (trampoline traverse-mobile-cps mobile identity)))


来源:https://stackoverflow.com/questions/26450982/sicp-continuation-passing-style-and-clojures-trampoline

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!