Search code examples
erlangerlang-shellerl

The erl program outputs different values than what is output by the erlang shell


Given the following erlang function

-module(fibonacci).

-export([my_function_3/1]).

my_function_3(Arg1) when Arg1==3 -> io:format("=3");
my_function_3(Arg1) when Arg1<3 -> io:format("<3");
my_function_3(Arg1) when Arg1>3 -> io:format(">3").

Calling the my_function_3 function from the command line shows different values than when calling it from the shell (see below).

Please note that I used 2, 3 and 4 as parameters in order to make the function be evaluated in all its definitions.

Calling the my_function_3 from the erlang shell

$ erl
Erlang/OTP 22 [erts-10.6.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Eshell V10.6.2  (abort with ^G)
1> c(fibonacci).
{ok,fibonacci}
2> fibonacci:my_function_3(2).
<3ok
3> fibonacci:my_function_3(3).
=3ok
4> fibonacci:my_function_3(4).
>3ok

Calling the my_function_3 from the command-line

$ erlc fibonacci.erl
$ erl -noshell -s fibonacci my_function_3 2 -s init stop
>3%
$ erl -noshell -s fibonacci my_function_3 3 -s init stop
>3%
$ erl -noshell -s fibonacci my_function_3 4 -s init stop
>3%

Therefore, my question is: Why does erlang output different values when calling the function from the command-line and when calling it from the erlang shell?


Solution

  • From the docs:

    -s Mod [Func [Arg1, Arg2, ...]](init flag)
    Makes init call the specified function. Func defaults to start. If no arguments are provided, the function is assumed to be of arity 0. Otherwise it is assumed to be of arity 1, taking the list [Arg1,Arg2,...] as argument. All arguments are passed as atoms. See init(3).

    1. Because of this line:

      If no arguments are provided, the function is assumed to be of arity 0. Otherwise it is assumed to be of arity 1, taking the list [Arg1,Arg2,...] as argument.

      your function is going to receive a list as the sole argument.

    2. Because of this line:

      All arguments are passed as atoms.

      all the arguments in the list are going to be atoms.

    Therefore, you need to pick out the head of the list to get the sole argument, and then you have to convert the atom to an integer in order to use the == comparison with another integer. Like this:

    -module(fib).
    -export([my_function_3/1]).
    
    my_function_3([Arg1|_Rest]) ->
        Arg1Int = list_to_integer(atom_to_list(Arg1)),
        print_result(Arg1Int).
    
    print_result(Arg1) when Arg1<3 ->
        io:format("<3~n");
    print_result(Arg1) when Arg1==3 ->
        io:format("=3~n");
    print_result(Arg1) when Arg1>3 ->
        io:format(">3~n").
    

    Note that in erlang, a term can be compared to another term of any type, and it will not cause an error. That's because in erlang all types are given a particular order:

    number < atom < reference < fun < port < pid < tuple < list < bit string
    

    As you can see a list is considered to be greater than a number, hence the reason that your Arg1, which was a list, was always considered greater than the number 3.