2
\$\begingroup\$

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
 ,GADTs
 ,ScopedTypeVariables
 #-}

module MyHList where
import GHC.Read
import Text.ParserCombinators.ReadPrec
import qualified Text.Read.Lex as L

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

infixr 2 `HCons`


instance Read (HList '[]) where
  readPrec = parens
    ( do
        expectP (L.Ident "H")
        expectP (L.Punc "[")
        expectP (L.Punc "]")
        return HNil
    )

instance forall e . Read e => Read (HList (e ': '[])) where
  readPrec = parens
    ( 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 ",")
        rest <- readTl :: ReadPrec (HList (f ': l))
        return (e `HCons` rest)
    )

class ReadTl l where
  readTl :: ReadPrec l

instance forall e . Read e => ReadTl (HList (e ': '[])) where
  {-# INLINE readTl #-}
  readTl = do
    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
  {-# INLINE readTl #-}
  readTl = do
    e <- reset $ (readPrec::ReadPrec e)
    expectP (L.Punc ",")
    rest <- readTl
    return (e `HCons` rest)
\$\endgroup\$
0
1
\$\begingroup\$

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 "[")
    readHList

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)
\$\endgroup\$
4
  • \$\begingroup\$ Welcome to Code Review! If you have another question, please ask it by clicking the Ask Question button. \$\endgroup\$
    – RubberDuck
    Jan 9 '15 at 18:29
  • \$\begingroup\$ There are a lot of missing pieces here. Could you explain how this is supposed to relate to and improve the code I posted? \$\endgroup\$
    – dfeuer
    Jan 9 '15 at 22:26
  • \$\begingroup\$ The missed pieces (...) are trivial to fill. I don't want to spoil everything. I added description at the beginning of the post. \$\endgroup\$
    – phadej
    Jan 10 '15 at 12:45
  • \$\begingroup\$ 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. \$\endgroup\$
    – dfeuer
    Jan 10 '15 at 20:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.