Haskell Wikibook - Generalized Algebraic Data Types Exercise - Maybe and Either












2















There's an exercise on this page of the Haskell Wikibook which gets you to work through a scenario using Maybe and Either (presumably to show that it is quite painful for the use case).



The exercise is:



data Expr = I Int
| B Bool -- boolean constants
| Add Expr Expr
| Mul Expr Expr
| Eq Expr Expr -- equality test

eval :: Expr -> Maybe (Either Int Bool)
-- Your implementation here.


The first lines of the solution are - I think - straightforward:



data Expr = I Int         -- integer constants
| B Bool -- boolean constants
| Add Expr Expr -- add two expressions
| Mul Expr Expr -- multiply two expressions
| Eq Expr Expr -- equality test
deriving (Show)

eval :: Expr -> Maybe (Either Int Bool)
eval (I n) = Just $ Left n
eval (B b) = Just $ Right b
eval (Add e1 e2) = ...
eval (Mul e1 e2) = ...
eval (Eq e1 e2) = ...


But I'm not exactly sure how to define the rest. As an example I guess for add I need to unpack the fromLeft, fromJust of each expression, but I'm not sure how to do this properly (with pattern matching?)



Thanks in advance!










share|improve this question





























    2















    There's an exercise on this page of the Haskell Wikibook which gets you to work through a scenario using Maybe and Either (presumably to show that it is quite painful for the use case).



    The exercise is:



    data Expr = I Int
    | B Bool -- boolean constants
    | Add Expr Expr
    | Mul Expr Expr
    | Eq Expr Expr -- equality test

    eval :: Expr -> Maybe (Either Int Bool)
    -- Your implementation here.


    The first lines of the solution are - I think - straightforward:



    data Expr = I Int         -- integer constants
    | B Bool -- boolean constants
    | Add Expr Expr -- add two expressions
    | Mul Expr Expr -- multiply two expressions
    | Eq Expr Expr -- equality test
    deriving (Show)

    eval :: Expr -> Maybe (Either Int Bool)
    eval (I n) = Just $ Left n
    eval (B b) = Just $ Right b
    eval (Add e1 e2) = ...
    eval (Mul e1 e2) = ...
    eval (Eq e1 e2) = ...


    But I'm not exactly sure how to define the rest. As an example I guess for add I need to unpack the fromLeft, fromJust of each expression, but I'm not sure how to do this properly (with pattern matching?)



    Thanks in advance!










    share|improve this question



























      2












      2








      2


      1






      There's an exercise on this page of the Haskell Wikibook which gets you to work through a scenario using Maybe and Either (presumably to show that it is quite painful for the use case).



      The exercise is:



      data Expr = I Int
      | B Bool -- boolean constants
      | Add Expr Expr
      | Mul Expr Expr
      | Eq Expr Expr -- equality test

      eval :: Expr -> Maybe (Either Int Bool)
      -- Your implementation here.


      The first lines of the solution are - I think - straightforward:



      data Expr = I Int         -- integer constants
      | B Bool -- boolean constants
      | Add Expr Expr -- add two expressions
      | Mul Expr Expr -- multiply two expressions
      | Eq Expr Expr -- equality test
      deriving (Show)

      eval :: Expr -> Maybe (Either Int Bool)
      eval (I n) = Just $ Left n
      eval (B b) = Just $ Right b
      eval (Add e1 e2) = ...
      eval (Mul e1 e2) = ...
      eval (Eq e1 e2) = ...


      But I'm not exactly sure how to define the rest. As an example I guess for add I need to unpack the fromLeft, fromJust of each expression, but I'm not sure how to do this properly (with pattern matching?)



      Thanks in advance!










      share|improve this question
















      There's an exercise on this page of the Haskell Wikibook which gets you to work through a scenario using Maybe and Either (presumably to show that it is quite painful for the use case).



      The exercise is:



      data Expr = I Int
      | B Bool -- boolean constants
      | Add Expr Expr
      | Mul Expr Expr
      | Eq Expr Expr -- equality test

      eval :: Expr -> Maybe (Either Int Bool)
      -- Your implementation here.


      The first lines of the solution are - I think - straightforward:



      data Expr = I Int         -- integer constants
      | B Bool -- boolean constants
      | Add Expr Expr -- add two expressions
      | Mul Expr Expr -- multiply two expressions
      | Eq Expr Expr -- equality test
      deriving (Show)

      eval :: Expr -> Maybe (Either Int Bool)
      eval (I n) = Just $ Left n
      eval (B b) = Just $ Right b
      eval (Add e1 e2) = ...
      eval (Mul e1 e2) = ...
      eval (Eq e1 e2) = ...


      But I'm not exactly sure how to define the rest. As an example I guess for add I need to unpack the fromLeft, fromJust of each expression, but I'm not sure how to do this properly (with pattern matching?)



      Thanks in advance!







      haskell






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 20 '18 at 16:20









      duplode

      22.9k44885




      22.9k44885










      asked Nov 20 '18 at 16:17









      rjmurtrjmurt

      455416




      455416
























          2 Answers
          2






          active

          oldest

          votes


















          4














          Yes, with pattern matching and perhaps even the Maybe monad.



          You could implement the eval (Add e1 e2) branch using just pattern matching:



          eval (Add e1 e2) = case eval e1 of
          Just (Left i1) -> case eval e2 of
          Just (Left i2) -> Just (Left (i1 + i2))
          _ -> Nothing
          _ -> Nothing


          Pattern matching on a pair is one good way of reducing the amount of nested case statements:



          eval (Add e1 e2) = case (eval e1, eval e2) of
          (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2))
          _ -> Nothing


          Or, you could use the Maybe monad as an abstraction over those case statements. It will automatically return Nothing if any of the pattern matching fails in the do block bindings (due to how the Maybe monad implements fail).



          eval (Add e1 e2) = do
          Left i1 <- eval e1
          Left i2 <- eval e2
          return (Left (i1 + i2))





          share|improve this answer





















          • 1





            Pairs are great for reducing the complexity of pattern matching. The first block above could be rewritten as case (eval e1, eval e2) of { (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2)); _ -> Nothing }

            – Chris Smith
            Nov 20 '18 at 17:12













          • @ChrisSmith Nice! I added that

            – 4castle
            Nov 20 '18 at 17:56



















          1















          eval (Add e1 e2) = ...




          You will want to evaluate e1 and e2 then pattern match on those results. There's various ways of doing that. For instance you can use let bindings.



          let ev1 = eval e1
          ev2 = eval e2
          in


          And then pattern match using the case construction. Or with no let bindings if you prefer, you can just do



          case (eval e1, eval e2) of 


          and pattern match on that pair.






          share|improve this answer























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53397200%2fhaskell-wikibook-generalized-algebraic-data-types-exercise-maybe-and-either%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            4














            Yes, with pattern matching and perhaps even the Maybe monad.



            You could implement the eval (Add e1 e2) branch using just pattern matching:



            eval (Add e1 e2) = case eval e1 of
            Just (Left i1) -> case eval e2 of
            Just (Left i2) -> Just (Left (i1 + i2))
            _ -> Nothing
            _ -> Nothing


            Pattern matching on a pair is one good way of reducing the amount of nested case statements:



            eval (Add e1 e2) = case (eval e1, eval e2) of
            (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2))
            _ -> Nothing


            Or, you could use the Maybe monad as an abstraction over those case statements. It will automatically return Nothing if any of the pattern matching fails in the do block bindings (due to how the Maybe monad implements fail).



            eval (Add e1 e2) = do
            Left i1 <- eval e1
            Left i2 <- eval e2
            return (Left (i1 + i2))





            share|improve this answer





















            • 1





              Pairs are great for reducing the complexity of pattern matching. The first block above could be rewritten as case (eval e1, eval e2) of { (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2)); _ -> Nothing }

              – Chris Smith
              Nov 20 '18 at 17:12













            • @ChrisSmith Nice! I added that

              – 4castle
              Nov 20 '18 at 17:56
















            4














            Yes, with pattern matching and perhaps even the Maybe monad.



            You could implement the eval (Add e1 e2) branch using just pattern matching:



            eval (Add e1 e2) = case eval e1 of
            Just (Left i1) -> case eval e2 of
            Just (Left i2) -> Just (Left (i1 + i2))
            _ -> Nothing
            _ -> Nothing


            Pattern matching on a pair is one good way of reducing the amount of nested case statements:



            eval (Add e1 e2) = case (eval e1, eval e2) of
            (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2))
            _ -> Nothing


            Or, you could use the Maybe monad as an abstraction over those case statements. It will automatically return Nothing if any of the pattern matching fails in the do block bindings (due to how the Maybe monad implements fail).



            eval (Add e1 e2) = do
            Left i1 <- eval e1
            Left i2 <- eval e2
            return (Left (i1 + i2))





            share|improve this answer





















            • 1





              Pairs are great for reducing the complexity of pattern matching. The first block above could be rewritten as case (eval e1, eval e2) of { (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2)); _ -> Nothing }

              – Chris Smith
              Nov 20 '18 at 17:12













            • @ChrisSmith Nice! I added that

              – 4castle
              Nov 20 '18 at 17:56














            4












            4








            4







            Yes, with pattern matching and perhaps even the Maybe monad.



            You could implement the eval (Add e1 e2) branch using just pattern matching:



            eval (Add e1 e2) = case eval e1 of
            Just (Left i1) -> case eval e2 of
            Just (Left i2) -> Just (Left (i1 + i2))
            _ -> Nothing
            _ -> Nothing


            Pattern matching on a pair is one good way of reducing the amount of nested case statements:



            eval (Add e1 e2) = case (eval e1, eval e2) of
            (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2))
            _ -> Nothing


            Or, you could use the Maybe monad as an abstraction over those case statements. It will automatically return Nothing if any of the pattern matching fails in the do block bindings (due to how the Maybe monad implements fail).



            eval (Add e1 e2) = do
            Left i1 <- eval e1
            Left i2 <- eval e2
            return (Left (i1 + i2))





            share|improve this answer















            Yes, with pattern matching and perhaps even the Maybe monad.



            You could implement the eval (Add e1 e2) branch using just pattern matching:



            eval (Add e1 e2) = case eval e1 of
            Just (Left i1) -> case eval e2 of
            Just (Left i2) -> Just (Left (i1 + i2))
            _ -> Nothing
            _ -> Nothing


            Pattern matching on a pair is one good way of reducing the amount of nested case statements:



            eval (Add e1 e2) = case (eval e1, eval e2) of
            (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2))
            _ -> Nothing


            Or, you could use the Maybe monad as an abstraction over those case statements. It will automatically return Nothing if any of the pattern matching fails in the do block bindings (due to how the Maybe monad implements fail).



            eval (Add e1 e2) = do
            Left i1 <- eval e1
            Left i2 <- eval e2
            return (Left (i1 + i2))






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 20 '18 at 17:54

























            answered Nov 20 '18 at 16:34









            4castle4castle

            21.1k54072




            21.1k54072








            • 1





              Pairs are great for reducing the complexity of pattern matching. The first block above could be rewritten as case (eval e1, eval e2) of { (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2)); _ -> Nothing }

              – Chris Smith
              Nov 20 '18 at 17:12













            • @ChrisSmith Nice! I added that

              – 4castle
              Nov 20 '18 at 17:56














            • 1





              Pairs are great for reducing the complexity of pattern matching. The first block above could be rewritten as case (eval e1, eval e2) of { (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2)); _ -> Nothing }

              – Chris Smith
              Nov 20 '18 at 17:12













            • @ChrisSmith Nice! I added that

              – 4castle
              Nov 20 '18 at 17:56








            1




            1





            Pairs are great for reducing the complexity of pattern matching. The first block above could be rewritten as case (eval e1, eval e2) of { (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2)); _ -> Nothing }

            – Chris Smith
            Nov 20 '18 at 17:12







            Pairs are great for reducing the complexity of pattern matching. The first block above could be rewritten as case (eval e1, eval e2) of { (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2)); _ -> Nothing }

            – Chris Smith
            Nov 20 '18 at 17:12















            @ChrisSmith Nice! I added that

            – 4castle
            Nov 20 '18 at 17:56





            @ChrisSmith Nice! I added that

            – 4castle
            Nov 20 '18 at 17:56













            1















            eval (Add e1 e2) = ...




            You will want to evaluate e1 and e2 then pattern match on those results. There's various ways of doing that. For instance you can use let bindings.



            let ev1 = eval e1
            ev2 = eval e2
            in


            And then pattern match using the case construction. Or with no let bindings if you prefer, you can just do



            case (eval e1, eval e2) of 


            and pattern match on that pair.






            share|improve this answer




























              1















              eval (Add e1 e2) = ...




              You will want to evaluate e1 and e2 then pattern match on those results. There's various ways of doing that. For instance you can use let bindings.



              let ev1 = eval e1
              ev2 = eval e2
              in


              And then pattern match using the case construction. Or with no let bindings if you prefer, you can just do



              case (eval e1, eval e2) of 


              and pattern match on that pair.






              share|improve this answer


























                1












                1








                1








                eval (Add e1 e2) = ...




                You will want to evaluate e1 and e2 then pattern match on those results. There's various ways of doing that. For instance you can use let bindings.



                let ev1 = eval e1
                ev2 = eval e2
                in


                And then pattern match using the case construction. Or with no let bindings if you prefer, you can just do



                case (eval e1, eval e2) of 


                and pattern match on that pair.






                share|improve this answer














                eval (Add e1 e2) = ...




                You will want to evaluate e1 and e2 then pattern match on those results. There's various ways of doing that. For instance you can use let bindings.



                let ev1 = eval e1
                ev2 = eval e2
                in


                And then pattern match using the case construction. Or with no let bindings if you prefer, you can just do



                case (eval e1, eval e2) of 


                and pattern match on that pair.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 20 '18 at 16:34









                Jorge AdrianoJorge Adriano

                2,220918




                2,220918






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53397200%2fhaskell-wikibook-generalized-algebraic-data-types-exercise-maybe-and-either%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    MongoDB - Not Authorized To Execute Command

                    How to fix TextFormField cause rebuild widget in Flutter

                    Npm cannot find a required file even through it is in the searched directory