Challenge 3: findall vs. setof With a Duplicate Fact — Possible Solution ==================================================================== family.pl: parent(tom, bob). parent(tom, liz). parent(bob, ann). parent(bob, pat). parent(liz, jim). parent(pat, bob). % added duplicate -- bob already appears above as tom's child Query 1 -- findall, no deduplication or sorting: ?- findall(Child, parent(_, Child), All). All = [bob, liz, ann, pat, jim, bob]. Query 2 -- setof, sorted and deduplicated: ?- setof(Child, Parent^parent(Parent, Child), Sorted). Sorted = [ann, bob, jim, liz, pat]. -- Comparing the two results -- -- -- findall's list is six items long and keeps BOTH occurrences of -- bob (once from tom, once from the new pat fact), in whatever order -- the facts were tried -- exactly the raw trace of the search, kept -- faithfully, duplicates and all. setof's list is only five items, -- with bob appearing just once despite two different facts producing -- it, and the items come back in alphabetical order (ann, bob, jim, -- liz, pat) rather than fact-declaration order. This is setof's own -- two extra guarantees beyond bagof's grouping behavior -- sorted -- standard order of terms, and duplicates collapsed into a single -- occurrence -- neither of which findall or plain bagof ever provide. WHY THIS WORKS AS AN ANSWER ------------------------------ This deliberately introduces a genuine duplicate into the database so the contrast is real rather than coincidental, then shows findall faithfully preserving both the duplicate and the raw search order against setof's sorted, deduplicated result, directly demonstrating the two guarantees that set setof apart from bagof and findall.