Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is it that, in SWI-Prolog Version 6.4.1, current_functor/2 is false for 0-arity predicates?

I'm using SWI-Prolog Version 6.4.1 on OS X 7, and am experiencing the following unexpected behavior with the predicate current_functor/2:

Given the facts

p(a).
q.

I get these answers to queries:

?- current_functor(p, Y).
Y = 1 

?- current_functor(q, Y).
false.

?- current_functor(q, 0).
true.

Not only do the second and third queries seem blatantly inconsistent, but the failure of the second doesn't seem consistent with the SWI-Prolog reference manual, which describes current_functor/2 as follows:

current_functor(?Name, ?Arity) Successively unifies Name with the name and Arity with the arity of functors known to the system.

Can anyone help me understand why the predicate is functioning in this way?

Edit:

In terms of solving my particular problem of testing whether or not predicates had been defined, including certain 0-arity ones, I ended up following false's advice and writing the following:

current_pred(P) :-
    current_predicate(P/_).
like image 455
Shon Avatar asked Oct 28 '13 18:10

Shon


People also ask

What does false mean in Prolog?

The concept of logical negation in Prolog is problematical, in the sense that the only method that Prolog can use to tell if a proposition is false is to try to prove it (from the facts and rules that it has been told about), and then if this attempt fails, it concludes that the proposition is false.

What does no mean in Prolog?

At page 7 of the intro to the language they made the assertion : "In Prolog the answer no is used to mean nothing unifies with the question. It is important to remember that no is not the same as false".


2 Answers

TL;DR: don't!

current_functor/2 is an SWI-specific built-in predicate that you will find nowhere else (except the only historically relevant DECsystem 10). The reason for this predicate is related to the specific representation of functors in SWI. In brief, SWI needs to register each functor, before using it. (And prior to that it needs to register the related atom.) What happens if the functor is no longer used? Will it then still be present or not? Is this resource garbage collected?

To answer your question: current_functor/2 will only succeed for functors. There are no functors of arity 0. A term with arity 0 is called an atom and is handled differently.

In any case you will write code that depends on a single implementation which is maintained by a single person. Not a very safe bet for a larger project.

Other Prolog systems work differently. They need to register atoms too, but then they can construct any functor up to max_arity without using some further global resource. For this reason, many systems offer current_atom/1.

But even that very predicate is ill defined. After all, what does it mean that an atom is still present? May an optimizing compiler remove an atom and thereby change its meaning? Is it a means to inspect the confidential atoms an application uses by some otherwise harmless looking query code?

This all is really a can of worms. Avoid them at any cost. Maybe use current_predicate instead.


All that said, if you still believe you need it, do:

current_f(F, A) :-
   current_functor(F, A).
current_f(F, 0) :-
   current_atom(F).
like image 153
false Avatar answered Nov 15 '22 12:11

false


I think there could be a bug at line 391 of pl-funct.c. That line read

if ( fd && fd->arity > 0 && (!nm || nm == fd->name) )

Now I'll try to correct to fd->arity >= 0 and test...

edit Apparently it worked:

1 ?- [user].
yy.
|: 
% user://1 compiled 0.00 sec, 2 clauses
true.

2 ?- current_functor(yy,X).
X = 0 ;
false.

I'll try to commit, but I don't think I have git access to the full source...

edit indeed, git refuses to accept my change... I'll report on SWI-Prolog mailing list.

like image 44
CapelliC Avatar answered Nov 15 '22 11:11

CapelliC