summaryrefslogtreecommitdiff
path: root/tests/lexers/lhs/example.txt
diff options
context:
space:
mode:
Diffstat (limited to 'tests/lexers/lhs/example.txt')
-rw-r--r--tests/lexers/lhs/example.txt4933
1 files changed, 4933 insertions, 0 deletions
diff --git a/tests/lexers/lhs/example.txt b/tests/lexers/lhs/example.txt
new file mode 100644
index 00000000..d91b31b3
--- /dev/null
+++ b/tests/lexers/lhs/example.txt
@@ -0,0 +1,4933 @@
+---input---
+ A Sukodku solver by Chris Kuklewicz (haskell (at) list (dot) mightyreason (dot) com)
+ The usual BSD license applies, copyright 2006.
+ Uploaded to HaskellWiki as DancingSudoku.lhs
+
+ I compile on a powerbook G4 (Mac OS X, ghc 6.4.2) using
+ ghc -optc-O3 -funbox-strict-fields -O2 --make -fglasgow-exts
+
+ This is a translation of Knuth's GDANCE from dance.w / dance.c
+
+ http://www-cs-faculty.stanford.edu/~uno/preprints.html
+ http://www-cs-faculty.stanford.edu/~uno/programs.html
+ http://en.wikipedia.org/wiki/Dancing_Links
+
+ I have an older verison that uses lazy ST to return the solutions on
+ demand, which was more useful when trying to generate new puzzles to
+ solve.
+
+> module Main where
+
+> import Prelude hiding (read)
+> import Control.Monad
+> import Control.Monad.Fix
+> import Data.Array.IArray
+> import Control.Monad.ST.Strict
+> import Data.STRef.Strict
+> import Data.Char(intToDigit,digitToInt)
+> import Data.List(unfoldr,intersperse,inits)
+
+> new = newSTRef
+> {-# INLINE new #-}
+> read = readSTRef
+> {-# INLINE read #-}
+> write = writeSTRef
+> {-# INLINE write #-}
+> modify = modifySTRef
+> {-# INLINE modify #-}
+
+ Data types to prevent mixing different index and value types
+
+> type A = Int
+> newtype R = R A deriving (Show,Read,Eq,Ord,Ix,Enum)
+> newtype C = C A deriving (Show,Read,Eq,Ord,Ix,Enum)
+> newtype V = V A deriving (Show,Read,Eq,Ord,Ix,Enum)
+> newtype B = B A deriving (Show,Read,Eq,Ord,Ix,Enum)
+
+ Sudoku also has block constraints, so we want to look up a block
+ index in an array:
+
+> lookupBlock :: Array (R,C) B
+> lookupBlock = listArray bb [ toBlock ij | ij <- range bb ]
+> where ra :: Array Int B
+> ra = listArray (0,pred (rangeSize b)) [B (fst b) .. B (snd b)]
+> toBlock (R i,C j) = ra ! ( (div (index b j) 3)+3*(div (index b i) 3) )
+
+ The values for an unknown location is 'u'.
+ The bound and range are given by b and rng. And bb is a 2D bound.
+
+> u = V 0 -- unknown value
+> b :: (Int,Int)
+> b = (1,9) -- min and max bounds
+> rng = enumFromTo (fst b) (snd b) -- list from '1' to '9'
+> bb = ((R (fst b),C (fst b)),(R (snd b),C (snd b)))
+
+ A Spec can be turned into a parsed array with ease:
+
+> type Hint = ((R,C),V)
+> newtype Spec = Spec [Hint] deriving (Eq,Show)
+
+> type PA = Array (R,C) V
+
+> parse :: Spec -> PA
+> parse (Spec parsed) = let acc old new = new
+> in accumArray acc u bb parsed
+
+ The dancing links algorithm depends on a sparse 2D node structure.
+ Each column represents a constraint. Each row represents a Hint.
+ The number of possible hints is 9x9x9 = 271
+
+> type (MutInt st) = (STRef st) Int
+
+ The pointer types:
+
+> type (NodePtr st) = (STRef st) (Node st)
+> type (HeadPtr st) = (STRef st) (Head st)
+
+ The structures is a 2D grid of nodes, with Col's on the top of
+ columns and a sparse collection of nodes. Note that topNode of Head
+ is not a strict field. This is because the topNode needs to refer to
+ the Head, and they are both created monadically.
+
+> type HeadName = (Int,Int,Int) -- see below for meaning
+
+> data Head st = Head {headName:: !HeadName
+> ,topNode:: (Node st) -- header node for this column
+> ,len:: !(MutInt st) -- number of nodes below this head
+> ,next,prev:: !(HeadPtr st) -- doubly-linked list
+> }
+
+> data Node st = Node {getHint:: !Hint
+> ,getHead:: !(Head st) -- head for the column this node is in
+> ,up,down,left,right :: !(NodePtr st) -- two doubly-linked lists
+> }
+
+> instance Eq (Head st) where
+> a == b = headName a == headName b
+
+> instance Eq (Node st) where
+> a == b = up a == up b
+
+ To initialize the structures is a bit tedious. Knuth's code reads in
+ the problem description from a data file and builds the structure
+ based on that. Rather than short strings, I will use HeadName as the
+ identifier.
+
+ The columns are (0,4,5) for nodes that put some value in Row 4 Col 5
+ (1,2,3) for nodes that put Val 3 in Row 2 and some column
+ (2,7,4) for nodes that put Val 4 in Col 7 and some row
+ (3,1,8) for nodes that put Val 8 in some (row,column) in Block 1
+
+ The first head is (0,0,0) which is the root. The non-root head data
+ will be put in an array with the HeadName as an index.
+
+> headNames :: [HeadName]
+> headNames = let names = [0,1,2,3]
+> in (0,0,0):[ (l,i,j) | l<-names,i<-rng,j<-rng]
+
+ A "row" of left-right linked nodes is a move. It is defined by a
+ list of head names.
+
+> type Move = [(Hint,HeadName)]
+
+ Initial hints are enforced by making them the only legal move for
+ that location. Blank entries with value 'u = V 0' have a move for
+ all possible values [V 1..V 9].
+
+> parseSpec :: Spec -> [Move]
+> parseSpec spec =
+> let rowsFrom :: Hint -> [Move]
+> rowsFrom (rc@(R r,C c),mv@(V v')) =
+> if mv == u then [ rsyms v | v <- rng ]
+> else [ rsyms v' ]
+> where (B b) = lookupBlock ! rc
+> rsyms :: A -> Move
+> rsyms v = map ( (,) (rc,V v) ) [(0,r,c),(1,r,v),(2,c,v),(3,b,v)]
+> in concatMap rowsFrom (assocs (parse spec))
+
+ mkDList creates doubly linked lists using a monadic smart
+ constructor and the recursive "mdo" notation as documented at
+ http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#mdo-notation
+ http://www.cse.ogi.edu/PacSoft/projects/rmb/
+
+ For more fun with this, see the wiki page at
+ http://haskell.org/hawiki/TyingTheKnot
+
+> mkDList :: (MonadFix m) => (b -> a -> b -> m b) -> [a] -> m b
+> mkDList _ [] = error "must have at least one element"
+> mkDList mkNode xs = mdo (first,last) <- go last xs first
+> return first
+> where go prev [] next = return (next,prev)
+> go prev (x:xs) next = mdo this <- mkNode prev x rest
+> (rest,last) <- go this xs next
+> return (this,last)
+
+ toSimple takes a function and a header node and iterates (read . function)
+ until the header is reached again, but does not return the header
+ itself.
+
+> toSingle step header = loop =<< (read . step) header
+> where loop y = if header/=y then liftM (y:) (read (step y) >>= loop)
+> else return []
+>
+
+ forEach is an optimization of (toSimple step header >>= mapM_ act)
+
+> forEach step header act = loop =<< (read . step) header
+> where loop y = if header/=y then (act y >> (read (step y)) >>= loop)
+> else return ()
+
+ Now make the root node and all the head nodes. This also exploits mdo:
+
+> makeHeads :: [HeadName] -> (ST st) (Head st)
+> makeHeads names = mkDList makeHead names
+> where makeHead before name after = mdo
+> ~newTopNode <- liftM4 (Node ((R 0,C 0),V 0) newHead) (new newTopNode) (new newTopNode)
+> (new newTopNode) (new newTopNode)
+> newHead <- liftM3 (Head name newTopNode)
+> (new 0) (new after) (new before)
+> return newHead
+
+ The Head nodes will be places in an array for easy lookup while building moves:
+
+> type HArray st = Array HeadName (Head st)
+> hBounds = ((0,1,1),(3,9,9))
+> type Root st = (Head st,HArray st)
+
+ The addMove function creates the (four) nodes that represent a move and adds
+ them to the data structure. The HArray in Root makes for a fast
+ lookup of the Head data.
+
+> addMove :: forall st. (Root st) -> Move -> (ST st) (Node st)
+> addMove (_,ha) move = mkDList addNode move
+> where addNode :: (Node st) -> (Hint,HeadName) -> (Node st) -> (ST st) (Node st)
+> addNode before (hint,name) after = do
+> let head = ha ! name
+> let below = topNode head
+> above <- read (up below)
+> newNode <- liftM4 (Node hint head) (new above) (new below)
+> (new before) (new after)
+> write (down above) newNode
+> write (up below) newNode
+> modify (len head) succ
+> l <- read (len head)
+> seq l (return newNode)
+
+ Create the column headers, including the fast lookup array. These
+ will be resused between puzzles.
+
+> initHA :: (ST st) (Root st)
+> initHA = do
+> root <- makeHeads headNames
+> heads <- toSingle next root
+> let ha = array hBounds (zip (map headName heads) heads)
+> return (root,ha)
+
+ Take the Root from initHA and a puzzle Spec and fill in all the Nodes.
+
+> initRoot :: (Root st) -> Spec -> (ST st) ()
+> initRoot root spec = do
+> let moves = parseSpec spec
+> mapM_ (addMove root) moves
+
+ Return the column headers to their condition after initHA
+
+> resetRoot :: (Root st) -> (ST st) ()
+> resetRoot (root,ha) = do
+> let heads@(first:_) = elems ha
+> let resetHead head = do
+> write (len head) 0
+> let node = topNode head
+> write (down node) node
+> write (up node) node
+> reset (last:[]) = do
+> write (prev root) last
+> write (next root) first
+> reset (before:xs@(head:[])) = do
+> resetHead head
+> write (prev head) before
+> write (next head) root
+> reset xs
+> reset (before:xs@(head:after:_)) = do
+> resetHead head
+> write (prev head) before
+> write (next head) after
+> reset xs
+> reset (root:heads)
+
+ getBest iterates over the unmet constraints (i.e. the Head that are
+ reachable from root). It locates the one with the lowest number of
+ possible moves that will solve it, aborting early if it finds 0 or 1
+ moves.
+
+> getBest :: (Head st) -> (ST st) (Maybe (Head st))
+> getBest root = do
+> first <- read (next root)
+> if first == root then return Nothing
+> else do
+> let findMin m best head | head == root = return (Just best)
+> | otherwise = do
+> l <- read (len head)
+> if l <= 1 then return (Just head)
+> else if l < m then findMin l head =<< read (next head)
+> else findMin l best =<< read (next head)
+> findMin 10 first first
+
+ The unlink and relink operations are from where Knuth got the name
+ "dancing links". So long as "a" does not change in between, the
+ relink call will undo the unlink call. Similarly, the unconver will
+ undo the changes of cover and unconverOthers will undo coverOthers.
+
+> unlink :: (a->STRef st a) -> (a->STRef st a) -> a -> (ST st) ()
+> unlink prev next a = do
+> before <- read (prev a)
+> after <- read (next a)
+> write (next before) after
+> write (prev after) before
+
+> relink :: (a->STRef st a) -> (a->STRef st a) -> a -> (ST st) ()
+> relink prev next a = do
+> before <- read (prev a)
+> after <- read (next a)
+> write (next before) a
+> write (prev after) a
+
+> cover :: (Head st) -> (ST st) ()
+> cover head = do
+> unlink prev next head
+> let eachDown rr = forEach right rr eachRight
+> eachRight nn = do
+> unlink up down nn
+> modify (len $ getHead nn) pred
+> forEach down (topNode head) eachDown
+
+> uncover :: (Head st) -> (ST st) ()
+> uncover head = do
+> let eachUp rr = forEach left rr eachLeft
+> eachLeft nn = do
+> modify (len $ getHead nn) succ
+> relink up down nn
+> forEach up (topNode head) eachUp
+> relink prev next head
+
+> coverOthers :: (Node st) -> (ST st) ()
+> coverOthers node = forEach right node (cover . getHead)
+
+> uncoverOthers :: (Node st) -> (ST st) ()
+> uncoverOthers node = forEach left node (uncover . getHead)
+
+ A helper function for gdance:
+
+> choicesToSpec :: [(Node st)] -> Spec
+> choicesToSpec = Spec . (map getHint)
+
+ This is the heart of the algorithm. I have altered it to return only
+ the first solution, or produce an error if none is found.
+
+ Knuth used several goto links to do what is done below with tail
+ recursion.
+
+> gdance :: (Head st) -> (ST st) Spec -- [Spec]
+> gdance root =
+> let
+> forward choices = do
+> maybeHead <- getBest root
+> case maybeHead of
+> Nothing -> if null choices
+> then error "No choices in forward" -- return [] -- for [Spec]
+> else do -- nextSols <- recover choices -- for [Spec]
+> return $ (choicesToSpec choices) -- :nextSols -- for [Spec]
+> Just head -> do cover head
+> startRow <- readSTRef (down (topNode head))
+> advance (startRow:choices)
+>
+> advance choices@(newRow:oldChoices) = do
+> let endOfRows = topNode (getHead newRow)
+> if (newRow == endOfRows)
+> then do uncover (getHead newRow)
+> if (null oldChoices)
+> then error "No choices in advance" -- return [] -- for [Spec]
+> else recover oldChoices
+> else do coverOthers newRow
+> forward choices
+>
+> recover (oldRow:oldChoices) = do
+> uncoverOthers oldRow
+> newRow <- readSTRef (down oldRow)
+> advance (newRow:oldChoices)
+>
+> in forward []
+
+
+ Convert a text board into a Spec
+
+> parseBoard :: String -> Spec
+> parseBoard s = Spec (zip rcs vs'check)
+> where rcs :: [(R,C)]
+> rcs = [ (R r,C c) | r <- rng, c <- rng ]
+> isUnset c = (c=='.') || (c==' ') || (c=='0')
+> isHint c = ('1'<=c) && (c<='9')
+> cs = take 81 $ filter (\c -> isUnset c || isHint c) s
+> vs :: [V]
+> vs = map (\c -> if isUnset c then u else (V $ digitToInt c)) cs
+> vs'check = if 81==length vs then vs else error ("parse of board failed\n"++s)
+
+ This is quite useful as a utility function which partitions the list into groups of n elements.
+ Used by showSpec.
+
+> groupTake :: Int->[a]->[[a]]
+> groupTake n b = unfoldr foo b
+> where foo [] = Nothing
+> foo b = Just (splitAt n b)
+
+ Make a nice 2D ascii board from the Spec (not used at the moment)
+
+> showSpec :: Spec -> String
+> showSpec spec = let pa = parse spec
+> g = groupTake 9 (map (\(V v) -> if v == 0 then '.' else intToDigit v) $ elems pa)
+> addV line = concat $ intersperse "|" (groupTake 3 line)
+> addH list = concat $ intersperse ["---+---+---"] (groupTake 3 list)
+> in unlines $ addH (map addV g)
+
+ One line display
+
+> showCompact spec = map (\(V v) -> intToDigit v) (elems (parse spec))
+
+ The main routine is designed to handle the input from http://www.csse.uwa.edu.au/~gordon/sudoku17
+
+> main = do
+> all <- getContents
+> let puzzles = zip [1..] (map parseBoard (lines all))
+> root <- stToIO initHA
+> let act :: (Int,Spec) -> IO ()
+> act (i,spec) = do
+> answer <- stToIO (do initRoot root spec
+> answer <- gdance (fst root)
+> resetRoot root
+> return answer)
+> print (i,showCompact answer)
+> mapM_ act puzzles
+
+> inits' xn@(_:_) = zipWith take [0..] $ map (const xn) $ undefined:xn
+> inits' _ = undefined
+
+---tokens---
+' A Sukodku solver by Chris Kuklewicz (haskell (at) list (dot) mightyreason (dot) com)\n' Text
+
+' The usual BSD license applies, copyright 2006.\n' Text
+
+' Uploaded to HaskellWiki as DancingSudoku.lhs\n' Text
+
+'\n' Text
+
+' I compile on a powerbook G4 (Mac OS X, ghc 6.4.2) using\n' Text
+
+' ghc -optc-O3 -funbox-strict-fields -O2 --make -fglasgow-exts\n' Text
+
+'\n' Text
+
+" This is a translation of Knuth's GDANCE from dance.w / dance.c\n" Text
+
+'\n' Text
+
+' http://www-cs-faculty.stanford.edu/~uno/preprints.html\n' Text
+
+' http://www-cs-faculty.stanford.edu/~uno/programs.html\n' Text
+
+' http://en.wikipedia.org/wiki/Dancing_Links\n' Text
+
+'\n' Text
+
+' I have an older verison that uses lazy ST to return the solutions on\n' Text
+
+' demand, which was more useful when trying to generate new puzzles to\n' Text
+
+' solve.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'module' Keyword.Reserved
+' ' Text
+'Main' Name.Namespace
+' ' Text
+'where' Keyword.Reserved
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'import' Keyword.Reserved
+' ' Text
+'Prelude' Name.Namespace
+' ' Text
+'hiding' Keyword
+' ' Text
+'(' Punctuation
+'read' Name.Function
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'import' Keyword.Reserved
+' ' Text
+'Control.Monad' Name.Namespace
+'\n' Text
+
+'> ' Comment.Special
+'import' Keyword.Reserved
+' ' Text
+'Control.Monad.Fix' Name.Namespace
+'\n' Text
+
+'> ' Comment.Special
+'import' Keyword.Reserved
+' ' Text
+'Data.Array.IArray' Name.Namespace
+'\n' Text
+
+'> ' Comment.Special
+'import' Keyword.Reserved
+' ' Text
+'Control.Monad.ST.Strict' Name.Namespace
+'\n' Text
+
+'> ' Comment.Special
+'import' Keyword.Reserved
+' ' Text
+'Data.STRef.Strict' Name.Namespace
+'\n' Text
+
+'> ' Comment.Special
+'import' Keyword.Reserved
+' ' Text
+'Data.Char' Name.Namespace
+'(' Punctuation
+'intToDigit' Name
+',' Punctuation
+'digitToInt' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'import' Keyword.Reserved
+' ' Text
+'Data.List' Name.Namespace
+'(' Punctuation
+'unfoldr' Name
+',' Punctuation
+'intersperse' Name
+',' Punctuation
+'inits' Name
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'new' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'newSTRef' Name
+'\n' Text
+
+'> ' Comment.Special
+'{-' Comment.Multiline
+'# INLINE new #' Comment.Multiline
+'-}' Comment.Multiline
+'\n' Text
+
+'> ' Comment.Special
+'read' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'readSTRef' Name
+'\n' Text
+
+'> ' Comment.Special
+'{-' Comment.Multiline
+'# INLINE read #' Comment.Multiline
+'-}' Comment.Multiline
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'writeSTRef' Name
+'\n' Text
+
+'> ' Comment.Special
+'{-' Comment.Multiline
+'# INLINE write #' Comment.Multiline
+'-}' Comment.Multiline
+'\n' Text
+
+'> ' Comment.Special
+'modify' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'modifySTRef' Name
+'\n' Text
+
+'> ' Comment.Special
+'{-' Comment.Multiline
+'# INLINE modify #' Comment.Multiline
+'-}' Comment.Multiline
+'\n' Text
+
+'\n' Text
+
+' Data types to prevent mixing different index and value types\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'type' Keyword.Reserved
+' ' Text
+'A' Keyword.Type
+' ' Text
+'=' Operator.Word
+' ' Text
+'Int' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+'newtype' Keyword.Reserved
+' ' Text
+'R' Keyword.Type
+' ' Text
+'=' Operator.Word
+' ' Text
+'R' Keyword.Type
+' ' Text
+'A' Keyword.Type
+' ' Text
+'deriving' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'Show' Keyword.Type
+',' Punctuation
+'Read' Keyword.Type
+',' Punctuation
+'Eq' Keyword.Type
+',' Punctuation
+'Ord' Keyword.Type
+',' Punctuation
+'Ix' Keyword.Type
+',' Punctuation
+'Enum' Keyword.Type
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'newtype' Keyword.Reserved
+' ' Text
+'C' Keyword.Type
+' ' Text
+'=' Operator.Word
+' ' Text
+'C' Keyword.Type
+' ' Text
+'A' Keyword.Type
+' ' Text
+'deriving' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'Show' Keyword.Type
+',' Punctuation
+'Read' Keyword.Type
+',' Punctuation
+'Eq' Keyword.Type
+',' Punctuation
+'Ord' Keyword.Type
+',' Punctuation
+'Ix' Keyword.Type
+',' Punctuation
+'Enum' Keyword.Type
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'newtype' Keyword.Reserved
+' ' Text
+'V' Keyword.Type
+' ' Text
+'=' Operator.Word
+' ' Text
+'V' Keyword.Type
+' ' Text
+'A' Keyword.Type
+' ' Text
+'deriving' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'Show' Keyword.Type
+',' Punctuation
+'Read' Keyword.Type
+',' Punctuation
+'Eq' Keyword.Type
+',' Punctuation
+'Ord' Keyword.Type
+',' Punctuation
+'Ix' Keyword.Type
+',' Punctuation
+'Enum' Keyword.Type
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'newtype' Keyword.Reserved
+' ' Text
+'B' Keyword.Type
+' ' Text
+'=' Operator.Word
+' ' Text
+'B' Keyword.Type
+' ' Text
+'A' Keyword.Type
+' ' Text
+'deriving' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'Show' Keyword.Type
+',' Punctuation
+'Read' Keyword.Type
+',' Punctuation
+'Eq' Keyword.Type
+',' Punctuation
+'Ord' Keyword.Type
+',' Punctuation
+'Ix' Keyword.Type
+',' Punctuation
+'Enum' Keyword.Type
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' Sudoku also has block constraints, so we want to look up a block\n' Text
+
+' index in an array:\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'lookupBlock' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'Array' Keyword.Type
+' ' Text
+'(' Punctuation
+'R' Keyword.Type
+',' Punctuation
+'C' Keyword.Type
+')' Punctuation
+' ' Text
+'B' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+'lookupBlock' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'listArray' Name
+' ' Text
+'bb' Name
+' ' Text
+'[' Punctuation
+' ' Text
+'toBlock' Name
+' ' Text
+'ij' Name
+' ' Text
+'|' Operator
+' ' Text
+'ij' Name
+' ' Text
+'<-' Operator.Word
+' ' Text
+'range' Name
+' ' Text
+'bb' Name
+' ' Text
+']' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'where' Keyword.Reserved
+' ' Text
+'ra' Name
+' ' Text
+'::' Operator.Word
+' ' Text
+'Array' Keyword.Type
+' ' Text
+'Int' Keyword.Type
+' ' Text
+'B' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+'ra' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'listArray' Name
+' ' Text
+'(' Punctuation
+'0' Literal.Number.Integer
+',' Punctuation
+'pred' Name
+' ' Text
+'(' Punctuation
+'rangeSize' Name
+' ' Text
+'b' Name
+')' Punctuation
+')' Punctuation
+' ' Text
+'[' Punctuation
+'B' Keyword.Type
+' ' Text
+'(' Punctuation
+'fst' Name
+' ' Text
+'b' Name
+')' Punctuation
+' ' Text
+'..' Operator
+' ' Text
+'B' Keyword.Type
+' ' Text
+'(' Punctuation
+'snd' Name
+' ' Text
+'b' Name
+')' Punctuation
+']' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'toBlock' Name.Function
+' ' Text
+'(' Punctuation
+'R' Keyword.Type
+' ' Text
+'i' Name
+',' Punctuation
+'C' Keyword.Type
+' ' Text
+'j' Name
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'ra' Name
+' ' Text
+'!' Operator
+' ' Text
+'(' Punctuation
+' ' Text
+'(' Punctuation
+'div' Name
+' ' Text
+'(' Punctuation
+'index' Name
+' ' Text
+'b' Name
+' ' Text
+'j' Name
+')' Punctuation
+' ' Text
+'3' Literal.Number.Integer
+')' Punctuation
+'+' Operator
+'3' Literal.Number.Integer
+'*' Operator
+'(' Punctuation
+'div' Name
+' ' Text
+'(' Punctuation
+'index' Name
+' ' Text
+'b' Name
+' ' Text
+'i' Name
+')' Punctuation
+' ' Text
+'3' Literal.Number.Integer
+')' Punctuation
+' ' Text
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+" The values for an unknown location is 'u'.\n" Text
+
+' The bound and range are given by b and rng. And bb is a 2D bound.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'u' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'V' Keyword.Type
+' ' Text
+'0' Literal.Number.Integer
+' ' Text
+'-- unknown value' Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+'b' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'Int' Keyword.Type
+',' Punctuation
+'Int' Keyword.Type
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'b' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'(' Punctuation
+'1' Literal.Number.Integer
+',' Punctuation
+'9' Literal.Number.Integer
+')' Punctuation
+' ' Text
+'-- min and max bounds' Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+'rng' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'enumFromTo' Name
+' ' Text
+'(' Punctuation
+'fst' Name
+' ' Text
+'b' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'snd' Name
+' ' Text
+'b' Name
+')' Punctuation
+' ' Text
+"-- list from '1' to '9'" Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+'bb' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'(' Punctuation
+'(' Punctuation
+'R' Keyword.Type
+' ' Text
+'(' Punctuation
+'fst' Name
+' ' Text
+'b' Name
+')' Punctuation
+',' Punctuation
+'C' Keyword.Type
+' ' Text
+'(' Punctuation
+'fst' Name
+' ' Text
+'b' Name
+')' Punctuation
+')' Punctuation
+',' Punctuation
+'(' Punctuation
+'R' Keyword.Type
+' ' Text
+'(' Punctuation
+'snd' Name
+' ' Text
+'b' Name
+')' Punctuation
+',' Punctuation
+'C' Keyword.Type
+' ' Text
+'(' Punctuation
+'snd' Name
+' ' Text
+'b' Name
+')' Punctuation
+')' Punctuation
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' A Spec can be turned into a parsed array with ease:\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'type' Keyword.Reserved
+' ' Text
+'Hint' Keyword.Type
+' ' Text
+'=' Operator.Word
+' ' Text
+'(' Punctuation
+'(' Punctuation
+'R' Keyword.Type
+',' Punctuation
+'C' Keyword.Type
+')' Punctuation
+',' Punctuation
+'V' Keyword.Type
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'newtype' Keyword.Reserved
+' ' Text
+'Spec' Keyword.Type
+' ' Text
+'=' Operator.Word
+' ' Text
+'Spec' Keyword.Type
+' ' Text
+'[' Punctuation
+'Hint' Keyword.Type
+']' Punctuation
+' ' Text
+'deriving' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'Eq' Keyword.Type
+',' Punctuation
+'Show' Keyword.Type
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'type' Keyword.Reserved
+' ' Text
+'PA' Keyword.Type
+' ' Text
+'=' Operator.Word
+' ' Text
+'Array' Keyword.Type
+' ' Text
+'(' Punctuation
+'R' Keyword.Type
+',' Punctuation
+'C' Keyword.Type
+')' Punctuation
+' ' Text
+'V' Keyword.Type
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'parse' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'Spec' Keyword.Type
+' ' Text
+'->' Operator.Word
+' ' Text
+'PA' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+'parse' Name.Function
+' ' Text
+'(' Punctuation
+'Spec' Keyword.Type
+' ' Text
+'parsed' Name
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'let' Keyword.Reserved
+' ' Text
+'acc' Name
+' ' Text
+'old' Name
+' ' Text
+'new' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'new' Name
+'\n' Text
+
+'> ' Comment.Special
+'in' Keyword.Reserved
+' ' Text
+'accumArray' Name
+' ' Text
+'acc' Name
+' ' Text
+'u' Name
+' ' Text
+'bb' Name
+' ' Text
+'parsed' Name
+'\n' Text
+
+'\n' Text
+
+' The dancing links algorithm depends on a sparse 2D node structure.\n' Text
+
+' Each column represents a constraint. Each row represents a Hint.\n' Text
+
+' The number of possible hints is 9x9x9 = 271\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'type' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'MutInt' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'(' Punctuation
+'STRef' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'Int' Keyword.Type
+'\n' Text
+
+'\n' Text
+
+' The pointer types:\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'type' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'NodePtr' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'(' Punctuation
+'STRef' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'Node' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'type' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'HeadPtr' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'(' Punctuation
+'STRef' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'Head' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+" The structures is a 2D grid of nodes, with Col's on the top of\n" Text
+
+' columns and a sparse collection of nodes. Note that topNode of Head\n' Text
+
+' is not a strict field. This is because the topNode needs to refer to\n' Text
+
+' the Head, and they are both created monadically.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'type' Keyword.Reserved
+' ' Text
+'HeadName' Keyword.Type
+' ' Text
+'=' Operator.Word
+' ' Text
+'(' Punctuation
+'Int' Keyword.Type
+',' Punctuation
+'Int' Keyword.Type
+',' Punctuation
+'Int' Keyword.Type
+')' Punctuation
+' ' Text
+'-- see below for meaning' Comment.Single
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'data' Keyword.Reserved
+' ' Text
+'Head' Keyword.Type
+' ' Text
+'st' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'Head' Keyword.Type
+' ' Text
+'{' Punctuation
+'headName' Name
+'::' Operator.Word
+' ' Text
+'!' Operator
+'HeadName' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+',' Punctuation
+'topNode' Name
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'Node' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'-- header node for this column' Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+',' Punctuation
+'len' Name
+'::' Operator.Word
+' ' Text
+'!' Operator
+'(' Punctuation
+'MutInt' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'-- number of nodes below this head' Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+',' Punctuation
+'next' Name
+',' Punctuation
+'prev' Name
+'::' Operator.Word
+' ' Text
+'!' Operator
+'(' Punctuation
+'HeadPtr' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'-- doubly-linked list' Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+'}' Punctuation
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'data' Keyword.Reserved
+' ' Text
+'Node' Keyword.Type
+' ' Text
+'st' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'Node' Keyword.Type
+' ' Text
+'{' Punctuation
+'getHint' Name
+'::' Operator.Word
+' ' Text
+'!' Operator
+'Hint' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+',' Punctuation
+'getHead' Name
+'::' Operator.Word
+' ' Text
+'!' Operator
+'(' Punctuation
+'Head' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'-- head for the column this node is in' Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+',' Punctuation
+'up' Name
+',' Punctuation
+'down' Name
+',' Punctuation
+'left' Name
+',' Punctuation
+'right' Name
+' ' Text
+'::' Operator.Word
+' ' Text
+'!' Operator
+'(' Punctuation
+'NodePtr' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'-- two doubly-linked lists' Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+'}' Punctuation
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'instance' Keyword.Reserved
+' ' Text
+'Eq' Keyword.Type
+' ' Text
+'(' Punctuation
+'Head' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'where' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'a' Name.Function
+' ' Text
+'==' Operator
+' ' Text
+'b' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'headName' Name
+' ' Text
+'a' Name
+' ' Text
+'==' Operator
+' ' Text
+'headName' Name
+' ' Text
+'b' Name
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'instance' Keyword.Reserved
+' ' Text
+'Eq' Keyword.Type
+' ' Text
+'(' Punctuation
+'Node' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'where' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'a' Name.Function
+' ' Text
+'==' Operator
+' ' Text
+'b' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'up' Name
+' ' Text
+'a' Name
+' ' Text
+'==' Operator
+' ' Text
+'up' Name
+' ' Text
+'b' Name
+'\n' Text
+
+'\n' Text
+
+" To initialize the structures is a bit tedious. Knuth's code reads in\n" Text
+
+' the problem description from a data file and builds the structure\n' Text
+
+' based on that. Rather than short strings, I will use HeadName as the\n' Text
+
+' identifier.\n' Text
+
+' \n' Text
+
+' The columns are (0,4,5) for nodes that put some value in Row 4 Col 5\n' Text
+
+' (1,2,3) for nodes that put Val 3 in Row 2 and some column\n' Text
+
+' (2,7,4) for nodes that put Val 4 in Col 7 and some row\n' Text
+
+' (3,1,8) for nodes that put Val 8 in some (row,column) in Block 1\n' Text
+
+'\n' Text
+
+' The first head is (0,0,0) which is the root. The non-root head data\n' Text
+
+' will be put in an array with the HeadName as an index.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'headNames' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'[' Punctuation
+'HeadName' Keyword.Type
+']' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'headNames' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'let' Keyword.Reserved
+' ' Text
+'names' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'[' Punctuation
+'0' Literal.Number.Integer
+',' Punctuation
+'1' Literal.Number.Integer
+',' Punctuation
+'2' Literal.Number.Integer
+',' Punctuation
+'3' Literal.Number.Integer
+']' Punctuation
+' \n' Text
+
+'> ' Comment.Special
+'in' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'0' Literal.Number.Integer
+',' Punctuation
+'0' Literal.Number.Integer
+',' Punctuation
+'0' Literal.Number.Integer
+')' Punctuation
+':' Keyword.Type
+'[' Punctuation
+' ' Text
+'(' Punctuation
+'l' Name
+',' Punctuation
+'i' Name
+',' Punctuation
+'j' Name
+')' Punctuation
+' ' Text
+'|' Operator
+' ' Text
+'l' Name
+'<-' Operator.Word
+'names' Name
+',' Punctuation
+'i' Name
+'<-' Operator.Word
+'rng' Name
+',' Punctuation
+'j' Name
+'<-' Operator.Word
+'rng' Name
+']' Punctuation
+'\n' Text
+
+'\n' Text
+
+' A "row" of left-right linked nodes is a move. It is defined by a\n' Text
+
+' list of head names.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'type' Keyword.Reserved
+' ' Text
+'Move' Keyword.Type
+' ' Text
+'=' Operator.Word
+' ' Text
+'[' Punctuation
+'(' Punctuation
+'Hint' Keyword.Type
+',' Punctuation
+'HeadName' Keyword.Type
+')' Punctuation
+']' Punctuation
+'\n' Text
+
+'\n' Text
+
+' Initial hints are enforced by making them the only legal move for\n' Text
+
+" that location. Blank entries with value 'u = V 0' have a move for\n" Text
+
+' all possible values [V 1..V 9].\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'parseSpec' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'Spec' Keyword.Type
+' ' Text
+'->' Operator.Word
+' ' Text
+'[' Punctuation
+'Move' Keyword.Type
+']' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'parseSpec' Name.Function
+' ' Text
+'spec' Name
+' ' Text
+'=' Operator.Word
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'rowsFrom' Name
+' ' Text
+'::' Operator.Word
+' ' Text
+'Hint' Keyword.Type
+' ' Text
+'->' Operator.Word
+' ' Text
+'[' Punctuation
+'Move' Keyword.Type
+']' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'rowsFrom' Name.Function
+' ' Text
+'(' Punctuation
+'rc' Name
+'@' Operator
+'(' Punctuation
+'R' Keyword.Type
+' ' Text
+'r' Name
+',' Punctuation
+'C' Keyword.Type
+' ' Text
+'c' Name
+')' Punctuation
+',' Punctuation
+'mv' Name
+'@' Operator
+'(' Punctuation
+'V' Keyword.Type
+' ' Text
+"v'" Name
+')' Punctuation
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' \n' Text
+
+'> ' Comment.Special
+'if' Keyword.Reserved
+' ' Text
+'mv' Name
+' ' Text
+'==' Operator
+' ' Text
+'u' Name
+' ' Text
+'then' Keyword.Reserved
+' ' Text
+'[' Punctuation
+' ' Text
+'rsyms' Name
+' ' Text
+'v' Name
+' ' Text
+'|' Operator
+' ' Text
+'v' Name
+' ' Text
+'<-' Operator.Word
+' ' Text
+'rng' Name
+' ' Text
+']' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'else' Keyword.Reserved
+' ' Text
+'[' Punctuation
+' ' Text
+'rsyms' Name
+' ' Text
+"v'" Name
+' ' Text
+']' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'where' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'B' Keyword.Type
+' ' Text
+'b' Name
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'lookupBlock' Name
+' ' Text
+'!' Operator
+' ' Text
+'rc' Name
+'\n' Text
+
+'> ' Comment.Special
+'rsyms' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'A' Keyword.Type
+' ' Text
+'->' Operator.Word
+' ' Text
+'Move' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+'rsyms' Name.Function
+' ' Text
+'v' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'map' Name
+' ' Text
+'(' Punctuation
+' ' Text
+'(' Punctuation
+',' Punctuation
+')' Punctuation
+' ' Text
+'(' Punctuation
+'rc' Name
+',' Punctuation
+'V' Keyword.Type
+' ' Text
+'v' Name
+')' Punctuation
+' ' Text
+')' Punctuation
+' ' Text
+'[' Punctuation
+'(' Punctuation
+'0' Literal.Number.Integer
+',' Punctuation
+'r' Name
+',' Punctuation
+'c' Name
+')' Punctuation
+',' Punctuation
+'(' Punctuation
+'1' Literal.Number.Integer
+',' Punctuation
+'r' Name
+',' Punctuation
+'v' Name
+')' Punctuation
+',' Punctuation
+'(' Punctuation
+'2' Literal.Number.Integer
+',' Punctuation
+'c' Name
+',' Punctuation
+'v' Name
+')' Punctuation
+',' Punctuation
+'(' Punctuation
+'3' Literal.Number.Integer
+',' Punctuation
+'b' Name
+',' Punctuation
+'v' Name
+')' Punctuation
+']' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'in' Keyword.Reserved
+' ' Text
+'concatMap' Name
+' ' Text
+'rowsFrom' Name
+' ' Text
+'(' Punctuation
+'assocs' Name
+' ' Text
+'(' Punctuation
+'parse' Name
+' ' Text
+'spec' Name
+')' Punctuation
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' mkDList creates doubly linked lists using a monadic smart\n' Text
+
+' constructor and the recursive "mdo" notation as documented at\n' Text
+
+' http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#mdo-notation\n' Text
+
+' http://www.cse.ogi.edu/PacSoft/projects/rmb/\n' Text
+
+'\n' Text
+
+' For more fun with this, see the wiki page at\n' Text
+
+' http://haskell.org/hawiki/TyingTheKnot\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'mkDList' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'MonadFix' Keyword.Type
+' ' Text
+'m' Name
+')' Punctuation
+' ' Text
+'=>' Operator.Word
+' ' Text
+'(' Punctuation
+'b' Name
+' ' Text
+'->' Operator.Word
+' ' Text
+'a' Name
+' ' Text
+'->' Operator.Word
+' ' Text
+'b' Name
+' ' Text
+'->' Operator.Word
+' ' Text
+'m' Name
+' ' Text
+'b' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'[' Punctuation
+'a' Name
+']' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'m' Name
+' ' Text
+'b' Name
+'\n' Text
+
+'> ' Comment.Special
+'mkDList' Name.Function
+' ' Text
+'_' Keyword.Reserved
+' ' Text
+'[]' Keyword.Type
+' ' Text
+'=' Operator.Word
+' ' Text
+'error' Name.Exception
+' ' Text
+'"' Literal.String
+'must have at least one element' Literal.String
+'"' Literal.String
+'\n' Text
+
+'> ' Comment.Special
+'mkDList' Name.Function
+' ' Text
+'mkNode' Name
+' ' Text
+'xs' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'mdo' Name
+' ' Text
+'(' Punctuation
+'first' Name
+',' Punctuation
+'last' Name
+')' Punctuation
+' ' Text
+'<-' Operator.Word
+' ' Text
+'go' Name
+' ' Text
+'last' Name
+' ' Text
+'xs' Name
+' ' Text
+'first' Name
+'\n' Text
+
+'> ' Comment.Special
+'return' Name.Function
+' ' Text
+'first' Name
+'\n' Text
+
+'> ' Comment.Special
+'where' Keyword.Reserved
+' ' Text
+'go' Name
+' ' Text
+'prev' Name
+' ' Text
+'[]' Keyword.Type
+' ' Text
+'next' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'return' Name
+' ' Text
+'(' Punctuation
+'next' Name
+',' Punctuation
+'prev' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'go' Name.Function
+' ' Text
+'prev' Name
+' ' Text
+'(' Punctuation
+'x' Name
+':' Keyword.Type
+'xs' Name
+')' Punctuation
+' ' Text
+'next' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'mdo' Name
+' ' Text
+'this' Name
+' ' Text
+'<-' Operator.Word
+' ' Text
+'mkNode' Name
+' ' Text
+'prev' Name
+' ' Text
+'x' Name
+' ' Text
+'rest' Name
+'\n' Text
+
+'> ' Comment.Special
+'(' Punctuation
+'rest' Name
+',' Punctuation
+'last' Name
+')' Punctuation
+' ' Text
+'<-' Operator.Word
+' ' Text
+'go' Name
+' ' Text
+'this' Name
+' ' Text
+'xs' Name
+' ' Text
+'next' Name
+'\n' Text
+
+'> ' Comment.Special
+'return' Name.Function
+' ' Text
+'(' Punctuation
+'this' Name
+',' Punctuation
+'last' Name
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' toSimple takes a function and a header node and iterates (read . function)\n' Text
+
+' until the header is reached again, but does not return the header\n' Text
+
+' itself.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'toSingle' Name.Function
+' ' Text
+'step' Name
+' ' Text
+'header' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'loop' Name
+' ' Text
+'=<<' Operator
+' ' Text
+'(' Punctuation
+'read' Name
+' ' Text
+'.' Operator
+' ' Text
+'step' Name
+')' Punctuation
+' ' Text
+'header' Name
+'\n' Text
+
+'> ' Comment.Special
+'where' Keyword.Reserved
+' ' Text
+'loop' Name
+' ' Text
+'y' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'if' Keyword.Reserved
+' ' Text
+'header' Name
+'/=' Operator
+'y' Name
+' ' Text
+'then' Keyword.Reserved
+' ' Text
+'liftM' Name
+' ' Text
+'(' Punctuation
+'y' Name
+':' Keyword.Type
+')' Punctuation
+' ' Text
+'(' Punctuation
+'read' Name
+' ' Text
+'(' Punctuation
+'step' Name
+' ' Text
+'y' Name
+')' Punctuation
+' ' Text
+'>>=' Operator
+' ' Text
+'loop' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'else' Keyword.Reserved
+' ' Text
+'return' Name
+' ' Text
+'[]' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+'\n' Text
+
+'\n' Text
+
+' forEach is an optimization of (toSimple step header >>= mapM_ act)\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'forEach' Name.Function
+' ' Text
+'step' Name
+' ' Text
+'header' Name
+' ' Text
+'act' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'loop' Name
+' ' Text
+'=<<' Operator
+' ' Text
+'(' Punctuation
+'read' Name
+' ' Text
+'.' Operator
+' ' Text
+'step' Name
+')' Punctuation
+' ' Text
+'header' Name
+'\n' Text
+
+'> ' Comment.Special
+'where' Keyword.Reserved
+' ' Text
+'loop' Name
+' ' Text
+'y' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'if' Keyword.Reserved
+' ' Text
+'header' Name
+'/=' Operator
+'y' Name
+' ' Text
+'then' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'act' Name
+' ' Text
+'y' Name
+' ' Text
+'>>' Operator
+' ' Text
+'(' Punctuation
+'read' Name
+' ' Text
+'(' Punctuation
+'step' Name
+' ' Text
+'y' Name
+')' Punctuation
+')' Punctuation
+' ' Text
+'>>=' Operator
+' ' Text
+'loop' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'else' Keyword.Reserved
+' ' Text
+'return' Name
+' ' Text
+'()' Name.Builtin
+'\n' Text
+
+'\n' Text
+
+' Now make the root node and all the head nodes. This also exploits mdo:\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'makeHeads' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'[' Punctuation
+'HeadName' Keyword.Type
+']' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'Head' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'makeHeads' Name.Function
+' ' Text
+'names' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'mkDList' Name
+' ' Text
+'makeHead' Name
+' ' Text
+'names' Name
+'\n' Text
+
+'> ' Comment.Special
+'where' Keyword.Reserved
+' ' Text
+'makeHead' Name
+' ' Text
+'before' Name
+' ' Text
+'name' Name
+' ' Text
+'after' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'mdo' Name
+'\n' Text
+
+'> ' Comment.Special
+'~' Operator
+'newTopNode' Name
+' ' Text
+'<-' Operator.Word
+' ' Text
+'liftM4' Name
+' ' Text
+'(' Punctuation
+'Node' Keyword.Type
+' ' Text
+'(' Punctuation
+'(' Punctuation
+'R' Keyword.Type
+' ' Text
+'0' Literal.Number.Integer
+',' Punctuation
+'C' Keyword.Type
+' ' Text
+'0' Literal.Number.Integer
+')' Punctuation
+',' Punctuation
+'V' Keyword.Type
+' ' Text
+'0' Literal.Number.Integer
+')' Punctuation
+' ' Text
+'newHead' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'new' Name
+' ' Text
+'newTopNode' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'new' Name
+' ' Text
+'newTopNode' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'(' Punctuation
+'new' Name
+' ' Text
+'newTopNode' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'new' Name
+' ' Text
+'newTopNode' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'newHead' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'liftM3' Name
+' ' Text
+'(' Punctuation
+'Head' Keyword.Type
+' ' Text
+'name' Name
+' ' Text
+'newTopNode' Name
+')' Punctuation
+' \n' Text
+
+'> ' Comment.Special
+'(' Punctuation
+'new' Name
+' ' Text
+'0' Literal.Number.Integer
+')' Punctuation
+' ' Text
+'(' Punctuation
+'new' Name
+' ' Text
+'after' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'new' Name
+' ' Text
+'before' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'return' Name.Function
+' ' Text
+'newHead' Name
+'\n' Text
+
+'\n' Text
+
+' The Head nodes will be places in an array for easy lookup while building moves:\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'type' Keyword.Reserved
+' ' Text
+'HArray' Keyword.Type
+' ' Text
+'st' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'Array' Keyword.Type
+' ' Text
+'HeadName' Keyword.Type
+' ' Text
+'(' Punctuation
+'Head' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'hBounds' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'(' Punctuation
+'(' Punctuation
+'0' Literal.Number.Integer
+',' Punctuation
+'1' Literal.Number.Integer
+',' Punctuation
+'1' Literal.Number.Integer
+')' Punctuation
+',' Punctuation
+'(' Punctuation
+'3' Literal.Number.Integer
+',' Punctuation
+'9' Literal.Number.Integer
+',' Punctuation
+'9' Literal.Number.Integer
+')' Punctuation
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'type' Keyword.Reserved
+' ' Text
+'Root' Keyword.Type
+' ' Text
+'st' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'(' Punctuation
+'Head' Keyword.Type
+' ' Text
+'st' Name
+',' Punctuation
+'HArray' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' The addMove function creates the (four) nodes that represent a move and adds\n' Text
+
+' them to the data structure. The HArray in Root makes for a fast\n' Text
+
+' lookup of the Head data.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'addMove' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'forall' Name
+' ' Text
+'st' Name
+'.' Operator
+' ' Text
+'(' Punctuation
+'Root' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'Move' Keyword.Type
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'Node' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'addMove' Name.Function
+' ' Text
+'(' Punctuation
+'_' Keyword.Reserved
+',' Punctuation
+'ha' Name
+')' Punctuation
+' ' Text
+'move' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'mkDList' Name
+' ' Text
+'addNode' Name
+' ' Text
+'move' Name
+'\n' Text
+
+'> ' Comment.Special
+'where' Keyword.Reserved
+' ' Text
+'addNode' Name
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'Node' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'Hint' Keyword.Type
+',' Punctuation
+'HeadName' Keyword.Type
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'Node' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'Node' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'addNode' Name.Function
+' ' Text
+'before' Name
+' ' Text
+'(' Punctuation
+'hint' Name
+',' Punctuation
+'name' Name
+')' Punctuation
+' ' Text
+'after' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'head' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'ha' Name
+' ' Text
+'!' Operator
+' ' Text
+'name' Name
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'below' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'topNode' Name
+' ' Text
+'head' Name
+'\n' Text
+
+'> ' Comment.Special
+'above' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'read' Name
+' ' Text
+'(' Punctuation
+'up' Name
+' ' Text
+'below' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'newNode' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'liftM4' Name
+' ' Text
+'(' Punctuation
+'Node' Keyword.Type
+' ' Text
+'hint' Name
+' ' Text
+'head' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'new' Name
+' ' Text
+'above' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'new' Name
+' ' Text
+'below' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'(' Punctuation
+'new' Name
+' ' Text
+'before' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'new' Name
+' ' Text
+'after' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'down' Name
+' ' Text
+'above' Name
+')' Punctuation
+' ' Text
+'newNode' Name
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'up' Name
+' ' Text
+'below' Name
+')' Punctuation
+' ' Text
+'newNode' Name
+'\n' Text
+
+'> ' Comment.Special
+'modify' Name.Function
+' ' Text
+'(' Punctuation
+'len' Name
+' ' Text
+'head' Name
+')' Punctuation
+' ' Text
+'succ' Name
+'\n' Text
+
+'> ' Comment.Special
+'l' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'read' Name
+' ' Text
+'(' Punctuation
+'len' Name
+' ' Text
+'head' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'seq' Name.Function
+' ' Text
+'l' Name
+' ' Text
+'(' Punctuation
+'return' Name
+' ' Text
+'newNode' Name
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' Create the column headers, including the fast lookup array. These\n' Text
+
+' will be resused between puzzles.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'initHA' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'Root' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'initHA' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'root' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'makeHeads' Name
+' ' Text
+'headNames' Name
+'\n' Text
+
+'> ' Comment.Special
+'heads' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'toSingle' Name
+' ' Text
+'next' Name
+' ' Text
+'root' Name
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'ha' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'array' Name
+' ' Text
+'hBounds' Name
+' ' Text
+'(' Punctuation
+'zip' Name
+' ' Text
+'(' Punctuation
+'map' Name
+' ' Text
+'headName' Name
+' ' Text
+'heads' Name
+')' Punctuation
+' ' Text
+'heads' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'return' Name.Function
+' ' Text
+'(' Punctuation
+'root' Name
+',' Punctuation
+'ha' Name
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' Take the Root from initHA and a puzzle Spec and fill in all the Nodes.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'initRoot' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'Root' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'Spec' Keyword.Type
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'()' Name.Builtin
+'\n' Text
+
+'> ' Comment.Special
+'initRoot' Name.Function
+' ' Text
+'root' Name
+' ' Text
+'spec' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'moves' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'parseSpec' Name
+' ' Text
+'spec' Name
+'\n' Text
+
+'> ' Comment.Special
+'mapM_' Name.Function
+' ' Text
+'(' Punctuation
+'addMove' Name
+' ' Text
+'root' Name
+')' Punctuation
+' ' Text
+'moves' Name
+'\n' Text
+
+'\n' Text
+
+' Return the column headers to their condition after initHA\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'resetRoot' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'Root' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'()' Name.Builtin
+'\n' Text
+
+'> ' Comment.Special
+'resetRoot' Name.Function
+' ' Text
+'(' Punctuation
+'root' Name
+',' Punctuation
+'ha' Name
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'heads' Name
+'@' Operator
+'(' Punctuation
+'first' Name
+':' Keyword.Type
+'_' Keyword.Reserved
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'elems' Name
+' ' Text
+'ha' Name
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'resetHead' Name
+' ' Text
+'head' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'len' Name
+' ' Text
+'head' Name
+')' Punctuation
+' ' Text
+'0' Literal.Number.Integer
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'node' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'topNode' Name
+' ' Text
+'head' Name
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'down' Name
+' ' Text
+'node' Name
+')' Punctuation
+' ' Text
+'node' Name
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'up' Name
+' ' Text
+'node' Name
+')' Punctuation
+' ' Text
+'node' Name
+'\n' Text
+
+'> ' Comment.Special
+'reset' Name.Function
+' ' Text
+'(' Punctuation
+'last' Name
+':' Keyword.Type
+'[]' Keyword.Type
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'prev' Name
+' ' Text
+'root' Name
+')' Punctuation
+' ' Text
+'last' Name
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'next' Name
+' ' Text
+'root' Name
+')' Punctuation
+' ' Text
+'first' Name
+'\n' Text
+
+'> ' Comment.Special
+'reset' Name.Function
+' ' Text
+'(' Punctuation
+'before' Name
+':' Keyword.Type
+'xs' Name
+'@' Operator
+'(' Punctuation
+'head' Name
+':' Keyword.Type
+'[]' Keyword.Type
+')' Punctuation
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'resetHead' Name.Function
+' ' Text
+'head' Name
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'prev' Name
+' ' Text
+'head' Name
+')' Punctuation
+' ' Text
+'before' Name
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'next' Name
+' ' Text
+'head' Name
+')' Punctuation
+' ' Text
+'root' Name
+'\n' Text
+
+'> ' Comment.Special
+'reset' Name.Function
+' ' Text
+'xs' Name
+'\n' Text
+
+'> ' Comment.Special
+'reset' Name.Function
+' ' Text
+'(' Punctuation
+'before' Name
+':' Keyword.Type
+'xs' Name
+'@' Operator
+'(' Punctuation
+'head' Name
+':' Keyword.Type
+'after' Name
+':' Keyword.Type
+'_' Keyword.Reserved
+')' Punctuation
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'resetHead' Name.Function
+' ' Text
+'head' Name
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'prev' Name
+' ' Text
+'head' Name
+')' Punctuation
+' ' Text
+'before' Name
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'next' Name
+' ' Text
+'head' Name
+')' Punctuation
+' ' Text
+'after' Name
+'\n' Text
+
+'> ' Comment.Special
+'reset' Name.Function
+' ' Text
+'xs' Name
+'\n' Text
+
+'> ' Comment.Special
+'reset' Name.Function
+' ' Text
+'(' Punctuation
+'root' Name
+':' Keyword.Type
+'heads' Name
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' getBest iterates over the unmet constraints (i.e. the Head that are\n' Text
+
+' reachable from root). It locates the one with the lowest number of\n' Text
+
+' possible moves that will solve it, aborting early if it finds 0 or 1\n' Text
+
+' moves.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'getBest' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'Head' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'Maybe' Keyword.Type
+' ' Text
+'(' Punctuation
+'Head' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'getBest' Name.Function
+' ' Text
+'root' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'first' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'read' Name
+' ' Text
+'(' Punctuation
+'next' Name
+' ' Text
+'root' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'if' Keyword.Reserved
+' ' Text
+'first' Name
+' ' Text
+'==' Operator
+' ' Text
+'root' Name
+' ' Text
+'then' Keyword.Reserved
+' ' Text
+'return' Name
+' ' Text
+'Nothing' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+'else' Keyword.Reserved
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'findMin' Name
+' ' Text
+'m' Name
+' ' Text
+'best' Name
+' ' Text
+'head' Name
+' ' Text
+'|' Operator
+' ' Text
+'head' Name
+' ' Text
+'==' Operator
+' ' Text
+'root' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'return' Name
+' ' Text
+'(' Punctuation
+'Just' Keyword.Type
+' ' Text
+'best' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'|' Operator
+' ' Text
+'otherwise' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'l' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'read' Name
+' ' Text
+'(' Punctuation
+'len' Name
+' ' Text
+'head' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'if' Keyword.Reserved
+' ' Text
+'l' Name
+' ' Text
+'<=' Operator
+' ' Text
+'1' Literal.Number.Integer
+' ' Text
+'then' Keyword.Reserved
+' ' Text
+'return' Name
+' ' Text
+'(' Punctuation
+'Just' Keyword.Type
+' ' Text
+'head' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'else' Keyword.Reserved
+' ' Text
+'if' Keyword.Reserved
+' ' Text
+'l' Name
+' ' Text
+'<' Operator
+' ' Text
+'m' Name
+' ' Text
+'then' Keyword.Reserved
+' ' Text
+'findMin' Name
+' ' Text
+'l' Name
+' ' Text
+'head' Name
+' ' Text
+'=<<' Operator
+' ' Text
+'read' Name
+' ' Text
+'(' Punctuation
+'next' Name
+' ' Text
+'head' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'else' Keyword.Reserved
+' ' Text
+'findMin' Name
+' ' Text
+'l' Name
+' ' Text
+'best' Name
+' ' Text
+'=<<' Operator
+' ' Text
+'read' Name
+' ' Text
+'(' Punctuation
+'next' Name
+' ' Text
+'head' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'findMin' Name.Function
+' ' Text
+'10' Literal.Number.Integer
+' ' Text
+'first' Name
+' ' Text
+'first' Name
+'\n' Text
+
+'\n' Text
+
+' The unlink and relink operations are from where Knuth got the name\n' Text
+
+' "dancing links". So long as "a" does not change in between, the\n' Text
+
+' relink call will undo the unlink call. Similarly, the unconver will\n' Text
+
+' undo the changes of cover and unconverOthers will undo coverOthers.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'unlink' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'a' Name
+'->' Operator.Word
+'STRef' Keyword.Type
+' ' Text
+'st' Name
+' ' Text
+'a' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'a' Name
+'->' Operator.Word
+'STRef' Keyword.Type
+' ' Text
+'st' Name
+' ' Text
+'a' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'a' Name
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'()' Name.Builtin
+'\n' Text
+
+'> ' Comment.Special
+'unlink' Name.Function
+' ' Text
+'prev' Name
+' ' Text
+'next' Name
+' ' Text
+'a' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'before' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'read' Name
+' ' Text
+'(' Punctuation
+'prev' Name
+' ' Text
+'a' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'after' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'read' Name
+' ' Text
+'(' Punctuation
+'next' Name
+' ' Text
+'a' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'next' Name
+' ' Text
+'before' Name
+')' Punctuation
+' ' Text
+'after' Name
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'prev' Name
+' ' Text
+'after' Name
+')' Punctuation
+' ' Text
+'before' Name
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'relink' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'a' Name
+'->' Operator.Word
+'STRef' Keyword.Type
+' ' Text
+'st' Name
+' ' Text
+'a' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'a' Name
+'->' Operator.Word
+'STRef' Keyword.Type
+' ' Text
+'st' Name
+' ' Text
+'a' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'a' Name
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'()' Name.Builtin
+'\n' Text
+
+'> ' Comment.Special
+'relink' Name.Function
+' ' Text
+'prev' Name
+' ' Text
+'next' Name
+' ' Text
+'a' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'before' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'read' Name
+' ' Text
+'(' Punctuation
+'prev' Name
+' ' Text
+'a' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'after' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'read' Name
+' ' Text
+'(' Punctuation
+'next' Name
+' ' Text
+'a' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'next' Name
+' ' Text
+'before' Name
+')' Punctuation
+' ' Text
+'a' Name
+'\n' Text
+
+'> ' Comment.Special
+'write' Name.Function
+' ' Text
+'(' Punctuation
+'prev' Name
+' ' Text
+'after' Name
+')' Punctuation
+' ' Text
+'a' Name
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'cover' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'Head' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'()' Name.Builtin
+'\n' Text
+
+'> ' Comment.Special
+'cover' Name.Function
+' ' Text
+'head' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'unlink' Name.Function
+' ' Text
+'prev' Name
+' ' Text
+'next' Name
+' ' Text
+'head' Name
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'eachDown' Name
+' ' Text
+'rr' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'forEach' Name
+' ' Text
+'right' Name
+' ' Text
+'rr' Name
+' ' Text
+'eachRight' Name
+'\n' Text
+
+'> ' Comment.Special
+'eachRight' Name.Function
+' ' Text
+'nn' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'unlink' Name.Function
+' ' Text
+'up' Name
+' ' Text
+'down' Name
+' ' Text
+'nn' Name
+'\n' Text
+
+'> ' Comment.Special
+'modify' Name.Function
+' ' Text
+'(' Punctuation
+'len' Name
+' ' Text
+'$' Operator
+' ' Text
+'getHead' Name
+' ' Text
+'nn' Name
+')' Punctuation
+' ' Text
+'pred' Name
+'\n' Text
+
+'> ' Comment.Special
+'forEach' Name.Function
+' ' Text
+'down' Name
+' ' Text
+'(' Punctuation
+'topNode' Name
+' ' Text
+'head' Name
+')' Punctuation
+' ' Text
+'eachDown' Name
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'uncover' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'Head' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'()' Name.Builtin
+'\n' Text
+
+'> ' Comment.Special
+'uncover' Name.Function
+' ' Text
+'head' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'eachUp' Name
+' ' Text
+'rr' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'forEach' Name
+' ' Text
+'left' Name
+' ' Text
+'rr' Name
+' ' Text
+'eachLeft' Name
+'\n' Text
+
+'> ' Comment.Special
+'eachLeft' Name.Function
+' ' Text
+'nn' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'modify' Name.Function
+' ' Text
+'(' Punctuation
+'len' Name
+' ' Text
+'$' Operator
+' ' Text
+'getHead' Name
+' ' Text
+'nn' Name
+')' Punctuation
+' ' Text
+'succ' Name
+'\n' Text
+
+'> ' Comment.Special
+'relink' Name.Function
+' ' Text
+'up' Name
+' ' Text
+'down' Name
+' ' Text
+'nn' Name
+'\n' Text
+
+'> ' Comment.Special
+'forEach' Name.Function
+' ' Text
+'up' Name
+' ' Text
+'(' Punctuation
+'topNode' Name
+' ' Text
+'head' Name
+')' Punctuation
+' ' Text
+'eachUp' Name
+'\n' Text
+
+'> ' Comment.Special
+'relink' Name.Function
+' ' Text
+'prev' Name
+' ' Text
+'next' Name
+' ' Text
+'head' Name
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'coverOthers' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'Node' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'()' Name.Builtin
+'\n' Text
+
+'> ' Comment.Special
+'coverOthers' Name.Function
+' ' Text
+'node' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'forEach' Name
+' ' Text
+'right' Name
+' ' Text
+'node' Name
+' ' Text
+'(' Punctuation
+'cover' Name
+' ' Text
+'.' Operator
+' ' Text
+'getHead' Name
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'uncoverOthers' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'Node' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'()' Name.Builtin
+'\n' Text
+
+'> ' Comment.Special
+'uncoverOthers' Name.Function
+' ' Text
+'node' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'forEach' Name
+' ' Text
+'left' Name
+' ' Text
+'node' Name
+' ' Text
+'(' Punctuation
+'uncover' Name
+' ' Text
+'.' Operator
+' ' Text
+'getHead' Name
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' A helper function for gdance:\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'choicesToSpec' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'[' Punctuation
+'(' Punctuation
+'Node' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+']' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'Spec' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+'choicesToSpec' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'Spec' Keyword.Type
+' ' Text
+'.' Operator
+' ' Text
+'(' Punctuation
+'map' Name
+' ' Text
+'getHint' Name
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' This is the heart of the algorithm. I have altered it to return only\n' Text
+
+' the first solution, or produce an error if none is found.\n' Text
+
+'\n' Text
+
+' Knuth used several goto links to do what is done below with tail\n' Text
+
+' recursion.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'gdance' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'Head' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'(' Punctuation
+'ST' Keyword.Type
+' ' Text
+'st' Name
+')' Punctuation
+' ' Text
+'Spec' Keyword.Type
+' ' Text
+'-- [Spec]' Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+'gdance' Name.Function
+' ' Text
+'root' Name
+' ' Text
+'=' Operator.Word
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'forward' Name.Function
+' ' Text
+'choices' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'maybeHead' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'getBest' Name
+' ' Text
+'root' Name
+'\n' Text
+
+'> ' Comment.Special
+'case' Keyword.Reserved
+' ' Text
+'maybeHead' Name
+' ' Text
+'of' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'Nothing' Keyword.Type
+' ' Text
+'->' Operator.Word
+' ' Text
+'if' Keyword.Reserved
+' ' Text
+'null' Name
+' ' Text
+'choices' Name
+'\n' Text
+
+'> ' Comment.Special
+'then' Keyword.Reserved
+' ' Text
+'error' Name.Exception
+' ' Text
+'"' Literal.String
+'No choices in forward' Literal.String
+'"' Literal.String
+' ' Text
+'-- return [] -- for [Spec]' Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+'else' Keyword.Reserved
+' ' Text
+'do' Keyword.Reserved
+' ' Text
+'-- nextSols <- recover choices -- for [Spec]' Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+'return' Name.Function
+' ' Text
+'$' Operator
+' ' Text
+'(' Punctuation
+'choicesToSpec' Name
+' ' Text
+'choices' Name
+')' Punctuation
+' ' Text
+'-- :nextSols -- for [Spec]' Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+'Just' Keyword.Type
+' ' Text
+'head' Name
+' ' Text
+'->' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+' ' Text
+'cover' Name
+' ' Text
+'head' Name
+'\n' Text
+
+'> ' Comment.Special
+'startRow' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'readSTRef' Name
+' ' Text
+'(' Punctuation
+'down' Name
+' ' Text
+'(' Punctuation
+'topNode' Name
+' ' Text
+'head' Name
+')' Punctuation
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'advance' Name.Function
+' ' Text
+'(' Punctuation
+'startRow' Name
+':' Keyword.Type
+'choices' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'\n' Text
+
+'> ' Comment.Special
+'advance' Name.Function
+' ' Text
+'choices' Name
+'@' Operator
+'(' Punctuation
+'newRow' Name
+':' Keyword.Type
+'oldChoices' Name
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'endOfRows' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'topNode' Name
+' ' Text
+'(' Punctuation
+'getHead' Name
+' ' Text
+'newRow' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'if' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'newRow' Name
+' ' Text
+'==' Operator
+' ' Text
+'endOfRows' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'then' Keyword.Reserved
+' ' Text
+'do' Keyword.Reserved
+' ' Text
+'uncover' Name
+' ' Text
+'(' Punctuation
+'getHead' Name
+' ' Text
+'newRow' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'if' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'null' Name
+' ' Text
+'oldChoices' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'then' Keyword.Reserved
+' ' Text
+'error' Name.Exception
+' ' Text
+'"' Literal.String
+'No choices in advance' Literal.String
+'"' Literal.String
+' ' Text
+'-- return [] -- for [Spec]' Comment.Single
+'\n' Text
+
+'> ' Comment.Special
+'else' Keyword.Reserved
+' ' Text
+'recover' Name
+' ' Text
+'oldChoices' Name
+'\n' Text
+
+'> ' Comment.Special
+'else' Keyword.Reserved
+' ' Text
+'do' Keyword.Reserved
+' ' Text
+'coverOthers' Name
+' ' Text
+'newRow' Name
+'\n' Text
+
+'> ' Comment.Special
+'forward' Name.Function
+' ' Text
+'choices' Name
+'\n' Text
+
+'> ' Comment.Special
+'\n' Text
+
+'> ' Comment.Special
+'recover' Name.Function
+' ' Text
+'(' Punctuation
+'oldRow' Name
+':' Keyword.Type
+'oldChoices' Name
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'uncoverOthers' Name.Function
+' ' Text
+'oldRow' Name
+'\n' Text
+
+'> ' Comment.Special
+'newRow' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'readSTRef' Name
+' ' Text
+'(' Punctuation
+'down' Name
+' ' Text
+'oldRow' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'advance' Name.Function
+' ' Text
+'(' Punctuation
+'newRow' Name
+':' Keyword.Type
+'oldChoices' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'\n' Text
+
+'> ' Comment.Special
+'in' Keyword.Reserved
+' ' Text
+'forward' Name
+' ' Text
+'[]' Keyword.Type
+'\n' Text
+
+'\n' Text
+
+'\n' Text
+
+' Convert a text board into a Spec\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'parseBoard' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'String' Keyword.Type
+' ' Text
+'->' Operator.Word
+' ' Text
+'Spec' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+'parseBoard' Name.Function
+' ' Text
+'s' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'Spec' Keyword.Type
+' ' Text
+'(' Punctuation
+'zip' Name
+' ' Text
+'rcs' Name
+' ' Text
+"vs'check" Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'where' Keyword.Reserved
+' ' Text
+'rcs' Name
+' ' Text
+'::' Operator.Word
+' ' Text
+'[' Punctuation
+'(' Punctuation
+'R' Keyword.Type
+',' Punctuation
+'C' Keyword.Type
+')' Punctuation
+']' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'rcs' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'[' Punctuation
+' ' Text
+'(' Punctuation
+'R' Keyword.Type
+' ' Text
+'r' Name
+',' Punctuation
+'C' Keyword.Type
+' ' Text
+'c' Name
+')' Punctuation
+' ' Text
+'|' Operator
+' ' Text
+'r' Name
+' ' Text
+'<-' Operator.Word
+' ' Text
+'rng' Name
+',' Punctuation
+' ' Text
+'c' Name
+' ' Text
+'<-' Operator.Word
+' ' Text
+'rng' Name
+' ' Text
+']' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'isUnset' Name.Function
+' ' Text
+'c' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'(' Punctuation
+'c' Name
+'==' Operator
+"'.'" Literal.String.Char
+')' Punctuation
+' ' Text
+'||' Operator
+' ' Text
+'(' Punctuation
+'c' Name
+'==' Operator
+"' '" Literal.String.Char
+')' Punctuation
+' ' Text
+'||' Operator
+' ' Text
+'(' Punctuation
+'c' Name
+'==' Operator
+"'0'" Literal.String.Char
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'isHint' Name.Function
+' ' Text
+'c' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'(' Punctuation
+"'1'" Literal.String.Char
+'<=' Operator
+'c' Name
+')' Punctuation
+' ' Text
+'&&' Operator
+' ' Text
+'(' Punctuation
+'c' Name
+'<=' Operator
+"'9'" Literal.String.Char
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'cs' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'take' Name
+' ' Text
+'81' Literal.Number.Integer
+' ' Text
+'$' Operator
+' ' Text
+'filter' Name
+' ' Text
+'(' Punctuation
+'\\' Name.Function
+'c' Name
+' ' Text
+'->' Operator.Word
+' ' Text
+'isUnset' Name
+' ' Text
+'c' Name
+' ' Text
+'||' Operator
+' ' Text
+'isHint' Name
+' ' Text
+'c' Name
+')' Punctuation
+' ' Text
+'s' Name
+'\n' Text
+
+'> ' Comment.Special
+'vs' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'[' Punctuation
+'V' Keyword.Type
+']' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'vs' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'map' Name
+' ' Text
+'(' Punctuation
+'\\' Name.Function
+'c' Name
+' ' Text
+'->' Operator.Word
+' ' Text
+'if' Keyword.Reserved
+' ' Text
+'isUnset' Name
+' ' Text
+'c' Name
+' ' Text
+'then' Keyword.Reserved
+' ' Text
+'u' Name
+' ' Text
+'else' Keyword.Reserved
+' ' Text
+'(' Punctuation
+'V' Keyword.Type
+' ' Text
+'$' Operator
+' ' Text
+'digitToInt' Name
+' ' Text
+'c' Name
+')' Punctuation
+')' Punctuation
+' ' Text
+'cs' Name
+'\n' Text
+
+'> ' Comment.Special
+"vs'check" Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'if' Keyword.Reserved
+' ' Text
+'81' Literal.Number.Integer
+'==' Operator
+'length' Name
+' ' Text
+'vs' Name
+' ' Text
+'then' Keyword.Reserved
+' ' Text
+'vs' Name
+' ' Text
+'else' Keyword.Reserved
+' ' Text
+'error' Name.Exception
+' ' Text
+'(' Punctuation
+'"' Literal.String
+'parse of board failed' Literal.String
+'\\' Literal.String.Escape
+'n' Literal.String.Escape
+'"' Literal.String
+'++' Operator
+'s' Name
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' This is quite useful as a utility function which partitions the list into groups of n elements.\n' Text
+
+' Used by showSpec.\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'groupTake' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'Int' Keyword.Type
+'->' Operator.Word
+'[' Punctuation
+'a' Name
+']' Punctuation
+'->' Operator.Word
+'[' Punctuation
+'[' Punctuation
+'a' Name
+']' Punctuation
+']' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'groupTake' Name.Function
+' ' Text
+'n' Name
+' ' Text
+'b' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'unfoldr' Name
+' ' Text
+'foo' Name
+' ' Text
+'b' Name
+'\n' Text
+
+'> ' Comment.Special
+'where' Keyword.Reserved
+' ' Text
+'foo' Name
+' ' Text
+'[]' Keyword.Type
+' ' Text
+'=' Operator.Word
+' ' Text
+'Nothing' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+'foo' Name.Function
+' ' Text
+'b' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'Just' Keyword.Type
+' ' Text
+'(' Punctuation
+'splitAt' Name
+' ' Text
+'n' Name
+' ' Text
+'b' Name
+')' Punctuation
+'\n' Text
+
+' \n' Text
+
+' Make a nice 2D ascii board from the Spec (not used at the moment)\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'showSpec' Name.Function
+' ' Text
+'::' Operator.Word
+' ' Text
+'Spec' Keyword.Type
+' ' Text
+'->' Operator.Word
+' ' Text
+'String' Keyword.Type
+'\n' Text
+
+'> ' Comment.Special
+'showSpec' Name.Function
+' ' Text
+'spec' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'let' Keyword.Reserved
+' ' Text
+'pa' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'parse' Name
+' ' Text
+'spec' Name
+'\n' Text
+
+'> ' Comment.Special
+'g' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'groupTake' Name
+' ' Text
+'9' Literal.Number.Integer
+' ' Text
+'(' Punctuation
+'map' Name
+' ' Text
+'(' Punctuation
+'\\' Name.Function
+'(' Punctuation
+'V' Keyword.Type
+' ' Text
+'v' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'if' Keyword.Reserved
+' ' Text
+'v' Name
+' ' Text
+'==' Operator
+' ' Text
+'0' Literal.Number.Integer
+' ' Text
+'then' Keyword.Reserved
+' ' Text
+"'.'" Literal.String.Char
+' ' Text
+'else' Keyword.Reserved
+' ' Text
+'intToDigit' Name
+' ' Text
+'v' Name
+')' Punctuation
+' ' Text
+'$' Operator
+' ' Text
+'elems' Name
+' ' Text
+'pa' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'addV' Name.Function
+' ' Text
+'line' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'concat' Name
+' ' Text
+'$' Operator
+' ' Text
+'intersperse' Name
+' ' Text
+'"' Literal.String
+'|' Literal.String
+'"' Literal.String
+' ' Text
+'(' Punctuation
+'groupTake' Name
+' ' Text
+'3' Literal.Number.Integer
+' ' Text
+'line' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'addH' Name.Function
+' ' Text
+'list' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'concat' Name
+' ' Text
+'$' Operator
+' ' Text
+'intersperse' Name
+' ' Text
+'[' Punctuation
+'"' Literal.String
+'---+---+---' Literal.String
+'"' Literal.String
+']' Punctuation
+' ' Text
+'(' Punctuation
+'groupTake' Name
+' ' Text
+'3' Literal.Number.Integer
+' ' Text
+'list' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'in' Keyword.Reserved
+' ' Text
+'unlines' Name
+' ' Text
+'$' Operator
+' ' Text
+'addH' Name
+' ' Text
+'(' Punctuation
+'map' Name
+' ' Text
+'addV' Name
+' ' Text
+'g' Name
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' One line display\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'showCompact' Name.Function
+' ' Text
+'spec' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'map' Name
+' ' Text
+'(' Punctuation
+'\\' Name.Function
+'(' Punctuation
+'V' Keyword.Type
+' ' Text
+'v' Name
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'intToDigit' Name
+' ' Text
+'v' Name
+')' Punctuation
+' ' Text
+'(' Punctuation
+'elems' Name
+' ' Text
+'(' Punctuation
+'parse' Name
+' ' Text
+'spec' Name
+')' Punctuation
+')' Punctuation
+'\n' Text
+
+'\n' Text
+
+' The main routine is designed to handle the input from http://www.csse.uwa.edu.au/~gordon/sudoku17\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+'main' Name.Function
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'all' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'getContents' Name
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'puzzles' Name
+' ' Text
+'=' Operator.Word
+' ' Text
+'zip' Name
+' ' Text
+'[' Punctuation
+'1' Literal.Number.Integer
+'..' Operator
+']' Punctuation
+' ' Text
+'(' Punctuation
+'map' Name
+' ' Text
+'parseBoard' Name
+' ' Text
+'(' Punctuation
+'lines' Name
+' ' Text
+'all' Name
+')' Punctuation
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'root' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'stToIO' Name
+' ' Text
+'initHA' Name
+'\n' Text
+
+'> ' Comment.Special
+'let' Keyword.Reserved
+' ' Text
+'act' Name
+' ' Text
+'::' Operator.Word
+' ' Text
+'(' Punctuation
+'Int' Keyword.Type
+',' Punctuation
+'Spec' Keyword.Type
+')' Punctuation
+' ' Text
+'->' Operator.Word
+' ' Text
+'IO' Keyword.Type
+' ' Text
+'()' Name.Builtin
+'\n' Text
+
+'> ' Comment.Special
+'act' Name.Function
+' ' Text
+'(' Punctuation
+'i' Name
+',' Punctuation
+'spec' Name
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'do' Keyword.Reserved
+'\n' Text
+
+'> ' Comment.Special
+'answer' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'stToIO' Name
+' ' Text
+'(' Punctuation
+'do' Keyword.Reserved
+' ' Text
+'initRoot' Name
+' ' Text
+'root' Name
+' ' Text
+'spec' Name
+' \n' Text
+
+'> ' Comment.Special
+'answer' Name.Function
+' ' Text
+'<-' Operator.Word
+' ' Text
+'gdance' Name
+' ' Text
+'(' Punctuation
+'fst' Name
+' ' Text
+'root' Name
+')' Punctuation
+' \n' Text
+
+'> ' Comment.Special
+'resetRoot' Name.Function
+' ' Text
+'root' Name
+'\n' Text
+
+'> ' Comment.Special
+'return' Name.Function
+' ' Text
+'answer' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'print' Name.Function
+' ' Text
+'(' Punctuation
+'i' Name
+',' Punctuation
+'showCompact' Name
+' ' Text
+'answer' Name
+')' Punctuation
+'\n' Text
+
+'> ' Comment.Special
+'mapM_' Name.Function
+' ' Text
+'act' Name
+' ' Text
+'puzzles' Name
+'\n' Text
+
+'\n' Text
+
+'> ' Comment.Special
+"inits'" Name.Function
+' ' Text
+'xn' Name
+'@' Operator
+'(' Punctuation
+'_' Keyword.Reserved
+':' Keyword.Type
+'_' Keyword.Reserved
+')' Punctuation
+' ' Text
+'=' Operator.Word
+' ' Text
+'zipWith' Name
+' ' Text
+'take' Name
+' ' Text
+'[' Punctuation
+'0' Literal.Number.Integer
+'..' Operator
+']' Punctuation
+' ' Text
+'$' Operator
+' ' Text
+'map' Name
+' ' Text
+'(' Punctuation
+'const' Name
+' ' Text
+'xn' Name
+')' Punctuation
+' ' Text
+'$' Operator
+' ' Text
+'undefined' Name
+':' Keyword.Type
+'xn' Name
+'\n' Text
+
+'> ' Comment.Special
+"inits'" Name.Function
+' ' Text
+'_' Keyword.Reserved
+' ' Text
+'=' Operator.Word
+' ' Text
+'undefined' Name
+'\n' Text