[Haskell-study] [haskell-study] push by carl... at bactrian.org - Mostly done with chapter 5; need to handle embedded newlines, should... on 2009-12-28 02:56 GMT

haskell-study at googlecode.com haskell-study at googlecode.com
Sun Dec 27 20:56:46 CST 2009


Revision: 6ada330ea4
Author: "David Carlton <carlton at bactrian.org>"
Date: Sun Dec 27 18:56:07 2009
Log: Mostly done with chapter 5; need to handle embedded newlines, should
probably try exercise 2.
http://code.google.com/p/haskell-study/source/detail?r=6ada330ea4

Modified:
  /carlton/Prettify.hs
  /carlton/PrettifyTest.hs
  /carlton/ch05-notes.txt

=======================================
--- /carlton/Prettify.hs	Sat Dec 26 19:03:27 2009
+++ /carlton/Prettify.hs	Sun Dec 27 18:56:07 2009
@@ -1,4 +1,6 @@
-module Prettify(Doc, (<>), fsep, hcat, char, text, empty) where
+module Prettify(Doc, (<>), fsep, hcat, char, text, empty, compact, pretty)  
where
+
+import Data.List

  data Doc = DocList [String]
             deriving (Eq, Show)
@@ -21,3 +23,13 @@
  text s = DocList [s]

  empty = DocList []
+
+compact (DocList strings) = intercalate "\n" strings
+
+pretty n (DocList doc) = fitToLine n doc where
+    fitToLine _ [] = ""
+    fitToLine _ [s] = s
+    fitToLine remainingLength (s:rest)
+        | remainingLength >= (length s) + (length (head rest)) + 1 =
+            s ++ " " ++ (fitToLine (remainingLength - (length s) - 1) rest)
+        | otherwise = s ++ "\n" ++ (fitToLine n rest)
=======================================
--- /carlton/PrettifyTest.hs	Sat Dec 26 19:03:27 2009
+++ /carlton/PrettifyTest.hs	Sun Dec 27 18:56:07 2009
@@ -3,7 +3,9 @@
  import Test.HUnit
  import Prettify

-docTest msg lines input = msg ~: fsep (map text lines) @=? input
+doc lines = fsep (map text lines)
+
+docTest msg lines input = msg ~: doc lines @=? input

  appendTests =
      TestList["two strings" ~: text "foobar" @=? text "foo" <> text "bar",
@@ -49,4 +51,20 @@
               docTest "fsep of fseps" ["1", "2", "3"]
                           (fsep [text "1", fsep [text "2", text "3"]])]

-tests = TestList[appendTests, hcatTests, fsepTests]
+compactTests =
+    TestList["empty" ~: "" @=? compact empty,
+             "one string" ~: "foo" @=? compact (text "foo"),
+             "many strings" ~: "1\n2\n3" @=? compact (doc ["1", "2", "3"])]
+
+prettyTests =
+    TestList["empty" ~: "" @=? pretty 3 empty,
+             "long string" ~: "foobar" @=? pretty 3 (text "foobar"),
+             "two fits" ~: "foo bar" @=? pretty 7 (doc ["foo", "bar"]),
+             "two don't fit" ~: "foo\nbar" @=? pretty 6 (doc  
["foo", "bar"]),
+             "three all fit" ~: "1 2 3" @=? pretty 5 (doc ["1", "2", "3"]),
+             "three two fit" ~: "1 2\n3" @=? pretty 4 (doc  
["1", "2", "3"]),
+             "three one fits" ~: "1\n2\n3" @=? pretty 2 (doc  
["1", "2", "3"]),
+             "four two two" ~: "1 2\n3 4" @=?
+                            pretty 3 (doc ["1", "2", "3", "4"])]
+
+tests = TestList[appendTests, hcatTests, fsepTests, compactTests,  
prettyTests]
=======================================
--- /carlton/ch05-notes.txt	Sat Dec 26 19:03:27 2009
+++ /carlton/ch05-notes.txt	Sun Dec 27 18:56:07 2009
@@ -58,6 +58,59 @@
     make me wish I'd gone with a representation like what the book
     uses?  Hmm, what are the semantics of 'text "\n"' versus 'line'?
     Maybe I should represent line as 'text "\n"', forcing me to
-   confront that issue.  Also, I haven't bothered to implement </>,
-   again beacuse PrettyJSON isn't using it, but here I'm not
+   confront that issue.  (Update: I kind of think the book is
+   inconsistent about this - fits treats '\n' specially, but 'best'
+   (inside 'pretty') doesn't, so it looks to me like it will behave
+   pretty differently with (text "1\n2") </> (text "3") versus (text
+   "1") </> (text "2\n3").  (Setting the wrap column at 3, say.)  I
+   could be wrong, though.)  Also, I haven't bothered to implement
+   </>, again beacuse PrettyJSON isn't using it, but here I'm not
     bothered - I guess 'foo </> bar' is the same as 'fsep [foo,bar]'.
+
+pp. 127-128: My version of 'compact' is a lot simpler, but of course
+   I've designed my representation in such a way as to make compact
+   particularly simple.  Also, I give a different answer for the
+   compact representation of {"f":1.0,"q":true} than the book does - I
+   don't have a newline before the closing brace.  Hmm, I guess the
+   difference is that the book's definition of fsep puts a soft line
+   break after the end, while mine doesn't.  It's not clear to me
+   which of those is better, if either; I'll leave it alone.
+
+pp. 128-131: My version of 'pretty' is simpler, too, but it
+   doesn't yet handle embedded newlines.  I should modify it to do
+   that (which will probably lead to my putting in code a lot like
+   'fits'); if I have the energy, I should do exercise 2 on
+   pp. 130-131, too.  I'm also not completely convinced that we always
+   make the same line breaking decisions, but I don't feel like
+   probing that further.
+
+I guess my overall question at this point is: what are the benefits of
+the book's representation versus mine?  I think part of my dislike for
+the book's representation comes from the way Doc objects would look if
+you printed them out, which is largely unfair: it's not that my
+representation has fewer compound objects, they're just ones (strings
+and lists) that Haskell knows how to print in compact fashion
+already.
+
+The book's representation means that you have a long but explicit list
+of cases that you have to consider when doing any printer.  In my
+version, the list of cases is shorter, but they're a bit less
+explicit.  I'm happy enough with the way it's turned out so far, but
+it may break down either if I add more printing options to the
+existing structure or if I extend the structure (e.g. to allow
+indentation on braces).
+
+The book's representation is non-canonical, and at least the overlap
+between Char + Concat and Text bothers me.  I can certainly imagine
+pushing more smarts into, say, <>, and having a significantly more
+canonical representation as a result; <> would be more complicated (as
+it is in my case), but that complication would be representing
+invariants that should hold for all printers acting on Doc trees, so
+doing that could be a win.  I suppose that's what I'm doing: creating
+a canonical representation that avoids using Concat at all.
+
+Union seems like a decent idea: specializing the representation to
+only allow one particular union is defensible in my case, I think, but
+generalizing at this point wouldn't feel too premature to me.
+
+I should definitely read the papers mentioned on p. 134.



More information about the Haskell-study mailing list