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
isEither Integer Integer
thenpatternMaster something
isInteger
- if
something
isEither Integer String
thenpatternMaster 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.