pyswip icon indicating copy to clipboard operation
pyswip copied to clipboard

Atom names changed when querying lists

Open ZvikaZ opened this issue 6 years ago • 3 comments

I'm Using Python 3.7.4, Pyswip from PIP. There seems to be a problem with Prolog atom names in lists.

Prolog code:

problem(Board) :-
    Board = [black].

Python code:

prolog = Prolog()
prolog.consult("main.pl")
print(list(prolog.query("problem(X)")))

returns: [{'X': [Atom('413701')]}]

If I change [black]. to black, it works OK.

ZvikaZ avatar Oct 03 '19 04:10 ZvikaZ

Hello,

A good starting point is to format your result, as seen at https://github.com/targodan/jupyter-swi-prolog/blob/master/jswipl/swipl.py.

from pyswip import Prolog
from pyswip import Functor


def format_value(value):
    output = ""
    if isinstance(value, list):
        output = "[ " + ", ".join([format_value(val) for val in value]) + " ]"
    elif isinstance(value, Functor) and value.arity == 2:
        output = "{0}{1}{2}".format(value.args[0], value.name, value.args[1])
    else:
        output = "{}".format(value)

    return output


def format_result(result):
    result = list(result)

    if len(result) == 0:
        return "false."

    if len(result) == 1 and len(result[0]) == 0:
        return "true."

    output = ""
    for res in result:
        tmpOutput = []
        for var in res:
            tmpOutput.append(var + " = " + format_value(res[var]))
        output += ", ".join(tmpOutput) + " ;\n"
    output = output[:-3] + " ."

    return output


prolog = Prolog()
prolog.consult("main.pl")
answer = list(prolog.query("problem(X)"))
print(format_result(answer))

returns: X = [ black ] .

@yuce maybe this should be included on pyswip, or be better documented.

Best, Theodore

tmitsi avatar Oct 04 '19 20:10 tmitsi

Thanks for this code. But it returns a string, that looks like a Python list in its content, but it's not a Python list.

I would expect it to return a list of strings.

I.e., X = ['black']

ZvikaZ avatar Oct 24 '19 08:10 ZvikaZ

Based on @MitsiCash 's answer, I'm using this code:

def atoms_to_strings(answer):
    if isinstance(answer, dict):
        result = {}
        for k in answer.keys():
            result[k] = atoms_to_strings(answer[k])
    elif isinstance(answer, list):
        result = [atoms_to_strings(val) for val in answer]
    elif isinstance(answer, Atom):
        result = answer.value
    elif isinstance(answer, int) or isinstance(answer, str):
        result = answer
    else:
        print("Unsupported result from Prolog: " + str(type(answer)) + str(answer))
    return result

I assume it might help others as well, @yuce , please incorporate this, or something similar.

Thanks

ZvikaZ avatar Oct 27 '19 09:10 ZvikaZ