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?

Original source

Related problems