-
-
Save veelenga/43465e7ea8954b5ca373d8da2e930ee6 to your computer and use it in GitHub Desktop.
############################## | |
##Exercise: ModulesAndFunctions-6 | |
defmodule Chop do | |
def guess(actual, lo..hi) when (lo <= hi) and (actual in lo..hi) do | |
current = guessing(lo, hi) | |
IO.puts "Is it #{current}" | |
guess(current, actual, lo..hi) | |
end | |
defp guess(value, actual, _) when value == actual, do: IO.puts value | |
defp guess(value, actual, lo.._) when actual < value, do: guess actual, lo..(value - 1) | |
defp guess(value, actual, _..hi) when actual > value, do: guess actual, (value + 1)..hi | |
defp guessing(lo, hi), do: lo + div(hi - lo, 2) | |
end | |
Chop.guess 273, 1..1000 | |
# Is it 500 | |
# Is it 250 | |
# Is it 375 | |
# Is it 312 | |
# Is it 281 | |
# Is it 265 | |
# Is it 273 | |
# 273 |
@TimFerrell nice catch!
To fix that, we have to do exactly what the exercise says about:
If our guess is too big, then the answer lies between the bottom of the range and one less than our guess. If our guess is too small, then the answer lies between one more than our guess and the end of the range.
So, we have to change:
guess actual, value..hi
->guess actual, (value + 1)..hi
guess actual, lo..value
->guess actual, lo..(value - 1)
I've updated the gist and tested it locally:
iex(2)> Chop.guess(1, 1..1000)
Is it 500
Is it 250
Is it 125
Is it 62
Is it 31
Is it 15
Is it 7
Is it 3
Is it 1
1
:ok
iex(3)> Chop.guess(1000, 1..1000)
Is it 500
Is it 750
Is it 875
Is it 938
Is it 969
Is it 985
Is it 993
Is it 997
Is it 999
Is it 1000
1000
:ok
iex(4)> Chop.guess(273, 1..1000)
Is it 500
Is it 250
Is it 375
Is it 312
Is it 281
Is it 265
Is it 273
273
:ok
I was working on the same exercise and came up with a similar solution.
I'd recommend that instead of adding the guard clause when (lo <= hi)
on guess/2
you define another function for swapping the range extremities, like below:
def guess(actual, a..b) when a > b, do: guess(actual, b..a)
Yup, that's also a solution π
I've been reading the book, and this solution was such an "a-ha!" moment for me when I looked at your pattern matching in the function signature: def guess(actual, lo..hi) when (lo <= hi) and (actual in lo..hi) do
. I know that pattern matching instead of control flow is a central idea in Elixir, but coming from Ruby, it's been hard to understand. This example really showcased that language feature. Thanks!
Nicely said π . It is good to see more and more people coming to Elixir from Ruby
hey @veelenga, your solution really helped me. I'm coming from 15 years of ruby and it is hard to wrap my old brain around new ideas.
But what's up with this? Doesn't your solution do this? What am I misunderstanding? Or is it because your defp functions have 3 params so it is considered totally different?
@pdbradley yes, the signature of def
and defp
functions are different, so they are valid.
Keep in mind, that solution was written 3 years ago, when the language was slightly different :)
I am a newbie in Elixir coming from Ruby. I'd written my solution for this but I felt like it could be better and then I came across your solution. Brilliant! I'd never thought about matching that range as lo..hi
in the function head, I was still doing the matching in the function body. π I was also doing the guessing in each of the functions separately, your code helped me learn a lot!
Hello, @veelenga ! Although your solution works, I would like to make a couple of notes:
- An extra work for the given exercise;
- Both your solution and the book author's solution use private functions,
which seems unfair to me, since this is the topic of the next section.
Thus, the solution can be rewritten as follows:
defmodule Chop do
def guess(actual, low..high) do
guessed = div(low + high, 2)
IO.puts "Is it #{guessed}"
processing_guessed =
fn
n when n == actual -> IO.puts n
n when n > actual -> guess actual, low..(n - 1)
n when n < actual -> guess actual, (n + 1)..high
end
processing_guessed.(guessed)
end
end
I'm reading across the same book and this is a neat solution.
However, if the range is 1..1000 and the actual is 1000, then it keeps guessing at 999 forever.
Any ideas on how to solve for that?