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

Posted

技术标签:

【中文标题】erl 程序输出的值与 erlang shell 输出的值不同【英文标题】:The erl program outputs different values than what is output by the erlang shell 【发布时间】:2020-06-16 12:00:50 【问题描述】:

给定以下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 调用时输出不同的值?

【问题讨论】:

【参考方案1】:

来自docs:

-s Mod [Func [Arg1, Arg2, ...]](初始化标志) 使 init 调用指定的函数。 Func 默认启动。如果没有参数 如果提供,则假定该函数的元数为 0。否则为 假定为元数 1,将列表 [Arg1,Arg2,...] 作为参数。 所有参数都作为原子传递。参见初始化(3)。

    因为这条线:

    如果没有参数 如果提供,则假定该函数的元数为 0。否则为 假定为元数 1,将列表 [Arg1,Arg2,...] 作为参数。

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

    因为这条线:

    所有参数都作为原子传递。

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

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

-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。

【讨论】:

【参考方案2】:

使用命令行

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

【讨论】:

要从命令行运行任意表达式而不是这样的意外,请使用-eval "fibonacci:my_function_3(2)" 而不是-s

以上是关于erl 程序输出的值与 erlang shell 输出的值不同的主要内容,如果未能解决你的问题,请参考以下文章

如何在不中止 erl 的情况下中止 Erlang shell (erl) 中的接收语句?

erl模块翻译

Erlang 标准模块与使用手册

Erlang Shell

从 Javascript(电子)执行 Erlang shell 命令不返回任何输出

Erlang:从命令行调用 erl -eval 永远不会退出