在长护卫队中去除orelse和andalso

时间:2016-09-28 10:00:06

标签: erlang

我在erlang中编写一个函数,它应该能够以不同的顺序和不同的格式接受各种参数集,并且我使用非常严格的防护来确保正确的匹配。

我这样写一个长长的守卫并不罕见:

my_fun(List, Number, OptionalList, Record)
when is_list(List) andalso length(List) >= 5, 
     is_integer(Number) andalso Number >= 10 andalso Number =< 50 orelse Number =:= undefined, 
     is_list(OptionalList) orelse OptionalList =:= undefined, 
     is_record(Record, my_record) ->

我在这里使用的是orelse,而且它使得代码的可读性差得多,而且通常更长。

有没有办法使用和实现相同的保护逻辑;仅?

1 个答案:

答案 0 :(得分:5)

不,您需要保留部分orelseandalso,因为在使用,;时,您实际上有许多替代方案(已分开)由;)组成的几个条件(由,分隔),以及至少一个备选方案中的每个条件必须为真。在这个例子中,你几乎有相反的情况:对于每个参数,你希望一个条件为真。

换句话说,像这样的警卫:

A, B; C, D

(几乎 1 )相当于:

(A andalso B) orelse (C andalso D)

并且如果不使用这些运算符,就无法执行(A orelse B) andalso (C orelse D)之类的操作。

但是,您可以将此示例缩短一点:

  • is_list(List)是多余的,因为如果length(List)不是列表,List将失败。在警卫中,“失败”并不意味着抛出错误;它只是意味着该条款不匹配。
  • is_integer(Number) 几乎多余,因为您还有Number >= 10 andalso Number =< 50。在Erlang中,可以比较任何两个术语的大小,因此如果Number在此范围内,它肯定是一个数字。 (但它可能是浮点数而不是整数。)
  • 您可以匹配函数头中的记录,而不是is_record(Record, my_record)

    my_fun(List, Number, OptionalList, Record = #my_record{})
    

1 如果AB会引发异常,则orelse版本将不匹配,而;版本将匹配C, D部分匹配。例如,此函数返回b

foo() when 1/0 == 1 orelse true ->
    a;
foo() when 1/0 == 1; true ->
    b.