从头开始定义列表函数而不是库函数

Posted

技术标签:

【中文标题】从头开始定义列表函数而不是库函数【英文标题】:defining list functions from scratch rather than library functions 【发布时间】:2019-12-07 20:03:06 【问题描述】:

erlang 新手并试图解决这个问题,请帮助:

这个问题要求您定义四个对列表进行操作的函数。每个问题都给出了函数应该如何表现的示例;在每种情况下,再举两个例子说明你的函数应该做什么。您应该从头开始定义函数,而不是使用库函数。

1.1 编写一个函数,给定一个整数列表和一个整数,将返回一个包含所有大于该整数的元素的列表。例如, 更大的([1,2,3,4,5],3) 是 [4,5]。

【问题讨论】:

尝试开始更简单。你能写一个打印出列表中每个元素的函数吗? io:format("~w~n", [Number]). 当您弄清楚时,发布您的解决方案。当你开始学习 erlang 时,很难。你必须为每一行代码奋斗。但奋斗会教你很多!而且,如果你不能想出一个解决方案,这并不重要,这会让你觉得你失败了,但是一旦你在解决问题后看到了解决方案,它就会真正陷入...... 这里有一个提示:编写一个接受问题中指定参数的函数。在该函数内部,使用相同的参数调用另一个函数,并添加一个空列表作为第三个参数。空列表可用于累积结果。 我一直在寻找如何操作列表等并提出了这个解决方案,但不完全确定它是否正确更大([],_) -> [];更大([X|Xs], A) -> 当 X>A -> [X|更大(A,Xs)];更大([_|Xs],A)-> 更大(A,Xs)。 【参考方案1】:

不要在 cmets 中发布代码。您可以编辑您的问题并将代码发布在底部(格式精美),然后发表评论,例如:@7stud, Can you take a another look?

您已接近,但您的代码无法编译,因为您有语法错误。这个:

bigger([X|Xs], A) -> when X>A -> 

应该这样写:

bigger([X|Xs], A) when X>A -> 

接下来,您将函数子句定义为将列表作为第一个参数,将数字作为第二个参数,但在某些情况下,您将列表作为第二个参数,将数字作为第一个参数来调用您的函数。当您使用数字作为第一个参数调用函数时,它与您在所有函数子句中定义为第一个参数的列表不匹配,因此您会收到 no function clause matching 错误。

以下是该错误的一个简单示例:

-module(a).
-compile(export_all).

go([Head|Tail], Number) ->
    Head, Tail, Number.

在外壳中:

11> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
ok,a

12> a:go(10, [1, 2, 3]).   
** exception error: no function clause matching a:go(10,[1,2,3]) (a.erl, line 4)

Erlang 尝试将函数调用与函数定义相匹配,如下所示:

               a:go(10, [1, 2, 3]).
                     |       |
  [Head|Tail] = 10   |       |  Number = [1, 2, 3]
                     V       V
            go([Head|Tail], Number) ->

整数10无头无尾,所以匹配失败。同样:

13> [Head|Tail] = 10.
** exception error: no match of right hand side value 10

【讨论】:

【参考方案2】:

实现目标的最简单方法是使用stdlib.lists 模块

如下:

 bigger(L,I) -> lists:filter(fun(X) -> X  > I end, L).

【讨论】:

【参考方案3】:
bigger(L, I) when is_list(L), is_integer(I) ->
    [X || X <- L, X > I].

不需要库函数。

【讨论】:

@yvvy19:这个解决方案是完全正确的,但是由于您是从 erlang 开始的,我认为您应该稍后再考虑这种语法,当您将掌握递归和模式匹配时。 @Pascal 我非常不同意。列表推导是语言和库函数列表的重要组成部分:filter/2 是使用列表推导实现的。为了掌握递归和模式匹配,我推荐以下练习:找到数字列表的最小或最大元素;计算列表元素的总和; ... @yvvy19:保护表达式“when is_list(L), is_integer(I)”可以去掉,功能不变。【参考方案4】:

我想你可以使用一个简单的列表生成器,例如:

1> [X || X <- [1, 2, 3, 4, 5], X > 3].
[4,5]

或者您可以创建一个简单的函数,例如 bigger.erl

-module(bigger).

-export([run/2]).

run([_|_] = L, N) when is_number(N) -> run(L, N, []);
run(_, _)                           -> error, badarg.

run([], _, Acc)                 -> lists:reverse(Acc);
run([H|T], N, Acc) when H > N   -> run(T, N, [H|Acc]);
run([_|T], N, Acc)              -> run(T, N, Acc).

在 Erlang shell 中:

1> c(bigger).
ok,bigger
2> bigger:run([1, 2, 3, 4, 5], 3).
[4,5]

或者您可以使用列表生成器创建函数,例如 bigger.erl

-module(bigger).

-export([run/2]).

run([_|_] = L, N) when is_number(N) -> [X || X <- L, X > N];
run(_, _)                           -> error, badarg.

在 Erlang shell 中:

1> c(bigger).
ok,bigger
2> bigger:run([1, 2, 3, 4, 5], 3).
[4,5]

注意事项:使用列表生成器的功能更清晰,工作速度更快,因为我们一次遍历列表。在其他情况下 - 您将需要反向列表,这意味着列表将被抓取两次。

【讨论】:

以上是关于从头开始定义列表函数而不是库函数的主要内容,如果未能解决你的问题,请参考以下文章

使用 Buzz.js 音频从我停止的最后一个位置开始,而不是从头开始。 (ipad1)

Lua函数(function)语法与库函数 --math 表(table)

为啥使用 null 函数而不是 == [] 来检查 Haskell 中的空列表?

什么是C语言标准函数库?平常用的哪些函数属于标准函数库?

我的列表中的打印函数返回 int 值而不是列表中的字符串

c 语言是不是需要头文件和库函数