Formatting nested Prolog output

71 Views Asked by At

I am working with a Prolog database that has a set of entities with properties and values. I would like to output every entity along with each of its properties and values.

I'm very new to Prolog, and I have something that gives me the information I need, but I need it to be formatted in a specific way.

First, I need the property value to be wrapped in quotations.

Second, I would like to have indentation and newlines to make it more readable, but this part isn't 100% necessary.

Here is a toy version:

% example objects
instanceOf(ball_1, physicalObject).
instanceOf(ball_2, physicalObject).
instanceOf(block_1, physicalObject).


% example properties
propertyOf(color_ball_1, ball_1).
propertyOf(size_ball_1, ball_1).

propertyOf(color_ball_2, ball_2).
propertyOf(size_ball_2, ball_2).

propertyOf(color_block_1, block_1).
propertyOf(size_block_1, block_1).


% example property values
hasValue(color_ball_1, red).
hasValue(size_ball_1, big).

hasValue(color_ball_2, blue).
hasValue(size_ball_2, small).

hasValue(color_block_1, red).
hasValue(size_block_1, small).

(Note: I am unable to change the actual database, so let's assume the facts have to be represented as they are.)

Here are my functors for getting all of the objects along with their properties and values:

% find all properties and values for one object
findEveryPropertyWithValue(Object, Properties) :-
    % get one object ...
    instanceOf(Object, physicalObject),

    % find every property of every object
    findall((Property, Value), (propertyOf(Property, Object), hasValue(Property, Value)), Properties).


% find all objects with properties and values
findAllObjects(Objects_and_Properties) :-
    % find every physicalObject with its Properties and Values
    findall((Obj, Properties), (instanceOf(Obj, physicalObject), findEveryPropertyWithValue(Obj, Properties)), Objects_and_Properties).

If I just run findEveryPropertyWithValue then it's readable, but I don't have quotes around the property values:

?- findEveryPropertyWithValue(Obj, Props).
Obj = ball_1,
Props = [(color_ball_1, red), (size_ball_1, big)] ;
Obj = ball_2,
Props = [(color_ball_2, blue), (size_ball_2, small)] ;
Obj = block_1,
Props = [(color_block_1, red), (size_block_1, small)].

But in that case I need to ask Prolog to keep finding solutions manually, and I want them all at once, which is what findAllObjects is for, but the output isn't readable and again lacks the quotations:

?- findAllObjects(Objs).
Objs = [(ball_1, [(color_ball_1, red), (size_ball_1, big)]), (ball_2, [(color_ball_2, blue), (size_ball_2, small)]), (block_1, [(color_block_1, red), (size_block_1, small)])].

This is what I would like the output to look like:

Objs = [
    (ball_1, 
        [
            (color_ball_1, "red"), 
            (size_ball_1, "big")
        ]
    ), 
    (ball_2, 
        [
            (color_ball_2, "blue"), 
            (size_ball_2, "small")
        ]
    ), 
    (block_1, 
        [
            (color_block_1, "red"), 
            (size_block_1, "small")
        ]
    )
].

The indentation and newlines aren't strictly necessary, but it would be nice. But the quotations are a must and I am struggling to figure out how to use format/2 to make this work.

Here is one thing I tried:

formatSandbox(Formatted) :-
    findall((Object), instanceOf(Object, idPhysicalObject), Objects),

    forall(Objects, format("Here is an object: ~q", [Object])).

It's clearly very wrong because this is my output:

?- formatSandbox(X).
ERROR: source_sink `ball_1' does not exist
ERROR: source_sink `ball_2' does not exist
ERROR: source_sink `block_1' does not exist
Here is an object: _50

What I thought I was doing was saying "for everything in Objects, tell me what it is" but I don't know how to refer to the "current object," which is why I just put [Object], but it's not right.

Any help appreciated!

2

There are 2 best solutions below

0
slago On

You can generate the desired output with the following code:

format_property_value((Property, Value), Atom) :-
    format(atom(Atom), '(~w, "~w")', [Property, Value]).

format_property_value_list(PropertyValueList, Atom) :-
    maplist(format_property_value, PropertyValueList, AtomicList),
    atomic_list_concat(AtomicList, ',\n            ', Atom0),
    format(atom(Atom), '        [\n            ~w\n        ]', Atom0).

format_object_properties((Object, Properties), Atom) :-
    format_property_value_list(Properties, Atom0),
    format(atom(Atom), '    (~w,\n~w\n    )', [Object, Atom0]).

format_object_properties_list(ObjectPropertiesList, Atom) :-
    maplist(format_object_properties, ObjectPropertiesList, AtomicList),
    atomic_list_concat(AtomicList, ',\n', Atom0),
    format(atom(Atom), '[\n~w\n]', Atom0).

print_all_objects :-
    findAllObjects(ObjectPropertiesList),
    format_object_properties_list(ObjectPropertiesList, Atom),
    writeln(Atom).

For example:

?- format_property_value((color,red), Atom).
Atom = '(color, "red")'.

?- format_property_value_list([(color,red), (size,small)], Atom).
Atom = '        [\n            (color, "red"),\n            (size, "small")\n        ]'.

?- print_all_objects.
[
    (ball_1,
        [
            (color_ball_1, "red"),
            (size_ball_1, "big")
        ]
    ),
    (ball_2,
        [
            (color_ball_2, "blue"),
            (size_ball_2, "small")
        ]
    ),
    (block_1,
        [
            (color_block_1, "red"),
            (size_block_1, "small")
        ]
    )
]
true.
0
damianodamiano On

You can write something like this:

pair_print([]).
pair_print([(A,B)]):- !,
    term_string(B,S),
    format('~2t(~w,~p)~n',[A,S]).
pair_print([(A,B)|T]):-
    term_string(B,S),
    format('~2t(~w,~p),~n',[A,S]),
    pair_print(T).

my_print([]).
my_print([(O,LP)|T]):-
    format('(~w,~n[~n',O),
    pair_print(LP),
    format(']~n)~n'),
    my_print(T).
?- findAllObjects(Objs), my_print(Objs).
(ball_1,
[
(color_ball_1,"red"),
(size_ball_1,"big")
]
)
(ball_2,
[
(color_ball_2,"blue"),
(size_ball_2,"small")
]
)
(block_1,
[
(color_block_1,"red"),
(size_block_1,"small")
]
)

Then you can add indentation and so on...