Dicts and assert()

I returned to Prolog and was happy to learn that Dicts are now available. They seem useful and I am trying to use them. So far they work like I expect, except with assert().

For example, I was able to define this rule:

person2(Obj, Person) :-
   member(Person, Obj.people).

When I tried assert( (person2(Obj, Person):- member(Person, Obj.people)) ). it failed with “Arguments are not sufficiently instantiated”.

I was able to rewrite the assert in a clumsy way and it worked:

assert( (person2(Obj, Person):- 
    .(Obj, people, People),
    member(Person, People)) ).

What was I doing wrong with the first assert()?

Assert doesn’t do term expansion and that is what sits between source code you
read and assert/1. So, you’d need to call expand_term/2 first. The more serious problem is that Obj.people will be evaluated when you try to expand/assert rather than at runtime. As code is data in Prolog, we do not know when we should evaluate. For short, the . notation only works for source code. Even there the expansion easily gets executed at the wrong moment when code is passed as in e.g. findall/3.

I don’t think that can be solved unless we have typing that tells us unambiguously when data is in fact code.

1 Like

You can see what’s happening under the covers using listing/1. For example:

$ cat q.pl
q(A) :-
    assertion(A.foo == a).

$ swipl -q q.pl
?- listing(q).
q(A) :-
    '.'(A, foo, B),
    assertion(B==a).

When I re-loaded this (using make/0), I got the following, which is what I would have expected the first time. I’m guessing that this is because assertion/1 was auto-loaded and it has special term expansion hooks - when I added :-use_module(library(debug)), the term expansion happened as expected. (Yet another unexpected subtlety in term-expansion …)

?- listing(q).
q(A) :-
    assertion(( '.'(A, foo, B),
                B==a
              )).
1 Like