2010-10-21 16 views
6

¿Cómo puedo hacer la coincidencia dinámica de patrones en Erlang?Coincidencia de patrón dinámico

supose I tiene el filtro de función/2:

filter(Pattern, Array) 

donde Pattern es una cadena con el patrón quiero para que coincida con (por ejemplo "{book, _ }" o "{ebook, _ }") tecleado por un usuario y la matriz es una matriz de elementos heterogéneos (por ejemplo, {dvd, "The Godfather" } , {book, "The Hitchhiker's Guide to the Galaxy" }, {dvd, "The Lord of Rings"}, etc.) Luego me gustaría que filter/2 arriba devuelva la matriz de elementos en Array que coincidan con Pattern.

He intentado algunas ideas con erl_eval sin ningún éxito ...

tks por adelantado.

Respuesta

5

Con poco estudio de la documentación bits:

Eval = fun(S) -> {ok, T, _} = erl_scan:string(S), {ok,[A]} = erl_parse:parse_exprs(T), {value, V, _} = erl_eval:expr(A,[]), V end, 
FilterGen = fun(X) -> Eval(lists:flatten(["fun(",X,")->true;(_)->false end."])) end, 
filter(FilterGen("{book, _}"), [{dvd, "The Godfather" } , {book, "The Hitchhiker's Guide to the Galaxy" }, {dvd, "The Lord of Rings"}]). 
[{book,"The Hitchhiker's Guide to the Galaxy"}] 
+0

¡Genial! Tks Hynek. – xboard

0

Puede usar lists:filter/2 para hacer la parte de filtrado. Convertir la cadena en código es una cuestión diferente. ¿Están todos los patrones en la forma de {atom, _}? Si es así, es posible que puedas almacenar el átomo y pasarlo al argumento de cierre de las listas: filter.

+0

Tks Nathon, pero para mi caso de uso que realmente necesitan una manera dinámica. – xboard

0

Varias posibilidades vienen a la mente, dependiendo de la dinámica de los patrones son y qué características que necesita en sus patrones:

  1. Si necesita exactamente la sintaxis de los patrones de erlang y el patrón no cambia muy a menudo. Puede crear el código fuente coincidente y escribirlo en un archivo. Use compile:file para crear un archivo binario y cárguelo con code:load_binary.

    • Ventaja: juego muy rápido

    • Desventaja: sobrecarga cuando el patrón cambia

  2. Rellenar los datos de Array en ETS y el uso match specifications salir los datos

    • Puede usar fun2ms para ayudar a crear la especificación de coincidencia. Pero fun2ms normalmente se usa como una transformación de parse durante el tiempo de compilación. También hay un modo utilizado por el intérprete de órdenes que se puede hacer funcionar desde cadenas con la ayuda del analizador probablemente. Para más detalles ver ms_transform
  3. También puede haber alguna forma de utilizar qlc pero yo no ver en esto en detalle.

En cualquier caso, tenga cuidado para desinfectar sus datos coincidentes si se trata de fuentes no fiables!

+0

Tks para responder, Peer. – xboard

2

¿Hay algún motivo especial por el que desee el patrón en una cuerda?

Los patrones como tales no existen en Erlang, en realidad solo pueden aparecer en el código.Una alternativa es usar las mismas convenciones que con ETS match y select y escribir su propia función de coincidencia. Es realmente bastante simple. La convención ETS usa un término para representar un patrón donde los átomos '$1', '$2', etc. se usan como variables que pueden ser enlazadas y probadas, y '_' es la variable "no importa". Por lo tanto, sus patrones de ejemplo serían:

{book,'_'} 
{ebook,'_'} 
{dvd,"The Godfather"} 

Esta es probablemente la forma más eficiente de hacerlo. Existe la posibilidad de utilizar las especificaciones de los partidos aquí, pero complicaría el código. Depende de la complicada coincidencia que necesites.

EDIT: añado sin código de comentario para parte de la matcher:

%% match(Pattern, Value) -> {yes,Bindings} | no. 

match(Pat, Val) -> 
    match(Pat, Val, orddict:new()). 

match([H|T], [V|Vs], Bs0) -> 
    case match(H, V, Bs0) of 
     {yes,Bs1} -> match(T, Vs, Bs1); 
     no -> no 
    end; 
match('_', _, Bs) -> {yes,Bs};     %Don't care variable 
match(P, V, Bs) when is_atom(P) -> 
    case is_variable(P) of 
     true -> match_var(P, V, Bs);   %Variable atom like '$1' 
     false -> 
      %% P just an atom. 
      if P =:= V -> {yes,Bs}; 
       true -> no 
      end 
    end. 

match_var(P, V, Bs) -> 
    case orddict:find(P, Bs) of 
     {ok,B} when B =:= V -> {yes,Bs}; 
     {ok,_} -> no; 
     error -> {yes,orddict:store(P, V, Bs)} 
    end. 
+0

Tks rvirding, haré una investigación con sus sugerencias muy pronto. – xboard

Cuestiones relacionadas