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 it's not readable to look at and it also is likely pretty inefficient.
Primarily, I'm wondering how to display the information more nicely, but also any obvious ways to make it more efficient would be very helpful too.
Here is a toy version of my database:
% 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).
(Side note: I don't love the way this is stored, it feels clunky that I have
color_ball_2 as opposed to anything that is a
physicalObject just having a
color, but I don't know how to go about doing that properly in Prolog.)
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 I get an okay format, but it could be better displayed to show each property on its own line or something:
?- 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 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 is even less readable:
?- 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)])].
How do I get a more readable output while still getting every solution in one call?
(And any notes on how to make the overall implementation better are very welcome!)
Logtalk (which you can run with most Prolog systems) provides straight-forward representation solutions. For example:
:- category(physical_object). :- public(color/1). color(black). :- public(size/1). size(tiny). :- end_category. % example objects :- object(ball_1, imports(physical_object)). color(red). size(big). :- end_object. :- object(ball_2, imports(physical_object)). color(blue). size(small). :- end_object. :- object(block_1, imports(physical_object)). color(red). size(small). :- end_object.
Notice that the
physical_object category provides default values for the color and size properties. Other representation are possible, including more compact/space-efficient ones. It would help to know how many objects and how many properties per object for an informed choice.
Query the objects is similar. For example:
% find all properties and values for one object find_property_value_pairs(Object, Pairs) :- imports_category(Object, physical_object), findall( Property-Value, ( Object::current_predicate(Property/1), functor(Template, Property, 1), Object::Template, arg(1, Template, Value) ), Pairs ). % find all objects with properties and values find_all_object_property_pairs(Pairs) :- findall( Object-Properties, find_property_value_pairs(Object, Properties), Pairs ).
Note, however, that querying and displaying of solutions is orthogonal. For example:
?- forall(find_property_value_pairs(Object, Pairs), format('~q - ~q~n', [Object, Pairs])). ball_1 - [color-red,size-big] ball_2 - [color-blue,size-small] block_1 - [color-red,size-small] true.