1.0 >(readF-6ren">
gpt4 book ai didi

haskell - 如何将字符串解析为 Haskell 中的函数?

转载 作者:行者123 更新时间:2023-12-04 03:58:38 25 4
gpt4 key购买 nike

我想要一个看起来像这样的函数

readFunc :: String -> (Float -> Float)

它运行这样的东西
>(readFunc "sin") (pi/2)
>1.0

>(readFunc "(+2)") 3.0
>5.0

>(readFunc "(\x -> if x > 5.0 then 5.0 else x)") 2.0
>2.0

>(readFunc "(\x -> if x > 5.0 then 5.0 else x)") 7.0
>5.0

难以置信的幼稚方法(注意这必须用 {-# LANGUAGE FlexibleContexts #-} 编译)
readFunc :: (Read (Float -> Float)) => String -> (Float -> Float)
readFunc s = read s


No instance for (Read (Float -> Float)) ...

这是有道理的,因为不存在这样的实例。我知道我可以通过从 String 编写映射来逐个字符地解析输入字符串。至 Float -> Float但我希望至少能够解析 prelude 中最常见的函数,即使这样也比我想要做的工作要多得多。有没有一种简单的方法可以做到这一点?

仅使用提示的一种解决方案
import Language.Haskell.Interpreter hiding (typeOf)
import Data.Typeable (typeOf)

data Domain = Dom Float Float Float Float Domain
| SDom Float Float Float Float
deriving (Show, Read)

--gets all the points that will appear in the domain
points (SDom a b c d) m = [(x, y)|x <- [a, a+m .. b], y <- [c, c+m .. d]]
points (Dom a b c d next) m = points next m ++ [(x, y)|x <- [a, a+m .. b], y <- [c, c+m .. d]]

readFunc = do
putStrLn "Enter a domain (as Dom x-min x-max y-min y-max subdomain, or, SDom x-min x-max y-min y-max)"
domain' <- getLine
let domain = (read domain') :: Domain
--
putStrLn "Enter a mesh size"
meshSize' <- getLine
let meshSize = (read meshSize') :: Float
--
putStrLn "Enter an initial value function (as f(x,y))"
func' <- getLine
values' <- runInterpreter $ setImports["Prelude"] >>
eval ("map (\\(x,y) -> " ++ func' ++ ")" ++ show (points domain meshSize))
let values = (\(Right v) -> (read v)::([Float])) values'

--the haskell expression being evaluated
putStrLn $ ("map (\\(x,y) -> " ++ func' ++ ")" ++ show (points domain meshSize))

--prints the actual values
putStrLn $ show values

--the type is indeed [float]
putStrLn $ show $ typeOf values

最佳答案

您可以使用 hint包,或 plugins .我将向您展示前者(部分原因是我的 Windows 安装显然有点损坏,因为 cabal 不同意我安装 C 的信念,因此 cabal 安装插件失败)。

字符串 -> 函数很简单:

import Language.Haskell.Interpreter

getF :: String -> IO (Either InterpreterError (Float -> Float))
getF xs = runInterpreter $ do
setImports ["Prelude"]
interpret xs (as :: Float -> Float)

您可能希望将其他模块添加到导入列表中。这测试为
ghci> getF "sin" >>= \(Right f) -> print $ f (3.1415927/2)
1.0
ghci> getF "(\\x -> if x > 5.0 then 5.0 else x)" >>= \(Right f) -> print $ f 7
5.0

(注意转义字符 \ 的转义。)

错误信息

您可能已经注意到,结果包含在 Either 数据类型中。 Right f是正确的输出,而 Left err给出 InterpreterError消息,这很有帮助:
ghci> getF "sinhh" >>= \(Left err) -> print err
WontCompile [GhcError {errMsg = "Not in scope: `sinhh'\nPerhaps you meant `sinh' (imported from Prelude)"}]

示例玩具程序

当然可以使用 either用你的代码来处理这个。让我们做一个假的例子 respond .你真正的将包含你程序的所有数学。
respond :: (Float -> Float) -> IO ()
respond f = do
-- insert cunning numerical method instead of
let result = f 5
print result

你的程序的一个简单的、一次性的、无用的版本可能是
main = 
putStrLn "Enter your function please:"
>> getLine
>>= getF
>>= either print respond

示例 session
ghci> main
Enter your function please:
\x -> x^2 + 4
29.0
ghci> main
Enter your function please:
ln
WontCompile [GhcError {errMsg = "Not in scope: `ln'"}]

它会为您进行类型检查:
ghci> main
Enter your function please:
(:"yo")
WontCompile [GhcError {errMsg = "Couldn't match expected type `GHC.Types.Float'\n with actual type `GHC.Types.Char'"}]

关于haskell - 如何将字符串解析为 Haskell 中的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16679089/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com