Open zhanwenchen opened 5 years ago
I have a monkey-patch for dicts deserialization. Replace these functions in easy.py
def getTerm(t, functor_to_constructor=None):
"""
:param t:
:param functor_to_constructor:
:return:
"""
if t is None:
return None
p = PL_term_type(t)
if p < PL_TERM:
res = _getterm_router[p](t)
elif PL_is_list(t):
res = getList(t, functor_to_constructor=functor_to_constructor,
visited=visited)
elif p == PL_DICT:
# assert PL_is_functor(t)
res = getDict(t
, functor_to_constructor=functor_to_constructor)
else:
res = getFunctor(t, functor_to_constructor=functor_to_constructor)
return res
def getDict(term, functor_to_constructor=None):
"""
Return t as a list.
"""
if isinstance(term, Term):
term = term.handle
elif not isinstance(term, (c_void_p, int)):
raise ArgumentTypeError((str(Term), str(int)), str(type(term)))
f = functor_t()
if PL_get_functor(term, byref(f)):
# get args
args = []
arity = PL_functor_arity(f.value)
# let's have all args be consecutive
a0 = PL_new_term_refs(arity)
for i, a in enumerate(range(1, arity + 1)):
if PL_get_arg(a, term, a0 + i):
args.append(getTerm(a0 + i,
functor_to_constructor=functor_to_constructor))
else:
raise Exception("Missing arg")
def pairwise(t):
it = iter(t)
return zip(it,it)
tag = args[0] # Dict Tag. Looks something like a class name.
d = {k.value:v
for v, k in pairwise(args[1:])}
if functor_to_constructor is not None \
and tag.value in functor_to_constructor:
# Treat the tag as a class name and the keys
# as named constructor parameters.
return functor_to_constructor[tag.value](**d)
return d
else:
res = getFunctor(term, functor_to_constructor=functor_to_constructor)
return res
... parsing the output is straightforward.
However, the bigger problems is that dict seem to misbehave with the .query call, which pyswip implements as:
pyrun(GoalString,BindingList) :-
(atom_chars(A,GoalString),
atom_to_term(A,Goal,BindingList),
call(Goal))).
Asserting this rountine in swipl, we can test it with dicts without data-marshalling concerns:
?- 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].
or more verbosely:
?- atom_chars(A__,"X=point{x:1, y:2}.x"), atom_to_term(A__,Goal,BindingList), call(Goal).
A__ = '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].
The vanilla swipl query without pyrun should be:
?- A = point{x:1,y:2}.x
A = 1.
so pyrun has changed the query somewhere and caused A not to be bound to 1 in the goal. :-(
Can anyone suggest a fix?
The output is
This behavior does not match Prolog's. In the SWI-Prolog terminal, the query
yields the result