Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell `where` with pattern-matching

I have such function:

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

I would like to rewrite this with one where usage. Can I do it? But pattern-matching should stay in this code. Thanks!

like image 902
user13112088 Avatar asked Feb 20 '26 14:02

user13112088


1 Answers

There's no general, straightforward way of matching against patterns with common variables:

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

and then writing expressions (in where clauses or elsewhere) such that a and b correspond to both patterns simultaneously. In Haskell, a pattern creates a new scope in which variables in the pattern are bound by that pattern, and there's no way to "combine" those bindings -- a usage of a or b will either refer to the bindings in Bar a b or Baz a b, never both.

About the best you can do is use a case statement to apply a common where clause to multiple patterns and make use of a common helper function that takes a and b as arguments and explicitly rebinds them to common names, on a pattern-by-pattern basis:

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)
like image 173
K. A. Buhr Avatar answered Feb 24 '26 17:02

K. A. Buhr