2010-11-09 16 views
13

Entonces el operador univ. No lo entiendo exactamente.Prolog GNU - Univ operator? Explicación de eso

Por ejemplo esto:

foo(PredList,[H|_]) :- bar(PredList,H). 
foo(PredList,[_|T]) :- foo(PredList,T),!. 

bar([H|_],Item) :- G =.. [H,Item],G. 
bar([_|T],Item) :- bar(T,Item). 

Lo que está haciendo esto? Esto busca ver si otro predicado es verdadero. No entiendo lo que hace el "...".

¿Cómo reescribiría esto sin el operador univ?

+1

+1 para preguntar cómo reescribir sin univ. Por cierto, hay predicados ISO functor/3 y arg/3 que podrían hacer el trabajo en algunos casos, y deberían ser preferidos, pero no estoy seguro de que siempre puedan usarse. – Kaarel

+0

@Kaarel, +1. Actualizado mi respuesta. –

Respuesta

14

Univ (=..) divide un término en una lista de elementos constitutivos o construye un término a partir de dicha lista. Proveedores:

?- f(x,y) =.. L. 
L = [f, x, y]. 

?- f(x,y,z) =.. [f|Args]. 
Args = [x, y, z]. 

?- Term =.. [g,x,y]. 
Term = g(x, y). 

bar parece llamar a cada predicado en PredList en Item, con foo vuelta hacia atrás a través de los Item s. (Uso de una variable como un predicado no es portátil; la call predicado debe preferirse.)

Editar: Kaarel es correcto, Univ puede ser sustituido por functor/3 y arg/3, como sigue:

bar([H|_],Item) :- 
    functor(Goal,H,1), % unifies Goal with H(_) 
    arg(1,Goal,Item), % unifies first argument of Goal with Item 
    call(Goal).   % use this for portability 
+3

Buena respuesta.Solo por aclaración: el operador univ unifica el término de la izquierda con la lista de la derecha, de modo que el encabezado de la lista es el funtor y la cola de la lista son los argumentos. –

+0

Hmm interesante. ¡Gracias! – Matt

+0

@larsmans: Estás forzando a 'H' a ser un átomo. ¡Así que estás impidiendo la aplicación parcial! Ver la solución de @Cookie Monster. – false

2

la reescritura más adecuado en mi opinión sería:

bar([H|_], Item) :- call(H, Item). 

call/n no son todavía parte de la norma ISO núcleo, pero podría becom e en el futuro cercano (*). Muchos sistemas Prolog ya los admiten.

Existe una razón por la call/n se prefiere en (=..)/2 sencilla y functor/3 + arg/3 soluciones. La solución call/n es capaz de manejar cierres (**).

Con el simple solución (=..)/2 y functor/3 + arg/3 uno puede invocar bar/2 únicamente con átomos en el primer argumento lista. Por ejemplo:

p1(1). 
p2(2). 
?- bar([p1, p2], 1). 
Yes 
?- bar([p1, p2], 2). 
Yes 
?- bar([p1, p2], 3). 
No 

Con los cierres no estamos limitados a los átomos, y podríamos ahorrar algo de esfuerzo de codificación. Por ejemplo, podemos hacer las siguientes directamente:

?- bar([=(1), =(2)], 1). 
Yes 
?- bar([=(1), =(2)], 2). 
Yes 
?- bar([=(1), =(2)], 3). 
No 

Saludos

(*)
Proyecto de Rectificación Técnica 2
http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#call

(**)
que lo inventó ?: call/n Predicados
http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/naish.html

+1

Acerca de "Quién lo inventó": la primera fuente escrita que conozco es el _1984 Proyecto de Norma Propuesta para Prolog Evaluable Predicates_ de Richard O'Keefe, que se anunció públicamente por primera vez el 19 de junio de 1984. Encontrará un precursor restringido a un tipo de lambdas no especificado pero ** que no permite la aplicación parcial ** en Mycroft, O'Keefe _Un sistema de tipo polimórfico para Prolog_, AI Journal, agosto de 1984. – false

+1

Supongo que esto está de acuerdo con el declaración "(1) Alan Mycroft y yo inventamos la llamada/N juntos. Nadie más estuvo involucrado". de ROK encontrado en la segunda referencia? –

+0

De alguna manera. Pero no del todo Hay otras declaraciones que sugieren que 'call/N' ya se inventó en ese documento. – false