Erlang递归
Erlang是一种函数式编程语言,需要记住的是所有函数式编程语言,它们不提供任何循环结构。 相反,函数式编程依赖于一种称为递归的概念。
编程语言中,函数Func(Type a,……)直接或间接调用函数本身,则该函数称为递归函数。递归函数不能定义为内联函数
递归demo1
测试递归和性能
tets(N) ->
Result = sum(N),
io:format("~p~n", [Result]),
erlang:process_info(self()).
sum(1) ->
1;
sum(N) ->
N + sum(N - 1).
结果:
(gs_framework@192.168.77.41)5> lib_test:tets(100000000).
5000000050000000
[{current_function,{lib_test,tets,1}},
{initial_call,{erlang,apply,2}},
{status,running},
{message_queue_len,0},
{messages,[]},
{links,[<0.55.0>]},
{dictionary,[]},
{trap_exit,false},
{error_handler,error_handler},
{priority,normal},
{group_leader,<0.54.0>},
{total_heap_size,237289198},
{heap_size,237288211},
{stack_size,25},
{reductions,99951263},
{garbage_collection,[{max_heap_size,#{error_logger => true,kill => true,
size => 0}},
{min_bin_vheap_size,46422},
{min_heap_size,233},
{fullsweep_after,65535},
{minor_gcs,46}]},
{suspending,[]}]
(gs_framework@192.168.77.41)6>
{heap_size,237288211},32位系统1word为4byte,64位系统1word为8byte,237288211word换算成内存为1,810.36537933349609375M(237288211*8/1024/1024)
?????????????
这么辣鸡吗 就算个1+2+3+4+。。。+100000000 用了老子1810M内存???
拉闸啊!!!不,等下 这只是递归 八四尾递归 那我们用尾递归看看
尾递归
如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。尾递归函数的特点是在回归过程中不用做任何操作,这个特性很重要,因为大多数现代的编译器会利用这种特点自动生成优化的代码。
test2(N) ->
Result = sum1(N),
io:format("~p~n", [Result]),
erlang:process_info(self()).
sum1(N) ->
sum1(N, 0).
sum1(0, Result) ->
Result;
sum1(N, Result) ->
sum1(N - 1, N + Result).
(gs_framework@192.168.77.41)4> lib_test:test2(100000000 ).
5000000050000000
[{current_function,{lib_test,test2,1}},
{initial_call,{erlang,apply,2}},
{status,running},
{message_queue_len,0},
{messages,[]},
{links,[<0.55.0>]},
{dictionary,[]},
{trap_exit,false},
{error_handler,error_handler},
{priority,normal},
{group_leader,<0.54.0>},
{total_heap_size,3196},
{heap_size,1598},
{stack_size,25},
{reductions,99959793},
{garbage_collection,[{max_heap_size,#{error_logger => true,kill => true,
size => 0}},
{min_bin_vheap_size,46422},
{min_heap_size,233},
{fullsweep_after,65535},
{minor_gcs,3}]},
{suspending,[]}]
{heap_size,1598},换算为0.0121917724609375 牛逼啊
总结QAQ
普通的线性递归比尾递归更加消耗资源, 在实现上说, 每次重复的过程
调用都使得调用链条不断加长. 系统不得不使用栈进行数据保存和恢复.而尾递归就不存在这样的问题, 因为他的状态完全由N和Result保存.
PS 那用LISTS:FOLDL/FOLDR来循环呢
List =lists:seq(1, N),
Fun = fun(Number, ResultStr) ->
ResultStr + Number
end,
Out = lists:foldl(Fun, 0, List),
io:format("~p~n", [Out])
以上方法使匿名函数Fun只要生成一次,作为参数放到lists函数即可,避免每次循环匿名函数都会重新生成,数组如果是提前生成的 使用lists:foldl只会消耗CPU性能不消耗内存哦。。(lists:seq(1,10000000)生成数组 但是消耗内存哦)
不过一般写这样的打死吧。。毕竟算法可以优化。项目这样写会被在头上爆扣
(PS:为什么写这个,因为面试了数字游戏公司,主程问erlang有什么和别的语言不同主要体现在哪几点,巴拉巴拉说到了没循环,用递归和尾递归,区别在于前者易于堆栈溢出后者不会,回答完了主程又问我 为什么要用尾递归 。。。算了,那么问题来了 为什么要用尾递归啊)