1

Prolog's grammar uses a <head> :- <body> format for rules as such:

tree(G) :- acyclic(G) , connected(G). , denoting status of G as a tree depends on status as acyclic and connected.

This grammar can be extended in an implicit fashion to facts. Following the same example:

connected(graphA) suggests connected(graphA):-true.

In this sense, one might loosely define Prolog facts as Prolog rules that are always true.

My question: Is in any context a bodiless rule (one that is presumed to be true under all conditions) ever appropriate? Syntactically such a rule would look as follows.

graph(X). (suggesting graph(X):-true.)

David Shaked
  • 3,171
  • 3
  • 20
  • 31
  • Using your terminology, what is the difference between a "bodiless rule" and a "fact"? –  Mar 05 '16 at 09:52
  • Example of bodiless rule: blah(X). Example of fact (bodiless by definition): blah(a). Note the use of a variable for the argument of the first. – David Shaked Mar 06 '16 at 21:59
  • I did remember at least one valid use for such rules: see my answer below. –  Mar 07 '16 at 07:43
  • What about this definition is "loose"? – Scott Hunter Mar 09 '16 at 19:04
  • @ScottHunter, not all rules that are always presumed to be true (in other words, have no bodies) qualify as facts. For instance, the recursive case in my answer below (member) is bodiless but not a fact. In other words, a bodiless rule does not a fact make. The definition is loose in that facts are only partially defined. – David Shaked Mar 09 '16 at 20:31
  • @DavidShaked: From whence does your definition of a fact come? A fact is a thing that is true without qualification, whether that thing refers to 1, many or all possible objects. In your example, it is a fact that anything that is the first element of a given list is a member of that list. – Scott Hunter Mar 09 '16 at 21:09

4 Answers4

3

A fact is just a bodiless rule, as you call it. And yes, there are plenty of use cases for bodiless facts:

  1. representing static data
  2. base cases for recursion
  3. instead of some curly brace language pseudo code

    boolean is_three(integer x) {
        if (x == 3) { return  true; }
        else        { return false; }
    }
    

    we can simply write

    is_three(3).
    
repeat
  • 18,496
  • 4
  • 54
  • 166
Anniepoo
  • 2,152
  • 17
  • 17
  • 2
    Looks like you might have run into an issue submitting your answer-- I'd be happy to hear your thoughts once you get a chance to revisit. – David Shaked Mar 05 '16 at 21:26
  • Not sure what 'issue' you mean. – Anniepoo Mar 08 '16 at 21:45
  • the content is good upon second reading... Formatting at first for some reason made the post look incomplete. I went ahead and reformatted quickly. I'll go ahead and give you the uptick for your helpful post. – David Shaked Mar 09 '16 at 17:55
3

Before answering, to rephrase your question:

In Prolog, would you ever write a rule with nothing but anonymous variables in the head, and no body?

The terminology is kind of important here. Facts are simply rules that have only a head and no body (which is why your question is a bit confusing). Anonymous variables are variables that you explicitly tell the compiler to ignore in the context of a predicate clause (a predicate clause is the syntactical scope of a variable). If you did try to give this predicate clause to the Prolog compiler:

foo(Bar).

you will get a "singleton variable" warning. Instead, you can write

foo(_).

and this tells the compiler that this argument is ignored on purpose, and no variable binding should be attempted with it.

Operationally, what happens when Prolog tries to prove a rule?

  • First, unification of all arguments in the head of the rule, which might lead to new variable bindings;
  • Then, it tries to prove the body of the rule using all existing variable bindings.

As you can see, the second step makes this a recursively defined algorithm: proving the body of a rule means proving each rule in it.

To come to your question: what is the operational meaning of this:

foo(_).

There is a predicate foo/1, and it is true for any argument, because there are no variable bindings to be done in the head, and always, because no subgoals need to be proven.

I have seen at least one use of such a rule: look at the very bottom of this section of the SWI-Prolog manual. The small code example goes like this:

term_expansion(my_class(_), Clauses) :-
        findall(my_class(C),
                string_code(_, "~!@#$", C),
                Clauses).

my_class(_).

You should read the linked documentation to see the motivation for doing this. The purpose of the code itself is to add at compile time a table of facts to the Prolog database. This is done by term expansion, a mechanism for code transformations, usually used through term_expansion/2. You need the definition of my_class/1 so that term_expansion/2 can pick it up, transform it, and replace it with the expanded code. I strongly suggest you take the snipped above, put it in a file, consult it and use listing/1 to see what is the effect. I get:

?- listing(my_class).
my_class(126).
my_class(33).
my_class(64).
my_class(35).
my_class(36).

true.

NB: In this example, you could replace the two occurrences of my_class(_) with anything. You could have just as well written:

term_expansion(foobar, Clauses) :-
        findall(my_class(C),
                string_code(_, "~!@#$", C),
                Clauses).

foobar.

The end result is identical, because the operational meaning is identical. However, using my_class(_) is self-documenting, and makes the intention of the code more obvious, at least to an experienced Prolog developer as the author of SWI-Prolog ;).

1

This is often how the base case of a recursive definition is expressed.

Scott Hunter
  • 48,888
  • 12
  • 60
  • 101
0

To highlight what I was initially looking for, I'll include the following short answer for those who might find themselves asking my initial question in the future.

An example of a bodiless rule is, as @Anniepoo suggested, a base case for a recursive definition. Look to the example of a predicate, member(X,L) for illustration:

member(X,[X|T]). /* recursive base case*/
member(X,[H|T]):- member(X,T).

Here, the first entry of the member rule represents a terminating base case-- the item of interest X matching to the head of the remaining list.

I suggest visiting @Boris's answer (accepted) for a more complete treatment.

David Shaked
  • 3,171
  • 3
  • 20
  • 31
  • 1
    With the risk to come off as pedantic, your terminology is still a bit off. In the `member/2` example you give, it is only one _predicate clause_ that does not have a body, not the _rule_! You might want to check out [SWI-Prologs glossary of terms](http://eu.swi-prolog.org/pldoc/man?section=glossary). You might notice that "rule" is not there at all ;) –  Mar 10 '16 at 07:42
  • Thanks. I'll look into the glossary to brush up. – David Shaked Mar 10 '16 at 19:34