2011-08-03 55 views
5

我正在尋找一種方法在Erlang中使用部分元組來查找列表中的元組,類似於在Prolog中匹配的函子。例如,我想下面的代碼返回true在Erlang中匹配與不關心變量的元組

member({pos, _, _}, [..., {pos, 1, 2}, ...]) 

此代碼不能馬上工作,因爲有下列錯誤:

variable '_' is unbound 

有沒有一種簡單的方法來達到同樣的效果?

回答

3

對於簡單情況,最好使用已經提到的lists:keymember/3。但是,如果你真的需要member功能,您可以自己實現這樣的:

member(_, []) -> 
    false; 
member(Pred, [E | List]) -> 
    case Pred(E) of 
     true -> 
      true; 
     false -> 
      member(Pred, List) 
    end. 

例子:

>>> member(fun ({pos, _, 2}) -> true; (_) -> false end, [..., {pos, 1, 2}, ...]). 
+0

這個問題中,我希望避免這種情況,但似乎謂詞函數是將模式作爲參數傳遞的唯一方法。 –

+0

'lists:any'實際上和這個'member'函數完全一樣:) – legoscia

+0

@legoscia你是對的:-) – hdima

0

你可以使用列表理解做到這一點:

Matches = [ Match || {Prefix, _, _} = Match <- ZeList, Prefix == pos].

+0

這很好,但它可以被重新 - 這樣模式將作爲函數參數給出(例如,用於寫入「my_member」函數)? –

+0

你可以寫得更簡單'[Match || {pos,_,_} =匹配<--ZeList]',但是_filter_不是_member_的功能。 – hdima

+0

@小鮑比桌[Elem || Elem < - List,my_member(Elem)],但是您可以對列表執行相同的操作:filter(fun my_member/1,List) – hdima

3

使用lists:keymember/3來代替。

+0

這是否也允許模式匹配?因爲問題不在於獲得平等匹配。 –

+0

@WardB'list:keymember(pos,1,List)'例如在 – hdima

0

另一種可能性是做什麼比賽的規格做,使用原子'_'代替原始的_。然後,你可以寫類似如下的功能:

member(X, List) when is_tuple(X), is_list(List) -> 
    member2(X, List). 

% non-exported helper functions: 

member2(_, []) -> 
    false; 
member2(X, [H|T]) when not is_tuple(H); size(X) =/= size(H) -> 
    member2(X, T); 
member2(X, [H|T]) -> 
    case is_match(tuple_to_list(X), tuple_to_list(H)) of 
     true -> true; 
     false -> member2(X, T) 
    end. 

is_match([], []) -> 
    true; 
is_match(['_'|T1], [_|T2]) -> 
    is_match(T1, T2); 
is_match([H|T1], [H|T2]) -> 
    is_match(T1, T2); 
is_match(_, _) -> 
    false. 

然後,您的電話現在會是:

member({pos, '_', '_'}, [..., {pos, 1, 2}, ...]) 

這會不會讓你像匹配模式{A, A, '_'}(檢查前兩個地方元素是相同的),但如果你不需要變量,這應該工作。

您還可以擴展它與更多的工作使用使用類似的語法來匹配規格('$1''$2'等)的變量 - 第三個參數添加到is_match與您目前爲止看到的變量綁定,然後爲它們編寫函數子句,類似於'_'的子句。

當然,這不會是最快的方法。由於我沒有真正衡量的警告,我期望使用有趣的語言使用模式匹配將會提供更好的性能,但它確實使調用站點更加冗長。這是一個折衷,你必須考慮。

2

您可以使用列表解析宏做到這一點:

-define(member(A,B), length([0 || A <- B])>0). 

?member({pos, _, _}, [{width, 17, 42}, {pos, 1, 2}, totally_irrelevant]). 

這不是很有效的(它貫穿整個列表),但它是我能想到的原始語法最接近的一次。

如果你想實際提取匹配你只是刪除「長度」,並添加一個變量的元素:

-define(filter(A,B), [_E || A =_E <- B]). 
0

可以使用ets:match

6> ets:match(T, '$1'). % Matches every object in the table 
[[{rufsen,dog,7}],[{brunte,horse,5}],[{ludde,dog,5}]] 
7> ets:match(T, {'_',dog,'$1'}). 
[[7],[5]] 
8> ets:match(T, {'_',cow,'$1'}). 
[]