Doposud jsme s Prologem pracovali jako s dialogem. Zeptali jsme se, on našel jedno řešení. Pokud jsme chtěli další, museli jsme říct "dál" (středník). Ale co když chceme seznam všech řešení najednou? Třeba chceme spočítat průměrnou známku ve třídě, nebo vypsat všechny studenty, kteří propadají. K tomu slouží speciální nástroje zvané meta-predikáty.
Představte si, že lovíte ryby. Backtracking je jako chytání na udici – vytáhnete jednu rybu, pak druhou. Predikát findall je jako hození velké sítě. Vytáhnete všechny ryby najednou a máte je v jednom velkém pytli (seznamu).
findall(Co, Podminka, Seznam), který najde všechna řešení Podminky a uloží výsledky (ve tvaru Co) do Seznamu.
Příklad: Kdo má rád pizzu?
ma_rad(petr, pizza).
ma_rad(jana, pizza).
ma_rad(karel, pizza).
ma_rad(eva, sushi).
% Chceme seznam všech lidí, kteří mají rádi pizzu.
?- findall(X, ma_rad(X, pizza), Milovnici).
Milovnici = [petr, jana, karel].
findall je skvělý, ale někdy je "hloupý". Bere všechno, včetně duplicit, a netřídí to. Pokud chcete chytřejší síť, použijte:
bagof (Bag of solutions): Podobné jako findall, ale umí seskupovat výsledky podle jiných proměnných.setof (Set of solutions): Nejchytřejší verze. Výsledný seznam seřadí a odstraní duplicity. (Jako matematická množina).Příklad: Známky
znamka(petr, 1).
znamka(petr, 1). % Petr dostal dvě jedničky
znamka(jana, 2).
?- findall(Z, znamka(petr, Z), S).
S = [1, 1]. % Seznam všech známek
?- setof(Z, znamka(petr, Z), S).
S = [1]. % Množina známek (duplicity zmizely)
Meta-predikáty nám umožňují přejít od "hledání jehly v kupce sena" k "práci s celou kupkou". Díky nim můžeme dělat statistiku, součty, průměry a hromadné operace nad daty.
findall, když žádné řešení neexistuje? (Vrátí prázdný seznam []. To je důležité – neselže, jen řekne "nic jsem nechytil").findall a setof? Kdy byste použili který?znamka(Student, Predmet, Znamka). Použijte findall k vytvoření seznamu všech studentů, kteří dostali jedničku z matematiky.findall a predikát length (délka seznamu) k tomu, abyste zjistili, kolik jedniček bylo celkem uděleno.