Reputation: 313
data Tree a = Leaf a | Branch (Tree a) (Tree a)
readsTree :: (Read a) => ReadS (Tree a)
readsTree s = [(Branch l r, x) | ("<", t) <- lex s,
(l, u) <- readsTree t,
("|", v) <- lex u,
(r, w) <- readsTree v,
(">", x) <- lex w ]
++ [(Leaf x, t) | (x, t) <- reads s]
For example in this recursive function, reads s needs a type signature such as
k = reads "34a" :: [(Integer, String)]
readsTree "<3|2>" :: [(Tree Integer, String)] \\works
but one more level of recursion fails readsTree "<3|<1|2>>" :: [(Tree Integer, String)]
. Its strange because reads s
appears to infer the right type after one recursive call, but not two. Is there a way to set the type of readsTree t to be based on the type signature of the inital call/a better way to do this?
Btw this example is straight out of Gentle Introduction to Haskell, kind of strange that it doesn't work. I might have missed something but I don't see it...
Upvotes: 0
Views: 65
Reputation: 91857
I don't see anything to suggest that type inference is at fault here. Rather, what jumps out to me is that you assume lex
will return a single-character string, but it is a much more complicated function than that, trying to be the lexer for a Haskell-like language. When you get to the ">>" at the end of your string, lex
returns [(">>", "")]
, and your pattern match fails. Since you don't in fact want any lexing, just write your own simple function for discarding a specific character:
readsTree :: (Read a) => ReadS (Tree a)
readsTree s = [(Branch l r, x) |
t <- discard '<' s,
(l, u) <- readsTree t,
v <- discard '|' u,
(r, w) <- readsTree v,
x <- discard '>' w]
++ [(Leaf x, t) | (x, t) <- reads s]
where discard :: Char -> String -> [String]
discard t s = case s of
(c:r) | c == t -> [r]
_ -> []
and then we have, as desired:
*Main> readsTree "<3|<1|2>>" :: [(Tree Integer, String)]
[(Branch (Leaf 3) (Branch (Leaf 1) (Leaf 2)),"")]
I cannot explain why your book includes a function which does not work. It could be because you are reading a 21-year-old technical document - perhaps the definition of lex
was different then, I don't know. Or maybe >>
was not a valid operator in Haskell at the time, and so lex
stopped after parsing the first >
.
Upvotes: 1