Haskell中的`where`与模式匹配

3
我有这样的函数:
eval :: Expr -> Either ArithmeticError Int
eval (Const a) = Right a
eval (Add a b) = liftM2 (+) ea eb
  where
    ea = eval a
    eb = eval b
eval (Sub a b) = liftM2 (-) ea eb
  where
    ea = eval a
    eb = eval b

我想使用一个 where 来重写这段代码,可以吗?但是模式匹配应该保留在代码中。谢谢!

1
为什么不编写一个辅助函数 _eval f a b = liftM2 f (eval a) (eval b),然后指定 eval (Add a b) = _eval (+) a beval (Sub a b) = _eval (-) a b 呢? - Willem Van Onsem
3
或者使用Data.Function.oneval (Add a b) = liftM2 (+) `on` eval。 (说明:Data.Function.on是一个高阶函数,它可以将一个二元函数转换成一个以某个函数为参数的函数。在这里,on被用于组合liftM2eval函数,使得(+)可以作用于eval的结果上) - chepner
@WillemVanOnsem,感谢您的推荐。是的,我知道这种方法,但我正在寻找一种不需要其他函数的方法。 - user13112088
@chepner 看起来很漂亮。但是旧的 eval (Add a b) = liftM2 (+) (eval a) (eval b) 有什么问题? - lsmor
@Ismor 请问原帖作者,他们一开始就没有写那个内容。 - chepner
显示剩余5条评论
1个回答

6

没有一种通用、简单的方法来匹配具有常见变量的模式:

foo (Bar a b) = ...
foo (Baz a b) = ...

然后编写表达式(在where子句或其他地方),使得ab同时对应这两个模式。在Haskell中,模式创建了一个新的作用域,在该模式中变量被该模式绑定,而且没有办法“结合”这些绑定——使用ab将只是指向Bar a bBaz a b中的绑定,而不会同时指向两者。
你最好的选择是使用case语句将共同的where子句应用于多个模式,并利用一个共同的辅助函数,将ab作为参数并在逐个模式的基础上明确地重新绑定到公共名称上。
eval :: Expr -> Either ArithmeticError Int
eval e = case e of
  Const a -> Right a
  Add a b -> go (+) a b
  Sub a b -> go (-) a b

  where go op a b = liftM2 op (eval a) (eval b)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接