2

To practice my Haskell skills, I'm following the Write Yourself a Scheme tutorial. I've implemented a parser for s-expressions, but I'm having trouble with the printing function.

When I run the following program

main :: IO ()
main  =  do args <- getArgs
            putStrLn $ readExpr (args !! 0)

it parses the s-expressions correctly, but when I define my own shows instead of deriving it, I get erroneous output for nested lists and lists inside vectors:

$ ./parser "(1 (2) 3)"
(1 (2 3))
$ ./parser "#(1 (2) 3)"
#(1 (2 3))
$ ./parser "(1 (2 (3)) 4)"
(1 (2 (3 4)))
$ ./parser "(1 (2 (3)) (4))"
(1 (2 (3 (4))))

Other cases and nested vectors work fine, though:

lars@zygmunt:~/src/scm48$ ./parser "(1 #(2) 3)"
(1 #(2) 3)
lars@zygmunt:~/src/scm48$ ./parser "#(1 #(2) 3)"
#(1 #(2) 3)
lars@zygmunt:~/src/scm48$ ./parser "(1 (2 3))"
(1 (2 3))

I've changed the representation of LispVal to include Nil and Pair constructors instead of List and DottedList, as these match better with the Scheme data model. Printing lists is done by

showsVal :: Value -> ShowS
showsVal Nil              =  ("()" ++)
showsVal (Pair x y)       =  ("(" ++) . showsPair x y . (++ ")")
showsVal (String s)       =  shows s
showsVal (Symbol n)       =  (n ++)
showsVal (Number x)       =  shows x
showsVal (Boolean True)   =  ("#t" ++)
showsVal (Boolean False)  =  ("#f" ++)
showsVal (Vector v)       =  ("#(" ++) . showsVec v . (")" ++)

showsPair x Nil         =  showsVal x
showsPair x (Pair y z)  =  (showsVal x) . (" " ++) . showsPair y z
showsPair x y           =  (showsVal x) . (" . " ++) . (showsVal y)

showsVec []      =  id
showsVec [x]     =  shows x
showsVec (x:xs)  =  shows x . (" " ++) . showsVec xs

I suspect the error is in showsPair, but I just can't figure it out.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • Hmm. How do you know the parsing is correct? – ephemient Mar 10 '11 at 16:40
  • Like the prior comment: you're testing both the parser and the printer at once: why not formulate separate test cases to see which one contains the bug? – John Clements Mar 10 '11 at 17:11
  • @ephemient: I know the parsing is correct because when I use `deriving Show`, it prints the right structure in Haskell notation. – Fred Foo Mar 10 '11 at 17:19

1 Answers1

3

I found out myself:

showsVal (Pair x y)  =  ("(" ++) . showsPair x y . (++ ")")

should have been

showsVal (Pair x y)  =  ("(" ++) . showsPair x y . (")" ++)
                                                --  ^^^^^^
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • 3
    You can avoid this problem if you use `showString` and `showChar`, e.g.: `showsVal (Pair x y) = showChar '(' . showsPair x y . showChar ')'` - there's even a showParens function to make it simpler still. – stephen tetley Mar 10 '11 at 22:17