erl 程序输出的值与 erlang shell 输出的值不同

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

给定以下 erlang 函数

-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").

从命令行调用 my_function_3 函数显示的值与从 shell 调用它时显示的值不同(见下文)。

请注意,我使用了 234 作为参数,以便在函数的所有定义中对其求值。

erlang shell

调用 my_function_3
$ 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

从命令行调用 my_function_3

$ 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%

因此,我的问题是:为什么从命令行调用函数时 erlang 和从 erlang shell 调用函数时输出不同的值?

来自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. 因为这一行:

    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.

    您的函数将接收一个列表作为唯一参数。

  2. 因为这一行:

    All arguments are passed as atoms.

    列表中的所有参数都将是原子。

因此,您需要挑出列表的头部以获得唯一参数,然后您必须将原子转换为整数才能使用 == 与另一个整数进行比较。像这样:

-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").

请注意,在 erlang 中,一个术语可以与任何类型的另一个术语进行比较,并且不会导致错误。那是因为在 erlang 中,所有类型都有一个特定的顺序:

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

如您所见,列表被认为大于数字,因此您的 Arg1(列表)始终被认为大于数字 3 的原因。

使用命令行

erl -noshell -s fibonacci my_function_3 3 -s init stop

您正在呼叫 fibonacci:my_function(['3']) 而不是您预期的 fibonacci:my_function(3)。请参阅 erl 的文档:

-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. Seeinit(3).

因此您的函数将 3 与一个原子列表 ['3'] 进行比较。在 erlang 中,两个术语之间总是可以进行比较。当它们具有相同的类型时;比较照常进行。当它们有不同的类型时,则使用类型比较,定义一个列表大于一个数:

The arguments can be of different data types. The following order is defined:

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