5
votes

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/_).
2
I see identical behavior with swipl version 6.0.2 on Linux.lurker
Can't you use current_predicate/1 instead?Paulo Moura
current_predicate appears consistent. current_predicate(p/Y). yields Y = 1 and current_predicate(q/Y). yields Y = 0 as expected.lurker
@PauloMoura Yes, current_predicate(q/X) succeeds, and is what I will use for my current project, although it doesn't answer the question. But are you suggesting that current_functor/2 has been depreciated in favor of current_predicate/1? I doesn't say so in the manual...Shon
current_functor/2 allows you to query both predicate and function functors. But, if you're only concerned about predicates, I expect that you could replace calls to current_functor/2 with calls to current_predicate/1.Paulo Moura

2 Answers

4
votes

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

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.