Haskell Wikibook - Generalized Algebraic Data Types Exercise - Maybe and Either
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
add a comment |
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
add a comment |
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
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
haskell
edited Nov 20 '18 at 16:20


duplode
22.9k44885
22.9k44885
asked Nov 20 '18 at 16:17


rjmurtrjmurt
455416
455416
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
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))
1
Pairs are great for reducing the complexity of pattern matching. The first block above could be rewritten ascase (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
add a comment |
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.
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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))
1
Pairs are great for reducing the complexity of pattern matching. The first block above could be rewritten ascase (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
add a comment |
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))
1
Pairs are great for reducing the complexity of pattern matching. The first block above could be rewritten ascase (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
add a comment |
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))
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))
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 ascase (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
add a comment |
1
Pairs are great for reducing the complexity of pattern matching. The first block above could be rewritten ascase (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
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered Nov 20 '18 at 16:34
Jorge AdrianoJorge Adriano
2,220918
2,220918
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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