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

2

5

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/_).
Hetzel answered 28/10, 2013 at 18:52 Comment(5)
I see identical behavior with swipl version 6.0.2 on Linux.Tidbit
Can't you use current_predicate/1 instead?Voe
current_predicate appears consistent. current_predicate(p/Y). yields Y = 1 and current_predicate(q/Y). yields Y = 0 as expected.Tidbit
@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...Hetzel
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.Voe
A
4

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).
Allout answered 28/10, 2013 at 21:18 Comment(10)
Thank you for the information and for your warning (though it doesn't answer the question). I don't know the answer to your first question, but I'd like to. current_atom/1 won't work for my purposes, since it is true even if an atom is just used in a clauses' body (at least, it does so in SWI). Are you just advising against testing for presence of predicates or functors in general, by any means?Hetzel
@aBathologist: Against any use of current_functor/2, and (to a lesser extent) against current_atom/1.Allout
are there similar problems with current_predicate/1?Hetzel
@aBathologist: No. Garbage-collection, and optimizations will not affect current_predicate/1. Once, a predicate is user-defined, it stays with you.Allout
Sorry I didn't understood the C code correctly, maybe Jan will take care to make current_functor(?Name, ?Arity) failing when arity is 0Glioma
"There are no functors of arity 0. A term with arity 0 is called an atom and is handled differently." - this terminology seems to be ambiguous, can you cite that from somewhere? The Prolog Dictionary seems to indirectly support your view via its definition of "structure", but the definition for "term" is ambiguous again ("Note that the arity might be 0"). I also know for a fact that SICStus Prolog refers to predicates of any arity, including 0, as "functors"...Periphery
@l4mpi: You do have a very good point here: The notion of functor I has implicitly referring to is what implementors view as a functor. So you need a functor only if there is at least one argument, otherwise it is an atom. However, in ISO terminology, also an atom is/has a functor.Allout
@Allout I don't know if you edited your answer or if I was simply reading poorly yesterday, but I wanted to note that your answer definitely does address my question--contrary to my first comment.Hetzel
@Allout According to what you say about functors, the error in the SWI implementation would be that, if there is a fact like a., it will succeed on the query ?- current_functor(a, 0). In any case, whether it is one way or another, it seems like this query should fair or succeed the same whether the second argument is 0 or a variable.Hetzel
@aBathologist: The notion functor, as used in current_functor/2 refers to structures and not atoms. This is the common implementor's terminology. I am not sure why you say that current_functor(a,X)should fail, think of p(a(X)) being used somewhere in the system.Allout
G
4

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.

Glioma answered 28/10, 2013 at 19:44 Comment(4)
@Allout Why is that? Would this change break something? (As an aside, I'm not sure it makes much sense for you to down-vote CapelliC's correct and informative answer just because you dislike his intended course of action.)Hetzel
@aBathologist: Please read the box at the down-arrow: "This answer is not useful".Allout
@Allout well, I guess our definitions of "useful" differ. I find accurate, detailed information which explains the cause of unexpected behavior quite useful. In any case, I'd like to know why you oppose this change, if you'd oblige.Hetzel
@aBathologist: "useful" implies one legitimate use case.Allout
A
4

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).
Allout answered 28/10, 2013 at 21:18 Comment(10)
Thank you for the information and for your warning (though it doesn't answer the question). I don't know the answer to your first question, but I'd like to. current_atom/1 won't work for my purposes, since it is true even if an atom is just used in a clauses' body (at least, it does so in SWI). Are you just advising against testing for presence of predicates or functors in general, by any means?Hetzel
@aBathologist: Against any use of current_functor/2, and (to a lesser extent) against current_atom/1.Allout
are there similar problems with current_predicate/1?Hetzel
@aBathologist: No. Garbage-collection, and optimizations will not affect current_predicate/1. Once, a predicate is user-defined, it stays with you.Allout
Sorry I didn't understood the C code correctly, maybe Jan will take care to make current_functor(?Name, ?Arity) failing when arity is 0Glioma
"There are no functors of arity 0. A term with arity 0 is called an atom and is handled differently." - this terminology seems to be ambiguous, can you cite that from somewhere? The Prolog Dictionary seems to indirectly support your view via its definition of "structure", but the definition for "term" is ambiguous again ("Note that the arity might be 0"). I also know for a fact that SICStus Prolog refers to predicates of any arity, including 0, as "functors"...Periphery
@l4mpi: You do have a very good point here: The notion of functor I has implicitly referring to is what implementors view as a functor. So you need a functor only if there is at least one argument, otherwise it is an atom. However, in ISO terminology, also an atom is/has a functor.Allout
@Allout I don't know if you edited your answer or if I was simply reading poorly yesterday, but I wanted to note that your answer definitely does address my question--contrary to my first comment.Hetzel
@Allout According to what you say about functors, the error in the SWI implementation would be that, if there is a fact like a., it will succeed on the query ?- current_functor(a, 0). In any case, whether it is one way or another, it seems like this query should fair or succeed the same whether the second argument is 0 or a variable.Hetzel
@aBathologist: The notion functor, as used in current_functor/2 refers to structures and not atoms. This is the common implementor's terminology. I am not sure why you say that current_functor(a,X)should fail, think of p(a(X)) being used somewhere in the system.Allout

© 2022 - 2024 — McMap. All rights reserved.