Erlang入门教程 - 10. 模式匹配,Guard,变量作用域

racaljkracaljk

像这样如果能找出列表中最高/最低气温是很有用的。在扩展程序以寻找气温极值之前,让我们看看在函数中寻找列表最大值:

-module(tut6).
-export([list_max/1]).

list_max([Head|Rest]) ->
   list_max(Rest, Head).

list_max([], Res) ->
    Res;
list_max([Head|Rest], Result_so_far) when Head > Result_so_far ->
    list_max(Rest, Head);
list_max([Head|Rest], Result_so_far)  ->
    list_max(Rest, Result_so_far).


37> c(tut6).
{ok,tut6}
38> tut6:list_max([1,2,3,4,5,7,4,3,2,1]).
7

首先注意有两个函数名字一样,list_max(指list_max([Head|Rest])list_max([], Res))。然而,它们接受不同数目的参数。在Erlang中它们被视作完全不同的函数。
当你需要区分这些函数的时候,你直接写 Name/Arity 即可,Name是函数名,Arity是函数参数个数,在这是list_max/1,list_max/2。

在这个例子中你遍历一个列表然后“带走”一个值,即Result_so_far。list_max/1简单的假定列表的最大值是表头元素然后把表头元素和列表剩余部分传递给list_max/2进行调用。按上面代码给出的参数将会调用list_max([2,3,4,5,7,4,3,2,1],1)。如果你尝试给list_max/1一个空列表或者给它一个不是列表的值,将引发一个错误。Erlang的哲学是不在函数中处理这类错误,而是在其他地方处理。关于这点后面会讨论。

在list_max/2, 当Head > Result_so_far时使用Head代替Result_so_far。在->后使用when表示你只在when后面的测试为true时才使用这个函数(clause)。这类测试叫做guard。如果guard为false(即guard失败),就转而尝试下一个函数(clause)。在这里,如果Head不大于Result_so_far,那它一定小于或等于。这意味着下面函数(clause)不需要guard。

在guards中有这么一些有用的运算符:

  • < 小于
  • > 大于
  • == 等于
  • >= 大于等于
  • =< 小于等于
  • /= 不等于

要修改上面的程序让它找出列表中的最小值,你只需要把>改成<。(但那样做最好也把函数名改成list_min)。

之前提到过一个变量在它的作用域内只能绑定一次值。但如你所见Result_so_far绑定了很多次值。这没问题,因为每次你调用list_max/2都会创建一个新的作用域,然后Result_so_far就在那个新作用域中进行绑定。

另一个创建变量并绑定值的方法是使用匹配运算符=。当你写下M = 5,一个名为M的变量创建了并绑定值5。如果,在相同的作用域,你写下M =6,就会返回错误。在shell中试试:

39> M = 5.
5
40> M = 6.
** exception error: no match of right hand side value 6
41> M = M + 1.
** exception error: no match of right hand side value 6
42> N = M + 1.
6

匹配运算符在分离Erlang 一个项并创建新项时是非常有用的。

43> {X, Y} = {paris, {f, 28}}.
{paris,{f,28}}
44> X.
paris
45> Y.
{f,28}


在这里X绑定为paris,Y绑定为{f,28}。

如果你尝试再使用其它城市,就会返回一个错误。

46> {X, Y} = {london, {f, 36}}.
** exception error: no match of right hand side value {london,{f,36}}

变量也可用于改善程序可读性。举个例子,在上面的list_max/2函数中,你可以这么写:

list_max([Head|Rest], Result_so_far) when Head > Result_so_far ->
    New_result_far = Head,
    list_max(Rest, New_result_far);

这样可能更清晰一些。

文章被以下专栏收录
2 条评论
推荐阅读