2011-08-03 16 views
5

Prolog'da eşleştirilen benzer işlevlere benzer şekilde, kısmi bir tuple Erlang'daki bir listeden bir kopça bulmanın bir yolunu arıyorum. Mesela ben true dönmek için aşağıdaki kod istiyorum:Erlang'de bakım yapmayan değişkenlerle eşleşmeler eşleştirme

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

Bu kod şu hatadan dolayı hemen çalışmaz:

variable '_' is unbound 

aynı etkiyi elde etmek için kısa bir yolu var mı ?

cevap

3

Basit durumlar için, daha önce belirtilen lists:keymember/3'u kullanmak daha iyidir. Ama gerçekten member fonksiyonunu gerekirse böyle kendiniz uygulayabilir:

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

Örnek:

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

sorusundan bunu yapmayı umuyordum, ama bir betimleme işlevi bir deseni argüman olarak iletmenin tek yolu. –

+0

'listeleri: herhangi bir' aslında bu 'üye 'işleviyle aynı şeyi yapar :) – legoscia

+0

@legoscia Haklısın :-) – hdima

0

Sen liste anlama kullanarak yapabileceğini:

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

+0

-yazı, böylece bir fonksiyon argümanı olarak verilecektir (örneğin, "my_member" fonksiyonunu yazmak için)? –

+0

Daha da basit yazabilirsiniz. {pos, _, _} = Eşleştir <- ZeList] 'ancak _filter_ _member_ işlevi değil. – hdima

+0

@Little Bobby Tables [Elem || Elem <- Liste, my_member (Elem)] ancak aynısını listelerle de yapabilirsiniz: filter (fun my_member/1, List) – hdima

3

kullanın lists:keymember/3 yerine.

+0

Bu, desen eşleştirmesine de izin verir mi? Soru eşitlik eşleşmesi ile ilgili değil. –

+0

@WardB 'listeleri: keymember (pos, 1, List)' örneğin – hdima

0

başka olasılık ne maç gözlük yapmak olacak ve ham yerine atom '_' kullanırsınız _. Ardından, aşağıdakine benzer bir fonksiyon yazabiliriz: Sonra

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. 

, aramanız şimdi olacaktır:

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

Bu {A, A, '_'} gibi kalıplarla eşleşen izin vermedi (burada ilk iki kontrol elemanlar aynıdır), ancak değişkenlere ihtiyacınız yoksa bu işe yarayacaktır.

Ayrıca biraz daha çalışma ile özellikleri maç için benzer bir sözdizimi ('$1', '$2', vs) kullanarak değişkenleri kullanmak genişletmek olabilir - Şimdiye kadar gördüğüm değişken bağlamaları ile is_match üçüncü bir parametre eklemek, sonra '_' için yan tümcesine benzer işlev cümleleri yazın.

Verilen en hızlı yöntem olmayacaktır. Gerçekten ölçmediğim uyarıyla, arama sitemini biraz daha ayrıntılı hale getirmesine rağmen, eğlenceli bir dilde kullanarak desen eşlemesini kullanmayı çok daha iyi bir performans göstermesini bekliyorum. Düşünmeniz gereken bir ticaret.

2

Bir liste anlama kullanarak bir makro ile bunu yapabilirsiniz:

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

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

O (bu bütün listede geçiyor) çok etkili değil ama ben orijinal sözdizimine düşünebiliriz yakın.aslında sadece 'uzunluğunu' kaldırıp bir değişken eklemek maç unsurları ayıklamak istiyorsanız

:

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

kullanabilir miyim ets:match: güzel, ama yeniden olabilir

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'}). 
[]