Language.Haskell.Interpreter:这是适合手头工作的工具吗?

Language.Haskell.Interpreter: is this the right tool for the job at hand?

我对自然语言有一点玩具语义,像这样的词:

ran :: String -> Bool
ran = (`elem` ["Bart", "Homer", "Marge"])

和:

bart :: String
bart = "Bart"

例如,我可以有 (ran bart) :: Bool,依此类推。

我想编写一个解析器,例如接受字符串 "Bart ran" 和 returns True。我可能会为此使用秒差距。

但是,问题在于能够通过字符串调用函数。例如。从 "ran" 到函数 ran。为此,我认为 Language.Haskell.Interpreterinterpret 函数可能是合适的。

所以我的问题是:

  1. 这是做我想做的事情的明智方法吗?

  2. 如果是这样,为什么下面的工作不起作用,进入 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: 16ran17\n    Perhaps you meant 16tan17 (imported from Prelude)"}])"

这表明导入无效,事实上,如果我尝试使用 Prelude 函数进行类似操作,一切正常。

  1. 如果我尝试编译与 Q2 中相同的代码(减去 let),为什么会出现以下类型错误(以及许多其他错误):

No instance for MonadIO m0 arising from a use of runInterpreter

至于 #2,您还需要将 "Grammar" 添加到 setImports 列表中:

runInterpreter $ do
    loadModules ["HintDefs"]
    setImports ["Prelude", "HintDefs"]
    interpret "ran" (as :: String -> Bool)

至于#3,是因为runInterpreter在monad的选择上是单态的运行它在:

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"

现在,关于 #1,我不认为您需要像 HInt 一样强大的东西。你可以只维护一个由 String 键键入的 String -> Bool 函数的字典,像 Map String (String -> Bool) 这样简单的东西,然后用它来查找 ran