title: Knowledge representation in Prolog - how to store data?
body: <p>as I got critic concerning my data structure in Prolog I asked here the experts for alternative solutions.</p>
  
  <p>As example, I have a data set of recipe decription in XML</p>
  
  <pre><code>&lt;recipeml fileversion="13.8.2014"&gt;
    &lt;recipe&gt;
      &lt;head&gt;
        &lt;title&gt;Green Soup&lt;/title&gt;
      &lt;/head&gt;
      &lt;ing-div type="titled"&gt;
          &lt;title&gt;soup&lt;/title&gt;
          &lt;ingredients&gt;
            &lt;ing&gt;
              &lt;amt&gt;&lt;qty&gt;500&lt;/qty&gt;&lt;unit&gt;gramm&lt;/unit&gt;&lt;/amt&gt;
              &lt;item&gt;pea&lt;/item&gt;
            &lt;/ing&gt;
            &lt;ing&gt;
              &lt;amt&gt;&lt;qty&gt;200&lt;/qty&gt;&lt;unit&gt;ml&lt;/unit&gt;&lt;/amt&gt;
              &lt;item&gt;cream&lt;/item&gt;
            &lt;/ing&gt;
            ...
          &lt;/ingredients&gt;
      &lt;/ing-div&gt;  
      &lt;directions&gt;
        &lt;step&gt;Do something, cooking ....&lt;/step&gt;
        &lt;step&gt;Next do again something...&lt;/step&gt;
        ...
      &lt;/directions&gt;
    &lt;/recipe&gt;
    &lt;recipe&gt;
     ...
    &lt;/recipe&gt;
    ...
  &lt;/recipeml&gt;
  </code></pre>
  
  <p>I choose to store it in Prolog as iterative element-tree using lists:</p>
  
  <pre><code>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',[],...
      )] 
  )]).
  </code></pre>
  
  <p>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.</p>
  
  <p>Actually I ran throught the elements by</p>
  
  <pre><code>ask_element(Name, Child, Parent) :-
          (
              member( element(Name,_,Child),Parent)
          ;
              member( element(_,_,NewParent),Parent),
              [_|_] = NewParent,
              ask_element(Name, Child, NewParent)
          ).
  </code></pre>
  
  <p>I got all recipes with a special ingredient by</p>
  
  <pre><code> 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),
  </code></pre>
  
  <p>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?</p>
  
  <p>One idea, following the remark by Paulo Moura (thanks), is to arrange the data as</p>
  
  <pre><code>recipe(IDnumber,'Green Soup',ingredients(item(500,gramm,'pea'),item(200,ml,'cream')),steps('Do something','Next step do again something')).
  </code></pre>
  
  <p>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. "<code>level(easy)</code>" I have to change all data calls as the number of element in <code>recipe()</code> changes. With the <code>element(element...)</code> 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" (<code>recipe(123,X,Y,Z)</code>) for further processing. Actually I 
  return as response "string text in a list" as you see it in "Bag" above... </p>
  
  <p>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.</p>