Haskell中python eval的等效项

hrysbysz  于 2023-01-24  发布在  Python
关注(0)|答案(7)|浏览(168)

python中有一个名为eval的函数,它接受字符串输入并对其求值。

>>> x = 1
>>> print eval('x+1')
2
>>> print eval('12 + 32')
44
>>>

什么是Haskell等价的eval函数?

ego6inou

ego6inou1#

的确,在Haskell中,就像在Java或C++或类似的语言中一样,你可以调用编译器,然后动态地加载代码并执行它,但是,这通常是很沉重的负担,而且几乎从来没有人在其他语言中使用eval()的原因。
人们倾向于在一种语言中使用eval(),因为给定该语言的功能,对于某些类的问题,从程序输入中构造一个类似于语言本身的字符串比直接解析和计算输入更容易。
例如,如果您希望用户不仅可以在输入字段中输入数字,还可以输入简单的算术表达式,那么在Perl或Python中,只对输入调用eval()要比为您希望允许的表达式语言编写解析器容易得多。几乎总是会导致糟糕的用户体验(编译器错误消息不是为非程序员准备的),并打开安全漏洞。不使用eval()解决这些问题通常会涉及相当多的代码。
在Haskell中,多亏了Parsec之类的东西,为这类输入问题编写解析器和求值器实际上非常容易,并且大大消除了对eval的渴望。

sigwle7e

sigwle7e2#

它没有一个内置的eval函数。但是在hackage that can do the same sort of thing.(docs)上有一些包。感谢@luqui还有hint

dgtucam1

dgtucam13#

虽然Template Haskell允许编译时求值,但该语言没有内置“eval”。
对于运行时“eval”--即运行时元编程--Hackage上有许多包本质上导入GHC或GHCi,包括旧的hs-plugins包和hint包。

1cosmwyk

1cosmwyk5#

这个问题是11年前提出的,现在使用包hint我们可以很容易地定义eval,下面是一个自包含脚本的示例(您仍然需要nix来运行它)

#!/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)
31moq8wy

31moq8wy6#

没有eval等价物,Haskell是一种静态编译语言,与C或C++一样,也没有eval。

htrmnn0y

htrmnn0y7#

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

相关问题