name = 'permute/2' slug = 'Generiraj permutacije elementov v seznamu' description = '''\
permute(L1, L2)
: seznam L2
je permutacija vrstnega reda elementov v seznamu L1
.
?- permute([1,2,3], L). L = [1,2,3] ; L = [1,3,2] ; L = [2,1,3] ; L = [2,3,1] ; L = [3,1,2] ; L = [3,2,1].''' plan = ['''\
Poskusi rekurzirvno pripraviti eno možnost, a pusti prologu svobodo. Le-ta bo potem sam od sebe vračal vse možne rešitve.
''', '''\Možnosti je več, a ena je naslednja: kaj, če vzamem prvi element stran, problem je s tem manjši in ga lahko prepustim rekurziji, potem pa ta element vstavim. Kaj ga pa vstavim? Vstavi ga na vse možne načine.
''', '''\Če predpostavim, da rekurzija permutira rep T
in vrne "permutirani" rep PT
in
ob vračanju v PT
nekam vstavim glavo H
, potem bom dobil neko permutacijo začetnega
seznama, ki je oblike [H|T]
.
Operator ==
je strožji od operatorja =
v smislu, da je za slednjega dovolj,
da elementa lahko naredi enaka (unifikacija).
Seveda pa lahko nalogo rešiš brez obeh omenjenih operatorjev, spomni se, da lahko unifikacijo narediš implicitno že kar v argumentih predikata (glavi stavka).
''', 'eq_instead_of_equ_markup': '''\Morda bi bil bolj primeren operator za unifikacijo (=)?
''', 'base_case': '''\Si pomislil na robni pogoj? Kaj je najbolj enostaven primer? Kaj, če je seznam kar prazen?
''', 'base_case_arbitrary': '''\Kako je lahko rezultat permutiranja seznama poljuben seznam oz. karkoli?
Če je tvoj robni pogoj podoben permute([], _)
,
ga še enkrat premisli: kaj je rezultat permutiranja, kaj vračaš? Robni pogoj je vedno dokončno specificirana
rešitev, tu načeloma ni neznank (_
ali spremenljivk brez prirejenih vrednosti) v tem kar se vrača.
Uporabljaš conc/3
? Pri tej nalogi to ni najboljša ideja, morda pa pride prav kakšna druga že
rešena naloga.
Ne vsiljuj rekurziji kaj naj vrne, prepusti se ji. To je tisti del, ko narediš predpostavko, če je ta izpolnjena, potem bo tvoje pravilo delovalo za večji primer.
Je tvoj rekurzivni klic oblike permute(T, [H|...])
? S tem vsiljuješ rekurziji
da mora vrniti tudi glavo, ki je sploh ne pozna, ker si jo ravnokar vzel stran! To moraš
narediti ti z rezultatom, ki ga rekurzija vrne. Skratka, element H
dodaj izven rekurzivnega klica.
Robni primer deluje. Kaj pa rekurzivni, splošni, primer?
''', 'no_insert_or_delete': '''\Robni primer deluje. Kaj pa rekurzivni, splošni, primer? Morda se ti splača uporabiti kakšno že rešeno nalogo s seznami?
''', 'predicate_always_false': '''\Vse kaže, da tvoj predikat vedno vrne "false". Si mu dal pravilno ime, si se morda pri imenu zatipkal?
Če je ime pravilno, se morda splača preveriti tudi, če se nisi zatipkal kje drugje, je morda kakšna pika namesto vejice ali obratno, morda kakšna spremenljivka z malo začetnico?
Možno je seveda tudi, da so tvoji pogoji prestrogi ali celo nemogoči (kot bi bila npr. zahteva,
da je X
hkrati starš in sestra od Y
ali kaj podobno zlobnega).
Je morda na delu potencialno neskončna rekurzija? Kako se bo ustavila?
Morda pa je kriv tudi manjkajoč, neustrezen ali preprosto nekompatibilen (s splošnim primerom) robni pogoj?
''', }