Erlang 学习之第三天 . 函数,模块,递归,数字,字符串
Erlang 函数
Erlang是一种众所周知的函数式编程语言,因此您将看到许多关于函数如何在Erlang中工作的重点。本章介绍如何使用Erlang中的函数完成所有操作。
直接上实例: 定义函数
add(X,Y) ->
Z = X+Y,
io:fwrite("~w~n",[Z]).
start() ->
add(5,6).
结果打印为11
直接上实例: 匿名函数 匿名函数是一个函数,但它没有与任何名称相关联。在 Erlang 中有工具可以用来定义匿名函数。以下的程序是一个匿名函数的一个实例。
start() ->
Fn = fun() ->
io:fwrite("Anonymous Function") end,
Fn().
结果打印为 Anonymous Function
函数使用序列 在 Erlang 中函数也都有保护序列的能力。这些都不算什么它只不过是一个表达式,只有当评估(计算)为 true 时函数才运行。
实例:
add(X) when X>3 ->
io:fwrite("~w~n",[X]).
start() ->
add(4).
上面的代码的输出结果是 4
如果 add 函数被调用为 add(3),该程序将会出现错误。
Erlang 模块
模块是在单个文件中以单个名称重新组合的一组函数。此外,Erlang中的所有函数都必须在模块中定义。模块中定义的每个其他函数都需要使用 Module: Function (Arguments) 的形式来调用。
Erlang 递归
递归是 Erlang 的重要组成部分。首先,让我们看看如何通过实现 factorial 程序来实现简单的递归。
普通递归语法实例1:
-module(helloworld).
-export([fac/1,start/0]).
fac(N) when N == 0 -> 1;
fac(N) when N > 0 -> N*fac(N-1).
start() ->
X = fac(4),
io:fwrite("~w",[X]). 输出结果是 24 4*3*2*1
在这个示例中,fac/1
函数计算了输入参数为4的阶乘,即4!。阶乘的计算规则是将给定的整数与比它小的所有正整数相乘,直到1为止。
- 当
N
等于4时,fac/1
函数首先判断N
不等于0,然后根据第二个定义分支,将4乘以fac(N-1)
。这里N-1
是3。 - 然后,函数继续递归调用
fac/1
函数来计算3的阶乘。在计算3的阶乘时,函数会将3乘以fac(N-1)
,即2。 - 接着,函数继续递归调用
fac/1
函数来计算2的阶乘。在计算2的阶乘时,函数会将2乘以fac(N-1)
,即1。 - 然后,函数继续递归调用
fac/1
函数来计算1的阶乘。在计算1的阶乘时,函数会将1乘以fac(N-1)
,即0。 - 最后,当
N
等于0时,递归调用结束,函数返回1。
根据阶乘的计算规则,4! = 4 × 3 × 2 × 1 = 24。因此,最终的结果是24。
普通递归语法实例2:
-module(recursion_demo).
-export([sum/1, test_normal/0]).
% 普通递归求列表的和
sum([]) -> 0;
sum([H|T]) -> H + sum(T).
% 测试普通递归
test_normal() ->
List = [1, 2, 3, 4, 5],
Result = sum(List),
io:format("Sum of the list: ~p~n", [Result]).
根据相加的计算规则,5+4+3+2+1 结果是15
尾递归语法实例:
-module(tail_recursion_demo).
-export([sum/1, test_tail/0]).
% 尾递归求列表的和
sum(List) -> sum(List, 0).
sum([], Acc) -> Acc;
sum([H|T], Acc) -> sum(T, H + Acc).
% 测试尾递归
test_tail() ->
List = [1, 2, 3, 4, 5],
Result = sum(List),
io:format("Sum of the list: ~p~n", [Result]).
根据相加的计算规则,5+4+3+2+1 结果是15
优缺点说明:
普通递归和尾递归在Erlang中的实现方式略有不同,以下是它们的语法和优缺点:
-
普通递归:
- 语法:普通递归是通过函数调用自身来实现的。在函数体内部,需要有一个递归终止条件,以防止无限递归。
- 优点:
- 实现简单,易于理解。
- 适用于大多数递归场景。
- 缺点:
- 对于大规模数据或者递归层次较深的情况,可能会导致栈溢出。
- 每次递归调用都需要保留函数调用栈,消耗内存较大。
-
尾递归:
- 语法:尾递归是一种特殊的递归形式,其递归调用是函数体的最后一个操作,并且这个调用的返回值直接返回给函数的调用者。尾递归调用不会在函数返回之前执行其他操作。
- 优点:
- 在Erlang中,尾递归可以被优化为迭代,不会导致栈溢出,因此更适合处理大规模数据或递归层次深的情况。
- 函数调用的开销较小,节省内存空间。
- 缺点:
- 有时候不太直观,对于一些复杂的逻辑可能需要重新设计以使用尾递归。
尾递归在Erlang中是一种重要的优化手段,可以有效避免普通递归中可能出现的栈溢出问题,提高程序的稳定性和性能。
尾递归函数定义:
- 尾递归函数的定义需要满足两个条件:函数体内部的递归调用是函数体的最后一个操作,并且递归调用的返回值直接返回给函数的调用者。
- 定义格式:
-
-
-
-
-
func_name(Parameters, Accumulator) ->
% 递归终止条件
if
Termination_condition -> Accumulator;
true -> func_name(NewParameters, NewAccumulator) % 尾递归调用
end.
-
-
-
-
-
尾递归的调用: 1,在尾递归函数中, 递归调用通常是 在 true 分支的 if 表达式中进行的
2,尾递归调用的返回值直接返回给函数的调用者,而不是要进行其他的操作,或者对返回的值进行进一步处理
参数传递: 1,尾递归函数通常使用一个累加器 (Acc) 参数来保存中间的结果,每次递归调用时,都会跟新累加器的值.
2,参数的传递,通常需要包含原始参数 以及累加器的参数, 这样在每次的递归调用时 都可以传递跟新后的参数.
-module(tail_recursion).
-export([length/1, start/0]).
length(List) -> length(List, 0).
length([], Acc) -> Acc;
length([_|T], Acc) -> length(T, Acc + 1).
start() ->
List = [1, 2, 3, 4, 5],
Size = length(List),
io:format("Length of the list: ~w~n", [Size]).
Erlang 数字
eralng中 数字有两种类型, 整数,浮点数
Erlang 字符串
通过将字符串文本括在引号中,可以在Erlang中构造一个字符串文字。需要使用双引号(例如“ Hello World”)构造Erlang中的字符串。