% predikat number z prednasky number([]) --> []. number([H|T]) --> [H], { code_type(H, digit) }, number(T). % predikat chars, ktory sa moze rozpisat na akykolvek retazec chars([]) --> []. chars([H|T]) --> [H], chars(T). % === 13.1 === % List -> Space* TrimList Space* % TrimList -> .* % zamerne prehodime poradie pravidiel, aby sa neterminal spaces vzdy pokusal % pohltit co najviac bielych znakov; inac by sme hladane riesenie v tomto % pripade nedostali ako prve spaces([H|T]) --> [H], { code_type(H, space) }, spaces(T). spaces([]) --> []. % btw toto pravidlo by mohlo byt umiestnene za trim, napriek tomu, ze trim % sa nan odkazuje trm(X) --> spaces(_), chars(X), spaces(_). % "standardna technicka cast" - vyvolat parsovanie a previest zoznam ascii % kodov na citatelny retazec trim(List, TrList) :- phrase(trm(Out), List), string_to_list(TrList, Out). % === 13.2 === % ten isty technicky kus kodu, akurat nacitavame zo suboru cpu_freq_list(FreqStr) :- phrase_from_file(cpuinfo_file(Freqs), '/proc/cpuinfo'), string_to_list(FreqStr, Freqs). % treba si premysliet, ako navrhneme gramatiku pre obsah cpuinfo; mozeme sa % inspirovat prikladom z prednasky na nakupny zoznam a vo vysledku je asi % najjednoduchsou gramatikou tato: % % FILE --> "" % FILE --> "cpu MHz\t\t: " CISLO "." CISLO "\n" FILE % FILE --> CHARS "\n" FILE % % - zakernostou vystupu cpuinfo je, ze obsahuje tabulatory, na ktore si treba % dat pozor, inak by ten uvodny retazec nefungoval % - a je dolezite umiestnit pravidlo s cpu pred vseobecne pravidlo, pretoze % je specifickejsie cpuinfo_file([]) --> []. cpuinfo_file(Freqs) --> "cpu MHz\t\t: ", !, number(N1), ".", number(N2), { append([N1, ".", N2], Freq) }, "\n", cpuinfo_file(Freqs1), { append([Freq, "\n", Freqs1], Freqs) }. cpuinfo_file(Freqs) --> chars(_), "\n", cpuinfo_file(Freqs). % viac informacii o DCG napriklad tu: http://www.learnprolognow.org/ % === 13.4 === % budeme pracovat s Constraint Logic Programming (for Finite Domains) :- use_module(library('clpfd')). % (+,+,?) mince(Values, Sum, Counts) :- % vynutime rovnaku dlzku zoznamov Values a Counts; tym vynutime, ze % Counts je zoznam... inac by nam predikat vypisoval chybu, ktoru je % pouzitim trace. odhalit, ze pouzitie ins by zlyhalo na teste, ci % Counts je zoznam length(Values, Len), length(Counts, Len), Counts ins 0..Sum, % vyuzijeme CLP predikat, ktory robi presne to, co potrebujeme % ako treti operator treba uviest #=, nie =, == alebo nieco ine, kedze % ide o symbol, s ktorym bude CLP pracovat; inac by ho spracoval uz % priamo Prolog scalar_product(Values, Counts, #=, Sum), % vynutime najdenie konkretnych hodnot, ktore vyhovuju label(Counts). % v tomto pripade velmi nie je nutne upravovat sposob, akym CLP engine % prehladava mozne riesenia, kedze aj bez pouzitia konkretnych prepinacov % v labeling/2 dostavame male riesenia skor (skuste sa zamysliet, ako % hodnoty prehladava a preco to moze povazovat za vyhodnejsie)