|
|
pl:prolog:prolog_lab:prolog_lab_system [2013/04/10 07:54] gjn [6.2 Ćwiczenie: Tworzenie potoków] |
pl:prolog:prolog_lab:prolog_lab_system [2019/06/27 15:50] |
====== LAB: Integracja z narzędziami systemowymi ====== | |
{{header>2}} | |
===== - #6 WPROWADZENIE ===== | |
==== - Temat: Uruchamianie programów ==== | |
| |
Przy pomocy interpretera SWI można uruchomić program w trybie wsadowym (ang. //batch//). | |
| |
swipl -s program.pl -g go -t halt | |
| |
Powyższe wywołanie załaduje podany plik, zada cel ''go.'', a po jego zakończeniu cel ''halt.''. | |
Co jest równoważne wywołaniu: | |
swipl | |
[program]. | |
go. | |
halt. | |
| |
Program można też uruchomić w postaci skryptu. | |
* w najprostszym przypadku można stworzyć skrypt //Sh//, np.: | |
| |
#!/bin/sh | |
swipl -s program.pl -g go -t halt | |
| |
* lub też | |
| |
#!/bin/sh | |
swipl -s $1 -g $2 -t halt | |
| |
wtedy można go uruchomić poleceniem | |
./nazwa_skryptu program.pl go | |
| |
* ciekawsze jest stworzenie skryptu Prologowego | |
| |
#!/usr/bin/swipl -q -t go -s | |
tresc programu w prologu | |
| |
* w obu przypadkach aby uruchomić skrypt należy wcześniej nadać mu odpowiednie atrybuty: | |
| |
chmod u+rx skrypt | |
| |
| |
Więcej można przeczytać na: | |
* [[http://www.swi-prolog.org/pldoc/doc_for?object=section%282%2c%20%272.3%27%2c%20swi%28%27%2fdoc%2fManual%2finitgoal.html%27%29%29|Initialisation files and goals]] | |
* [[http://www.swi-prolog.org/pldoc/doc_for?object=section%282%2c%20%272.10%27%2c%20swi%28%27%2fdoc%2fManual%2fcompilation.html%27%29%29|Compilation]] | |
* [[http://www.swi-prolog.org/pldoc/doc_for?object=section%281%2c%20%2710%27%2c%20swi%28%27%2fdoc%2fManual%2fruntime.html%27%29%29|Generating Runtime Applications]] | |
| |
==== - Temat: Potoki i przekierowanie we/wy ==== | |
=== Wstęp === | |
W systemie typu Unix (POSIX) standardowe wejście, wyjście jak i wyjście błędów aplikacji można przekierować do pliku. | |
Do przekierowania standardowego wyjścia należy posłużyć się >, dla standardowego wejścia: <. | |
| |
Przykładowo: | |
* Przekierowanie informacji o aktualnym czasie do pliku: ''date > dzisiaj.txt'' | |
* Posortowanie zawartości pliku ''lista-osob.txt'' i umieszczenie rezultatu w pliku ''lista-osob-posortowana'': ''sort < lista-osob.txt > lista-osob-posortowana.txt'' | |
* Można również zlecić wykonanie aplikacji współbieżnie (w tle): ''sort < lista-osob.txt > lista-osob-posortowana.txt &'' | |
| |
Standardowe wyjścia aplikacji można również połączyć ze standardowym wejściem innej aplikacji za pomocą potoków (ang. //pipe//). | |
Typowe użyciem potoków jest np. wyświetlenie (''ls'') posortowanej (''sort'') listy plików w aktualnym katalogu z podziałem na strony (''less''). | |
Standardowe wyjście ''ls'' jest przekierowane do standardowego wejścia ''sort'', następnie wyjście ''sort'' jest przekierowane na wejście ''less''. | |
Aplikacje uruchamiane w potoku wykonywane są współbieżnie. | |
| |
ls | sort | less | |
| |
Więcej informacji w [[http://home.agh.edu.pl/~gjn/wiki/dydaktyka:unix:lab_zadania_i_procesy|laboratorium z Unixa]]. | |
| |
| |
=== Potoki w Prologu === | |
| |
Do utworzenia potoku w Prologu można wykorzystać predykat ''open/3'', [[http://gollem.science.uva.nl/SWI-Prolog/Manual/IO.html#sec:edinburghIO|oraz specjalny term pipe/1]]. | |
W przykładzie poniżej ''open(pipe(sort)...)'' uruchamia aplikację systemową ''sort''. | |
| |
<code prolog> | |
| |
osoba(franek). | |
osoba(jurek). | |
osoba(ania). | |
| |
wypisz_osoby(A) :- | |
osoba(B), | |
write(A, B), | |
write(A, '\n'), | |
fail. | |
| |
wypisz_posortowane :- | |
open(pipe(sort), write, A), | |
\+ wypisz_osoby(A), | |
close(A). | |
</code> | |
| |
==== - Temat: GraphViz i ImageMagick ==== | |
| |
[[misc:Graphviz]] jest aplikacją służącą do wizualizacji grafów. | |
Przetwarza plik wejściowy z symbolicznym tekstowym zapisem węzłów oraz krawędzi i generuje plik wyjściowy w jednym z wybranych formatów: JPG, PNG, EPS, SVG, PDF, PS... | |
| |
Przykładowy plik wejściowy dla grafu skierowanego{{:pl:prolog:prolog_lab:przyklad.dot}}: | |
| |
<code> | |
digraph G { | |
"wezel o dlugiej nazwie" -> B | |
B -> inny | |
inny -> wezelek | |
wezelek -> B | |
wezelek -> "wezel o dlugiej nazwie" | |
} | |
</code> | |
| |
''digraph'' jest słowem kluczowym określającym graf skierowany, ''G'' jest nazwą grafu (może to być dowolny ciąg znaków), pomiędzy {} należy umieścić zbiór krawędzi, zapisanych jako: | |
| |
nazwa1 -> nazwa2 | |
| |
gdzie ''nazwa1'' oraz ''nazwa2'' to nazwy wierzchołków pomiędzy którymi znajduje się krawędź; jeżeli w nazwie wierzchołka znajdują się znaki białe (np. spacje) należy nazwę wierzchołka umieścić w cudzysłowiach np. | |
"wezel o dlugiej nazwie". | |
| |
Wywołanie generujące graf jako obrazek PNG ([[misc:Graphviz]] generuje graf na standardowym wyjściu): | |
dot -T png przyklad.dot > przyklad.png | |
| |
Więcej informacji: ''man dot'' | |
| |
Zamiast zachowywać graf jako obrazek, można go wyświetlić korzystając z aplikacji ImageMagick (''display'') oraz potoków: | |
| |
dot -T png przyklad.dot | display | |
| |
Czego rezultatem będzie okno z grafem: | |
| |
{{:pl:prolog:prolog_lab:przyklad.png}} | |
| |
==== - Metaprogramowanie i Potoki ==== | |
| |
Metaprogramowanie można połączyć z możliwościami jakie daje tworzenie potoków do napisania uniwersalnego programu wyświetlającego graf skierowany na podstawie faktów przechowywanych przez wskazany predykat (patrz {{:pl:prolog:prolog_lab:graph2.pl}}) będący argumentem wywołania predykatu ''dotegen/1'', np.: | |
| |
dotgen(mojUlubionyGraf/2). | |
| |
wygeneruje graf na podstawie krawędzi zdefiniowanych przez dwuargumentowy predykat ''mojUlubionyGraf''. | |
Należy zwrócić uwagę, że ''dotgen/1'' generuje graf pod warunkiem, że wskazany predykat reprezentujący graf ma 2 lub więcej argumentów; założono, że pierwsze dwa argumenty są nazwami wierzchołków tworzących krawędź. | |
| |
Przykładowe wykorzystanie //rysuj.pl//: | |
| |
<code prolog> | |
graf(jeden,dwa). | |
graf(dwa,trzy). | |
graf(trzy,jeden). | |
graf(jeden,cztery). | |
| |
:- [graph2]. | |
rysuj :- | |
open(pipe('dot -T png | display'), write, A), | |
dotgen(A, graf/2), | |
close(A). | |
| |
rysuj_w :- | |
open(pipe('dot -T png | display &'), write, A), | |
dotgen(A, graf/2), | |
close(A). | |
</code> | |
| |
==== - Temat: Uruchamianie Prologu w potoku ==== | |
| |
Program w Prologu można również uruchomić z poziomu systemu operacyjnego w potoku. | |
Np. do wygenerowania grafu może służyć polecenie: | |
| |
swipl -s rysuj.pl -q -t 'dotgen(graf/2).' | dot -Tpng | display | |
| |
bądź też współbieżnie: | |
| |
swipl -s rysuj.pl -q -t 'dotgen(graf/2).' | dot -Tpng | display & | |
| |
| |
| |
===== - #6 ĆWICZENIA ===== | |
| |
==== - Ćwiczenie: Tworzenie skryptów ==== | |
| |
Sprawdź działanie: | |
swipl -g help | |
swipl -g help -t halt | |
| |
Uruchom w podobny sposób program //rodzina// z 1. zajęć (lub inny). | |
Zadaj z linii poleceń różne pytania, np. "kto jest rodzicem piotra?". | |
| |
Uruchom program //rodzina// jako skrypt Sh, gdzie z linii poleceń można zadać pytanie jako 1. argument skryptu. | |
| |
Uruchom program //rodzina// jako skrypt Prolog. | |
| |
==== - Ćwiczenie: Tworzenie potoków ==== | |
| |
Przeanalizuj działanie {{graph2.pl}}. | |
| |
Przetestuj i porównaj działanie predykatów ''rysuj'' oraz ''rysuj_w'' z {{rysuj2.pl}}. | |
Jaka jest różnica? dlaczego? | |
| |
| |
==== - Ćwiczenie: Wizualizacja drzewa genealogicznego potomków ==== | |
| |
Korzystając z predykatów określających koligacje rodzinne z [[pl:prolog:prolog_lab:wprowadzenie]] oraz na podstawie {{graph2.pl}} napisz predykat generujący graf będący drzewem genealogicznym określającym potomków wskazanej osoby: | |
| |
rysuj_potomek(+Kto) | |
| |
gdzie Kto to osoba, dla której zostanie wygenerowane drzewo potomków, zakładając, że istnieją predykaty: ''rodzic/2'', ''kobieta/1'', ''mezczyzna/1''. | |
Przykładowe wywołanie: | |
| |
rysuj_potomek(franek). | |
| |
Wygeneruje drzewo genealogiczne potomków dla osoby franek. | |
| |
Podpowiedź: najpierw napisz predykat znajdujący potomków, potem dodaj generację danych dla [[misc:Graphviz]], następnie wizualizację. | |
| |
==== - Ćwiczenie: Wizualizacja drzewa genealogicznego potomków, metaprogramowanie ==== | |
| |
Korzystając z predykatów określających koligacje rodzinne z laboratorium [[wprowadzenie]] oraz na podstawie {{graph.pl}} napisz predykat generujący graf będący drzewem genealogicznym określającym potomków wskazanej osoby: | |
| |
rysuj_potomek(+Kto,+Rodzic,+Kobieta,+Mezczyzna) | |
| |
gdzie Kto to osoba, dla której zostanie wygenerowane drzewo potomków, pozostałe argumenty są nazwami predykatów określającymi odpowiednio kto jest czyim rodzicem, kto jest kobietą, kto jest mężczyzną. | |
Przykładowe wywołanie: | |
| |
rysuj_potomek(franek,rodzic/2,kobieta/1,mezczyzna/1) | |
| |
Wygeneruje drzewo genealogiczne potomków dla osoby ''franek'', przy czym ''rodzic/2, kobieta/1, mezczyzna/1'' są zdefiniowanymi predykatami, których klauzule przechowują informacje o koligacjach rodzinnych. | |
| |
Podpowiedź: najpierw napisz predykat znajdujący potomków, potem dodaj generację danych dla [[misc:Graphviz]], następnie wizualizację. | |
| |
Uwaga: | |
Można pokolorować krawędzie i węzły grafu, zadając: | |
digraph G { | |
"ala" [style=filled, fillcolor=yellow] | |
"ala" ->"ma" [color=blue] | |
"kota"->"ma" [color=red] | |
"ma" -> "w ciapki" | |
} | |
| |
Pokoloruj innymi kolorami węzły związane z kobietami i mężczyznami. | |
| |
===== Dla Zainteresowanych ===== | |
| |
==== Ćwiczenie: Wizualizacja drzewa genealogicznego ==== | |
| |
Napisz predykat: | |
| |
rysuj_drzewo(+Kto,+Rodzic,+Kobieta,+Meżczyzna) | |
| |
rysujący kompletne drzewo dla wskazanej osoby; zarówno potomków jak i przodków. | |
| |
Przykład drzewa genealogicznego: | |
{{:pl:prolog:prolog_lab:drzewo_gen_przyklad.dot}} | |
| |
{{:pl:prolog:prolog_lab:drzewo_gen_przyklad.png}} | |
| |
====== Uwagi, komentarze, propozycje ====== | |
Tu studenci mogą wpisywać swoje uwagi. | |
| |
| |
| |
--- //[[gjn@agh.edu.pl|Grzegorz J. Nalepa]] 2009/05/06 09:13// | |
| |