Iker Olarra
Iker Olarra

Reputation: 85

Convert plain JSON to SWI-Prolog Dict

I have a simple rule in SWI-Prolog which I want to implement in an AWS Lambda function.

I will receive an Event in the following json form:

{
  "key1": "value1",
  "key2": "value2",
  "key3": "value3"
}

My problem is that I can only read from atom-like arrays or json files but not plain json in a compound form.

What I would like to do is something like this:

lambda_handler(Event, Context, Response) :-
    atom_json_dict(Event, Dict, []),
    my_simple_rule(Dict.key1, Dict.key2, Dict.key3),
    Response = '{"result": "yes"}'.

my_simple_rule is a condition which returns true or false depending on the values passed.

What I've tried so far does not work because SWI-Prolog expects either a Stream o a String when using atom_json_term/3, json_read/2,3 or json_read_dict/2,3.

I also tried to force the JSON into a string this way:

format(atom(A), "~w", {"key1": "value1", "key2": "value2", "key3":"value3"}).

Expecting this so that I can then convert it to a Term (Prolog dict):

{"key1": "value1", "key2": "value2", "key3":"value3"}

But the result is the following:

'{key1:value1,key2:value2,key3:value3}'

Which fails.

Does any one know how I can use a plain JSON within Prolog?

Upvotes: 1

Views: 378

Answers (2)

Iker Olarra
Iker Olarra

Reputation: 85

So... I was wrong about how SWI-Prolog handles the Event json in Lambda, so I will post my findings here in case someone encounters a similar challenge.

At first I though that the Event json arrived like this: {"key1": 1, "key2": 2, "key3": 3}.

However, it looks a little more like this: json([key1=1, key2=2, key3=3]. Which makes the parsing task different.

To solve it I used the following code which I hope will be self explanatory:

:- use_module(library(http/json)).
:- use_module(library(http/json_convert)).

% use this to test locally. If it works this way i should work in lambda:
handler(json([key1=10, key2=2, key3=3]), _, Response).


% Function handler
handler(json(Event), _, Response) :-

    json_to_prolog(json(Event), Json_term), % I transform the event json into a prolog term

    atom_json_term(A, Json_term, []), % I convert the JSON_term into an atom

    atom_json_dict(A, Dicty, []), % I convert the atom into a dict

    my_simple_function(Dicty.key1, Dicty.key2, Dicty.key3, Result), % Function evaluation

    json_to_prolog(json([result_key1="some_message", result_key2=Result]), Result_json), % Transform json term into actual json

    atom_json_term(Response, Result_json, []). % Transform json into atom so that lambda does not complain


my_simple_function(N1, N2, N3, Result) :-
    
    Result is N1 + N2 + N3.

The input needed (your test json in lambda) would be:

{
  "key1": 1,
  "key2": 2,
  "key3": 3
}

While the output should look like this:

{
  "result_key1": "some_message",
  "result_key2": 6
}

I hope this works as a template to use SWI-Prolog on AWS.

By the way, I recommend you take a look to this repository to make your custom Prolog runtime for Lambda.

Upvotes: 0

CapelliC
CapelliC

Reputation: 60004

Event it's already a structured term, so here is an 'ad hoc' adapter. Let's say we have a file j2d.pl containing

:- module(j2d,
          [ j2d/2
          ]).

j2d(Event,Dict) :-
    Event={CommaSequence},
    l2d(CommaSequence,_{},Dict).

l2d((A,R),D,U) :- !, updd(A,D,V), l2d(R,V,U).
l2d(A,D,U) :- updd(A,D,U).

updd(K:V,D,U) :- atom_string(A,K), put_dict(A,D,V,U).

then it's possible to test the code from the SWI-Prolog console:

?- use_module(j2d).
true.

?- Event={
"key1": "value1",
"key2": "value2",
"key3": "value3"
}.
Event = {"key1":"value1", "key2":"value2", "key3":"value3"}.

?- j2d($Event,Dict).

Dict = _14542{key1:"value1", key2:"value2", key3:"value3"},
Event = {"key1":"value1", "key2":"value2", "key3":"value3"}.

The unusual $Event syntax it's an utility of the console (a.k.a REPL), that replaces the variable Event with its last value (a.k.a binding).

Your code could become

:- use_module(j2d).

lambda_handler(Event, Context, Response) :-
    j2d(Event,Dict),
    my_simple_rule(Dict.key1, Dict.key2, Dict.key3),
    Response = '{"result": "yes"}'.

Upvotes: 2

Related Questions