Method for adding + 1 gives varied results

I’m reading the Programming Elixir 1.2 book, and I’m at the chapter where we use head and tail to build lists. The example code given is:

defmodule MyList do
  def square([]), do: []
  def square([ head | tail ]), do: [ head*head | square(tail) ]

  def add_1([]),              do: [] 
  def add_1([ head | tail ]), do: [ head+1 | add_1(tail) ]
end

When I run:
MyList.add_1([1000]) it returns 1001

however if I do:

MyList.add_1([10]) 
 >  '\v' 
MyList.add_1 [100]
>  'e'

does anybody know why this is happening? If I try it with the number given in the example it works out.

2 Likes

You’re missing a clause for the case where only the head remains and the tail is an empty list

iex(10)> defmodule MyList do                          
...(10)> def add_1([]), do: []                        
...(10)> def add_1([h | []]), do: [h + 1]               
...(10)> def add_1([h | t]), do: [h + 1 | add_1(t)]   
...(10)> end  
iex:10: warning: redefining module MyList
{:module, MyList,
 <<70, 79, 82, 49, 0, 0, 5, 60, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 152, 131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115, 95, 118, 49, 108, 0, 0, 0, 4, 104, 2, ...>>,
 {:add_1, 1}}
iex(11)> MyList.add_1([10])
11
3 Likes

Interesting, why does the code work then when giving:

MyList.add_1 [1000]
but not when you do:
MyList.add_1 [10]

Also you’re returning the function as not being a list, and that’s what makes it work. Why is that?

I tried just creating a list and posting it in iex and it returns the same:
[10]
> '\n'
[99]
> 'c'

1 Like

@sebastian it works with 1000 because it’s a value outside of the ASCII table. The e and \v that were returned are the code value for those characters in the ASCII Table. Since at the end of the computation that is the remaining value and Elixir doesn’t know what to do with it, it gets outputted as its ASCII character.

The clause I added there is basic recursion. Maybe you’re having trouble understanding how recursion works. The function gets called everytime but it has to stop at some point. I defined that point as being when there’s a head but the tail is an empty list (meaning when there’s just one element left in the list). Then I just return the value left + 1 and that value gets returned and no function call is made (or else it wouldn’t stop).

Please remember that I tried to solve your problem without actual context about the problem so I do not guarantee this is the actual solution.

1 Like

Got it, this solution and example is actually straight out of the Programing Elixir book so seems like the solution given by the book has that flaw.

Hands down this is the most F.A.Q by beginners

Few tricks to avoid that:

1) Configure IEx as you run it

iex> [10]                                               
'\n'
...> ?\n
10
...> 'hello'                                            
'hello'

# configure IEx
iex> IEx.configure inspect: [char_lists: :as_lists]     
:ok
...> [10]                                          
[10]
...> 'hello'                                       
[104, 101, 108, 108, 111]

# switch-back to default setting
iex> IEx.configure inspect: [char_lists: :as_char_lists]
:ok
...> [10]                                               
'\n'
...> 'hello' 
'hello'

2) Configure IEx via configuration file

simply create a .iex.exs in your local dir, or in a global dir such as ~/.iex.exs with this statement:

IEx.configure inspect: [char_lists: :as_lists]

More info: http://elixir-lang.org/docs/stable/iex/IEx.html (find the section called “The .iex.exs file”)

3) Call inspect with the char_lists: :as_lists option

iex> [10] |> inspect(char_lists: :as_lists)

iex> [5 + 5]
'\n'
...> [5 + 5] |> inspect
"'\\n'"
...> [5 + 5] |> IO.inspect
'\n'
'\n'

iex> [5 + 5] |> inspect(char_lists: :as_lists)
"[10]"
...> [5 + 5] |> IO.inspect(char_lists: :as_lists)
[10]
'\n'

More info about options that can be passed to the inspect functions, can be found at:
http://elixir-lang.org/docs/stable/elixir/Inspect.Opts.html

7 Likes

a more idiomatic way of doing that optimization would be:

def add_1([h]), do: h + 1

EDIT: actually, it should be

def add_1([h]), do: [h + 1]

1 Like

it’s not a flaw,it’s simply not optimized.

I understand where you’re coming from but I usually prefer to have the clause to be explicit and to have it saying “when there’s just one element left do this” :stuck_out_tongue:

1 Like

This clause is not necessary. Moreover it contains a bug (doesn’t return a list as supposed) and violates DRY principle.
Solution of the topic starter is much more correct. He just didn’t know how Elixir/Erlang REPL handles lists of numbers which are printable ASCII codes.

1 Like

True @romul I actually noticed that later but didn’t have time to correct it. Thank you for the correction :slight_smile:

For posterity I have corrected the typo in @sashaafm’s original post. Thank you very much for the great contributions, everyone!

1 Like