Hello everyone, I looked at Wadler's "A Prettier Printer" paper (http:// homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf) and did a rote translation of it into Clojure. Then I wrote printing routines for sequences and maps -- very barebones. They work OK:
user> (def something '(a b c d (e f g h i) j k (l m n) (o p q r s t u v) w x y (z))) #'user/something user> (pp something 20) nil (a b c d (e f g h i) j k (l m n) (o p q r s t u v) w x y (z)) user> (def things {:one "another" :two {:map "inside" :a "map"} :three [1 2 3 4 5] :four "still making things up" :five :done}) #'user/things user> (pp things) nil {:three [1 2 3 4 5], :one "another", :five :done, :four "still making things up", :two {:a "map", :map "inside"}} user> user> (pp (bean (. java.awt.Color black))) nil {:RGB -16777216, :class class java.awt.Color, :red 0, :colorSpace [EMAIL PROTECTED], :transparency 1, :blue 0, :green 0, :alpha 255} BUT -- Wadler's implementation is for Haskell, so my transcription predictably blows up with a stack overflow: user> (pp (range 1000)) [Thrown class java.lang.StackOverflowError] Restarts: 0: [ABORT] Return to SLIME's top level. Backtrace: 0: java.lang.Number.<init>(Number.java:32) 1: java.lang.Integer.<init>(Integer.java:602) 2: sun.reflect.GeneratedMethodAccessor27.invoke(Unknown Source) 3: sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:25) 4: java.lang.reflect.Method.invoke(Method.java:597) 5: clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:82) 6: clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java: 245) 7: user.fn__4400.invoke(pretty.clj:98) What could be some good strategies to adapt the code I have here to Clojure, where tail calls are not eliminated and structs are not lazy? (defstruct NIL :type) (defstruct CONCAT :type :doc1 :doc2) (defstruct NEST :type :level :doc) (defstruct TEXT :type :contents) (defstruct LINE :type) (defstruct UNION :type :doc1 :doc2) (defn doc-nil [] (struct NIL :NIL)) (defn doc-concat [x y] (struct CONCAT :CONCAT x y)) (defn doc-nest [i x] (struct NEST :NEST i x)) (defn doc-text [s] (struct TEXT :TEXT s)) (defn doc-line [] (struct LINE :LINE)) (defn doc-union [x y] (struct UNION :UNION x y)) (defstruct Nil :type) (defstruct Text :type :contents :rest) (defstruct Line :type :level :rest) (defmulti flatten :type) (defmethod flatten :NIL [x] x) (defmethod flatten :TEXT [x] x) (defmethod flatten :CONCAT [x] (doc-concat (flatten (:doc1 x)) (flatten (:doc2 x)))) (defmethod flatten :NEST [x] (doc-nest (:level x) (flatten (:doc x)))) (defmethod flatten :LINE [x] (doc-text " ")) (defmethod flatten :UNION [x] (flatten (:doc1 x))) (defmulti layout :type) (defmethod layout :Nil [x] "") (defmethod layout :Text [x] (lazy-cat (:contents x) (layout (:rest x)))) (defmethod layout :Line [x] (lazy-cat (lazy-cons \newline (replicate (:level x) \space)) (layout (:rest x)))) (defn group [x] (doc-union (flatten x) x)) (defmulti fits (fn [w x] (if (< w 0) :ZERO (:type x)))) (defmethod fits :ZERO [w x] false) (defmethod fits :Nil [w x] true) (defmethod fits :Line [w x] true) (defmethod fits :Text [w x] (fits (- w (.length (:contents x))) (:rest x))) (defn better [w k x y] (if (fits (- w k) x) x y)) (defmulti be (fn [w k d] (if (empty? d) :EMPTY (:type (second (first d)))))) (defmethod be :EMPTY [w k d] (struct Nil :Nil)) (defmethod be :NIL [w k d] (be w k (rest d))) (defmethod be :CONCAT [w k d] (let [level (first (first d)) doc (second (first d))] (be w k (lazy-cons [level,(:doc1 doc)] (lazy-cons [level,(:doc2 doc)] (rest d)))))) (defmethod be :NEST [w k d] (let [level (first (first d)) doc (second (first d))] (be w k (lazy-cons [(+ level (:level doc)), (:doc doc)] (rest d))))) (defmethod be :TEXT [w k d] (let [doc (second (first d))] (struct Text :Text (:contents doc) (be w (+ k (.length (:contents doc))) (rest d))))) (defmethod be :LINE [w k d] (let [level (first (first d))] (struct Line :Line level (be w level (rest d))))) (defmethod be :UNION [w k d] (let [level (first (first d)) doc (second (first d))] (better w k (be w k (lazy-cons [level,(:doc1 doc)] (rest d))) (be w k (lazy-cons [level,(:doc2 doc)] (rest d)))))) (defn best [w k x] (be w k (list [0,x]))) (defn pretty [w x] (layout (best w 0 x))) (defn show-dispatch [x] (cond (seq? x) :list (map? x) :map true :default)) (defmulti show show-dispatch) (def show-list-children) (defn show-list-children [x] (cond (empty? x) (doc-nil) (= (count x) 1) (show (first x)) true (reduce doc-concat (list (show (first x)) (doc-line) (show-list-children (rest x)))))) (defn show-list-braces [x] (reduce doc-concat (list (doc-text "(") (doc-nest 1 (show-list-children x)) (doc-text ")")))) (defn show-map-item [x] (reduce doc-concat (list (show (first x)) (doc-text " ") (doc-nest (+ (.length (pr-str (first x))) 1) (show (second x)))))) (def show-map-items) (defn show-map-items [x] (cond (empty? x) (doc-nil) (= (count x) 1) (show-map-item (first x)) true (reduce doc-concat (list (show-map-item (first x)) (doc-text ",") (doc-line) (show-map-items (rest x)))))) (defn show-map-braces [x] (reduce doc-concat (list (doc-text "{") (doc-nest 1 (show-map-items (seq x))) (doc-text "}")))) (defmethod show :default [x] (doc-text (pr-str x))) (defmethod show :list [x] (group (show-list-braces x))) (defmethod show :map [x] (group (show-map-braces x))) (defn pp ([obj width] (print (apply str (pretty width (show obj))))) ([obj] (pp obj 80))) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---