我是Haskell的新手,并尝试创建一个评估算术表达式的函数:
data Expr = Number Rational | Variable String | Plus Expr Expr deriving (Eq, Show , Read)
eval (Plus lhs rhs) = Number (a + b)
where Number a = eval lhs
Number b = eval rhs
eval x = x
main = putStrLn . show $ eval (Plus (Number 1) (Variable "x"))
我希望eval
函数在表达式Variable
之前评估表达式,这意味着只要Plus
中的两个表达式计算为Number
,就可以将其折叠为Number
一个新的Plus
,否则您无法折叠Plus
,但也许您只能折叠Number b
的一侧。例如:eval(加号(数字a)(数字b))==数字(a + b)eval(加号(Var" a")b)==加号(Var" a&#34 ;)(评估b)
我预计模式eval x = x
会失败并继续main: main.hs:5:9-27: Irrefutable pattern failed for pattern Main.Number b
并按原样返回表达式,但它会产生错误:
with cte as (
select *
, rn = row_number() over (
partition by cltid, Invnum
order by [date] desc
)
from a
)
select cltid, Invnum, Cash, [date]
from cte
where rn = 1
为什么会发生这种情况,我该如何解决?
答案 0 :(得分:4)
您需要使用case
表达式来匹配内部eval
调用的所有可能结果,而不仅仅是Number
s:
eval (Plus lhs rhs) = case (eval lhs, eval rhs) of
(Number a, Number b) -> Number (a + b) -- two numbers can be summed
(otherA, otherB) -> Plus otherA otherB -- other values form a Plus with collapsed parts
eval x = x
答案 1 :(得分:3)
您可以使用ViewPatterns
使其相对漂亮:
{-# LANGUAGE ViewPatterns #-}
eval (Plus (eval -> Number a) (eval -> Number b)) = Number (a+b)
eval x = x
鉴于你的评论,如果我没有指出你提出的算法存在一些缺陷,我会失职;例如:
> eval (Number 3 `Plus` Number 4 `Plus` Variable "a") -- doesn't know about associativity of Plus
Plus (Plus (Number (3 % 1)) (Number (4 % 1))) (Variable "a")
> eval (Variable "a" `Plus` (Number 3 `Plus` Number 4)) -- doesn't simplify recursively when it hits a variable
Plus (Variable "a") (Plus (Number (3 % 1)) (Number (4 % 1)))
考虑规范化为较不结构化的类型;或许类似
data Sum = Sum Rational (MultiSet String)
告诉第一部分中所有Number
的总和以及每个变量在the second part中出现的频率。然后
eval :: Expr -> Sum
eval (Number r) = Sum r empty
eval (Variable v) = Sum 0 (singleton v)
eval (Plus l r) = Sum (r+r') (union vs vs') where
Sum r vs = eval l
Sum r' vs' = eval r