如何在列表与单个元素上进行模式匹配

How to pattern match on list vs single element

我想了解如何在 Erlang 中针对单个元素与列表进行模式匹配:

guarded(T) when T>5 ; T<3 -> 3+T;
guarded([X,Y]) when X>3,Y>3 ->{X+1,Y+1};
guarded([X,_|[T,_]]) when X rem 2==0, T rem 2 =/= 1-> [T,X];
guarded(_)->"something else".



guarded([1,2,3]).  -> goes into case 1 , how can i make sure it doesn't (and goes to last case)

** exception error: an error occurred when evaluating an arithmetic expression in function main:guarded/1

当我想在单个上进行模式匹配时,我需要将第一个案例放在哪里 elements.I 意味着我想要一个适用于单个元素的案例和一个通配符模式(最后表达式).

你可以给你的守卫添加一个is_list/1检查来检查T不是一个列表:

guarded(T) when not is_list(T) andalso (T>5 orelse T<3) -> 3+T;
guarded([X,Y]) when X>3, Y>3 ->{X+1,Y+1};
guarded([X,_|[T,_]]) when X rem 2==0, T rem 2 =/= 1-> [T,X];
guarded(_)->"something else".

或者您可以使用 is_number/1 or is_integer/1 分别检查 T 是数字还是整数:

guarded(T) when is_number(T) andalso (T>5 orelse T<3) -> 3+T;
guarded([X,Y]) when X>3, Y>3 ->{X+1,Y+1};
guarded([X,_|[T,_]]) when X rem 2==0, T rem 2 =/= 1-> [T,X];
guarded(_)->"something else".

作为 Vinoski 答案的替代方法,您还可以将不太具体的模式移到末尾,这样列表会首先匹配:

guarded([X,Y]) when X>3,Y>3 ->{X+1,Y+1};
guarded([X,_|[T,_]]) when X rem 2==0, T rem 2 =/= 1-> [T,X];
guarded(T) when T>5 ; T<3 -> 3+T;
guarded(_)->"something else".

但在这种特定情况下它不会很好地工作,因为像 guarded([1,1]) 这样的东西仍然不会匹配前两个分支但会匹配 T 一个;这是因为 Erlang allows comparing any two values 只考虑列表大于数字。

I mean how does a method like is_list (mentioned above) implemented?

使用 erlang,您可以像这样实现 is_list()

-module(my).
-compile([export_all]).

islist([]) ->     % empty list
    true;
islist([_|_]) ->  % non-empty list
    true;
islist(_) ->      % anything else
    false.

当你调用一个函数时,erlang 从定义中的第一个函数子句开始,并尝试将函数调用中指定的参数与函数定义中的参数相匹配。如果没有匹配,erlang 会尝试下一个函数子句。当找到匹配项时,相应的函数体就会执行。如果 none 个函数子句匹配,则会出现 function_clause 错误。

在shell:

~/erlang_programs$ erl
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V6.4  (abort with ^G)

1> c(my).
{ok,my}

2> my:islist(3).
false

3> my:islist({1, 2}).
false

4> my:islist([1, 2]).
true

5> my:islist([]).
true

6> my:islist("abc"). 
true

在第 6 行中,您应该知道 "abc" 对于整数列表 [97, 98, 99] 是 shorthand。在 erlang 中,对于包含双引号字符串中字符的整数代码点的列表,双引号字符串是 shorthand。