strings/parse.exs
defmodule Parse do
def number([ ?- | tail ]), do: _number_digits(tail, 0) * -1
def number([ ?+ | tail ]), do: _number_digits(tail, 0)
def number(str), do: _number_digits(str, 0)
defp _number_digits([], value), do: value
defp _number_digits([ digit | tail ], value)
when digit in '0123456789' do
_number_digits(tail, value*10 + digit - ?0)
end
defp _number_digits([ non_digit | _ ], _) do
raise "Invalid digit '#{[non_digit]}'"
end
end
Let’s try it in iex.
iex> c("parse.exs") [Parse]
iex> Parse.number('123') 123
iex> Parse.number('-123') -123
iex> Parse.number('+123') 123
So the above code is from the book Programming Elixir Page (118) ebook version. I have typed and run the script and it works as expected however I get lost when I try to walk through the code by hand. So the following is my reasoning,
Using the eg Parse.number('123')
At the first pass, the first two def number
patterns fail since the list of characters doesn’t start with -
or +
. The third def number
matches do: _number_digits(str, 0)
causing _number_digits([ digit | tail ], value)
to be executed.
At this point, still in the first pass, digit = '1', tail = '23'
and value = 0
. Since digit is in '0123456789'
the when
code is executed where _number_digits
is recursively called.
I think the call is made with the following arguments _number_digits( '23', 0*10 + 1 - 48)
where 48
comes from ?0
, simplyfing to _number_digits( '23', -47)
.
The second pass follows the same route as the first leading to another recursive call of _number_digits( '3', -47*10 + 2 - 48)
. Clearly this isn’t going to give me the result that I expect i.e. 123
.
Where am I going wrong in my understanding? Thanks.