Parsing 在Haskell中为简单语言的AST进行良好的类型设计
我是哈斯凯尔的新人,我一直在工作。在其中,作者定义了一个简单的代数数据类型来表示ASTParsing 在Haskell中为简单语言的AST进行良好的类型设计,parsing,haskell,parsec,Parsing,Haskell,Parsec,我是哈斯凯尔的新人,我一直在工作。在其中,作者定义了一个简单的代数数据类型来表示AST 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
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)
但是,这不是一个理想的结构,因为解析器实际上期望Extern
中的Expr
列表只包含表示变量的表达式(即,这种情况下的参数不能是任意表达式)。我想让类型反映这个约束(使用QuickCheck更容易生成随机有效的AST);但是,为了解析器函数的一致性(它们都有类型parser Expr
),我不想只说|Expr Name[Name]
。我想这样做:
data Expr
= ...
| Var String
...
| Function Name [Expr] Expr
| Extern Name [Var] -- enforce constraint here
deriving (Eq, Ord, Show)
但在哈斯克尔是不可能的
总之,
Extern
和Var
都应该是Expr
,并且Extern
应该有一个表示参数的Var
列表。最好的方法是将所有这些都分离出来,使它们成为Expr
typeclass的实例(没有任何方法)?还是有一种更惯用的方法(或者最好放弃这些类型,做一些完全不同的事情)?免责声明,我是您提到的LLVM教程的作者
只需使用外部名称[Name]
,教程第3章之后的所有内容都使用该名称。我想我只是忘了让第2章的语法与其他章节保持一致
我不担心解析器定义的一致性,它们可以返回不同的类型。下面是后面的解析器使用的内容identifier
只是LanguageDef中字母数字标识符的parsec内置项,该标识符将成为AST中的Name
类型
extern :: Parser Expr
extern = do
reserved "extern"
name <- identifier
args <- parens $ many identifier
return $ Extern name args
extern::Parser Expr
extern=do
保留的“外部”
命名您的|外部名称[name]
解决方案就是一条出路。你不喜欢它的什么地方?不同的解析函数返回不同的类型是很自然的。