Parsing 在Haskell中为简单语言的AST进行良好的类型设计

Parsing 在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

我是哈斯凯尔的新人,我一直在工作。在其中,作者定义了一个简单的代数数据类型来表示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
  | 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]
解决方案就是一条出路。你不喜欢它的什么地方?不同的解析函数返回不同的类型是很自然的。