as I got critic concerning my data structure in Prolog I asked here the experts for alternative solutions.
As example, I have a data set of recipe decription in XML
<recipeml fileversion="13.8.2014">
<recipe>
<head>
<title>Green Soup</title>
</head>
<ing-div type="titled">
<title>soup</title>
<ingredients>
<ing>
<amt><qty>500</qty><unit>gramm</unit></amt>
<item>pea</item>
</ing>
<ing>
<amt><qty>200</qty><unit>ml</unit></amt>
<item>cream</item>
</ing>
...
</ingredients>
</ing-div>
<directions>
<step>Do something, cooking ....</step>
<step>Next do again something...</step>
...
</directions>
</recipe>
<recipe>
...
</recipe>
...
</recipeml>
I choose to store it in Prolog as iterative element-tree using lists:
database([element('recipeml',[version=0.5],
[element('recipe',[],
[element('head',[],
[element('title',[],['Green Soup']
)]
),
element('ing-div',[type=titled],
[element('title',[],['soup']),
element('ingredients',[],
[element(ing,[],
[ element(amt,[],
[ element(qty,[],['500']), element(unit,[],[gramm]),]),
element(item,[],['pea'])
]),
element(ing,[],
[ element(amt,[],
[ element(qty,[],['200']), element(unit,[],[ml]),]),
element(item,[],['pea'])
])
]
)]
)]
),
element('recipe',[],...
)]
)]).
What I want to do is to look easily for recipes based on user input. The user might give an ingredient or part of the recipe name as input.
Actually I ran throught the elements by
ask_element(Name, Child, Parent) :-
(
member( element(Name,_,Child),Parent)
;
member( element(_,_,NewParent),Parent),
[_|_] = NewParent,
ask_element(Name, Child, NewParent)
).
I got all recipes with a special ingredient by
findall(RTitle,
(
ask_element('recipe',RKnot,Knot),
ask_element('item',TmpIng,RKnot),
contains(TmpIng,Ingredient),
[Ing|_] = TmpIng, % avoid brackets [Egg]
define_xml_knot(['head','title'],_,RKnot,TmpRTitle),
[RTitle|_] = TmpRTitle % avoid brackets [Soup]
,Bag),
My result is then a list of the recipes titles. If a list of ingredients is entered I need a second analysing step to get the recipe with the most matching ingredients. Maybe this is not really Prolog style?
One idea, following the remark by Paulo Moura (thanks), is to arrange the data as
recipe(IDnumber,'Green Soup',ingredients(item(500,gramm,'pea'),item(200,ml,'cream')),steps('Do something','Next step do again something')).
I am not sure if this would be really help. Looking for a recipe with a certain ingredient I have to look again step by step in each recipe through every item if the ingredient I am looking for (or part of the word) is contained. And if I want to add a new descriptor, e.g. "level(easy)
" I have to change all data calls as the number of element in recipe()
changes. With the element(element...)
construction I do not have to change the calls.
But the response would be better, by returning only the IDnumber, then I get the whole recipe in one "call" (recipe(123,X,Y,Z)
) for further processing. Actually I
return as response "string text in a list" as you see it in "Bag" above...
It is my first application in Prolog, so I am not very familiar with an adquate data storing. I would be grateful for every hint.
recipe(IDnumber,'Green Soup',ingredients([item(500,gramm,'pea'),item(200,ml,'cream')]),steps(['Do something','Next step do again something'])).
. Having ingredients and steps as compound terms with recipe-depending arity would just complicate processing for no benefit. This will also mirror more closely the XML structure you present (assuming that's your intention). – Paulo Moura