-
Notifications
You must be signed in to change notification settings - Fork 192
Ch4 isEven exercise does not mention sign #327
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
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: