我有一个自然语言的小玩具语义,如:
ran :: String -> Bool
ran = (`elem` ["Bart", "Homer", "Marge"])
:
bart :: String
bart = "Bart"
例如,我可以有(ran bart) :: Bool
,等等。
我想写一个解析器,例如接受字符串"Bart ran"
并返回True
。我可能会用秒差距。
然而,问题是能够通过字符串调用函数。例如,从"ran"
得到函数ran
。为此,我认为Language.Haskell.Interpreter
的interpret
函数可能是合适的。
我的问题是:
这是一个明智的方式来做我想做的事吗?
如果是,为什么不工作,进入GHCi,给定一个名为
Grammar.hs
的模块,与上面定义的ran
在同一目录下:let a = runInterpreter $ do loadModules ["Grammar"] setImports ["Prelude"] interpret "ran" (as :: String -> Bool) let b = do x <- a return $ x <*> pure "John" b
我得到错误:
"Left (WontCompile [GhcError {errMsg = "<interactive>:2:1:n Not in scope: 8216ran8217n Perhaps you meant 8216tan8217 (imported from Prelude)"}])"
,这表明导入不工作,事实上,如果我尝试类似的序曲函数,一切工作。
- 为什么我得到以下类型错误(在许多其他),如果我试图编译相同的代码在Q2,(减去
let
):
没有
MonadIO m0
因使用runInterpreter
而产生的实例
对于#2,您需要将"Grammar"
也添加到setImports
列表中:
runInterpreter $ do
loadModules ["HintDefs"]
setImports ["Prelude", "HintDefs"]
interpret "ran" (as :: String -> Bool)
对于#3,这是因为runInterpreter
在选择单态运行时是单态的:
runInterpreter :: (MonadIO m, MonadMask m) => InterpreterT m a -> m (Either InterpreterError a)
所以你需要选择一个特定的m
通过运行它,例如IO
:
main :: IO ()
main = do
ran <- runInterpreter $ do
loadModules ["HintDefs"]
setImports ["Prelude", "HintDefs"]
interpret "ran" (as :: String -> Bool)
print $ ran <*> pure "John"
现在,关于第一条,我不相信你需要像HInt这样愚蠢而强大的东西。你可以只维护一个String -> Bool
函数的字典,用String
键键,像Map String (String -> Bool)
这样简单的键键,然后用它来查找ran
等。