I have problems using setof/3
, some results are missing.
The context:
I load a xml-file using SWI-Prolog load_xml() to get a recursive
list element (see testelement in the example). Then I want to look
up specific elements in this list (in the xml tree).
Using findall/3
combined with sort/2
, it works fine. But if
I use setof/3
, I miss one result. I suppose that setof/3
has problems due
to the recursive call in askElement/3
to get/keep the elements? Knows anyone another
solution to get the elements out of the recursive list?
My test code:
testElement([element('recipeml',[version=0.5],
[element('recipe',[],
[element('head',[],
[element('title',[],['Spaghetti Bolognese']
)]
),
element('ing-div',[type=titled],
[element('title',[],['sauce']),
element('ingredients',[],
[element('ing',[],
[element('item',[],['hackfleisch']),
element('item',[],['fleischtomaten']),
element('item',[],['zwiebeln']),
element('item',[],['sellerie']
)]
)]
)]
)]
),
element('recipe',[],
[element('head',[],
[element('title',[],['Erbsensuppe']
)]
),
element('ing-div',[type=titled],
[element('title',[],['elementar']),
element('ingredients',[],
[element('ing',[],
[element('item',[],['sahne']),
element('item',[],['erbsen']),
element('item',[],['gemüsebrühe']
)]
)]
)]
)]
)]
)]).
askElement(Name, Child, Parent) :-
(
member( element(Name,_,Child),Parent)
;
member( element(_,_,NewParent),Parent),
[_|_] = NewParent,
askElement(Name, Child, NewParent)
).
allRecipes_findall(RecipeName) :-
testElement(Knot),
findall(TmpR,(askElement('head',HKnot,Knot),askElement('title',TmpR,HKnot)),Bag),
sort(Bag, RecipeName).
allRecipes_setof(RecipeName) :-
testElement(Knot),
setof(TmpR,(askElement('head',HKnot,Knot),askElement('title',TmpR,HKnot)),RecipeName).
My Output:
3 ?- allRecipes_findall(X).
X = [['Erbsensuppe'], ['Spaghetti Bolognese']].
4 ?- allRecipes_setof(X).
X = [['Erbsensuppe']]
I expected that in both case I get
X = [['Erbsensuppe'], ['Spaghetti Bolognese']].
What's wrong?
Many thanks in advance!
PS: Every comment/review of my (first try of) Prolog code is very welcome :}
The standard setof/3
predicate gives you a solution per each different instantiation of the free variables in the goal. Using your code as-is gives:
?- allRecipes_findall(X).
X = [['Erbsensuppe'], ['Spaghetti Bolognese']].
?- allRecipes_setof(X).
X = [['Erbsensuppe']] ;
X = [['Spaghetti Bolognese']].
That's the expected result. You can, however, make setof/3
ignore the free variables by existentially quantifying them using the ^/2
operator:
allRecipes_setof(RecipeName) :-
testElement(Knot),
setof(TmpR,HKnot^(askElement('head',HKnot,Knot),askElement('title',TmpR,HKnot)),RecipeName).
With this change you'll get the same result as with the findall/3
predicate:
?- allRecipes_setof(X).
X = [['Erbsensuppe'], ['Spaghetti Bolognese']].
Regarding comments on your programming style, use underscores instead of CamelCase in atoms for code readability. E.g. ask_element
instead of askElement
. For variables, on the other hand, CamelCase is often used.