当我使用erlang 编程的时候,总是为没有循环而苦恼。连乘法口诀表都很难实现,想想都郁闷。
然而当你必须要解决循环的时候,你发现了另外一条路。
C语言:
for(int i=1;i<10;i++)
{
for(int j=1;j<10;j++)
{
if(i>=j) printf("%d",i*j);
}
printf("\n");
}
第一层循环和第二层的关系:
i 为第二层的输入,j从 1 迭代到 9
然后 i 和 从1~9 相乘,就是 i 和列表的相乘 ;而元素的收集代码如下:
collect_sequence(Start_V,End_V,Result) -> if
Start_V>End_V ->
Result;
true -> collect_sequence(Start_V,End_V-1,[End_V|Result])
这是一个尾递归调用
将相乘抽象为一个函数MapFun,那么
filter_map(X,Start_V,End_V,MapFun) ->
Lst = collect_sequence(Start_V,End_V,[]),
lists:map(fun(Value) -> MapFun(X,Value) end,Lst).
如下调用
second:filter_map(2,1,9,fun(X,Y)->X*Y end) 就会打印 2和 1~9 相乘的列表
如果在这个上面加一个过滤器的话就类似C语言实现的 if(i>=j)
实现代码如下:
filter_map(X,Start_V,End_V,MapFun,FilterFun) ->
Lst = collect_sequence(Start_V,End_V,[]),
Lst1 = lists:filter(fun(Value) -> FilterFun(X,Value) end,Lst),
lists:map(fun(Value) -> MapFun(X,Value) end,Lst1).
测试用例:
second:filter_map(2,1,9,fun(X,Y)->X*Y end,fun(X,Y)->X>=Y end).
然后我们实现第一层循环
arithmetic(A1_Start,A2_End,B1_Start,B2_Start,MapFun,FilterFun)
->
if
A1_Start>A2_End
->
[];
true ->
io:format("~w~n",[filter_map(A1_Start,B1_Start,B2_Start,MapFun,FilterFun)]),
arithmetic(A1_Start+1,A2_End,B1_Start,B2_Start,MapFun,FilterFun)
end.
测试用例如下:
second:arithmetic(1,9,1,9,fun(X,Y)->
X*Y end,fun(X,Y)-> X>=Y end).
元素从A1_Start 到A2_End终止,区间为[A1_Start,A1_End]
打印为:
[1]
[2,4]
[3,6,9]
[4,8,12,16]
[5,10,15,20,25]
[6,12,18,24,30,36]
[7,14,21,28,35,42,49]
[8,16,24,32,40,48,56,64]
[9,18,27,36,45,54,63,72,81]
[]
最后一个是函数的返回值,其他为九九乘法表输出
我们仅仅是想通过递归实现九九乘法表,最后我们得到了一个通用的函数:
arithmetic(A1_Start,A2_End,B1_Start,B2_Start,MapFun,FilterFun)
这个函数能够处理两组数(两个集合或者说是两个向量)的叉积,得到一个矩阵。而不仅仅是九九乘法表.
arithmetic_list(Lst1,Lst2,MapFun,FilterFun) 是以列表的方式作为输入最后输出一个运算后的矩阵的通用函数
因为没有了循环而被迫使用递归,而正因为实现的艰难发现了更加深刻的外层和内层循环的关系,而得到了一个通用函数。这和列表的通用函数lists:map,lists:filter,lists:reduce 有些类似。上帝关闭了一扇门,会为我们打开一扇窗。
代码如下:
-module(second). -export ([filter_map/5]). -export ([collect_sequence/3]). -export ([arithmetic/6]). -export ([arithmetic_list/4]). %% collect_sequence(Start_V,End_V,Result) %% 收集 Start_V~End_V 到结果Result中 区间[Start_V,End_V] %% Start_V - 左边界 %% End_V - 右边界 collect_sequence(Start_V,End_V,Result) -> if Start_V>End_V -> Result; true -> collect_sequence(Start_V,End_V-1,[End_V|Result]) end. % filter_map(X,Start_V,End_V,MapFun,FilterFun) filter_map(X,Start_V,End_V,MapFun,FilterFun) -> Lst = collect_sequence(Start_V,End_V,[]), Lst1 = lists:filter(fun(Value) -> FilterFun(X,Value) end,Lst), lists:map(fun(Value) -> MapFun(X,Value) end,Lst1). %arithmetic(A1,A2,B1,B2,MapFun,FilterFun) %根据算法F来计算两组数,比如计算[1~9] 和 [1~9] 的乘法口诀表 %A1_Start 第一组开始值 %A2_End 第一组终止值 %B1_Start 第二组开始值 %B2_Start 第二组终止值 %F为算法 比如 fun(X,Y) -> X*Y end. %% 例子:arithmetic(1,9,1,9,fun(X,Y) -> X*Y end,fun(X,Y) ->X>=Y end). arithmetic(A1_Start,A2_End,B1_Start,B2_Start,MapFun,FilterFun) -> if A1_Start>A2_End -> []; true -> io:format("~w~n",[filter_map(A1_Start,B1_Start,B2_Start,MapFun,FilterFun)]), arithmetic(A1_Start+1,A2_End,B1_Start,B2_Start,MapFun,FilterFun) end. filter_map_list(X,Lst2,MapFun,FilterFun) -> TempList = lists:filter(fun(Value) -> FilterFun(X,Value) end,Lst2), lists:map(fun(Value) -> MapFun(X,Value) end,TempList). %arithmetic_list - 通过 FilterFun,并且通过MapFun来将两个集合(向量)进行运算, %得到一个矩阵 %参数:Lst1 - 第一个集合,Lst2 - 第二个集合,MapFun - 两个集合预算的函数,FilterFun 过滤函数 %例子: %arithmetic_list([1,2,3,4,5,6,7,8,9],[1,2,3,4,5,6,7,8,9],fun(X,Y) ->X*Y end,fun(X,Y)->X>=Y end). arithmetic_list([],Lst2,MapFun,FilterFun) -> []; arithmetic_list(Lst1,Lst2,MapFun,FilterFun) -> [H|T] = Lst1, TempLst = filter_map_list(H,Lst2,MapFun,FilterFun), io:format("~w~n",[TempLst]), arithmetic_list(T,Lst2,MapFun,FilterFun).