I'm using Haskell to interpret a dynamically-typed language. I have a sum type called
Value which can represent some basic objects:
data Value = Integer Integer | Float Double | Char Char | List [Value] deriving Show
(For now I'm not adding a special case for strings - they'll just be lists of characters.)
I have instantiated
Read for it, so that I can parse string inputs into
Values as though they're normal Haskell values.
While for this demo I just derived
Show using the default implementation, I had to define
Read manually, because I don't want the input to need the data constructors prefixed before every element. (I would have to write input as
Integer 43 instead of just
43, for example)
readsPrec (which seems a needlessly complex method to have as the minimal typeclass implementation, but it's what Haskell requires...) in terms of Haskell's default implementations for the underlying data types.
readsPrec takes a precedence value, which I just pass on to the
readsPrec of other types; it returns a list of possible parses as tuples of
The basic algorithm I use is to attempt to parse the input into each type, and choose the first result from each. Unfortunately there's quite a lot of plumbing required to deal with the list of tuples produced by
instance Read Value where readsPrec precedence s = -- `justs` stops the parsing once all of the read attempts are failing justs $ map (foldl orElse Nothing) $ transpose attempts where -- try to parse the input into each of these types, one at a time attempts = [u Integer, u Float, u Char, u List] u constructor = maybes [(constructor val, rest) | (val, rest) <- readsPrec precedence s]
This implementation also uses a couple of utility functions:
-- | Create an infinite list of Maybes, where the elements in the input -- | are `Just`s, and everything after that is a `Nothing` maybes xs = map Just xs ++ repeat Nothing -- | Collect the values of all Justs at the start of a list justs (Just x : xs) = x : justs xs justs _ = 
I want to know if my code, especially the plumbing around
readsPrec, can be made more idiomatic, perhaps using some more builtin functions. Maybe the whole algorithm can be simplified.
I also don't like the fact I'm using a constant-sized list for the attempts. I'd like to be able to just use a tuple, but if I ever wanted to add more data types, I'd have to change things like
unzip5, because I can't write it polymorphically over tuple size. (where
unzip would be used for tuples, in place of
transpose for lists)
I'm not really interested in whether the minutiae of my syntax style are "correct".