在长护卫队中去除orelse和andalso

Ser*_*nik 1 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) ->
Run Code Online (Sandbox Code Playgroud)

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

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

leg*_*cia 5

不,你需要保留一些orelseandalso,因为当使用,和时;,你基本上有许多;由几个条件(分开)组成的备选方案,,并且至少有一个备选方案中的每个条件都必须是真正.在这个例子中,你几乎有相反的情况:对于每个参数,你希望其中一个条件为真.

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

A, B; C, D
Run Code Online (Sandbox Code Playgroud)

是(几乎1)相当于:

(A andalso B) orelse (C andalso D)
Run Code Online (Sandbox Code Playgroud)

并且没有办法像(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{})
    
    Run Code Online (Sandbox Code Playgroud)

1如果AB将抛出异常,则orelse版本将不匹配,而;如果该C, D部分匹配,则版本将匹配.例如,此函数返回b:

foo() when 1/0 == 1 orelse true ->
    a;
foo() when 1/0 == 1; true ->
    b.
Run Code Online (Sandbox Code Playgroud)