use*_*704 0 variables parsing haskell eval parsec
我发现在Haskell中学习Parsec很难,所以我正在尝试创建我的大学项目(一个用表格解析文件的解析器)
x=3
y=4
z=x+y
badluck=(x+sqrt(z)*7)
Run Code Online (Sandbox Code Playgroud)
我设法写了一个函数,从文件中获取所有内容并验证文件,我坚持让x成为变量名.我知道在javascript中它是eval但我在Haskell中找不到类似的东西.请帮忙!
这是我到目前为止所做的事情:
ischarorscore :: Char -> Bool
ischarorscore a = if ((a>='A' && a<='Z') || (a>='a' && a<='z') || a=='_')
then True
else False
ischarscoredigit :: Char -> Bool
ischarscoredigit a = if ((a>='A' && a<='Z') ||
(a>='a' && a<='z') ||
a=='_' ||
a>='0' && a<='9') then True else False
isvar :: String -> Bool
isvar [] = False
isvar (h:t) = if (ischarorscore h) then (isvarbody t) else False
isvarbody :: String -> Bool
isvarbody [] = True
isvarbody (h:t) = if (ischarscoredigit h) then (isvarbody t) else False
isoperator :: Char -> Bool
isoperator a = if (a=='+' || a=='-' || a=='*' || a=='/' || a=='^') then True else False
issqrt :: String -> Bool
issqrt [] = True
issqrt x = if (x=="sqrt(") then True else False
isnumber :: String -> Bool
isnumber (h:t) = if (h>='0' && h<='9') then isnumber t else False
charsetall :: String -> Bool
charsetall [] = True
charsetall (h:t) = if (h>='0' && h<='9' ||
h>='a' && h<='z' ||
h>='A' && h<='Z' ||
h>='0' && h<='9' ||
h=='+' || h=='-' || h=='*' || h=='/' || h=='^' || h=='(' || h==')' || h=='=')
then charsetall t else False
charsetexpr :: String -> Bool
charsetexpr [] = True
charsetexpr (h:t) = if (h>='0' && h<='9' ||
h>='a' && h<='z' ||
h>='A' && h<='Z' ||
h>='0' && h<='9' ||
h=='+' || h=='-' || h=='*' || h=='/' || h=='^' || h=='(' || h==')')
then charsetexpr t else False
paranthesis :: String -> Int -> Bool
paranthesis [] a = if (a==0) then True else False
paranthesis (h:t) a = if (h=='(') then (paranthesis t (a+1))
else (if (h==')') then
paranthesis t (a-1) else paranthesis t a)
paranthesis' :: String -> Bool
paranthesis' (h:t) = paranthesis (h:t) 0
obeyrules :: String -> Bool
obeyrules [] = True
obeyrules (h:t) = if (ischarorscore h) then (contvar t)
else if (h>='0' && h<='9') then (contnumber t)
else if (h=='(' || h=='-') then obeyrules t
else False
contnumber :: String -> Bool
contnumber [] = True
contnumber (h:t) = if (h>='0' && h<='9') then contnumber t
else if (isoperator h) then contoperator t
else if (h==')') then contoperator h
else False
contvar :: String -> Bool
contvar [] = True
contvar (h:t) = if (ischarorscore h || h>='0' && h<='9') then contvar t
else if (isoperator h) then contoperator t
else if (h==')') then contoperator
else False
contoperator :: String -> Bool
contoperator [] = True
contoperator (h:t) = if (ischarorscore h) then contvar t
else if (h>='0' && h<='9') then contnumber t
else if (h=='(') then obeyrules t
else False
isexpression :: String -> Bool
isexpression [] = True
isexpression (h:t) = if (charsetexpr (h:t) && paranthesis' (h:t) && obeyrules (h:t)) then True else False
Run Code Online (Sandbox Code Playgroud)
isexpression函数结合了上述所有函数来验证文件的一行.项目是这样的:你必须读取一个看起来像上面那个的随机文件并包含变量name = expression并识别(,),+, - ,*,/,^这是幂,sqrt(k)其中k是数字或变量名称,mod,计算表达式并提供结果变量名称及其值.
您最有可能想要解析所谓的抽象语法树.对于这里给出的片段,它可能看起来像
data AST
= Var String
| Lit Double
| Plus AST AST
| Mult AST AST
| Sqrt AST
| Assign String AST
| Then AST AST
Run Code Online (Sandbox Code Playgroud)
有了AST的这种选择,你给出的代码片段就像
fragment :: AST
fragment = foldr1 Then [
Assign "x" (Lit 3)
, Assign "y" (Lit 4)
, Assign "z" (Plus (Var "x") (Var "y"))
, Assign "badluck" (Plus (Var "x") (Mult (Sqrt (Var "z")) (Lit 7)))
]
Run Code Online (Sandbox Code Playgroud)
然后我们选择一个求值函数,将这些AST值转换为它们的"规范"值.在这种情况下,基本规范值将是a Double,但由于AST可能由于引用未知变量而失败,因此我们将具有规范值Maybe Double.最后,由于我们希望在评估表达式时环境发生变化,因此我们返回更新的环境.
为了操作此评估者,我们需要一个被分配的环境概念.一个很好的选择是Data.Map
import Control.Applicative
import qualified Data.Map as Map
import Data.Map (Map)
type Env = Map String Double
eval :: Env -> AST -> Maybe (Double, Env)
eval env (Var s) = fmap (\x -> (x, env)) (Map.lookup s env)
eval env (Plus e1 e2) = do -- maybe monad
(v1, env') <- eval env e1
(v2, env'') <- eval env' e2
return (v1 + v2, env'')
eval env (Mult e1 e2) = do -- maybe monad
(v1, env') <- eval env e1
(v2, env'') <- eval env' e2
return (v1 * v2, env'')
eval env (Sqrt e) = fmap (\(x, e) -> (sqrt x, e)) (eval env e)
eval env (Assign s e) = do
(v, env') <- eval env e
return (v, Map.insert s v env')
eval env (Then e1 e2) = do
(_, env') <- eval env e1
(v, env'') <- eval env' e2
return (v, env'')
Run Code Online (Sandbox Code Playgroud)
从技术上讲,这可能已经使用的单子转换栈完成State Env和Maybe,但如果编写繁琐的操作可能是一个更加清楚一点.