Haskell实例化带记录语法的多构造函数Expr类型遇作用域问题
解决Haskell中无法实例化未导出构造器的Expr类型问题
问题原因
你遇到的报错是因为ParseTree模块仅导出了Expr类型本身,没有导出它的构造器(如LiteralValue)和记录字段(如value)。Haskell中,若模块未导出构造器,外部模块无法直接使用构造器或记录语法来创建该类型的实例。
两种可行解决方案
方案1:修改ParseTree模块的导出列表,导出所需构造器/字段
在ParseTree模块的头部,修改导出声明,把需要的构造器或字段包含进去。比如:
- 导出所有Expr构造器:
module ParseTree (Expr(..), Literal(..)) where
- 仅导出
LiteralValue构造器(更严谨,限制外部只能创建这种实例):
module ParseTree (Expr(LiteralValue), Literal(..)) where
修改后,Parser模块就能直接使用LiteralValue {value = NONE}来创建Expr实例了。
方案2:在ParseTree模块中添加智能构造函数
如果不想暴露构造器,保持封装性,可以在ParseTree模块里定义专门的函数来创建特定的Expr实例:
-- ParseTree模块内 module ParseTree (Expr, literalNone) where data Expr = Binary {left :: Expr, operator :: Token, right :: Expr} | Grouping {expression :: Expr} | LiteralValue {value :: Literal} | Unary {operator :: Token, right :: Expr} -- 用于创建值为NONE的LiteralValue类型Expr literalNone :: Expr literalNone = LiteralValue {value = NONE}
然后在Parser模块中直接调用这个函数:
expression :: [Token] -> Expr expression (head:remainder) | checkType head EOF = literalNone | otherwise = equality (head:remainder)
方案选择建议
- 若需要灵活创建各种类型的Expr实例,选方案1;
- 若希望严格控制Expr的创建逻辑,避免外部模块构造不符合预期的实例,选方案2。
内容的提问来源于stack exchange,提问作者Glenn Jansson
相关产品推荐
相关产品推荐

