前文我们谈到了Erlang中的递归调用,其中有这样的函数
sum([]) -> 0;
sum([Head|Tail]) -> Head + sum(Tail).
在上面我们使用了直接递归样式。
另一种方法是用一个额外的函数参数,即累加参数,在计算时保存总和
sum(List) -> sum_acc(List, 0).
其中sum_acc/2的实现如下:
sum_acc([], Sum) -> Sum;
sum_acc([Head|Tail], Sum) -> sum_acc(Tail, Head+Sum).
我们用第二个参数保存“到目前为止的加和”,当列表为空,返回Sum;若列表不为空,拿下Head,加到Sum,接着调用sum_acc/2和新的“到目前为止的加和”
sum_acc/2的定义成为尾递归(Tail-recursion),函数体调用函数本身。只要函数f 的调用发生在f 的函数体的最后一个表达式(即尾部)里,这个函数f 就是尾递归。
下面我们简单谈一下这两种sum函数的区别:
- 直接定义更容易理解,可以理解为列表求和的直接表述
- 尾递归更像是调用C或Java风格程序,需要了解程序在执行时是如何展开的,了解第二个变量的最后值实际上是列表的总和。另外,某些情况下,尾递归可以更有效地使用内存。
kvs是一个简单的Key-->Value服务器,接口如下:
-spec kvs:start() -> true
启动服务器,创建一个注册名为kvs的服务器
-spec kvs:strore(Key, Value) -> true
关联Key和Value
-spec kvs:lookup(Key) -> {ok, Value} | undefined
查询Key的值,若Key带有关联值,返回{ok, Value},否则undefined
-module(kvs).
-export([start/0, store/2, lookup/1]).
start() ->
register(kvs, spawn(fun() -> loop() end)).
store(Key, Value) ->
rpc({store, Key, Value}).
lookup(Key) ->
rpc({lookup, Key}).
rpc(Q) ->
kvs ! {self(), Q},
receive
{kvs, Reply} ->
Reply
end.
loop() ->
receive
{From,{store, Key, Value}} ->
put(Key,{ok, Value}),
From ! {kvs, true},
loop();
{From,{lookup, Value}} ->
From ! {kvs, get(Value)},
loop()
end.
运行结果