You should use IO.inspect
instead of IO.puts
to print the internal representation of a value:
iex> IO.puts [1, 2]
^A^B # prints "^A^B"
:ok # return value of IO.puts
iex> IO.inspect [1, 2]
[1, 2] # prints "[1, 2]"
[1, 2] # return value of IO.inspect
However you might still get problems with some special values:
iex> IO.inspect [97, 98]
'ab' # prints "'ab'"
'ab' # return value of IO.inspect
To explain this behavior we need to understand how strings work in Elixir. There are two kinds of strings. Binary strings (double quoted) and character lists (single quoted). Internally, these are built from simpler primitives. Binary strings are built from binaries, and character lists are built from lists:
iex> "ab" # a binary string
"ab"
iex> <<97, 98>> # the same string in binary syntax
"ab"
iex> 'ab' # a character list
'ab'
iex> [97, 98] # the same character list in list syntax
'ab'
It might seem confusing at first, but this happens due to two things. First, there is no built in string type, as we have seen strings are built from other primitive types. Second, there are no user defined types in Elixir. So when Elixir sees a list with only integers, it tries to print it as a string for convenience. However, under the hood it is still just a list of integers.
In the examples above, 97
and 98
represent the unicode code points for the characters a
and b
so these will be shown as a string, even if using IO.inspect
.
Now you can see why it printed ^A^B
in your examples – these are just control characters from the ASCII encoding, which happen to be represented by the codepoints 1
and 2
.
However, you can pass the option char_lists: :as_lists
in order to print raw lists without an attempt to do such a conversion:
iex> IO.inspect [97, 98], char_lists: :as_lists
[97, 98] # prints '[97, 98]'
'ab' # Iex still shows the return value as 'ab'
If you open up iex
and type h Inspect.Opts
, you will see that Elixir does this kind of thing with other values as well, specifically structs and binaries.