Dict access odd behavior


Trying to understand why the different behavior in dict access in the following calls:

?- current_input(S), read_term(S, T, []), T = (_ :- G), writeq(G), nl, call(G).
|: p :- A.foo = [].

?- A.foo = [].
ERROR: Arguments are not sufficiently instantiated
ERROR:   [13] throw(error(instantiation_error,_11490))
ERROR:   [10] '<meta-call>'(user:user: ...) <foreign>
ERROR:    [9] <user>
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.

Notably, why we get false in the first call.


Functional notation is ultimately implemented by expand_goal/2 which scans the goal arguments for A.B and turns g(A.B) into .(A,B,C), g(C).

In the first example no expansion on the term happens, so in the end it just tries to unify A.foo with [], which fails. Note that call/1 (I think unlike SICStus) does not perform any expansion. If we want that:

?- read(X), expand_goal(X,Y), call(Y).
|: A.foo = [].

ERROR: Arguments are not sufficiently instantiated
ERROR:   [14] throw(error(instantiation_error,_9142))
ERROR:   [12] '$dicts':'.'(_9172,foo,_9176) at /ufs/wielemak/src/swipl-devel/linux/home/boot/dicts.pl:46
ERROR:   [11] '<meta-call>'(('.'(_9220,foo,_9224),_9228=[])) <foreign>
ERROR:   [10] '<meta-call>'(user:user: ...) <foreign>
ERROR:    [9] <user>

As you probably guessed by now, the toplevel calls expand_goal/2 on the query you typed.

1 Like

Thanks for the quick reply. As the documentation states that " Functions are recognised if they appear in the argument of a goal in the source text, possibly nested in a term.", I was expecting the same behavior in both cases. I don’t think calling expand_goal/2 is an option on my case, but I will research it further.

Calling either term_expansion/2 or goal_expansion/2 on the read term (a clause) doesn’t expand its A.B arguments. Tried calls in both user and system modules. What am I missing? Looked into the boot/dicts.pl file but the expansion rules there don’t apply to clauses.

expand_goal/2 and expand_term/2 call user goal_expansion/2 and expand_term/2, but end with DCG expansion and functional notation. The code is a bit of a mess and subject to change, but you find it in boot/expand.pl, replace_functions/4.

Noticed the expand:replace_functions/4 predicate. I was loping/looking for a way to access dict expansions independently of any other expansions and accessible by calling term_expansion/2 and goal_expansion/2 rules in a specific module. I do understand the current solution. Traditionally, DCG expansion have been implemented as a default expansion.

In due time, all of that is likely to become possible. Not yet though …