Haskell Switch/Case Use
haskell, recursion, switch-statement
Solution
The second part of your case statement shouldn't try to retest because you already know it's not an `Error` - that would have matched the first. (Skip `/= Error err`.)
`eval e1 = v1` tries to redo the eval you did at the start. You don't need to do that.
Here's what I think you intended to do:
eval :: Exp -> Error Val
eval (App e1 e2) = case eval e1 of
Error _ -> Error "Not an application"
S v1 -> case eval e2 of -- nested case statement
Error _ -> Error "Not an application"
S v2 -> appVals v1 v2 -- match the S away
But it all seems a bit ugly, so let's take exellent advice from Gabriel Gonzalez and make an applicative out of `Error`.
instance Functor Error where
fmap f (Error e) = Error e -- pass through errors
fmap f (S x) = S (f x) -- edit successes
So for example, `fmap (+4) (Error "oops") = Error "oops"` whereas `fmap (+4) (S 5) = S 9`.
If this `fmap` is all new to you, why not read a Functors tutorial?
Next let's make an Applicative instance. Applicative lets you use complicated functions like simple ones. You need to `import Control.Applicative` at the top of your file to get it working.
instance Applicative Error where
pure x = S x -- how to put ordinary data in
S f <*> S x = S (f x)
Error e <*> _ = Error e
_ <*> Error e = Error e
Now, if there weren't any errors then you'd define
appVal' :: Val -> Val -> Val
eval' :: Exp -> Val
eval' (App e1 e2) = appVal' (eval' e1) (eval' e2)
With applicative, we can use `<$>` which works a bit like `$` except it does whatever plumbing you defined in `fmap`. Similarly, `<*>` works a bit like `` function application, except for the extra plumbing, so we can define
eval :: Exp -> Error Val
eval (App e1 e2) = appVals <$> eval e1 <*> eval e2
which is a nice clean way of dealing with the errors behind the scenes whilst focussing on the functionality.
Problem
As part of a mini interpreter that I'm writing in Haskell, I'm writing a function that does the following: In case of `eval (App e1 e2)`, I want to recursively evaluate `e1` (`eval e1`), setting the result to `v1`. Then using Switch/Case, I want to check the pattern of the `v1` and if it's not an Error then recursively evaluate `e2` (`eval e2`) and setting that value to `v2`. Using these two values `v1` and `v2`, then I apply another function (`appVals`) on those values. ``` eval :: Exp -> Error Val eval (App e1 e2) = appVals v1 v2 where v1 = case (eval e1) of Error err -> Error "Not an application" /= Error err -> eval e1 = v1 v2 = case (eval e2) of Error err -> Error "Not an application" /= Error err -> eval e2 = v2 ``` I think I may have figured it out but I'm not entirely sure I've done the switch/case part correctly. Any ideas/suggests?