Problem with unicode characters (e.g. →) in prolog file on swiplserver

I have some simple prolog file logic.pl introducing some operator with unicode characters:

:-op(803, xfy, →).

binary_connective(X  → Y, X, Y).

The problem now is, that my python query does not work on that operator:

from swiplserver import PrologMQI, PrologThread

with PrologMQI() as mqi:
    with mqi.create_thread() as prolog_thread:
    	prolog_thread.query(f"consult('logic.pl').")
    	prolog_thread.query_async("binary_connective(p  → q, X, Y).",
                                  find_all=False)
    	while True:
    		result = prolog_thread.query_async_result()
    		if result is None:
    			break
    		else:
    			print(result)

If I change → in – it gives me some working result.

Is their some way to solve this in swiplserver libary?

I also made some post on this site (Problem with unicode characters (e.g. →) in prolog file · Issue #14 · SWI-Prolog/packages-mqi · GitHub)

What is the error you see when you run the query from Python?

Also: Does it work if you run it from the top level (it should (almost) always work the same if you are using the MQI library)? I.e.:

?- consult('logic.pl').
true

?- binary_connective(p  → q, X, Y).
????

Edit: If I try putting your code, exactly as you have it above, in a logic.pl file and consulting it, I get the following error. I may have missed some magic unicode incantation though, I haven’t done anything with unicode and SWI Prolog before:

ERROR: logic.pl:1:17: Syntax error: illegal_character
ERROR: logic.pl:3:21: Syntax error: Operator expected
true.

Hello,
thank you for your response. I don’t get some error if I put the predicate directly into swipl with
SWI-Prolog version 8.2.4 for x86_64-linux.

My prolog file simply contains the following content

:-op(803, xfy, →).

binary_connective(X  → Y, X, Y).

My output in swipl is:

?- consult('logic.pl').
true.

?- binary_connective(p → q, X, Y).
X = p,
Y = q.

I also tested it on https://swish.swi-prolog.org/ and it worked exactly the same.

If I run the query from Python I don’t get some error. It seems the program stucks at some point in some endless loop.

How can I run the program from toplevel? Did you mean use:

from swiplserver import PrologServer, PrologThread

with PrologServer() as server:
    with server.create_thread() as prolog_thread:
        prolog_thread.query("consult('logic.pl').")
        result = prolog_thread.query("binary_connective(p → q, X, Y).")
        print(result)

This doesn’t work, cause of error
ImportError: cannot import name ‘PrologServer’ from ‘swiplserver’ (/home/~/.local/lib/python3.9/site-packages/swiplserver/init.py)

It seams the __init__.py looks like this:

from swiplserver.prologmqi import (
    PrologMQI,
    PrologThread,
    PrologError,
    PrologLaunchError,
    PrologQueryTimeoutError,
    PrologQueryCancelledError,
    PrologConnectionFailedError,
    PrologResultNotAvailableError,
    PrologNoQueryError,
    is_prolog_variable,
    is_prolog_list,
    is_prolog_functor,
    is_prolog_atom,
    create_posix_path,
    prolog_name,
    prolog_args,
    quote_prolog_identifier,
    json_to_prolog,
)

# make "from swiplserver import *" work
__all__ = [
    "PrologLaunchError",
    "PrologQueryTimeoutError",
    "PrologQueryCancelledError",
    "PrologConnectionFailedError",
    "PrologResultNotAvailableError",
    "PrologNoQueryError",
    "PrologError",
    "PrologMQI",
    "PrologThread",
    "create_posix_path",
    "is_prolog_functor",
    "is_prolog_list",
    "is_prolog_variable",
    "is_prolog_atom",
    "prolog_name",
    "prolog_args",
    "quote_prolog_identifier",
    "json_to_prolog",
]

I am able to replicate the hang you are hitting on my mac if I do the below. On my mac, at least, I need to set the Prolog encoding to utf8 in order to load the logic.pl file properly:

with PrologMQI() as mqi:
	with mqi.create_thread() as prolog_thread:
		prolog_thread.query(f"set_prolog_flag(encoding,utf8).")
		prolog_thread.query(f"consult('logic.pl').")
		unicode = "binary_connective(p → q, X, Y)."
		prolog_thread.query(unicode)

The problem is a bug in the swiplserver library that sends the wrong count of characters to Prolog. I was able to fix the hang with the below change to the prologmqip.py file that is part of the library. I need to do some more research to make sure this is a good overall fix but I think it should unblock you for the moment. I’ll post when I have the final fix.

    def _send(self, value):
        value = value.strip()
        value = value.rstrip("\n.")
        value += ".\n"
        _log.debug("PrologMQI send: %s", value)
        utf8Value = value.encode("utf-8")

        # Comment out this line:
        # msgHeader = f"{str(len(utf8Value))}.\n".encode("utf-8")

        # Replace with this line:
        msgHeader = f"{str(len(value))}.\n".encode("utf-8")

        self._socket.sendall(msgHeader)
        self._socket.sendall(utf8Value)
3 Likes

Thank you, with that replacement it seems to be correct for me too.

I have submitted a more comprehensive fix to both the server and the Python client, but the client fix is basically what I posted above, the submitted fix just works against the existing MQI interface and the new fixed one. It also includes a really simple protocol versioning “feature” to more robustly handle versioning issues going forward.

I’ll push the Python library 1.0.2 to pypi.org early next week.

Thanks! Updated the git submodule.

1 Like

Thank you I have closed the GitHub issue.

Thanks! You can now pip install swiplserver and get the latest version (1.0.2) with the above fix in it.

3 Likes