Haskell Switch / Enclosure Use

As part of the mini-interpreter that I am writing in Haskell, I am writing a function that does the following: In the case of eval (App e1 e2) I want to recursively evaluate e1 ( eval e1 ) by setting the result to v1 . Then, using Switch / Case, I want to check the v1 pattern and, if it is not an error, then recursively evaluate e2 ( eval e2 ) and set this value to v2 . Using these two values v1 and v2 , I apply another function ( appVals ) to these 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 might have figured this out, but I'm not quite sure what the switch / case part did right. Any ideas / suggestions?

+4
source share
4 answers

The second part of your case statement should not try to retest, because you already know that this is not an Error that would correspond to the first. (Skip /= Error err .)

eval e1 = v1 trying to redo the eval you did at the beginning. You do not need to do this.

Here 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 all this seems a little ugly, so let me digress from Gabriel Gonzalez and make an application from Error .

 instance Functor Error where fmap f (Error e) = Error e -- pass through errors fmap f (S x) = S (fx) -- edit successes 

So, for example, fmap (+4) (Error "oops") = Error "oops" , while fmap (+4) (S 5) = S 9 .

If this fmap all new for you, why not read the Feature Tutorial ?

Then create an applicative instance. Application allows you to use complex functions, such as simple ones. You need import Control.Applicative at the top of the file for it to work.

 instance Applicative Error where pure x = S x -- how to put ordinary data in S f <*> S x = S (fx) Error e <*> _ = Error e _ <*> Error e = Error e 

Now, if there were no errors, you must determine

 appVal' :: Val -> Val -> Val eval' :: Exp -> Val eval' (App e1 e2) = appVal' (eval' e1) (eval' e2) 

Applying, we can use <$> , which is a bit like $ , except that you do everything you specify in fmap . Similarly, <*> works a bit as a function application , with the exception of additional plumbing, so we can determine

 eval :: Exp -> Error Val eval (App e1 e2) = appVals <$> eval e1 <*> eval e2 

which is a good clean way to handle bugs backstage by focusing on functionality.

+12
source

I left you yesterday (change names modulo) with

 eval (App e1 e2) = appVals <$> eval e1 <*> eval e2 

This is almost what you want, the difference is that if either of the two inputs is an error, you want to replace it with a specific error message. (I don’t understand why.) So write a function to make only this last bit!

 butError :: String -> Error a -> Error a butError message (Error _) = Error message butError _ noError = noError 

Now you can rewrite the sentence eval as

 eval (App e1 e2) = appVals <$> butError message (eval e1) <*> butError message (eval e2) where message = "Not an application" 
+4
source

I assume that you have some data type that looks like this:

 data Result a = Error String | Success a 

The solution to your problem is this:

(a) Make your Result type a Monad

(b) Use an Either String instead of the result, as it already has a Monad instance.

Whatever you do, then you simply write:

 eval :: SyntaxTree a -> Result a eval (App ef ex) = do f <- eval ef x <- eval ex return (fx) 

Technically, Applicative sufficient for this purpose, and you could write:

 eval (App ef ex) = eval ef <*> eval ex 
+3
source

In case you need to have templates for alternatives, you cannot /= Error err .

In addition, you cannot have = right of the arrow -> in the case expression, therefore -> eval e1 = v1 not valid Haskell.

In your case, you do not care that it is not Error something , but as soon as the first template does not match, it is automatic, and since you do not care what else you get, you can use the variable structure:

 eval (App e1 e2) = appVals v1 v2 where v1 = case (eval e1) of Error err -> Error "Not an application" other -> other v2 = case (eval e2) of Error err -> Error "Not an application" other -> other 
+2
source

Source: https://habr.com/ru/post/1446824/


All Articles