大多数情况直接来自提示示例。我想做的是使用模块和导入等初始化解释器,并以某种方式保留它。稍后(用户事件或其他事件),我希望能够以该初始化状态调用一个函数并多次解释一个表达式。因此,在代码的--split here位置,我希望将init上面的代码和下面的代码包含在一个接受表达式并对其进行解释的新函数中。
module Main where
import Language.Haskell.Interpreter
import Test.SomeModule
main :: IO ()
main = do r <- runInterpreter testHint
case r of
Left err -> printInterpreterError err
Right () -> putStrLn "Done."
-- Right here I want to do something like the following
-- but how do I do testInterpret thing so it uses the
-- pre-initialized interpreter?
case (testInterpret "expression one")
Left err -> printInterpreterError err
Right () -> putStrLn "Done."
case (testInterpret "expression two")
Left err -> printInterpreterError err
Right () -> putStrLn "Done."
testHint :: Interpreter ()
testHint =
do
loadModules ["src/Test/SomeModule.hs"]
setImportsQ [("Prelude", Nothing), ("Test.SomeModule", Just "SM")]
say "loaded"
-- Split here, so what I want is something like this though I know
-- this doesn't make sense as is:
-- testExpr = Interpreter () -> String -> Interpreter ()
-- testExpr hintmonad expr = interpret expr
let expr1 = "let p1o1 = SM.exported undefined; p1o2 = SM.exported undefined; in p1o1"
say $ "e.g. typeOf " ++ expr1
say =<< typeOf expr1
say :: String -> Interpreter ()
say = liftIO . putStrLn
printInterpreterError :: InterpreterError -> IO ()
printInterpreterError e = putStrLn $ "Ups... " ++ (show e)
最佳答案
我无法理解您的问题。我对提示也不太熟悉。但我会努力的。
据我所知,Interpreter
monad只是IO
周围的一个简单的状态包装器-它仅存在,以便您可以说例如。 setImportsQ [...]
并进行后续计算取决于该功能所修改的“设置”。因此,基本上,您希望共享多个计算的单子上下文。做到这一点的唯一方法是留在monad中-通过在Interpreter
中构建单个计算并运行一次。您不能具有转义和重用runInterpreter
的“全局变量”。
幸运的是,Interpreter
是MonadIO
的实例,这意味着您可以使用IO
交错Interpreter
计算和liftIO :: IO a -> Interpreter a
计算。基本上,您是由内而外的思考(对于Haskell的学习者来说,这是一个极为常见的错误)。不要在IO
中使用在解释器中运行代码的函数,而应在Interpreter
中使用在IO
(即liftIO
)中运行代码的函数。因此,例如。
main = runInterpreter $ do
testHint
expr1 <- liftIO getLine
r1 <- interpret "" expr1
case r1 of
...
expr2 <- liftIO getLine
r2 <- interpret "" expr2
case r2 of
...
而且,如果需要的话,您可以使用参照透明的美感轻松地将后面的代码提取到函数中!只需将其拉出即可。
runSession :: Interpreter ()
runSession = do
expr1 <- liftIO getLine
r1 <- interpret "" expr1
case interpret expr1 of
...
main = runInterpreter $ do
testHint
runSession
那有意义吗?您的整个程序都是
Interpreter
计算,只有在最后一刻,您才将其拉到IO
中。(这并不意味着您编写的每个函数都应该在
Interpreter
monad中。远离它!与往常一样,在程序边缘使用Interpreter
并保持核心纯功能。Interpreter
是新的IO
)。