Lekcja 25
25. Wejście/wyjście
W LISP istnieje szereg struktur i instrukcji służących do obsługi szeroko rozmuianego wejścia/wyjścia.
25.1 Napisy
Podstawową strukturą, która przechowuje zbiory liter jest napis. W LISP zapisujemy go przy pomocy tekstu ograniczonego podójnym cudzysłowem, np. “To jest napis”. Jest on reprezentowany jako jednowymiarowa tablica znaków o zmiennej długości. Z tego względu wszelki instrukcje nadające się dla tablic, będą działały również dla napisów. Isnieją również dedykowane istrukcje służące do manipulacji napisami. Jeśli chcemy aby napis zawierał znak podówjnego cudzysłowu lub lewego ukośnika, to musimy go poprzedzić lewym ukośnikiem np. “Cytat: \”Kości zostały rzucone \” – koniec cytatu”.
25.1.1 char
Instrukcja char pozwala na dostęp do n-tego elementu napisu. Odpowiada ona instrukcji aref, przy czym może przyjmować tylko dwa argumenty – napis oraz pozycję w napisie. Litery są indeksowane od zera. Chcą zastąpić wybrany znak innym możemy napisać
25.1
(setq napis "Ala ma kota") => "Ala ma kota" ( char napis 2) => #\a ( setf (char napis 2) #\b) => #\a napis => "Alb ma kota"
Warto zwrócić uwagę, że znaki drukują się inaczej niż napisy. Jeśli chcemy uzyskać znaki w postaci napisów, mosimy dokonać konwersji coerce ze znaku na napis.
25.1.2 format
Ważną instrukcją związana z napisami jest format. Pozwala ona wydrukwać na dowolne wyjście napisy, których elementy mogą zostać zadane jako argumenty jej wywołani. W ogólności ma ona postać (format destination string arg1 arg2 …). Destination przyjmuje najczęściej wartości nil oraz t, ale może to być dowolny strumień. Argument ten określa gdzie wynikowy łańcuch ma zostać złożony. nil oznacza, że wynikowy łańcuch ma zostać zwrócony przez instrukcję format, podczas gdy t oznacza, że wynikowy łańcuch ma zostać wydrukowany na standardowym wyjściu, a instrukcja zwraca nil.
25.2
(setq napis (fomrat nil "Ala ma kota")) => "Ala ma kota" napis => "Ala ma kota" (setq napis (format t "Ala ma kota")) "Ala ma kota" => nil napis => nil
Jak wcześniej zauważyliśmy, w napisie mogą pojawić się elementy zadane jako argumenty insrukcji format. W napisie jednak muszą wystąpić odpowiednie znaki, które informują tą funkcję, gdzie mają się pojawić owe argumenty i jak mają zostać wydrukowane. Najczęściej stosowane zestawienia znaków, to ~D oraz ~S. Piewrszy z nich pozwala wstawić liczbę do napisu, drugi zaś inny napis bądź symbol.
25.3
(setq a 10) => 10 (format t "Zmienna ~S ma wartość ~D" `a a) Zmienna a ma wartość 10 => nil
25.4
(format t "Napis ~& w kilku ~& linijkach") Napis w kilku linijkach => nil
25.2 Odczytywanie informacji z wejścia
Do wprowadzania informacji przez użytkownika złuży instrukcja read. Zwraca ona po prostu wartość odczytaną ze standardowego wejścia. Wartość ta nie musi być cytowan przy pomocy znaku`, ponieważ nie będzie ewaluowana.
25.5
(defun kwadrat () (format t "Podaj liczbe ktorej kwadrat chcesz obliczyc: ") (let ((x (read))) (format t "~&Kwadratem liczby ~D jest ~D~%" x (* x x)) ) ) => kwadrat (kwadrat) Podaj liczbę której kwadrat chcesz obliczyć: 10 Kwadratem liczby 10 jest 100 => nil
25.3 Operacje na plikach
Operacje na plikach najłatwiej przeprowadza się przy pomocy instrukcji with-open-file. Ma ona postać (with-open-file (var pathname) body), gdzie var to nazwa zmiennej, z którą będzie utożsamiany strumień do otwartego pliku, pathname to ścieżka dostępu do tego pliku, zaś body zawiera instukcje dokonujące operacji na otwartym pliku. Zaraz po opuszczeniu tej instrukcji, połączenie do pliku jest zamykane.
25.3.1 Odczyt z pliku
Przypuśćmy, że wpliku “dane.dat” w katalogu bieżącym znajdują sią następujące wpisy
25.6
1 (maluch polonez syrenka)
Dostęp do tych danych jest następujący
25.7
(with-open-file (plik "dane.dat") (let ((numer-samochodu (read plik)) (lista-samochodow (read plik))) (format t "Najlepszym samochodem jest ~S~%" (nth numer-samochodu lista-samochodow)) ) ) Najlepszym samochodem jest polonez => nil
25.3.2 Zapis do pliku
Jeśli chcemy zapisać jakieś informacje do pliku, to w instrukcji with-open-file dodatkowo musimy zastosować dwa słowa kluczowe :direction i :output, całą zaś forma przyjmuje postać (with-open-file (var pathname :direction :output) body). Do zapisu możemy wykorzystać wcześniej poznana instrukcję format, przy czym jej pierwszy argument powinien być nazwą otwartego pliku.
25.8
(let ((lista-samochodow '(maluch polonez syrenka)) (numer-samochodu 2)) (with-open-file (plik "dane.dat" :direction :output) (format plik "~S~%" numer-samochodu) (format plik "~S~%" lista-samochodow) ) ) => nil
Po wykonani tej formy w pliku “dane.dat” pojawią się następujące linie:
25.9
2 (maluch polonez syrenka)