#!/usr/bin/env nix-shell
#! nix-shell -p "haskellPackages.ghcWithPackages (p: with p; [hint])"
#! nix-shell -i "ghci -ignore-dot-ghci -fdefer-type-errors -XTypeApplications"
{-# LANGUAGE ScopedTypeVariables, TypeApplications, PartialTypeSignatures #-}
import Data.Typeable (Typeable)
import qualified Language.Haskell.Interpreter as Hint
-- DOC: https://www.stackage.org/lts-18.18/package/hint-0.9.0.4
eval :: forall t. Typeable t => String -> IO t
eval s = do
mr <- Hint.runInterpreter $ do
Hint.setImports ["Prelude"]
Hint.interpret s (Hint.as :: t)
case mr of
Left err -> error (show err)
Right r -> pure r
-- * Interpret expressions into values:
e1 = eval @Int "1 + 1 :: Int"
e2 = eval @String "\"hello eval\""
-- * Send values from your compiled program to your interpreted program by interpreting a function:
e3 = do
f <- eval @(Int -> [Int]) "\\x -> [1..x]"
pure (f 5)
This answer显示了使用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
7条答案
按热度按时间ego6inou1#
的确,在Haskell中,就像在Java或C++或类似的语言中一样,你可以调用编译器,然后动态地加载代码并执行它,但是,这通常是很沉重的负担,而且几乎从来没有人在其他语言中使用
eval()
的原因。人们倾向于在一种语言中使用
eval()
,因为给定该语言的功能,对于某些类的问题,从程序输入中构造一个类似于语言本身的字符串比直接解析和计算输入更容易。例如,如果您希望用户不仅可以在输入字段中输入数字,还可以输入简单的算术表达式,那么在Perl或Python中,只对输入调用
eval()
要比为您希望允许的表达式语言编写解析器容易得多。几乎总是会导致糟糕的用户体验(编译器错误消息不是为非程序员准备的),并打开安全漏洞。不使用eval()
解决这些问题通常会涉及相当多的代码。在Haskell中,多亏了Parsec之类的东西,为这类输入问题编写解析器和求值器实际上非常容易,并且大大消除了对
eval
的渴望。sigwle7e2#
它没有一个内置的eval函数。但是在hackage that can do the same sort of thing.(docs)上有一些包。感谢@luqui还有hint。
dgtucam13#
虽然Template Haskell允许编译时求值,但该语言没有内置“eval”。
对于运行时“eval”--即运行时元编程--Hackage上有许多包本质上导入GHC或GHCi,包括旧的hs-plugins包和hint包。
pod7payv4#
hs-plugins具有System.Eval.Haskell。
1cosmwyk5#
这个问题是11年前提出的,现在使用包
hint
我们可以很容易地定义eval
,下面是一个自包含脚本的示例(您仍然需要nix来运行它)31moq8wy6#
没有eval等价物,Haskell是一种静态编译语言,与C或C++一样,也没有eval。
htrmnn0y7#
This answer显示了使用hint包的一个最小示例,但它缺少以下几点:
1.如何使用绑定(如
let x = 1 in x + 1
)进行计算。1.如何处理异常,特别是被零除。
下面是一个更完整的示例: