语言.haskell.解释器:这是适合手头工作的工具吗?



我有一个自然语言的小玩具语义,如:

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

:

bart :: String
bart = "Bart"

例如,我可以有(ran bart) :: Bool,等等。

我想写一个解析器,例如接受字符串"Bart ran"并返回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: 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等。

    最新更新