1

I have been reading and noticed that predicates like call are called meta-predicates and they can return other predicates as a result (Don't know if return is a good use of the word here) for example here:

assert(call(goal, X,Y)).

Edit: lurker called me to reason, this doesn't work.

I understand that it's not supposed to call predicates functions but is there a way of making assert over a predicate that will be unknown until runtime?

I want to use the same insertion predicate for more than one fact , so assert(fact(X)) does not suit my needs. I can retrieve the fact's name on runtime but how could i use assert without unifying a fact directly?

false
  • 10,264
  • 13
  • 101
  • 209
Souza
  • 1,124
  • 5
  • 19
  • 44
  • 1
    When you say that `assert(call(goal, X, Y)).` *will work* what does that mean? Work in what way? What I see happening is an attempt to assert `call(...)` would result in an error attempting to modify an existing Prolog procedure (`call`). – lurker Mar 17 '17 at 14:20
  • @lurker you are very right my friend, i am so tired that i imagined i saw it work. Is there a way of making assert without previous knowing of the predicate of which is needed the assert? i will modify my question. I am sorry – Souza Mar 17 '17 at 14:26
  • 1
    No worries. On to the question at hand: a predicate is just a *term* right? It looks like `':-'(head, body)`. So you can do `assertz(':-'(Head, Body)).` where `Head` and `Body` are instantiated at run time. You can also write it as `assertz((Head :- Body)).` since `:-` is an operator. Note that `Head` and `Body` should be istantiated at the time of the `assertz/1` call. – lurker Mar 17 '17 at 14:35
  • Lurker, i will try your approach, i am really enjoying the language. Thank you for your input, it certainly helps to progress . – Souza Mar 17 '17 at 14:40

1 Answers1

1

You should explicitly use assertz/1 or asserta/1. assert/1 is an alias for assertz/1 but only in some Prolog systems.

The call:

assertz(call(goal, X, Y)).

will attempt to assert a fact with functor call. This is what it tries to assert in the database:

call(goal, _, _).

Since call is a functor already defined in Prolog as a predicate, it will generate an error. If you were to assert, say, the following:

assertz(foo(goal, X, Y)).

It would be successful, but what you'd get in the database is something like this:

foo(goal, _, _).

Which doesn't seem very useful. In other words, the assert is just doing what you asked it: asserting a term that you just described whose functor is call or foo in the above cases.

If you want to assert an actual predicate, you just need to use the fact that a predicate is a term whose functor is :-. The general predicate term would be something like Head :- Body or, in canonical form, ':-'(Head, Body). This kind of term can be asserted, as long as at least Head is instantiated before the assertz call.

assertz(':-'(Head, Body)).

Or equivalently (since :- is an operator):

assertz((Head :- Body)).

If I do this:

Head = goal, assertz((Head :- Body)).

I get (using listing/0):

:- listing.

goal :-
    call(_).

Not very useful. So Body really should be instantiated before making this assertz/1 call. Here then is another example:

Head = double(X, Y), Body = (Y is X * 2), assertz((Head :- Body)).

Which now results in the following:

:- listing.

double(A, B) :-
        B is A * 2.
lurker
  • 56,987
  • 9
  • 69
  • 103