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)?
source to share
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
source to share