diff --git a/Text/PrettyPrint/Compact.hs b/Text/PrettyPrint/Compact.hs
--- a/Text/PrettyPrint/Compact.hs
+++ b/Text/PrettyPrint/Compact.hs
@@ -2,34 +2,18 @@
 
 module Text.PrettyPrint.Compact (
    -- * Documents
-   Doc, 
+   Doc,
 
    -- * Basic combinators
-   mempty, char, text, (<>), nest, line, linebreak, group, softline,
-   softbreak,
+   module Data.Monoid, text, flush, char,
 
-   -- * Alignment
-   --
-   -- The combinators in this section can not be described by Wadler's
-   -- original combinators. They align their output relative to the
-   -- current output position - in contrast to @nest@ which always
-   -- aligns to the current nesting level. This deprives these
-   -- combinators from being \`optimal\'. In practice however they
-   -- prove to be very useful. The combinators in this section should
-   -- be used with care, since they are more expensive than the other
-   -- combinators. For example, @align@ shouldn't be used to pretty
-   -- print all top-level declarations of a language, but using @hang@
-   -- for let expressions is fine.
-   align, hang, indent, encloseSep, list, tupled, semiBraces,
+   hang, encloseSep, list, tupled, semiBraces,
 
    -- * Operators
-   (<+>), (<$>), (</>), (<$$>), (<//>),
+   (<+>), ($$),
 
    -- * List combinators
-   hsep, vsep, fillSep, sep, hcat, vcat, fillCat, cat, punctuate,
-
-   -- * Fillers
-   fill, fillBreak,
+   hsep, sep, hcat, vcat, cat, punctuate,
 
    -- * Bracketing combinators
    enclose, squotes, dquotes, parens, angles, braces, brackets,
@@ -49,16 +33,10 @@
    -- column, nesting, width
    ) where
 
-import Control.Applicative
 import Data.Monoid
 
 import Text.PrettyPrint.Compact.Core as Text.PrettyPrint.Compact
 
-type Indentation = Int
-
-infixr 5 </>,<//>,<$$$>,<$$>
-infixr 6 <+>
-
 -- | The document @(list xs)@ comma separates the documents @xs@ and
 -- encloses them in square brackets. The documents are rendered
 -- horizontally if that fits the page. Otherwise they are aligned
@@ -109,7 +87,7 @@
     = case ds of
         []  -> left <> right
         [d] -> left <> d <> right
-        _   -> align (cat (zipWith (<>) (left : repeat sep) ds) <> right)
+        _   -> cat (zipWith (<>) (left : repeat sep) ds) <> right
 
 -----------------------------------------------------------
 -- punctuate p [d1,d2,...,dn] => [d1 <> p,d2 <> p, ... ,dn]
@@ -154,10 +132,11 @@
 -- horizontally with @(\<+\>)@, if it fits the page, or vertically with
 -- @(\<$\>)@.
 --
--- > sep xs  = group (vsep xs)
 sep :: [Doc] -> Doc
-sep             = group . vsep
+sep [] = mempty
+sep xs = hsep xs <|> vcat xs
 
+
 -- | The document @(fillSep xs)@ concatenates documents @xs@
 -- horizontally with @(\<+\>)@ as long as its fits the page, than
 -- inserts a @line@ and continues doing that for all documents in
@@ -173,38 +152,6 @@
 hsep            = foldDoc (<+>)
 
 
--- | The document @(vsep xs)@ concatenates all documents @xs@
--- vertically with @(\<$\>)@. If a 'group' undoes the line breaks
--- inserted by @vsep@, all documents are separated with a space.
---
--- > someText = map text (words ("text to lay out"))
--- >
--- > test     = text "some" <+> vsep someText
---
--- This is layed out as:
---
--- @
--- some text
--- to
--- lay
--- out
--- @
---
--- The 'align' combinator can be used to align the documents under
--- their first element
---
--- > test     = text "some" <+> align (vsep someText)
---
--- Which is printed as:
---
--- @
--- some text
---      to
---      lay
---      out
--- @
-vsep :: [Doc] -> Doc
-vsep            = foldDoc (<$$$>)
 
 -- | The document @(cat xs)@ concatenates all documents @xs@ either
 -- horizontally with @(\<\>)@, if it fits the page, or vertically with
@@ -212,7 +159,8 @@
 --
 -- > cat xs  = group (vcat xs)
 cat :: [Doc] -> Doc
-cat             = group . vcat
+cat [] =  mempty
+cat xs = hcat xs <> vcat xs
 
 -- | The document @(fillCat xs)@ concatenates documents @xs@
 -- horizontally with @(\<\>)@ as long as its fits the page, than inserts
@@ -228,13 +176,12 @@
 hcat            = foldDoc (<>)
 
 -- | The document @(vcat xs)@ concatenates all documents @xs@
--- vertically with @(\<$$\>)@. If a 'group' undoes the line breaks
--- inserted by @vcat@, all documents are directly concatenated.
+-- vertically with @($$)@.
 vcat :: [Doc] -> Doc
-vcat            = foldDoc (<$$>)
+vcat            = foldDoc ($$)
 
 foldDoc :: (Doc -> Doc -> Doc) -> [Doc] -> Doc
-foldDoc f []       = mempty
+foldDoc _ []       = mempty
 foldDoc f ds       = foldr1 f ds
 
 -- | The document @(x \<+\> y)@ concatenates document @x@ and @y@ with a
@@ -242,43 +189,23 @@
 (<+>) :: Doc -> Doc -> Doc
 x <+> y         = x <> space <> y
 
--- | The document @(x \<\/\> y)@ concatenates document @x@ and @y@ with a
--- 'softline' in between. This effectively puts @x@ and @y@ either
--- next to each other (with a @space@ in between) or underneath each
--- other. (infixr 5)
+-- | The document @(x \<\/\> y)@ puts @x@ and @y@ either next to each other
+-- (with a @space@ in between) or underneath each other. (infixr 5)
 (</>) :: Doc -> Doc -> Doc
-x </> y         = x <> softline <> y
+x </> y         = ((x <> space) <|> flush x) <> y
 
--- | The document @(x \<\/\/\> y)@ concatenates document @x@ and @y@ with
--- a 'softbreak' in between. This effectively puts @x@ and @y@ either
--- right next to each other or underneath each other. (infixr 5)
+-- | The document @(x \<\/\/\> y)@ puts @x@ and @y@ either right next to each
+-- other or underneath each other. (infixr 5)
 (<//>) :: Doc -> Doc -> Doc
-x <//> y        = x <> softbreak <> y
+x <//> y        = (x <|> flush x) <> y
 
--- | The document @(x \<$\> y)@ concatenates document @x@ and @y@ with a
--- 'line' in between. (infixr 5)
-(<$$$>) :: Doc -> Doc -> Doc
-x <$$$> y         = x <> line <> y
 
 -- | The document @(x \<$$\> y)@ concatenates document @x@ and @y@ with
--- a @linebreak@ in between. (infixr 5)
+-- a linebreak in between. (infixr 5)
 (<$$>) :: Doc -> Doc -> Doc
-x <$$> y        = x <> linebreak <> y
+x <$$> y = flush x <> y
 
--- | The document @softline@ behaves like 'space' if the resulting
--- output fits the page, otherwise it behaves like 'line'.
---
--- > softline = group line
-softline :: Doc
-softline        = group line
 
--- | The document @softbreak@ behaves like 'empty' if the resulting
--- output fits the page, otherwise it behaves like 'line'.
---
--- > softbreak  = group linebreak
-softbreak :: Doc
-softbreak       = group linebreak
-
 -- | Document @(squotes x)@ encloses document @x@ with single quotes
 -- \"'\".
 squotes :: Doc -> Doc
@@ -380,10 +307,7 @@
 -- characters. It is used instead of 'text' whenever the text contains
 -- newline characters.
 string :: String -> Doc
-string ""       = mempty
-string ('\n':s) = line <> string s
-string s        = case (span (/='\n') s) of
-                    (xs,ys) -> text xs <> string ys
+string = vcat . map text . lines
 
 bool :: Bool -> Doc
 bool b          = text (show b)
@@ -413,85 +337,8 @@
 rational :: Rational -> Doc
 rational r      = text (show r)
 
------------------------------------------------------------
--- semi primitive: fill and fillBreak
------------------------------------------------------------
 
--- | The document @(fillBreak i x)@ first renders document @x@. It
--- than appends @space@s until the width is equal to @i@. If the
--- width of @x@ is already larger than @i@, the nesting level is
--- increased by @i@ and a @line@ is appended. When we redefine @ptype@
--- in the previous example to use @fillBreak@, we get a useful
--- variation of the previous output:
---
--- > ptype (name,tp)
--- >        = fillBreak 6 (text name) <+> text "::" <+> text tp
---
--- The output will now be:
---
--- @
--- let empty  :: Doc
---     nest   :: Indentation -> Doc -> Doc
---     linebreak
---            :: Doc
--- @
-fillBreak :: Indentation -> Doc -> Doc
-fillBreak f x   = width x (\w ->
-                  if (w > f) then nest f linebreak
-                             else spacing (f - w))
 
-
--- | The document @(fill i x)@ renders document @x@. It than appends
--- @space@s until the width is equal to @i@. If the width of @x@ is
--- already larger, nothing is appended. This combinator is quite
--- useful in practice to output a list of bindings. The following
--- example demonstrates this.
---
--- > types  = [("empty","Doc")
--- >          ,("nest","Indentation -> Doc -> Doc")
--- >          ,("linebreak","Doc")]
--- >
--- > ptype (name,tp)
--- >        = fill 6 (text name) <+> text "::" <+> text tp
--- >
--- > test   = text "let" <+> align (vcat (map ptype types))
---
--- Which is layed out as:
---
--- @
--- let empty  :: Doc
---     nest   :: Indentation -> Doc -> Doc
---     linebreak :: Doc
--- @
-fill :: Indentation -> Doc -> Doc
-fill f d        = width d (\w ->
-                  if (w >= f) then mempty
-                              else spacing (f - w))
-
-width :: Doc -> (Indentation -> Doc) -> Doc
-width d f       = column (\k1 -> d <> column (\k2 -> f (k2 - k1)))
-
-
------------------------------------------------------------
--- semi primitive: Alignment and indentation
------------------------------------------------------------
-
--- | The document @(indent i x)@ indents document @x@ with @i@ spaces.
---
--- > test  = indent 4 (fillSep (map text
--- >         (words "the indent combinator indents these words !")))
---
--- Which lays out with a page width of 20 as:
---
--- @
---     the indent
---     combinator
---     indents these
---     words !
--- @
-indent :: Indentation -> Doc -> Doc
-indent i d      = hang i (spacing i <> d)
-
 -- | The hang combinator implements hanging indentation. The document
 -- @(hang i x)@ renders document @x@ with a nesting level set to the
 -- current column plus @i@. The following example uses hanging
@@ -511,43 +358,10 @@
 -- The @hang@ combinator is implemented as:
 --
 -- > hang i x  = align (nest i x)
-hang :: Indentation -> Doc -> Doc
-hang i d        = align (nest i d)
-
--- | The document @(align x)@ renders document @x@ with the nesting
--- level set to the current column. It is used for example to
--- implement 'hang'.
---
--- As an example, we will put a document right above another one,
--- regardless of the current nesting level:
---
--- > x $$ y  = align (x <$$$> y)
---
--- > test    = text "hi" <+> (text "nice" $$ text "world")
---
--- which will be layed out as:
---
--- @
--- hi nice
---    world
--- @
-align :: Doc -> Doc
-align d         = column (\k ->
-                  nesting (\i -> nest (k - i) d))   --nesting might be negative :-)
+hang :: Int -> Doc -> Doc -> Doc
+hang n x y = (x <+> y) <|> (x $$ nest' n y)
 
 
--- | The @line@ document advances to the next line and indents to the
--- current nesting level. Document @line@ behaves like @(text \" \")@
--- if the line break is undone by 'group'.
-line :: Doc
-line            = Line False
-
--- | The @linebreak@ document advances to the next line and indents to
--- the current nesting level. Document @linebreak@ behaves like
--- 'empty' if the line break is undone by 'group'.
-linebreak :: Doc
-linebreak       = Line True
-
 -- | The document @(nest i x)@ renders document @x@ with the current
 -- indentation level increased by i (See also 'hang', 'align' and
 -- 'indent').
@@ -561,9 +375,15 @@
 --   world
 -- !
 -- @
-nest :: Indentation -> Doc -> Doc
-nest i x        = Nest i x
 
-column, nesting :: (Indentation -> Doc) -> Doc
-column f        = Column f
-nesting f       = Nesting f
+
+space = text " "
+
+
+nest' n x = spaces n <> x
+
+spaces :: Int -> Doc
+spaces n = text $ replicate n ' '
+
+($$) :: Doc -> Doc -> Doc
+a $$ b = flush a <> b
diff --git a/Text/PrettyPrint/Compact/Core.hs b/Text/PrettyPrint/Compact/Core.hs
--- a/Text/PrettyPrint/Compact/Core.hs
+++ b/Text/PrettyPrint/Compact/Core.hs
@@ -1,142 +1,124 @@
-{-# LANGUAGE RecordWildCards #-}
-module Text.PrettyPrint.Compact.Core(Doc(..),render,group,flatten,space,spacing,text) where
+{-# LANGUAGE ScopedTypeVariables, TypeSynonymInstances, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, ViewPatterns #-}
+module Text.PrettyPrint.Compact.Core(Layout(..),Document(..),Doc) where
 
-import Data.Monoid
+import Data.List (intercalate,sort,groupBy)
 import Data.Function (on)
-import Data.List (partition,minimumBy,sort)
-import Data.Either (partitionEithers)
-import Data.String
+import Data.Monoid
+import Data.Sequence (singleton, Seq, viewl, viewr, ViewL(..), ViewR(..))
+import qualified Data.Sequence as S
 
-type Indentation = Int
 
-data Box = Str String | Spacing Indentation | NewLine {-^ not allowed in the input -}
 
-instance IsString Doc where
-  fromString = text
+newtype L = L (Seq String) -- non-empty sequence
+  deriving (Eq,Ord)
 
-data Doc = Empty
-         | Text Box
-         | Line !Bool            -- True <=> when undone by group, do not insert a space
-         | Cat Doc Doc
-         | Nest Indentation Doc
-         | Union Doc Doc           -- invariant: first lines of first doc longer than the first lines of the second doc
-         | Column  (Indentation -> Doc)
-         | Nesting (Indentation -> Doc)
+instance Monoid L where
+   mempty = L (singleton "")
+   L (viewr -> xs :> x) `mappend` L (viewl -> y :< ys) = L (xs <> singleton (x ++ y) <> fmap (indent ++) ys)
+      where n = length x
+            indent = Prelude.replicate n ' '
 
+newtype N = N {fromN :: String}
+instance Monoid N where
+  mempty = N ""
+  mappend (N x) (N y) = N (x ++ "\n" ++ y)
+instance Layout L where
+   render (L xs) = fromN $ foldMap N xs
+   text = L . singleton
+   flush (L xs) = L (xs <> singleton "")
 
-instance Monoid Doc where
-  mempty = Empty
-  mappend = Cat
 
-text :: String -> Doc
-text = Text . Str
+class Monoid d => Layout d where
+  text :: String -> d
+  flush :: d -> d
+  render :: d -> String
 
-spacing = Text . Spacing
+class Layout d => Document d where
+  (<|>) :: d -> d -> d
 
-space = spacing 1
+data M = M {height    :: Int,
+            lastWidth :: Int,
+            maxWidth  :: Int
+            }
+  deriving (Show,Eq,Ord)
 
-group :: Doc -> Doc
-group x         = Union (flatten x) x
+instance Monoid M where
+  mempty = text ""
+  a `mappend` b =
+    M {maxWidth = max (maxWidth a) (maxWidth b + lastWidth a),
+       height = height a + height b,
+       lastWidth = lastWidth a + lastWidth b}
 
-flatten :: Doc -> Doc
-flatten (Cat x y)       = Cat (flatten x) (flatten y)
-flatten (Nest i x)      = Nest i (flatten x)
-flatten (Line noSpace)  = if noSpace then Empty else space
-flatten (Union x _y)    = flatten x
-flatten (Column f)      = Column (flatten . f)
-flatten (Nesting f)     = Nesting (flatten . f)
-flatten other           = other                     --Empty,Char,Text
+instance Layout M where
+  text s = M {height = 0, maxWidth = length s, lastWidth = length s}
+  flush a = M {maxWidth = maxWidth a,
+               height = height a + 1,
+               lastWidth = 0}
+  render = error "don't use this render"
 
-len :: Box -> Int
-len (Str s) = length s
-len (Spacing x) = x
-len NewLine = 0
+fits :: M -> Bool
+fits x = maxWidth x <= 80
 
-data Docs   = Nil
-            | Cons !Indentation Doc Docs
+class Poset a where
+  (≺) :: a -> a -> Bool
 
-data Process = Process {overflow :: Indentation
-                       ,curIndent :: !Indentation -- current indentation
-                       ,numToks :: Int -- total number of non-space tokens produced
-                       ,tokens :: [Box] -- tokens produced, in reverse order
-                       ,rest :: !Docs -- rest of the input document to process
-                       }
--- The ⟨filtering⟩ step takes all process states starting at the current
--- line, and discards those that are dominated.  A process state
--- dominates another one if it was able to produce more tokens while
--- having less indentation. This is implemented by first sorting the
--- process states by following 'measure', and then applying the
--- 'filtering' function.
 
-measure :: Process -> (Indentation, Int)
-measure Process{..} = (curIndent, negate numToks)
+instance Poset M where
+  M c1 l1 s1 ≺ M c2 l2 s2 = c1 <= c2 && l1 <= l2 && s1 <= s2
 
-instance Eq Process where
-  (==) = (==) `on` measure
-instance Ord Process where
-  compare = compare `on` measure
 
-filtering :: [Process] -> [Process]
-filtering (x:y:xs) | numToks x >= numToks y = filtering (x:xs)
-                   | otherwise = x:filtering (y:xs)
-filtering xs = xs
 
-renderAll :: Double -> Indentation -> Doc -> [Box]
-renderAll rfrac w doc = reverse $ loop [Process 0 0 0 [] $ Cons 0 doc Nil]
-    where
-      loop ps = case dones of
-        ((_,done):_) -> done -- here we could attempt to do a better choice. Seems to be fine for now.
-        [] -> case conts of
-          (_:_) -> loop $ filtering $ sort $ conts -- See the comment ⟨filtering⟩ above
-          [] -> case conts'over of
-            (_:_) -> loop [minimumBy (compare `on` overflow) conts'over]
-            [] -> case dones'over of
-              ((_,done):_) -> done
-              [] -> [Str "Pretty print: Panic"]
+merge :: Ord a => [a] -> [a] -> [a]
+merge [] xs = xs
+merge xs [] = xs
+merge (x:xs) (y:ys)
+  | x <= y = x:merge xs (y:ys)
+  | otherwise = y:merge (x:xs) ys
 
-        where
-          -- advance all processes by one line (if possible)
-          ps' = concatMap (\Process{..} -> rall numToks tokens curIndent curIndent rest) ps
-          -- Have some processes reached the end? With some overflow?
-          (dones0,conts0) = partitionEithers ps'
-          (conts,conts'over) = partition (\p -> overflow p <= 0) conts0
-          (dones,dones'over) = partition (\(o,_) -> o <= 0) dones0
 
-      -- r :: the ribbon width in characters
-      r  =  max 0 (min w (round (fromIntegral w * rfrac)))
+mergeAll :: Ord a => [[a]] -> [a]
+mergeAll [] = []
+mergeAll (x:xs) = merge x (mergeAll xs)
 
-      -- Automatically inserted spacing does not count as doing more production.
-      count (Spacing _) = 0
-      count (Str _) = 1
+bests :: forall a. (Ord a, Poset a) => [[a]] -> [a]
+bests = pareto' [] . mergeAll
 
-      -- Compute the state(s) after reaching the end of line.
-      -- rall :: n = indentation of current line
-      --         k = current column
-      --        (ie. (k >= n) && (k - n == count of inserted characters)
-      rall :: Int -> [Box] -> Indentation -> Indentation -> Docs -> [Either (Indentation,[Box]) Process]
-      rall nts ts n k ds0 = case ds0 of
-         Nil ->  [Left $ (overflow,ts)] -- Done!
-         Cons i d ds -> case d of
-            Empty       -> rall nts ts n k ds
-            Text s      -> let k' = k+len s in seq k' (rall (nts+count s) (s:ts) n k' ds)
-            Line _      -> [Right $ Process overflow i nts (Spacing i:NewLine:ts) ds] -- "yield" when the end of line is reached
-            Cat x y     -> rall nts ts n k (Cons i x (Cons i y ds))
-            Nest j x    -> let i' = i+j in seq i' (rall nts ts n k (Cons i' x ds))
-            Union x y   -> rall nts ts n k (Cons i x ds) ++ rall nts ts n k (Cons i y ds)
-            Column f    -> rall nts ts n k (Cons i (f k) ds)
-            Nesting f   -> rall nts ts n k (Cons i (f i) ds)
-        where overflow = negate $ min (w - k) (r - k + n)
+pareto' :: Poset a => [a] -> [a] -> [a]
+pareto' acc [] = Prelude.reverse acc
+pareto' acc (x:xs) = if any (≺ x) acc
+                       then pareto' acc xs
+                       else pareto' (x:acc) xs
 
 
-layout :: [Box] -> String
-layout [] = []
-layout (Str s:xs) = s ++ layout xs
-layout (NewLine:xs) = '\n' : layout xs
-layout (Spacing x:xs) = replicate x ' ' ++ layout xs
+newtype Doc = MkDoc [(M,L)]
 
-render :: Double -> Indentation -> Doc -> String
-render rfrac w d = do
-  layout $ renderAll rfrac w d
+quasifilter :: (a -> Bool) -> [a] -> [a]
+quasifilter p xs = let fxs = filter p xs in if null fxs then take 1 xs else fxs
 
-instance Show Doc where
-  show = render 0.8 80
+instance Monoid Doc where
+  mempty = text ""
+  MkDoc xs `mappend` MkDoc ys = MkDoc $ bests [ quasifilter (fits . fst) [x <> y | y <- ys] | x <- xs]
+
+instance Layout Doc where
+  flush (MkDoc xs) = MkDoc $ bests $ map sort $ groupBy ((==) `on` (height . fst)) $ (map flush xs)
+  -- flush xs = pareto' [] $ sort $ (map flush xs)
+  text s = MkDoc [text s]
+  render (MkDoc []) = error "No suitable layout found."
+  render (MkDoc (x:_)) = render x
+
+instance Document Doc where
+  MkDoc m1 <|> MkDoc m2 = MkDoc (bests [m1,m2])
+
+
+--  (a,b) `mappend` (c,d) = (a<>c ,b<>d)
+
+instance (Layout a, Layout b) => Layout (a,b) where
+  text s = (text s, text s)
+  flush (a,b) = (flush a, flush b)
+  render = render . snd
+
+instance (Document a, Document b) => Document (a,b) where
+  (a,b) <|> (c,d) = (a<|>c,b<|>d)
+
+instance (Poset a) => Poset (a,b) where
+  (a,_) ≺ (b,_) = a ≺ b
diff --git a/pretty-compact.cabal b/pretty-compact.cabal
--- a/pretty-compact.cabal
+++ b/pretty-compact.cabal
@@ -1,5 +1,5 @@
 name: pretty-compact
-version: 1.0
+version: 2.0
 synopsis: Pretty-printing library
 description:
   This package contains a pretty-printing library, a set of API's
@@ -9,7 +9,7 @@
   .
   This library produces more compact outputs than both
   Wadler-Leijen or Hughes-PJ algorithms, at the expense of computational ressources.
-  The API is the same as Wadler-Leijen's.
+  The core API is based on Hughes-PJ, but some combinators of the Leijen API are implemented as well.
 license: GPL
 license-file: LICENSE
 category: Text
@@ -21,9 +21,11 @@
                   type: git
                   location: http://github.com/jyp/prettiest.git
 
+
 Library
         exposed-modules:
                 Text.PrettyPrint.Compact
                 Text.PrettyPrint.Compact.Core
         build-depends:
-                base >= 3 && < 5
+                      base >= 3 && < 5,
+                      containers
