Scheme解释器Haskell实现:环境集成类型匹配报错求助
Haskell实现Scheme时的环境集成类型不匹配问题
我正在做课程项目,要给基于Haskell实现的Scheme语言添加环境支持,涉及main.hs和Evaluation.hs两个核心文件。main模块负责接收用户输入,把解析后的字符串传给run函数。我需要在评估模块里加环境来支持lambda和let定义变量,但不能修改main模块里run函数以外的代码。
我试过直接在评估函数、eval_maybe里集成环境,甚至在eval_maybe里用do语法预加载环境,但都触发了类型不匹配错误,具体报错如下:
run :: Datum -> Env -> Maybe String run = fmap printDatum . eval_maybe [] src\Main.hs:16:7: error: * Couldn't match type `Datum' with `[(String, Datum)]' Expected type: Datum -> Env -> Maybe String Actual type: Evaluation.Env -> Datum -> String * In the expression: fmap printDatum . eval_maybe In an equation for `run': run = fmap printDatum . eval_maybe | 16 | run = fmap printDatum . eval_maybe | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ src\Main.hs:16:25: error: * Couldn't match type `Maybe Datum' with `Datum' Expected type: Evaluation.Env -> Datum -> Datum Actual type: Evaluation.Env -> Datum -> Maybe Datum * In the second argument of `(.)', namely `eval_maybe' In the expression: fmap printDatum . eval_maybe In an equation for `run': run = fmap printDatum . eval_maybe | 16 | run = fmap printDatum . eval_maybe
相关代码片段
type Env = [(String, Datum)] run :: Env -> Datum -> Maybe String run = fmap printDatum . eval_maybe printDatum :: Datum -> String printDatum = pretty 80 . ppd eval_maybe :: Env -> Datum -> Maybe Datum eval_maybe env = forgetError . eval env data Result = Good Datum | Bad Error forgetError :: Result -> Maybe Datum forgetError (Good r) = Just r forgetError _ = Nothing
问题分析与修复
这两个类型错误的核心是函数组合的顺序和类型不匹配:
eval_maybe是柯里化的双参数函数,类型为Env -> Datum -> Maybe Datum;而fmap printDatum的类型是Maybe Datum -> Maybe String。直接用(.)组合时,Haskell会尝试把fmap printDatum应用到eval_maybe的返回值上,但eval_maybe返回的是Datum -> Maybe Datum,不是Maybe Datum,导致类型兼容问题。- 最初尝试的
eval_maybe []提前传入环境参数,进一步导致函数类型偏离run的签名要求。
只需要修改run函数的实现即可,有两种简洁的写法:
写法1(直观版)
run :: Env -> Datum -> Maybe String run env datum = fmap printDatum (eval_maybe env datum)
直接传入环境和待求值的Datum,对eval_maybe的结果用fmap转换为字符串。
写法2(柯里化组合版)
run :: Env -> Datum -> Maybe String run = \env -> fmap printDatum . eval_maybe env
先绑定环境参数,得到针对该环境的求值函数Datum -> Maybe Datum,再和fmap printDatum组合,得到最终的Datum -> Maybe String,符合run的柯里化类型要求。
修改后,run的类型就能完全匹配要求,同时实现了环境的传递和结果的格式化输出。
内容的提问来源于stack exchange,提问作者Tarwyn
相关产品推荐
相关产品推荐

