【Erlang】九、遞回函數

2020-08-14 21:08:17

遞回

1. 概念

假設 函數A 是個遞回函數,當我們在外部呼叫 函數A 時,在函數A在滿足條件的情況下會一直自己呼叫自己
簡單的說:函數自己呼叫自己

2. 例子

前提

我們在超市買了一些東西,當去櫃檯結賬時,通過呼叫模組的函數 計算出商品的總價格

Items = [{orange,4},{apple,10},{pear,6}].

模組實現

%% 結賬模組 price.erl
-module(price).
-export({sum/1}).

%% 單個商品對應的價格
itemPrice(orange) -> 0.5;
itemPrice(apple) -> 1;
itemPrice(pear) -> 0.8;

%% 遞回函數1
%% 只要傳遞進來的列表中,有一個商品,就匹配成功
%%  |--一種商品--||--剩餘商品--|	  |---計算該商品消費金額----|  |--遞回呼叫,計算剩餘商品價格--|
sum([{Item, ItemNum}|ItemList]) -> itemPrice(Item) * ItemNum + sum(ItemList);
%% 遞回函數2
%% 如果傳遞進來的列表是個空列表,函數執行結束
sum([])	-> 0.

模組呼叫

> erl
> c(price).
> price:sum([{orange,4},{apple,10},{pear,6}]).
16.8

詳解

我們詳細分解下遞回函數的呼叫
在erlangShell中呼叫時,函數是怎麼執行的

%% 參數:[{orange,4}|{apple,10},{pear,6}]
%% 從上往下對函數 sum 進行模式匹配
%% 第一個函數匹配成功:sum([{Item, ItemNum}|ItemList])
%% Item=orange,ItemNum=4,ItemList = [{apple,10},{pear,6}]
sum([{orange,4}|{apple,10},{pear,6},{milk,3}])) ->
	%% 這裏只是單純的計算價格
	itemPrice(orange) * 4	%% 橘子2元
	%% 遞回呼叫,計算下一個商品的價格
	+ sum([{apple,10},{pear,6}]).

%% 第一次遞回呼叫
%% 參數:[{apple,10},{pear,6}]
%% 從上往下對函數 sum 進行模式匹配
%% 第一個函數匹配成功:sum([{Item, ItemNum}|ItemList])
%% Item=apple,ItemNum=10,ItemList = [{pear,6}]
sum([{apple,10}|{pear,6}])) ->
	%% 這裏只是單純的計算價格
	itemPrice(apple) * 10	%% 蘋果10元
	%% 遞回呼叫,計算下一個商品的價格
	+ sum([{pear,6}]).

%% 第二次遞回呼叫
%% 參數:[{pear,6}]
%% 從上往下對函數 sum 進行模式匹配
%% 第一個函數匹配成功:sum([{Item, ItemNum}|ItemList])
%% Item=pear,ItemNum=6,ItemList = []
sum([{pear,6}|{}])) ->
	%% 這裏只是單純的計算價格
	itemPrice(pear) * 6  %% 梨4.8元
	%% 遞回呼叫,計算下一個商品的價格
	+ sum([]).

%% 第三次遞回呼叫
%% 參數:[]
%% 從上往下對函數 sum 進行模式匹配
%% 第一個函數匹配失敗
%% 第二個函數匹配成功
sum([])	-> 0.

%% 最終結果
%% 外部呼叫時得到:橘子2元
%% 第一次遞回呼叫得到:蘋果10元
%% 第二次遞回呼叫得到:梨4.8元
%% 第三次遞回呼叫得到:結束
sum([{orange,4}|{apple,10},{pear,6},{milk,3}])) ->
	橘子2+ 蘋果10+4.8+ 0.