簡體   English   中英

相當於 python 在 Haskell 中求值

[英]Equivalent of python eval in Haskell

python 中有 function 稱為eval ,它接受字符串輸入並對其求值。

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

什么是 Haskell eval function?

確實,在Haskell中,如在Java或C ++或類似語言中,您可以調用編譯器,然后動態加載代碼並執行它。 然而,這通常很重,幾乎從來沒有人為什么在其他語言中使用eval()

人們傾向於在語言中使用eval() ,因為考慮到語言的設施,對於某些類的問題,從類似於語言本身的程序輸入構造字符串更容易,而不是直接解析和評估輸入。

例如,如果您希望允許用戶不僅輸入輸入字段中的數字,而且輸入簡單的算術表達式,在Perl或Python中,只需在輸入上調用eval()就可以比編寫解析器更容易。您想要允許的表達式語言。 不幸的是,這種方法幾乎總是導致整體用戶體驗不佳(編譯器錯誤消息不適用於非程序員)並打開安全漏洞。 在不使用eval()情況下解決這些問題通常需要相當多的代碼。

在Haskell中,由於像Parsec這樣的東西,實際上很容易為這些類型的輸入問題編寫解析器和求值器,並且大大消除了對eval的渴望。

它沒有內置的eval函數。 然而,一些關於hackage的包可以做同樣的事情 docs )。 感謝@luqui也有提示

雖然Template Haskell允許編譯時評估,但語言中沒有內置'eval'。

對於運行時'eval' - 即運行時元編程 - Hackage上有許多包基本上導入GHC或GHCi,包括舊的hs-plugins包和提示包。

沒有等效的eval,Haskell是一種靜態編譯的語言,與C或C ++相同,也沒有eval。

這個問題是 11 年前問的,現在我們有了新的選擇:使用我們可以很容易地定義eval的包hint ,下面是一個自包含腳本的例子(你仍然需要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)

這個答案顯示了使用提示package 的最小示例,但它缺少一些東西:

  1. 如何使用let x = 1 in x + 1之類的綁定進行評估。
  2. 如何處理異常,具體除以零。

這是一個更完整的例子:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM