# Writing Read instances for HList

I'm a total newbie at parsing, so I figured I'd start by writing instances of Read for HList, which does not currently have them. I'd appreciate some feedback on the following:

{-# LANGUAGE
DataKinds
,KindSignatures
,FlexibleContexts
,FlexibleInstances
,TypeOperators
,ScopedTypeVariables
#-}

module MyHList where

-- This declaration is copied from Data.HList.HList.
data HList (l::[*]) where
HNil  :: HList '[]
HCons :: e -> HList l -> HList (e ': l)

infixr 2 HCons

( do
expectP (L.Ident "H")
expectP (L.Punc "[")
expectP (L.Punc "]")
return HNil
)

instance forall e . Read e => Read (HList (e ': '[])) where
( do
expectP (L.Ident "H")
expectP (L.Punc "[")
e <- reset $(readPrec::ReadPrec e) expectP (L.Punc "]") return (e HCons HNil) ) instance forall e f (l::[*]) . (Read e, ReadTl (HList (f ': l))) => Read (HList (e ': f ': l)) where readPrec = parens ( do expectP (L.Ident "H") expectP (L.Punc "[") e <- reset$ (readPrec::ReadPrec e)
expectP (L.Punc ",")
return (e HCons rest)
)

instance forall e . Read e => ReadTl (HList (e ': '[])) where
e <- reset $(readPrec::ReadPrec e) expectP (L.Punc "]") return$ e HCons HNil

instance forall e f (l::[*]) . (Read e, ReadTl (HList (f ': l)))
=> ReadTl (HList (e ': f ': l)) where
e <- reset $(readPrec::ReadPrec e) expectP (L.Punc ",") rest <- readTl return (e HCons rest)  ## 1 Answer This is indeed interesting challenge! -- Read after H[ class ReadHList (a :: [*]) where readHList :: ReadPrec (HList a) -- Read after element: -- ] for nil -- , readHList for cons class ReadHListAfter (a :: [*]) where readHListAfter :: ReadPrec (HList a) instance ReadHList '[] where readHList = expectP (L.Punc "]") >> return HNil instance ReadHListAfter '[] where readHListAfter = readHList instance (Read a, ReadHListAfter l) => ReadHList (a ': l) where readHList = ... -- We could use ReadHList (a ': l) as additional constraint, -- But then we need UndecidableInstances extension instance (Read a, ReadHListAfter l) => ReadHListAfter (a ': l) where readHListAfter = ... -- Parsing HList is trivial as composing functions! instance ReadHList a => Read (HList a) where readPrec = parens$ do
expectP (L.Ident "H")
expectP (L.Punc "[")


This way it's a bit more elegant. IMHO.

Compare it to pseudo-codish parsing of lists of known length (aka vectors):

list :: Int -> Parser a -> Parser [a]
list n p =
token '['
list' n p

list' :: Int -> Parser a -> Parser [a]
list' 0 _ = token ']' >> return []
list' n p = do
h <- p
t <- listTail (n - 1) p
return (h : t)

listTail :: Int -> Parser a -> Parser [a]
listTail 0 _ = token ']' >> return []
listTail n = do
h <- p
token ','
t <- listTail (n - 1) p
return (h : t)

• Welcome to Code Review! If you have another question, please ask it by clicking the Ask Question button. Jan 9 '15 at 18:29
• There are a lot of missing pieces here. Could you explain how this is supposed to relate to and improve the code I posted? Jan 9 '15 at 22:26
• The missed pieces (...) are trivial to fill. I don't want to spoil everything. I added description at the beginning of the post. Jan 10 '15 at 12:45
• I think I see what you're getting at now—you simplify the instance declarations at the cost of adding another class. It looks likely to be similar in the end (once some common code is factored out of my version), but I'll see what I think once I've filled in the blanks. Jan 10 '15 at 20:45