PageRenderTime 24ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/sicp/chpt2/ex2_67.clj

http://github.com/grinnbearit/sicp
Clojure | 104 lines | 63 code | 35 blank | 6 comment | 6 complexity | 9af2965ca07bf73ccf14da7a235ff930 MD5 | raw file
  1. (ns sicp.chpt2.ex2-67)
  2. ;;; Clojure has better alternatives for dynamic dispatch, [protocols](http://clojure.org/protocols)
  3. (defprotocol CodeNode
  4. (symbols [this])
  5. (weight [this]))
  6. (defrecord Leaf [sym w]
  7. CodeNode
  8. (symbols [this]
  9. [(.sym this)])
  10. (weight [this]
  11. (.w this)))
  12. (defn make-leaf
  13. [symbol weight]
  14. (Leaf. symbol weight))
  15. (defn leaf?
  16. [this]
  17. (= (class this) Leaf))
  18. (defrecord CodeTree [left right syms w]
  19. CodeNode
  20. (symbols [this]
  21. (.syms this))
  22. (weight [this]
  23. (.w this)))
  24. (defn make-code-tree
  25. [left right]
  26. (CodeTree. left
  27. right
  28. (concat (symbols left)
  29. (symbols right))
  30. (+ (weight left)
  31. (weight right))))
  32. (defn left-branch
  33. [tree]
  34. (.left tree))
  35. (defn right-branch
  36. [tree]
  37. (.right tree))
  38. ;;; Both `Leaf` and `CodeTree` have their own implementations of `weight` and `symbols`
  39. ;;; which are part of the `CodeNode` protocol, no conditional switching in the code required
  40. (defn choose-branch
  41. [bit branch]
  42. (cond (zero? bit)
  43. (left-branch branch)
  44. (= 1 bit)
  45. (right-branch branch)
  46. :else
  47. (throw (RuntimeException. (str "Invalid bit, " bit)))))
  48. (defn decode
  49. [bits tree]
  50. (letfn [(decode-1 [bs current-branch]
  51. (if (empty? bs)
  52. ()
  53. (let [next-branch (choose-branch (first bs) current-branch)]
  54. (if (leaf? next-branch)
  55. (conj (decode-1 (rest bs) tree)
  56. (first (symbols next-branch)))
  57. (recur (rest bs) next-branch)))))]
  58. (decode-1 bits tree)))
  59. ;;; __example__
  60. (def sample-tree
  61. (make-code-tree (make-leaf 'A 4)
  62. (make-code-tree
  63. (make-leaf 'B 2)
  64. (make-code-tree (make-leaf 'D 1)
  65. (make-leaf 'C 1)))))
  66. (def sample-message
  67. [0 1 1 0 0 1 0 1 0 1 1 1 0])
  68. ;; (decode sample-message sample-tree)
  69. ;; => (A D A B B C A)