Prolog GNU - Univ operator? Explanation of it
Asked Answered
L

2

14

So the univ operator. I don't exactly understand it.

For example this:

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).

What is this doing? This looks to see if another predicate is true. I don't understand what the ".." does.

How would you rewrite this without the univ operator?

Lice answered 9/11, 2010 at 0:41 Comment(1)
+1 for asking how to rewrite without univ. Btw, there are ISO predicates functor/3 and arg/3 which might do the job in some cases, and should be preferred, but I'm not sure they can always be used.Impecunious
L
17

Univ (=..) breaks up a term into a list of constituents, or constructs a term from such a list. Try:

?- 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 seems to call each predicate in PredList on Item, with foo backtracking over the Items. (Using a variable as a predicate is not portable; the call predicate should be preferred.)

Edit: Kaarel is right, univ can be replaced by functor/3 and arg/3, as follows:

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
Libya answered 9/11, 2010 at 8:18 Comment(2)
Good answer. Just for clarification: The univ operator unifies the term on the left with the list on the right, so that the head of the list is the functor, and the tail of the list are the arguments.Dysuria
@larsmans: You are forcing H to be an atom. So you are preventing partial application! See @Cookie Monster's solution.Philhellene
P
3

The most appropriate rewrite in my opinion would be:

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

call/n are not yet part of the ISO core standard, but they might become in the near future (*). A lot of Prolog systems already support them.

There is one reason why call/n should be preferred over simple (=..)/2 and functor/3 + arg/3 solutions. The call/n solution is capable to handle closures (**).

With the simple (=..)/2 and functor/3 + arg/3 solution one can invoke bar/2 only with atoms in the first list argument. For example:

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

With closures we are not restricted to atoms, and we might save some coding effort. For example we can do the following directly:

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

Best Regards

(*)
Draft Technical Corrigendum 2
http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#call

(**)
Who Invented It?: call/n Predicates
http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/naish.html

Puke answered 14/12, 2011 at 11:43 Comment(10)
About "Who invented it": The actual first written source I am aware of is the 1984 Draft Proposed Standard for Prolog Evaluable Predicates by Richard O'Keefe which was first publicly announced 1984-07-25. You find a precursor restricted to some not fully specified kind of lambdas but not permitting partial application in Mycroft, O'Keefe A polymorphic type system for Prolog, AI Journal, August 1984.Philhellene
I guess this is in accordance with the statement "(1) Alan Mycroft and I invented call/N together. No-one else was involved." from ROK found in the second reference?Puke
Somehow. But not entirely. There are other statements suggesting that call/N was already invented in that paper.Philhellene
Well it must be this paper and not the draft, since the draft is by ROK and the paper is by Mycroft & ROK, and ROK says in the news exchange (my second reference marked (**)) Mycroft AND ROK invented it.Puke
That is what common reasoning in the absence of sources suggests. But it is no substitute reading the paper. This is what is written there.Philhellene
Yeah I didn't verify the sources. But anyway since call/n is inspired by LISP funcall (ROK admits that), its more a joke to say it has been invented then and then for Prolog.Puke
Is it? What is the funcall analogon to call(=(1),Y)?Philhellene
Well, it seems that it is not: I found: X3J13 voted in June 1988 (FUNCTION-TYPE) to allow the fn to be only of type symbol or function; a lambda-expression is no longer acceptable as a functional argument. One must use the function special form or the abbreviation #' before a lambda-expression that appears as an explicit argument form. Compatibility note: The Common Lisp function funcall corresponds roughly to the Interlisp primitive apply*. ida.liu.se/imported/cltl/clm/node81.htmlPuke
So partial application is not present. And there are still proposals to it. So this step from apply in the AI paper to call/N is the real thing!Philhellene
I cannot judge, I don't have the paper at hand. But putting too much curry in your meal can make it too spicy and less balanced. Pitty ROKs proposal is incomplete, no ^/n. BTW: In this news exchange there is also a mention of a type for call/n: dtai.cs.kuleuven.be/projects/ALP/newsletter/archive_93_96/net/…Puke

© 2022 - 2024 — McMap. All rights reserved.