import Language.Haskell.Interpreter (eval, runInterpreter, Interpreter, InterpreterError)
main = do let resIO = eval "3" :: Interpreter String
res <- runInterpreter resIO
print res
结果是Right "3",我尝试了下面的变体,结果却遇到了令人费解的错误:
... eval "3 + 3" ....
-- yields --
Left (WontCompile [GhcError (errMsg = "Not in scope: `+'"])
+运算符不在范围内???wtf...
import Language.Haskell.Interpreter (interpret, as, runInterpreter, Interpreter)
main = do let resIO = interpret "3" (as :: Int) :: Interpreter Int
res <- runInterpreter resIO
print res
-- yields --
Left (WontCompile [GhcError (errMsg = "Not in scope: type constructor or class 'Int'")])
可接受的答案显示了一个使用hint的最小示例,但缺少以下几点: 1.如何使用绑定(如let x = 1 in x + 1)进行计算。 1.如何处理异常,特别是被零除。 下面是一个更完整的示例:
import qualified Control.DeepSeq as DS
import Control.Exception (ArithException (..))
import qualified Control.Exception as Ex
import qualified Control.Monad as M
import qualified Data.Either as E
import qualified Language.Haskell.Interpreter as I
evalExpr :: String -> [(String, Integer)] -> IO (Maybe Integer)
evalExpr expr a = Ex.handle handler $ do
i <- I.runInterpreter $ do
I.setImports ["Prelude"]
-- let var = value works too
let stmts = map (\(var, val) -> var ++ " <- return " ++ show val) a
M.forM_ stmts $ \s -> do
I.runStmt s
I.interpret expr (I.as :: Integer)
-- without force, exception is not caught
(Ex.evaluate . DS.force) (E.either (const Nothing) Just i)
where
handler :: ArithException -> IO (Maybe Integer)
handler DivideByZero = return Nothing
handler ex = error $ show ex
4条答案
按热度按时间hmmo2u0o1#
你的问题给解释留下了很大的空间。我猜你还不习惯构建词法分析、解析、类型检查和求值的整个管道。详细的答案将包括定义你希望求值的语言(只使用带"+"的整数,也可以使用所有带"+"、"-"、"*"、"/"的有理数,甚至更大的语言?),然后为该语言执行上述每个步骤。
简短的回答是:要计算Haskell表达式,其中包含了你可能正在讨论的基本数学运算符,只需使用"hint"包:
耶!
n3ipq98p2#
也许值得一阅读Real World Haskell的Parsec部分。你可以把它解析成一个表达式树,然后把值代入。当你使用Parsec时,你会用类型构建一个表达式树(非常粗略地说,我确信我犯了一些错误,当人们指出它们时,我会在修复中编辑它们!)
那么1 + 2就是
(Expr (Variable "x") Plus (Variable "y"))
,你可以进行适当的替换。要得到结果,我想您可以修改一个简单的函数
evaluate :: Map String Int -> Expression -> Either ErrorMessage Int
,它将应用Map中的绑定,然后计算结果(如果可能的话)。kuarbcqp3#
我一直在努力尝试hint,但现在我给予了。我知道hint可以做到这一点,但我不确定如何做到。[edit]***关于如何为hint设置导入,请参阅TomMD的答案。***[/edit]
结果是
Right "3"
,我尝试了下面的变体,结果却遇到了令人费解的错误:+
运算符不在范围内???wtf...Int
类不在范围内???啊...我邀请那些比我更有知识的人来详细阐述暗示的细节。
bejyjqdl4#
可接受的答案显示了一个使用hint的最小示例,但缺少以下几点:
1.如何使用绑定(如
let x = 1 in x + 1
)进行计算。1.如何处理异常,特别是被零除。
下面是一个更完整的示例: