Home > database >  Patternmatching in Haskell with Either type
Patternmatching in Haskell with Either type

Time:08-12

I try to patternmatch on the Either type but I get an error. Why does the following work

patternMaster :: Either a b -> b  
patternMaster (Right a) = a
patternMaster (Left b) = b

with patternMaster (Right a)

whereas I get the following output when I apply the function with its type mentioned just below:

Arithmetic.hs:101:26: error:
    * Couldn't match expected type `b' with actual type `a'
      `a' is a rigid type variable bound by
        the type signature for:
          patternMaster :: forall a b. Either a b -> b
        at Arithmetic.hs:99:1-32
      `b' is a rigid type variable bound by
        the type signature for:
          patternMaster :: forall a b. Either a b -> b
        at Arithmetic.hs:99:1-32
    * In the expression: b
      In an equation for `patternMaster': patternMaster (Left b) = b
    * Relevant bindings include
        b :: a (bound at Arithmetic.hs:101:21)
        patternMaster :: Either a b -> b (bound at Arithmetic.hs:100:1)
-- -----------Types
initEnvironment :: Env
initEnvironment = \_v -> Nothing

-- --------Function
evalErr :: Exp -> Env -> Either ArithError Integer
evalErr (Cst e1) _ = Right e1 
evalErr (Div e1 e2) env = 
                          case evalErr e2 env of
                            Left az -> Left az 
                            Right az -> 
                              if az == 0 
                                then Left EDivZero 
                              else 
                                case (evalErr e1 env) of
                                Left b -> Left b
                                Right b -> Right (b `div` az)

Shouldn't it be the same?

CodePudding user response:

In this demo function:

patternMaster :: Either b b -> b  
patternMaster (Right a) = a
patternMaster (Left a) = a

the input has to have the same type for the left and right alternatives, and patternMaster something has that type as well. E.g.

  • if something is Either Integer Integer then patternMaster something is Integer
  • if something is Either Integer String then patternMaster something does not compile

Meanwhile your real code:

something =
    case (evalErr (Cst 4) initEnvironment) of
      (Left a) -> a
      (Right a) -> a

what is the type of the case expression? If evalErr evaluates, then it's Integer. If evalErr returns an error, then it's ArithError. Those are incompatible types - there's no valid type for something.

If you wanted to say it could be either Integer or ArithError, then you wouldn't have written this case statement and the overall type would be Either ArithError Integer


At some point your program has to care about whether it's an ArithError or an Integer and run different code for each one. That's where you put the case statement. E.g. if you want to convert either both of them to strings, you could write:

showMaster :: (Show a, Show b) => Either a b -> String
showMaster (Right x) = show x
showMaster (Left x) = show x

noting that each show calls a different function so it's different code, but both of them return strings so the return value of showMaster is always a string.

  • Related