Good design in Haskell for AST of a simple language

I am new to Haskell and am working on the Haskell LLVM tutorial . In it, the author defines a simple algebraic data type for the AST representation.

type Name = String

data Expr
  = Float Double
  | BinOp Op Expr Expr
  | Var String
  | Call Name [Expr]
  | Function Name [Expr] Expr
  | Extern Name [Expr]
  deriving (Eq, Ord, Show)

data Op
  = Plus
  | Minus
  | Times
  | Divide
  deriving (Eq, Ord, Show)

      

However, this is not an ideal structure, because the parser actually expects the list Expr

in Extern

to contain only expressions representing variables (that is, the parameters in this situation cannot be arbitrary expressions). I would like the types to reflect this constraint (making it easier to generate random valid ACTs with QuickCheck); however, for consistency in the parser functions (all of which are of type Parser Expr

), I don't just want to say | Expr Name [Name]

. I would like to do something like this:

data Expr
  = ...
  | Var String
    ...
  | Function Name [Expr] Expr
  | Extern Name [Var] -- enforce constraint here
  deriving (Eq, Ord, Show)

      

But this is not possible in Haskell.

To summarize, Extern

and Var

should be Expr

, and Extern

should have a list Vars

representing the parameters. Your best bet would be to split them all and make them instances of the class Expr

(which would not have any methods)? Or is there a more idiomatic method (or would it be better to drop these types and do something completely different)?

+3


source to share


1 answer


Disclaimer, I am the author of the LLVM tutorial you mentioned.

Just use Extern Name [Name]

, anything after chapter 3 in the tutorial uses the exact definition anyway . I think I just forgot to make chapter 2 Syntax.hs

compatible with others.



I wouldn't bother with the parser definitions being consistent and they are great for different types. This is what later parsers use. identifier

is just a parsec built in for an alphanumeric identifier from LanguageDef, which becomes a type Name

in AST.

extern :: Parser Expr
extern = do
  reserved "extern"
  name <- identifier
  args <- parens $ many identifier
  return $ Extern name args

      

+5


source







All Articles