-
Notifications
You must be signed in to change notification settings - Fork 194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ch4 isEven exercise does not mention sign #327
Comments
Yes, that's a good suggestion. Would you like to make a PR with that clarification? We could also add a follow-up exercise that asks users to write an |
I'm not sure if it's a good idea to ask for an I'd just update it for negative numbers and be done with it: isEven :: Int -> Boolean
isEven n = case n of
0 -> true
1 -> false
_ -> isEven $ n + sign * 2
where sign = if n < 0 then 1 else -1 What do you think @milesfrain? Should I PR this? |
That's a mistake, since So I'm thinking the best path forward here is to do the following:
Ideally, we'd restructure the book a bit using something like the following strategy:
|
That's true, I don't know why I thought of isEven :: Int -> Boolean
isEven n
= if sign * n < 2
then n == 0
else isEven $ n - sign * 2
where sign = if n < 0 then -1 else 1 It uses only |
Another one. isEven :: Int -> Boolean
isEven i = isEven' 0 true
where
isEven' step isIt =
if step == i
then isIt
else let nextStep = if i > 0 then step + 1 else step - 1
in isEven' nextStep (not isIt) |
For reference, I think this was the original beginner-friendly solution that the exercise had in mind: isEven :: Int -> Boolean
isEven n =
if n == 0
then true
else not (isEven (n - 1)) I believe this is the simplest way to extend it to support negative inputs: isEven :: Int -> Boolean
isEven n =
if n == 0
then true
else if n < 0
then isEven (-n)
else not (isEven (n - 1)) It might be nice to revisit this isEven :: Int -> Boolean
isEven n = case n of
0 -> true
n | n < 0 -> isEven (-n)
n -> not (isEven (n - 1)) Alternatives are: isEven :: Int -> Boolean
isEven n = case n of
0 -> true
_ | n < 0 -> isEven (-n)
_ -> not (isEven (n - 1)) // point free
isEven :: Int -> Boolean
isEven = case _ of
0 -> true
n | n < 0 -> isEven (-n)
n -> not (isEven (n - 1)) Not sure which of the above is least confusing. Side note, here's a version that's 2x as fast: isEven :: Int -> Boolean
isEven n = case n of
0 -> true
1 -> false
_ | n < 0 -> isEven (-n)
_ -> isEven (n - 2) We should also improve the test output. Here's what we currently have:
I think this is more helpful:
Opened #339 with some of these changes |
I forgot that this issue with There are a few other issues with this sequence of exercises though - specifically |
The simplest way to extend the solution
is to use -- intentionally not point-free
isEven n = isPositiveEven (abs n)
isPositiveEven n = {- the original solution -} All proposed solutions are variants of inverting the algorithm depending on sign or inverting the input had it been negative. Why not do it upfront? -- not using `abs`
isEven n =
if n < 0
then isPositiveEven (-n)
else isPositiveEven n
-- be explicit about algorithm
isEven n =
if n < 0
then isNegativeEven n
else isPositiveEven n In the spirit of be beginner-friendly, we can make the first exercise work on only positive integers, then follow by supporting negatives. |
The sample solution won't halt if given a negative integer as input. Perhaps the exercise specification should mention only positive integers as input.
The text was updated successfully, but these errors were encountered: