26 May 2013, 09:28
Generic-user-small

Dennis Woodruff (2 posts)

I am working through section 6.4 and have a problem implementing the guess(actual, range) API. I seem to be unable to pass a range as a parameter.

def guess(actual, range), do: “#{actual}, #{range}”

results in

Chop.guess(2, 1..10) ** (UndefinedFunctionError) undefined function: Binary.Chars.Range.to_binary/1 Binary.Chars.Range.to_binary(1..10)

My original attempt at the first function was:

def guess(actual, range) when not actual in range, do: “Must be within the range provided!”

but that resulted in

invalid args for operator in, it expects an explicit array or an explicit range on the right side when used in guard expressions

I am struggling to find much documentation on ranges and realise how spoilt I have been by the auto completion in irb as a way of discovering the api.

Is any one else having problems?

Am I approaching this the wrong way with my c#/ruby brain?

26 May 2013, 20:13
Generic-user-small

pmlarocque (4 posts)

The error you get is because, I guess, the range have no implicit conversion to string.

But I am struggling on that problem as well.

My naive attempt look like:

defmodule Chop do
  def guess(n, range) when Enum.max(range) > n, do: Chop.guess(n, ( Enum.min(range)..( (Enumx.max(range) / 2 ))))
  def guess(n, range) when Enum.max(range) < n, do: Chop.guess(n, ( (div(Enum.max(range), 2))..( Enumx.max(range) )))
  def guess(n, range) when Enum.min(range) == Enumx.max(range), do: IO.puts "Found it! #{n}"
end

But it seem like a Enum.max(range) > n in a guard is not valid.

27 May 2013, 03:38
Generic-user-small

pmlarocque (4 posts)

Found it! Had to code it in ruby to wrap my head around but the Elixir version is much nicer IMO. The last hint about pattern matching in the book make the guard work…

PML

27 May 2013, 09:56
Generic-user-small

Dennis Woodruff (2 posts)

It is so simple when you see the solution. And I am sure there are still simpler ways to be found.

27 May 2013, 15:35
Generic-user-small

pmlarocque (4 posts)

Here is my final solutions, could use some renaming, but time to move on:

defmodule Chop do
  def guess(n, range), do: Chop.finder(div(Enum.max(range), 2), n, range)

  def finder(x, n, range) when x > n do
    IO.puts("Is it? #{x}")
    a..b = range
    Chop.finder((div((x - 1) - a, 2) + a), n, a..(x - 1))
  end

  def finder(x, n, range) when x < n do
    IO.puts("Is it? #{x} -> #{Enum.min(range)} - #{Enum.max(range)}")
    a..b = range
    Chop.finder((div(b - x, 2) + x + 1), n, (x + 1)..b)
  end

  def finder(x, n, _) when x === n do
   IO.puts "Found it! #{x}"
  end
end

Happy hacking!

06 Jun 2013, 20:39
Generic-user-small

David Simmons (3 posts)

Hi - thought I’d add my version - comments welcome.

defmodule Chop do def guess(actual, range) do g = Enum.min(range) + div(Enum.max(range) - Enum.min(range), 2) IO.puts(“Is it #{g}”) check_guess(g, actual, range) end

def check_guess(g, actual, range) when g > actual do guess(actual, Enum.min(range)..(g -1)) end

def check_guess(g, actual, range) when g < actual do guess(actual, (g + 1)..Enum.max(range)) end

def check_guess(g, actual, _range) when g == actual do g end end

07 Jun 2013, 06:18
Generic-user-small

David Simmons (3 posts)

Hi Folks.

Just discovered this so maybe I’m just a bit behind the curve but Enum.max iterates over the entire range which becomes a real performance hit if you have a large range. I’ve recoded my attempt to be the following.

defmodule Chop do def guess(actual, first..last) do g = first + div(last - first, 2) IO.puts(“Is it #{g}”) check_guess(g, actual, first..last) end

def check_guess(g, actual, first..last) when g > actual do guess(actual, first..(g -1)) end

def check_guess(g, actual, first..last) when g < actual do guess(actual, (g + 1)..last) end

def check_guess(g, actual, _first.._last) when g == actual do g end end

This is much more performant for large ranges.

08 Jun 2013, 03:24
Generic-user-small

pmlarocque (4 posts)

Thanks for sharing

21 Mar 2014, 22:47
Generic-user-small

Richard Bishop (1 post)

Here’s a solution I came up with. It was a pretty fun exercise. I certainly had a few “Oh, this is different” moments when playing with the function argument lists. I made a point to use things only covered in the book yet.

defmodule Chop do
  def guess(actual, lower..upper) do
    number = div(upper + lower, 2)
    IO.puts "Is it #{number}"
    make_guess(number, actual, lower..upper)
  end

  def make_guess(number, actual, _) when number == actual do
    IO.puts "Nailed it!"
  end

  def make_guess(number, actual, lower.._) when number > actual do
    guess(actual, lower..number)
  end

  def make_guess(number, actual, _..upper) when number < actual do
    guess(actual, number..upper)
  end
end
  You must be logged in to comment