PL_get_dict. How to retrieve unified goals involving dicts, if provided as strings?

I’m trying parse dict query responses in the the foreign language interface.

In Prolog.h, I see we have the type ID PL_LIST and PL_get_list, and type id PL_DICT, but no PL_get_dict. Are dicts a functor?

Thanks in advance,

  • Stuart

Seems I can indeed decode it as a functor.

Hmm…

Through the foreign API, I can get back:
?- A = point{x:1, y:2}
A = point{x:1, y:2}

But:
?- A = point{x:1, y:2}.x

returns:

A = .(point{'x': 1, 'y': 2}, x)     

The retrieved term data is something like:

   PL_FUNCTOR( =, A ,PL_FUNCTOR( . ,  PL_DICT(point, x, 1, y, 2 ), x )  )

Yet when I run the same query in the swipl command-line tool:

?-  A = point{x:1,y:2}.x.
A = 1.

Does the swipl client unpack and apply the .x, or is it done internally and I’m reading the data out through the API incorrectly?

Hmmm … this seems to be caused by the way pyswip executes querys, which is more or less:

pyrun(GoalString,BindingList) :- 
      (atom_chars(Z,GoalString),
      atom_to_term(Z,Goal,BindingList),
      call(Goal))).

Whereas normally, we’d get variables bound to values:

?- pyrun("fact(X)",BindingList).
BindingList = ['X'=123].

for the dict query we get:

?- pyrun("A = point{x:1,y:2}.x.", BindingList).
BindingList = ['A'=point{x:1, y:2}.x].

… with A not correctly unified with the value 1.

It seems wrapping execution inside this pyrun broke something. Breaking the query down:

?- atom_chars(Z__,"X=point{x:1, y:2}.x"), atom_to_term(Z__,Goal,BindingList), call(Goal).
Z__ = 'X=point{x:1, y:2}.x',
Goal =  (point{x:1, y:2}.x=point{x:1, y:2}.x),
BindingList = ['X'=point{x:1, y:2}.x].

I thought perhaps call was incompatible with the dict syntax.

?- atom_chars(Z__,"X=point{x:1, y:2}.x"), atom_to_term(Z__,Goal,BindingList), X=point{x:1, y:2}.x.
Z__ = 'X=point{x:1, y:2}.x',
Goal =  (_17164=point{x:1, y:2}.x),
BindingList = ['X'=_17164],
X = 1.

but the following works fine:

?- Goal = (X=point{x:1, y:2}.x), call(Goal).
Goal =  (1=1),
X = 1.

… therefore, is some issue with the earlier part of the query?

Pwsip works this way because it makes it easy to load the PL_open_query() call with the predicate name pyrun, and the arguments list ["query_chars … ", ‘BindingList’). Without building the query the long-way, I don’t see a convenient way to execute dict querys via the foreign interface. Ideas?

The latest version comes with PL_get_dict_key() and a couple of more functions to deal with dicts from C. If your foreign interface does not support dicts the safest route is to do the dict <-> something translation in Prolog. Yes, dicts are compound terms, but there is no guarantee this never changes or the internal representation never changes (it did once already).

Hi @jan . Thank you. Separate to the foreign interface, the larger problem I’m having here is that the dot / . operator for dict is interfering with atom_to_term (I think):

?- atom_chars(Z,"X=point{x:1, y:2}.x"), atom_to_term(Z,Goal,BindingList), call(Goal).
Z = 'X=point{x:1, y:2}.x',
Goal =  (point{x:1, y:2}.x=point{x:1, y:2}.x),
BindingList = ['X'=point{x:1, y:2}.x]. 

which doesn’t unify BindingList = ['X'=1] as expected.

I’ll check out PL_get_dict_key once its in master (I assume its not in master yet, I don’t see similar functions here: https://github.com/SWI-Prolog/swipl/blob/6429a9cbdbca9cb807acc3c4fa40e7a67c08e4de/src/SWI-Prolog.h).

Dict evaluation is based on goal rewriting. That doesn’t happen in your code. See expand_goal/2.

It is in the development repository (swipl-devel.git) and already in the latest development release.

Worked perfectly. Thank you.