question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

JS-Tau Interop Issues + Proposal

See original GitHub issue

Tau’s js module auto-converts JS strings to atoms:

%% Assume: window.foo = "hello"
?- prop(foo, Foo).
Foo = hello.

This is great. However, booleans also get converted to atoms. This causes both a string and a boolean to unify in Tau:

%% Assume: window.foo = false
%% Assume: window.bar = "false"
?- prop(foo, Foo), prop(bar, Bar), Foo = Bar.
Foo = false, Bar = false.

Similarly, null gets auto converted to an empty list in json_prolog:

%% Assume: window.myObj = { a: null, b: [], c: undefined }
?- prop(myObj, O), json_prolog(O, X).
O = <javascript>(object), X = [a-[],b-[],c-_].

As seen above, undefined gets assigned to an unbound variable, which will certainly cause logic bugs since it unifies with anything.


The main issue with these conversions is:

  1. You can’t differentiate one type from another when reading JS values
  2. When creating JS objects, there’s no way to specify true/false, null, or undefined

Proposal

Instead of converting to the above values, convert to the following instead:

JS Tau
true {true}
false {false}
null {null}
undefined {undefined}

Benefits:

  • No ambiguity
  • Works bidirectionally (Tau -> JS; JS -> Tau)
  • Doesn’t take up operator space
  • Low chance of conflict with other Prolog code

What do you think?

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:2
  • Comments:11 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
triskacommented, Mar 11, 2022

Yes, this is the approach used by the two other most recent Prolog systems, Scryer Prolog and Trealla Prolog: They store a string very compactly internally (as a sequence of raw bytes in UTF-8 encoding), and Prolog programs “see” it as a list of characters.

In the case of Tau Prolog, a string could be represented as a JavaScript string in the engine, and still appear as a list of characters to Prolog programs. This would be an ideal approach, combining the memory-efficiency of strings with the convenience of being able to reason about strings with DCGs and common predicates over lists.

0reactions
guregucommented, May 31, 2022

If anyone needs this feature now, here’s a “module” that monkey-patches in support. It doesn’t handle the undefined case. I wrote it before finding this issue, apologies for the duplicated effort.

function betterJSON(pl, functor = "{}") {
  // JS → Prolog
  pl.fromJavaScript.conversion.boolean = function(obj) {
    return new pl.type.Term(functor, [
      new pl.type.Term(obj ? "true" : "false", [])
    ]);
  };
  const js2term = pl.fromJavaScript.conversion.object;
  pl.fromJavaScript.conversion.object = function(obj) {
    if (obj === null) {
      return new pl.type.Term(functor, [
        new pl.type.Term("null", [])
      ]);
    }
    return js2term.apply(this, arguments);
  };

  // Prolog → JS
  const term2js = pl.type.Term.prototype.toJavaScript;
  pl.type.Term.prototype.toJavaScript = function() {
    if (this.indicator == functor + "/1") {
      switch (this.args[0].indicator) {
        case "true/0": return true;
        case "false/0": return false;
        case "null/0": return null;
        case "undefined/0": return undefined;
      }
    }
    return term2js.apply(this, arguments);
  };
}

At first thought it would be nice to get SWI compatibility and use @/1, but I agree with @gilbert’s proposal that {}/1 is more ergonomic.

Tangentially related, I think it would be nice if json_atom/2 could take a Prolog object as its first argument as well as a JS object, or if there was some other way to convert directly from Prolog → JSON atom/string instead of needing to pass around the native object. It’s trivial to work around at the moment, so definitely not a dire need, but would make things a little easier to use IMO.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Proposal for a European Interoperability Framework for Smart ...
The European Commission actively supports local administrations and other actors with challenges related with interoperability services to ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found