Tytuł oryginału: Programming Clojure
Tłumaczenie: Tomasz Walczak
ISBN: 978-83-246-5372-0
© Helion 2013.
All rights reserved.
Copyright © 2012 The Pragmatic Programmers, LLC.
All rights reserved.
No part of this publication may be reproduced, stored in retrieval system, or transmitted,
in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise,
without the prior consent of the poublisher.
Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej
publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną,
fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym
powoduje naruszenie praw autorskich niniejszej publikacji.
Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi
ich właścicieli.
Wydawnictwo HELION dołożyło wszelkich starań, by zawarte w tej książce informacje
były kompletne i rzetelne. Nie bierze jednak żadnej odpowiedzialności ani za ich wykorzystanie,
ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Wydawnictwo
HELION nie ponosi również żadnej odpowiedzialności za ewentualne szkody wynikłe
z wykorzystania informacji zawartych w książce.
Wydawnictwo HELION
ul. Kościuszki 1c, 44-100 GLIWICE
tel. 32 231 22 19, 32 230 98 63
e-mail: helion@helion.pl
WWW: http://helion.pl (księgarnia internetowa, katalog książek)
Pliki z przykładami omawianymi w książce można znaleźć pod adresem:
ftp://ftp.helion.pl/przyklady/proclo.zip
Drogi Czytelniku!
Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres
http://helion.pl/user/opinie/proclo
Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję.
Printed in Poland.
•
Kup książkę
•
Poleć książkę
•
Oceń książkę
•
Księgarnia internetowa
•
Lubię to! » Nasza społeczność
Spis tre$ci
Podzi kowania ............................................................................................10
Przedmowa do wydania drugiego .............................................................11
Przedmowa do wydania pierwszego ........................................................13
Wst p ...........................................................................................................15
Rozdzia# 1. Wprowadzenie .........................................................................23
1.1. Dlaczego Clojure? .............................................................................................24
1.2. Szybkie wprowadzenie do programowania w Clojure ...........................................34
1.3. Biblioteki j(zyka Clojure .....................................................................................40
1.4. Podsumowanie ..................................................................................................44
Rozdzia# 2. Przegl$d j zyka Clojure ..........................................................45
2.1. Konstrukcje sk+adniowe ......................................................................................46
2.2. Makra odczytu ...................................................................................................55
2.3. Funkcje .............................................................................................................56
2.4. Zmienne, wi1zania i przestrzenie nazw ...............................................................61
2.5. Wywo+ywanie kodu Javy .....................................................................................68
2.6. Przep+yw sterowania ..........................................................................................70
2.7. Gdzie si( podzia+a p(tla for? ..............................................................................74
2.8. Metadane ..........................................................................................................77
2.9. Podsumowanie ..................................................................................................79
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
8
Programowanie w j"zyku Clojure
Rozdzia# 3. Ujednolicanie danych za pomoc$ sekwencji .......................81
3.1. Wszystko jest sekwencj1 .....................................................................................83
3.2. Stosowanie biblioteki sekwencji ...........................................................................87
3.3. Sekwencje niesko5czone i „leniwe” .....................................................................96
3.4. W Clojure Java jest sekwencyjna .........................................................................98
3.5. Funkcje przeznaczone dla konkretnych struktur ..................................................104
3.6. Podsumowanie ................................................................................................113
Rozdzia# 4. Programowanie funkcyjne ...................................................115
4.1. Zagadnienia z obszaru programowania funkcyjnego ...........................................116
4.2. Jak stosowa8 „leniwe” podej9cie? ......................................................................121
4.3. Leniwsze ni; leniwe .........................................................................................130
4.4. Jeszcze o rekurencji ..........................................................................................136
4.5. Podsumowanie ................................................................................................146
Rozdzia# 5. Stan .........................................................................................147
5.1. Wspó+bie;no98, równoleg+o98 i blokady .............................................................148
5.2. Referencje i pami(8 STM ................................................................................150
5.3. Nieskoordynowane i synchroniczne aktualizacje za pomoc1 atomów ....................157
5.4. Stosowanie agentów do asynchronicznego aktualizowania danych .......................158
5.5. Zarz1dzanie stanem specyficznym dla w1tku za pomoc1 zmiennych ....................163
5.6. Gra Snake w j(zyku Clojure .............................................................................168
5.7. Podsumowanie ................................................................................................178
Rozdzia# 6. Protoko#y i typy danych .......................................................179
6.1. Programowanie z wykorzystaniem abstrakcji ......................................................180
6.2. Interfejsy .........................................................................................................183
6.3. Protoko+y ........................................................................................................184
6.4. Typy danych ...................................................................................................188
6.5. Rekordy ..........................................................................................................193
6.6. Makro reify .....................................................................................................198
6.7. Podsumowanie ................................................................................................199
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Spis tre'ci
!
9
Rozdzia# 7. Makra .....................................................................................201
7.1. Kiedy nale;y stosowa8 makra? ..........................................................................202
7.2. Makro do sterowania przebiegiem programu ......................................................202
7.3. Upraszczanie makr ..........................................................................................209
7.4. Taksonomia makr ............................................................................................214
7.5. Podsumowanie ................................................................................................224
Rozdzia# 8. Wielometody ..........................................................................225
8.1. >ycie bez wielometod ......................................................................................226
8.2. Definiowanie wielometod .................................................................................228
8.3. Wi(cej ni; proste wybieranie metod ...................................................................231
8.4. Tworzenie dora@nych taksonomii ......................................................................233
8.5. Kiedy nale;y korzysta8 z wielometod? ...............................................................237
8.6. Podsumowanie ................................................................................................241
Rozdzia# 9. Sztuczki z Jav$ ......................................................................243
9.1. Obs+uga wyj1tków ............................................................................................244
9.2. Zmagania z liczbami ca+kowitymi .....................................................................248
9.3. Optymalizowanie wydajno9ci ............................................................................250
9.4. Tworzenie klas Javy w j(zyku Clojure ................................................................255
9.5. Praktyczny przyk+ad .........................................................................................261
9.6. Podsumowanie ................................................................................................268
Rozdzia# 10. Tworzenie aplikacji ............................................................269
10.1. Wynik w grze Clojurebreaker ..........................................................................270
10.2. Testowanie kodu zwracaj1cego wynik ..............................................................274
10.3. Biblioteka test.generative ................................................................................278
10.4. Tworzenie interfejsu .......................................................................................287
10.5. Instalowanie kodu ..........................................................................................292
10.6. Po;egnanie ....................................................................................................295
Dodatek A. Edytory kodu .........................................................................297
Dodatek B. Bibliografia ............................................................................299
Skorowidz ..................................................................................................301
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
22
Programowanie w j"zyku Clojure
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Rozdzia# 1.
Wprowadzenie
zybki wzrost popularno9ci j(zyka Clojure wynika z wielu przyczyn. Po krót-
kich poszukiwaniach w sieci WWW dowiesz si(, ;e Clojure:
jest j(zykiem funkcyjnym;
jest Lispem na maszyny JVM;
ma specjalne mechanizmy do obs+ugi wspó+bie;no9ci.
Wszystkie te cechy s1 wa;ne, jednak ;adna z nich nie odgrywa najwa;niejszej
roli. Naszym zdaniem najistotniejszymi aspektami j(zyka Clojure s1 jego pro-
stota i mo;liwo9ci.
Prostota
w kontek9cie oprogramowania jest wa;na z kilku wzgl(dów, tu jednak
mamy na my9li pierwotne i najwa;niejsze znaczenie tego s+owa — proste jest
to, co nie jest z+o;one. Proste komponenty umo;liwiaj1 systemowi przeprowa-
dzanie operacji zaplanowanych przez projektantów i nie wykonuj1 czynno9ci
niepowi1zanych z danym zadaniem. Z naszych do9wiadcze5 wynika, ;e nie-
wielka z+o;ono98 zwykle szybko przekszta+ca si( w niebezpiecznie powa;n1.
Tak;e s+owo mo$liwo%ci ma wiele znacze5. Tu mamy na my9li zdolno98 do
wykonywania stawianych aplikacji zada5. Aby programista mia+ odpowiednie
mo;liwo9ci, musi wykorzysta8 platform(, która sama je posiada i jest powszechnie
dost(pna. Tak1 platform1 jest na przyk+ad maszyna JVM. Ponadto u;ywane
narz(dzia musz1 zapewnia8 pe+ny, nieograniczony dost(p do oferowanych
mo;liwo9ci. Dost(p do mo;liwo9ci jest cz(sto podstawowym wymogiem w pro-
jektach, w których trzeba w pe+ni wykorzysta8 platform(.
S
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
24
Programowanie w j"zyku Clojure
Przez lata tolerowali9my bardzo skomplikowane narz(dzia, które by+y jedynym
sposobem na uzyskanie potrzebnych mo;liwo9ci. Czasem akceptowali9my te; ogra-
niczone mo;liwo9ci w celu uproszczenia modelu programowania. Niekiedy nie da
si( unikn18 pewnych kompromisów, jednak w obszarze mo;liwo9ci i prostoty nie
trzeba si( z nimi godzi8. J(zyk Clojure to dowód na to, ;e cechy te mo;na po+1czy8.
1.1. Dlaczego Clojure?
Wszystkie charakterystyczne cechy j(zyka Clojure maj1 zapewnia8 prostot(,
mo;liwo9ci lub i jedno, i drugie. Oto kilka przyk+adów:
Programowanie funkcyjne jest proste, poniewa; pozwala oddzieli8 ob-
liczenia od stanu i to;samo9ci. Zalet1 jest to, ;e programy funkcyjne s1
+atwiejsze do zrozumienia, pisania, testowania, optymalizowania i rów-
noleg+ego wykonywania.
Konstrukcje umo;liwiaj1ce wspó+dzia+anie j(zyków Clojure i Java daj1
du;e mo;liwo9ci, poniewa; zapewniaj1 bezpo9redni dost(p do sk+adni
Javy. Zalet1 jest to, ;e mo;na uzyska8 wydajno98 na poziomie Javy
i stosowa8 sk+adni( charakterystyczn1 dla tego j(zyka. Co wa;niejsze,
nie trzeba ucieka8 si( do j(zyka ni;szego poziomu, aby zapewni8 sobie
dodatkowe mo;liwo9ci.
Lisp jest prosty w dwóch bardzo wa;nych aspektach — oddziela
wczytywanie od wykonania, a jego sk+adnia obejmuje niewielk1 liczb(
niezale;nych elementów. Zalet1 jest to, ;e wzorce projektowe s1 uj(te
w abstrakcyjne konstrukcje sk+adniowe, a S-wyra;enia obejmuj1 kod
w j(zykach XML, JSON i SQL.
Lisp daje te; du;e mo;liwo9ci, poniewa; udost(pnia kompilator i sys-
tem makr dzia+aj1cy w czasie wykonywania programu. Zalet1 jest to, ;e
w Lispie wyst(puje pó@ne wi1zanie i mo;na +atwo tworzy8 j(zyki DSL.
Model czasu w j(zyku Clojure jest prosty. Oddzielono w nim warto9ci,
to;samo98, stan i czas. Zalet1 jest to, ;e w programach mo;na spraw-
dza8 i zapami(tywa8 informacje bez obaw o to, ;e starsze dane zostan1
nadpisane.
Protoko+y s1 proste. W Clojure polimorfizm jest niezale;ny od dzie-
dziczenia. Zalet1 jest to, ;e mo;na bezpiecznie i w konkretnym celu
rozszerza8 typy oraz abstrakcje. Nie wymaga to stosowania zawi+ych
wzorców projektowych lub wprowadzania zmian w cudzym kodzie
(co cz(sto prowadzi do b+(dów).
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Rozdzia+ 1. • Wprowadzenie
!
25
Ta lista cech stanowi „map(” pomocn1 w dalszych rozdzia+ach ksi1;ki. Nie
martw si(, je9li na razie nie rozumiesz wszystkich szczegó+ów. Ka;dej z tych
cech po9wi(camy ca+y rozdzia+.
Zobaczmy, jak niektóre z tych cech sprawdzaj1 si( w praktyce. Zbudujmy
w tym celu prost1 aplikacj(. Przy okazji dowiesz si(, jak wczytywa8 i wykony-
wa8 wi(ksze przyk+adowe programy, które prezentujemy dalej w ksi1;ce.
J1zyk Clojure jest elegancki
W j(zyku Clojure stosunek sygna+u do szumu jest wysoki. Dlatego programy
pisane w tym j(zyku s1 krótkie. Takie programy s1 ta5sze w tworzeniu, insta-
lowaniu i konserwacji
1
. Jest to prawd1 zw+aszcza wtedy, gdy programy s1 zwi(-
z+e, a nie tylko tre9ciwe. Przyjrzyj si( na przyk+ad poni;szemu kodowi w Javie
(pochodzi on z projektu Apache Commons):
data/snippets/isBlank.java
public class
StringUtils {
public static boolean isBlank(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if ((Character.isWhitespace(str.charAt(i)) == false)) {
return false;
}
}
return true;
}
}
Metoda
isBlank()
sprawdza, czy +a5cuch znaków jest pusty (nie zawiera ;ad-
nych znaków lub obejmuje same odst(py). Oto kod podobnej metody w j(zyku
Clojure:
src/examples/introduction.clj
(defn blank? [str]
(every? #(Character/isWhitespace %) str))
Wersja w j(zyku Clojure jest krótsza, a co wa;niejsze — prostsza. Nie wyst(-
puj1 tu zmienne, modyfikowalny stan ani rozga+(zienia. Efekt ten jest mo;liwy
dzi(ki funkcjom wy$szego rz)du. Funkcje tego rodzaju przyjmuj1 inne funkcje
1
Software Estimation: Demystifying the Black Art [McC06] to znakomita ksi1;ka.
Jej autorzy dowodz1, ;e krótsze jest ta5sze.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
26
Programowanie w j"zyku Clojure
jako argumenty i (lub) zwracaj1 funkcje. Funkcja
every?
przyjmuje funkcj(
i kolekcj(, a zwraca warto98
true
, je9li otrzymana funkcja zwraca
true
dla ka;-
dego elementu z kolekcji.
Poniewa; w wersji w j(zyku Clojure nie ma rozga+(zie5, kod jest bardziej czy-
telny i +atwiejszy do przetestowania. Zalety te s1 jeszcze wyra@niejsze w wi(k-
szych programach. Ponadto, cho8 kod jest zwi(z+y, mo;na go +atwo zrozumie8.
Program w j(zyku Clojure mo;na potraktowa8 jak definicj) pustego +a5cucha
znaków — jest to +a5cuch, w którym ka;dy znak jest odst(pem. Kod ten jest
znacznie lepszy od metody z projektu Commons, w którym definicja pustego
+a5cucha znaków jest ukryta za szczegó+owym kodem p(tli i instrukcji
if
.
Oto inny przyk+ad. Przyjrzyj si( banalnej klasie
Person
napisanej w j(zyku Java:
data/snippets/Person.java
public class
Person {
private String firstName;
private String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
W j(zyku Clojure rekord
Person
mo;na zdefiniowa8 w jednym wierszu:
(defrecord Person [first-name last-name])
Korzysta8 z tego rekordu mo;na tak:
(def foo (->Person "Aaron" "Bedra"))
-> #'user/foo
foo
-> #:user.Person{:first-name "Aaron", :last-name "Bedra"}
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Rozdzia+ 1. • Wprowadzenie
!
27
Instrukcj(
defrecord
i powi1zane funkcje omawiamy w podrozdziale 6.3,
„Protoko+y”.
Kod w j(zyku Clojure nie tylko jest znacznie krótszy; rekord
Person
jest tu nie-
zmienny
. Niezmienne struktury danych s1 z natury bezpieczne ze wzgl(du
na w1tki, a mechanizmy modyfikowania danych mo;na utworzy8 w odr(bnej
warstwie za pomoc1 referencji, agentów i atomów j(zyka Clojure. Techniki te
omawiamy w rozdziale 5., „Stan”. Poniewa; rekordy s1 niezmienne, j(zyk
Clojure automatycznie udost(pnia poprawne implementacje funkcji
hashCode()
i
equals()
.
J(zyk Clojure ma wbudowanych wiele eleganckich rozwi1za5, je9li jednak
stwierdzisz, ;e czego9 Ci w nim brakuje, mo;esz samodzielnie doda8 potrzebne
mechanizmy. Umo;liwiaj1 to cechy Lispa.
Clojure to od$wie2ony Lisp
Clojure jest Lispem. Od dziesi(cioleci zwolennicy Lispa mówi1 o przewagach,
jakie j(zyk ten ma w porównaniu z w+a9ciwie wszystkimi innymi j(zykami. Plan
opanowania 9wiata przez Lispa jest jednak realizowany do98 powoli.
Twórcy j(zyka Clojure, podobnie jak autorzy ka;dej odmiany Lispa, musieli
zmierzy8 si( z dwoma problemami. Oto one:
Clojure ma odnie98 sukces jako odmiana Lispa. Wymaga to przeko-
nania u;ytkowników Lispa, ;e Clojure obejmuje najwa;niejsze mecha-
nizmy swojego poprzednika.
Jednocze9nie Clojure ma odnie98 sukces tam, gdzie wcze%niejsze wersje
Lispa si) nie przyj)4y
. Wymaga to zdobycia poparcia wi(kszej spo+ecz-
no9ci programistów.
Autorzy j(zyka Clojure radz1 sobie z tymi problemami przez udost(pnienie me-
chanizmów metaprogramowania (charakterystycznych dla Lispa) i wprowadze-
nie zestawu usprawnie5 sk+adniowych u+atwiaj1cych stosowanie j(zyka Clojure
programistom, którzy nie znaj1 Lispa.
Dlaczego Lisp?
Wersje Lispa maj1 ma+y rdze5, s1 prawie pozbawione sk+adni i maj1 rozbudo-
wane mechanizmy do obs+ugi makr. Z uwagi na te cechy mo;na zmodyfikowa8
Lispa pod k1tem projektu, zamiast dostosowywa8 projekt do Lispa. Przyjrzyj si(
poni;szemu fragmentowi kodu w Javie:
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
28
Programowanie w j"zyku Clojure
public class
Person {
private String firstName;
public String getFirstName() {
// Ci$g dalszy.
W kodzie wyst(puje metoda
getFirstName()
. Metody s1 polimorficzne i mo;na je
dostosowa8 do potrzeb. Jednak znaczenie ka$dego innego s4owa w przyk+ado-
wym kodzie jest okre%lane przez j)zyk. Czasem wygodna jest mo;liwo98 zmiany
znaczenia poszczególnych s+ów. Pozwala to na przyk+ad:
zdefiniowa8 s+owo
private
jako „prywatne w kodzie produkcyjnym, ale
publiczne na potrzeby serializacji i testów jednostkowych”;
zdefiniowa8 s+owo
class
w taki sposób, aby platforma automatycznie
generowa+a metody pobieraj1ce i ustawiaj1ce dla pól prywatnych (o ile
programista nie zarz1dzi inaczej);
utworzy8 podklas( dla
class
i umie9ci8 w niej wywo+ywane zwrotnie
uchwyty dla zdarze5 cyklu ;ycia; klasa z obs+ug1 cyklu ;ycia mo;e na
przyk+ad zg+asza8 zdarzenie utworzenia egzemplarza tej klasy.
Natykali9my si( na programy, w których potrzebne by+y wszystkie te cechy. Bez
potrzebnych mechanizmów programi9ci musieli ucieka8 si( do powtarzalnych
i podatnych na b+(dy sztuczek. Aby poradzi8 sobie z brakiem niezb(dnych
rozwi1za5, napisano dos+ownie miliony wierszy kodu.
W wi(kszo9ci j(zyków trzeba poprosi8 osoby odpowiedzialne za implementacj(,
aby doda+y wspomniane wcze9niej mechanizmy. W Clojure mo;esz samodzielnie
doda8 potrzebne cechy, pisz1c makra (rozdzia+ 7., „Makra”). Nawet sam j(zyk
Clojure jest zbudowany za pomoc1 makr, takich jak
defrecord
:
(defrecord name [arg1 arg2 arg3])
Je9li chcesz zmieni8 znaczenie s+owa, mo;esz napisa8 w+asne makro. Je;eli
potrzebujesz rekordów o 9cis+ej kontroli typów i z opcjonalnym sprawdzaniem,
czy pola nie maj1 warto9ci
null
, wystarczy utworzy8 w+asne makro
defrecord
.
Powinno ono wygl1da8 tak:
(defrecord name [Type :arg1 Type :arg2 Type :arg3]
:allow-nulls false)
Mo;liwo98 zmiany dzia+ania j(zyka w nim samym jest wyj1tkow1 zalet1 Lispa.
Mo;na znale@8 wiele opisów ró;nych aspektów tego podej9cia:
Lisp jest homoikoniczny
2
. Oznacza to, ;e kod w Lispie to dane. Dlatego
+atwo jest tworzy8 programy za pomoc1 innych programów.
2
http://pl.wikipedia.org/wiki/homoikoniczno%7
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Rozdzia+ 1. • Wprowadzenie
!
29
Ca+y j(zyk jest dost(pny w ka;dym momencie. Paul Graham w artykule
Revenge of the Nerds
3
wyja9nia, dlaczego jest to wa;ne.
Sk+adnia Lispa eliminuje te; problemy z priorytetami operatorów i +1czno9ci1
operacji. W ksi1;ce tej nie znajdziesz tabel dotycz1cych tych zagadnie5. Z uwagi
na wymóg stosowania nawiasów wyra;enia s1 jednoznaczne.
Wad1 prostej, jednolitej sk+adni Lispa (przynajmniej dla pocz1tkuj1cych) jest
nacisk na nawiasy i listy (listy to g+ówny typ danych w Lispie). Clojure udo-
st(pnia ciekawe po+1czenie cech, które u+atwiaj1 u;ywanie Lispa programistom
znaj1cym inne j(zyki.
Lisp z mniejsz4 liczb4 nawiasów
Clojure zapewnia istotne zalety programistom u;ywaj1cym innych odmian Lispa.
Oto te korzy9ci:
W j(zyku Clojure fizyczne listy z Lispa s1 uogólnione do abstrakcyjnej
postaci — sekwencji. Pozwala to zachowa8 mo;liwo9ci, jakie daj1 listy,
a przy tym wykorzysta8 ich zalety w innych strukturach danych.
Wykorzystanie maszyn JVM jako podstawy dla kodu w j(zyku Clojure
daje dost(p do standardowej biblioteki i bardzo popularnej platformy.
Sposób analizowania symboli i cudzys+owów sprawia, ;e w j(zyku
Clojure pisanie standardowych makr jest stosunkowo proste.
Wielu u;ytkowników j(zyka Clojure nie zna Lispa, za to prawdopodobnie
s+ysza+o niepochlebne opinie na temat stosowania w nim nawiasów. W j(zyku
Clojure zachowano nawiasy (i mo;liwo9ci Lispa!), jednak pod kilkoma wzgl(-
dami usprawniono tradycyjn1 sk+adni( Lispa.
Clojure zapewnia wygodn1, opart1 na litera+ach sk+adni( dla ró;nych
struktur danych (nie tylko dla list), takich jak wyra;enia regularne, od-
wzorowania, zbiory, wektory i metadane. Dlatego kod w j(zyku Clojure
jest mniej zale;ny od list ni; w wi(kszo9ci innych odmian Lispa. Mi(dzy
innymi parametry funkcji s1 podawane w wektorach,
[]
, a nie w listach,
()
.
src/examples/introduction.clj
(defn hello-world [username]
(println (format "Witaj, %s" username)))
Zastosowanie wektora sprawia, ;e lista argumentów jest lepiej widoczna,
co u+atwia czytanie definicji funkcji w j(zyku Clojure.
3
http://www.paulgraham.com/icad.html
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
30
Programowanie w j"zyku Clojure
W j(zyku Clojure, inaczej ni; w wi(kszo9ci odmian Lispa, przecinki
s1 traktowane jak odst(py.
; Wektory przypominaj$ tablice z innych j*zyków.
[1, 2, 3, 4]
-> [1 2 3 4]
J(zyk Clojure jest idiomatyczny i nie wymaga niepotrzebnego zagnie;-
d;ania nawiasów. Przyjrzyj si( makru
cond
, które wyst(puje zarówno
w Common Lispie, jak i w Clojure. Makro
cond
sprawdza zestaw par
test-wynik i zwraca pierwszy wynik, dla którego warto98 wyra;enia te-
stowego to
true
. Ka;da para test-wynik znajduje si( w nawiasach:
; Makro cond w Common Lispie.
(cond ((= x 10) "equal")
((> x 10) "more"))
W j(zyku Clojure dodatkowe nawiasy s1 niepotrzebne.
; Makro cond w Clojure.
(cond (= x 10) "equal"
(> x 10) "more")
Jest to kwestia czysto estetyczna i oba podej9cia maj1 swoich zwolenników.
Wa;ne jest to, ;e j(zyk Clojure pozbawiono uci1;liwych aspektów Lispa,
je9li by+o to mo;liwe bez utraty zalet tego ostatniego.
Clojure jest 9wietn1 odmian1 Lispa zarówno dla ekspertów, jak i dla pocz1t-
kuj1cych programistów Lispa.
Clojure to j1zyk funkcyjny
Clojure jest j(zykiem funkcyjnym, natomiast nie jest (w odró;nieniu od Haskella)
czysto funkcyjny. Oto cechy j(zyków funkcyjnych:
Funkcje to pe4noprawne obiekty. Oznacza to, ;e funkcje mo;na two-
rzy8 w czasie wykonywania programu, przekazywa8, zwraca8 i ogólnie
u;ywa8 ich jak wszelkich innych typów danych.
Dane s1 niezmienne.
Funkcje s1 czyste, czyli nie maj1 efektów ubocznych.
W wielu obszarach programy funkcyjne s1 +atwiejsze do zrozumienia, mniej
podatne na b+(dy i znacznie +atwiejsze do wielokrotnego u;ytku. Na przyk+ad
poni;szy krótki program wyszukuje w bazie danych utwory ka;dego kompozy-
tora, który napisa+ dzie+o pod tytu+em „Requiem”:
(for [c compositions :when (= "Requiem" (:name c))] (:composer c))
-> ("W. A. Mozart" "Giuseppe Verdi")
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Rozdzia+ 1. • Wprowadzenie
!
31
S+owo
for
nie jest pocz1tkiem p(tli, ale wyra$enia listowego (ang. list compre-
hension
). Kod ten oznacza „dla ka;dego
c
z kolekcji
compositions
, gdzie nazw1
c
jest
"Requiem"
, podaj kompozytora
c
”. Wyra;enia listowe omawiamy w punkcie
„Przekszta+canie sekwencji”.
Przyk+adowy kod ma cztery po;1dane cechy:
Jest prosty. Nie obejmuje p(tli, zmiennych ani zmiennego stanu.
Jest bezpieczny ze wzgl)du na w?tki. Nie wymaga stosowania blokad.
Jest mo$liwy do równoleg4ego wykonywania. Ka;dy krok mo;na przy-
dzieli8 do odr(bnego w1tku bez konieczno9ci modyfikowania kodu po-
szczególnych kroków.
Jest uniwersalny. Kolekcj1
compositions
mo;e by8 zwyk+y zbiór, kod
w XML-u lub zbiór wyników z bazy danych.
Warto porówna8 programy funkcyjne z programami imperatywnymi, w których
instrukcje zmieniaj1 stan programu. Wi(kszo98 programów obiektowych pisze si(
w stylu imperatywnym, dlatego nie maj1 one $adnych z wymienionych wcze9niej
zalet. S1 niepotrzebnie skomplikowane, niebezpieczne ze wzgl(du na w1tki, nie
umo;liwiaj1 równoleg+ego dzia+ania, a kod jest trudny do uogólnienia. Bezpo-
9rednie porównanie podej9cia funkcyjnego i imperatywnego znajdziesz w pod-
rozdziale 2.7, „Gdzie si( podzia+a p(tla for?”.
Programi9ci znaj1 zalety j(zyków funkcyjnych ju; od d+ugiego czasu. Jednak
j(zyki funkcyjne, na przyk+ad Haskell, nie zdoby+y dominuj1cej pozycji. Wyni-
ka to z tego, ;e nie wszystkie operacje mo;na wygodnie wykona8 w podej9ciu
czysto funkcyjnym.
S1 cztery powody, dla których j(zyk Clojure mo;e zyska8 wi(ksze zaintereso-
wanie ni; dawne j(zyki funkcyjne:
Podej9cie funkcyjne jest dzi9 bardziej przydatne ni; kiedykolwiek
wcze9niej. Pojawiaj1 si( maszyny o coraz wi(kszej liczbie rdzeni, a j(-
zyki funkcyjne pozwalaj1 +atwo wykorzysta8 mo;liwo9ci takiego sprz(tu.
Programowanie funkcyjne omawiamy w rozdziale 4., „Programowanie
funkcyjne”.
W j(zykach funkcyjnych niewygodnie zarz1dza si( stanem, je9li musi
si( on zmienia8. Clojure udost(pnia mechanizmy do obs+ugi zmien-
nego stanu za pomoc1 programowej pami(ci transakcyjnej i referencji,
agentów, atomów i wi1zania dynamicznego.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
32
Programowanie w j"zyku Clojure
W wielu j(zykach funkcyjnych typy s1 okre9lane statycznie. W j(zyku
Clojure stosuje si( dynamiczne okre9lanie typów, co u+atwia zadanie
programistom poznaj1cym dopiero programowanie funkcyjne.
Wywo+ywanie w j(zyku Clojure kodu Javy nie odbywa si( w modelu
funkcyjnym. Przy korzystaniu z Javy wkraczamy w znany 9wiat zmien-
nych obiektów. Zapewnia to wygod( pocz1tkuj1cym, którzy ucz1 si(
programowania funkcyjnego, a tak;e pozwala w razie potrzeby zrezy-
gnowa8 z podej9cia funkcyjnego. Wywo+ywanie kodu Javy opisujemy
w rozdziale 9., „Sztuczki z Jav1”.
Mechanizmy zarz1dzania zmian1 stanu w j(zyku Clojure umo;liwiaj1 pisanie
programów wspó+bie;nych bez bezpo9redniego korzystania z blokad i uzupe+-
niaj1 podstawowy funkcjonalny rdze5 j(zyka.
Clojure upraszcza programowanie wspó7bie2ne
Mechanizmy programowania funkcyjnego dost(pne w Clojure u+atwiaj1 pisanie
kodu bezpiecznego ze wzgl(du na w1tki. Poniewa; niezmienne struktury danych
nigdy
si( nie zmieniaj1, nie wyst(puje zagro;enie uszkodzeniem danych w wy-
niku dzia+ania innych w1tków.
Jednak obs+uga wspó+bie;no9ci w Clojure wykracza poza mechanizmy progra-
mowania funkcyjnego. Je9li potrzebne s1 referencje do zmiennych danych, Clojure
zabezpiecza je za pomoc1 programowej pami(ci transakcyjnej (ang. software
transactional memory
— STM). STM s+u;y do tworzenia kodu bezpiecznego
ze wzgl(du na w1tki i jest rozwi1zaniem wy;szego poziomu ni; blokady z Javy.
Zamiast stosowa8 podatne na b+(dy strategie blokowania danych, mo;na za-
bezpieczy8 wspó+u;ytkowany stan za pomoc1 transakcji. Jest to du;o lepsze
podej9cie, poniewa; wielu programistów dobrze zna transakcje z uwagi na do-
9wiadczenie w korzystaniu z baz danych.
Poni;szy kod tworzy dzia+aj1c1, bezpieczn1 ze wzgl(du na w1tki baz( danych
z kontami przechowywan1 w pami(ci:
(def accounts (ref #{}))
(defrecord Account [id balance])
Funkcja
ref
tworzy zabezpieczon1 za pomoc1 transakcji referencj( do bie;1cego
stanu bazy danych. Aktualizowanie stanu jest niezwykle proste. Poni;ej poka-
zujemy, jak doda8 do bazy nowe konto:
(dosync
(alter accounts conj (->Account "CLJ" 1000.00)))
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Rozdzia+ 1. • Wprowadzenie
!
33
Instrukcja
dosync
powoduje aktualizowanie bazy
accounts
w transakcji. Rozwi1-
zanie to zapewnia bezpiecze5stwo ze wzgl(du na w1tki i jest +atwiejsze w sto-
sowaniu od blokad. Dzi(ki transakcjom nigdy nie trzeba martwi8 si( o to, które
obiekty i w jakiej kolejno9ci nale;y zablokowa8. Podej9cie transakcyjne spraw-
dza si( lepiej tak;e w niektórych standardowych zastosowaniach. Przyk+adowo:
w modelu tym w1tki wczytuj1ce dane nigdy nie musz1 blokowa8 danych.
Cho8 przedstawiony przyk+ad jest bardzo prosty, technika jest ogólna i spraw-
dza si( tak;e w praktyce. Wi(cej informacji o wspó+bie;no9ci i pami(ci STM
w j(zyku Clojure znajdziesz w rozdziale 5., „Stan”.
Wykorzystanie maszyny JVM w Clojure
Clojure zapewnia przejrzysty, prosty i bezpo9redni dost(p do Javy. W kodzie
mo;na bezpo9rednio wywo+a8 metody z dowolnego interfejsu API Javy:
(System/getProperties)
-> {java.runtime.name=Java(TM) SE Runtime Environment
... i wiele innych ...
Clojure obejmuje wiele sk+adniowych mechanizmów do wywo+ywania kodu
w Javie. Nie omawiamy tu ich szczegó+owo (zobacz podrozdzia+ 2.5, „Wywo-
+ywanie kodu w Javie”), warto jednak wspomnie8, ;e w Clojure wyst(puje mniej
kropek i mniej nawiasów ni; w analogicznym kodzie Javy:
// Java
"hello".getClass().getProtectionDomain()
; Clojure
(.. "hello" getClass getProtectionDomain)
Clojure udost(pnia proste funkcje do implementowania interfejsów Javy i two-
rzenia klas pochodnych od klas Javy. Ponadto wszystkie funkcje j(zyka Clojure
obejmuj1 implementacj( interfejsów
Callable
i
Runnable
. Dlatego mo;na +atwo
przekaza8 poni;sz1 funkcj( anonimow1 do konstruktora klasy
Thread
Javy:
(.start (new Thread (fn [] (println "Witaj" (Thread/currentThread)))))
-> Witaj #<Thread Thread[Thread-0,5,main]>
Dziwne dane wyj9ciowe wynikaj1 ze sposobu wy9wietlania informacji o obiek-
tach Javy w j(zyku Clojure.
Thread
to nazwa klasy danego obiektu, a cz+on
Thread[Thread-0,5,main]
to efekt wywo+ania metody
toString
obiektu.
(Zauwa;, ;e w przedstawionym kodzie nowy w1tek dzia+a a; do zako5czenia pracy,
natomiast jego dane wyj9ciowe mog1 w dziwny sposób przeplata8 si( z wierszami
zach(ty 9rodowiska REPL. Nie jest to problem z j(zykiem Clojure, a jedynie
wynik zapisywania danych do strumienia wyj9cia przez wi(cej ni; jeden w1tek).
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
34
Programowanie w j"zyku Clojure
Poniewa; sk+adnia do wywo+ywania kodu Javy w Clojure jest przejrzysta i pro-
sta, zwykle u;ywa si( Javy bezpo9rednio, zamiast ukrywa8 kod w tym j(zyku za
charakterystycznymi dla Lispa nak+adkami.
Pozna+e9 ju; kilka powodów do stosowania j(zyka Clojure. Pora przyst1pi8 do
pisania kodu.
1.2. Szybkie wprowadzenie
do programowania w Clojure
Aby uruchomi8 9rodowisko j(zyka Clojure i kod z tej ksi1;ki, potrzebujesz
dwóch rzeczy. Oto one:
Brodowisko uruchomieniowe Javy
. Pobierz
4
i zainstaluj Jav( w wersji
5. lub nowszej. W wersji 6. znacznie poprawiono wydajno98 i system
informowania o wyj1tkach, dlatego warto stosowa8 w+a9nie j1.
Leiningen
5
. Leiningen to narz(dzie do zarz1dzania zale;no9ciami i uru-
chamiania operacji na kodzie. Jest to tak;e najpopularniejsze w 9wiecie
j(zyka Clojure narz(dzie do wykonywania tych zada5.
Leiningen pos+u;y do zainstalowania j(zyka Clojure i wszystkich elementów
wymaganych w przyk+adowym kodzie. Je9li masz ju; zainstalowane narz(dzie
Leiningen, wiesz zapewne, jak z niego korzysta8. Je;eli jeszcze nie masz po-
trzebnej wiedzy, zapoznaj si( z krótkim wprowadzeniem ze strony narz(dzia
w serwisie GitHub
6
. Znajdziesz tam instrukcje dotycz1ce instalacji, a tak;e pod-
stawowe informacje na temat u;ytkowania Leiningena. Nie musisz jednak uczy8
si( wszystkiego, poniewa; w ksi1;ce opisujemy polecenia potrzebne do uru-
chomienia przyk+adów.
W trakcie pracy z ksi1;k1 korzystaj z j(zyka Clojure w wersji w+a9ciwej dla
przyk+adowego kodu. Po przeczytaniu ksi1;ki mo;esz zastosowa8 si( do in-
strukcji z ramki „Samodzielne budowanie j(zyka Clojure” i zbudowa8 aktualn1
wersj( j(zyka.
4
http://www.oracle.com/technetwork/java/javase/downloads/index.html
5
http://github.com/technomancy/leiningen
6
http://github.com/technomancy/leiningen
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Rozdzia+ 1. • Wprowadzenie
!
35
W punkcie „Pobieranie przyk+adowego kodu”, znajdziesz instrukcje dotycz1ce
pobierania przyk+adowego kodu. Po 9ci1gni(ciu przyk+adowego kodu trzeba
u;y8 Leiningena do pobrania zale;no9ci. W katalogu g+ównym z kodem wywo+aj
nast(puj1c1 instrukcj(:
lein deps
Samodzielne budowanie j"zyka Clojure
Mo9liwe, 9e chcesz zbudowa@ jAzyk Clojure na podstawie kodu DródFo-
wego, aby uzyska@ nowe funkcje i wprowadzi@ poprawki bFAdów. Mo9na
zrobi@ to w nastApujJcy sposób:
git clone git://github.com/clojure/clojure.git
cd
clojure
mvn package
PrzykFadowy kod jest regularnie aktualizowany pod kJtem nowych rozwiJ-
zaL wprowadzanych w jAzyku Clojure. Zapoznaj siA z plikiem README
w przykFadowym kodzie, aby sprawdzi@ numer najnowszej wersji, dla
której sprawdzono kod.
Zale;no9ci s1 pobierane i umieszczane w odpowiednim miejscu. Mo;esz prze-
testowa8 zainstalowane narz(dzia przez przej9cie do katalogu z przyk+adowym
kodem i uruchomienie 9rodowiska REPL j(zyka Clojure. Leiningen obejmuje
skrypt uruchomieniowy 9rodowiska REPL, który wczytuje j(zyk Clojure wraz
z zale;no9ciami potrzebnymi w dalszych rozdzia+ach.
lein repl
Po udanym uruchomieniu 9rodowiska REPL powinien pojawi8 si( wiersz
zach(ty z tekstem
user=>
:
Clojure
user=>
Teraz jeste9 gotowy do wy9wietlenia tekstu „Witaj, 9wiecie”.
Korzystanie ze $rodowiska REPL
Aby pokaza8, jak korzysta8 ze 9rodowiska REPL, tworzymy kilka wersji kodu
wy9wietlaj1cego tekst „Witaj, 9wiecie”. Najpierw wpisz kod
(println "Witaj,
Mwiecie")
w wierszu zach(ty 9rodowiska REPL.
user=> (println "Witaj, Mwiecie")
-> Witaj, 3wiecie
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
36
Programowanie w j"zyku Clojure
Drugi wiersz,
Witaj, Mwiecie
, to ;1dane dane wyj9ciowe z konsoli.
Teraz umie98my kod w funkcji, która potrafi „zwraca8 si(” do u;ytkownika po
imieniu.
(defn hello [name] (str "Witaj, " name))
-> #'user/hello
Roz+ó;my ten kod na fragmenty. Oto one:
defn
s+u;y do definiowania funkcji;
hello
to nazwa funkcji;
funkcja
hello
przyjmuje jeden argument,
name
;
str
to wywo+anie funkcji +1cz1cej dowoln1 list( argumentów w +a5cuch
znaków;
defn
,
hello
,
name
i
str
to symbole, czyli nazwy prowadz1ce do ró;nych
elementów; dozwolone symbole opisujemy w punkcie „Symbole”.
Przyjrzyj si( zwracanej warto9ci,
#'user/hello
. Przedrostek
#'
oznacza, ;e
funkcj( zapisano w zmiennej j(zyka Clojure, a
user
to przestrzeF nazw, w której
znajduje si( ta funkcja. Jest to domy9lna przestrze5 nazw w 9rodowisku REPL,
odpowiadaj1ca domy9lnemu pakietowi w Javie. Na razie zmienne i przestrzenie
nazw nie maj1 znaczenia. Omawiamy je w podrozdziale 2.4, „Zmienne, wi1-
zanie i przestrzenie nazw”.
Teraz mo;na wywo+a8 funkcj(
hello
i przekaza8 do niej imi(.
user=> (hello "Janku")
-> "Witaj, Janku"
Je9li 9rodowisko REPL znajduje si( w dziwnym stanie, naj+atwiej zamkn18 je
za pomoc1 kombinacji klawiszy Ctrl+C w systemie Windows lub Ctrl+D
w systemach uniksowych, a nast(pnie ponownie uruchomi8.
Specjalne zmienne
]rodowisko REPL obejmuje szereg przydatnych zmiennych specjalnych. W czasie
pracy w 9rodowisku REPL wyniki obliczania trzech ostatnich wyra;e5 znaj-
duj1 si( w specjalnych zmiennych
*1
,
*2
i
*3
. Pozwala to na wygodn1 prac(
w modelu iteracyjnym. Spróbujmy po+1czy8 kilka powita5.
user=> (hello "Janku")
-> "Witaj, Janku"
user=> (hello "Clojure")
-> "Witaj, Clojure"
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Rozdzia+ 1. • Wprowadzenie
!
37
Teraz mo;na zastosowa8 specjalne zmienne do po+1czenia wyników ostatnich
instrukcji.
(str *1 " i " *2)
-> "Witaj, Clojure i Witaj, Janku"
Pope+nienie b+(du w 9rodowisku REPL prowadzi do zg+oszenia wyj1tku Javy
(z uwagi na zwi(z+o98 szczegó+y pomijamy). Niedozwolone jest na przyk+ad
dzielenie przez zero.
user=> (/ 1 0)
-> ArithmeticException Divide by zero clojure.lang.Numbers.divide
Tu problem jest oczywisty, jednak czasem jest bardziej skomplikowany i po-
trzebujemy szczegó+owego stosu wywo+a5. W specjalnej zmiennej
*e
znajduj1
si( informacje o ostatnim wyj1tku. Poniewa; wyj1tki w Clojure s1 wyj1tkami
Javy, mo;na wy9wietli8 stos wywo+a5 za pomoc1 instrukcji
pst
(od ang. print
stacktrace
, czyli wy9wietl stos wywo+a5)
7
.
user=> (pst)
-> ArithmeticException Divide by zero
| clojure.lang.Numbers.divide
| sun.reflect.NativeMethodAccessorImpl.invoke0
| sun.reflect.NativeMethodAccessorImpl.invoke
| sun.reflect.DelegatingMethodAccessorImpl.invoke
| java.lang.reflect.Method.invoke
| clojure.lang.Reflector.invokeMatchingMethod
| clojure.lang.Reflector.invokeStaticMethod
| user/eval1677
| clojure.lang.Compiler.eval
| clojure.lang.Compiler.eval
| clojure.core/eval
Wspó+dzia+anie z Jav1 omawiamy w rozdziale 9., „Sztuczki z Jav1”.
Je9li blok kodu jest zbyt d+ugi, aby mo;na go wygodnie wpisa8 w 9rodowisku
REPL, umie98 kod w pliku, a nast(pnie wczytaj ten plik w 9rodowisku. Mo;esz
u;y8 9cie;ki bezwzgl(dnej lub poda8 j1 wzgl(dem miejsca uruchomienia 9rodo-
wiska REPL.
; Zapisz kod w pliku temp.clj, a nast*pnie wywo2aj instrukcj*:
user=> (load-file "temp.clj")
REPL to znakomite 9rodowisko do wypróbowywania pomys+ów i otrzymywania
natychmiastowych informacji zwrotnych. Aby jak najlepiej wykorzysta8 ksi1;k(,
w trakcie jej lektury nie zamykaj 9rodowiska REPL.
7
Instrukcja
pst
jest dost(pna tylko w Clojure 1.3.0 i nowszych wersjach.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
38
Programowanie w j"zyku Clojure
Dodawanie stanu wspó7u2ytkowanego
Funkcja
hello
z poprzedniego przyk+adu to czysta funkcja, czyli taka, której
dzia+anie nie ma efektów ubocznych. Czyste funkcje +atwo si( pisze i testuje.
S1 tak;e +atwe do zrozumienia, dlatego w wielu sytuacjach warto je stosowa8.
Jednak w wi(kszo9ci programów wyst(puje wspó+u;ytkowany stan, a do zarz1-
dzania nim s+u;1 funkcje typu impure (czyli takie, które nie s1 czyste). Dodajmy
do funkcji
hello
mechanizm 9ledzenia liczby u;ytkowników. Najpierw trzeba
utworzy8 struktur( danych do przechowywania tej liczby. U;yjmy do tego zbioru.
#{}
-> #{}
#{}
to litera+ oznaczaj1cy pusty zbiór. Potrzebna jest te; operacja
conj
.
(conj coll item)
Instrukcja
conj
(od ang. conjoin, czyli +1czy8) tworzy now1 kolekcj( z dodawanym
elementem. Do+1czmy element do zbioru, aby upewni8 si(, ;e powstaje nowy zbiór.
(conj #{} "Janku")
-> #{"Janku"}
Tworzenie nowych zbiorów jest ju; mo;liwe. Pora opracowa8 sposób na spraw-
dzanie aktualnego zbioru u;ytkowników. Clojure udost(pnia kilka s+u;1cych do
tego typów referencyjnych. Najprostszym typem referencyjnym jest atom.
(atom initial-state)
Aby okre9li8 nazw( atomu, nale;y u;y8 instrukcji
def
.
(def symbol initial-value?)
Instrukcja
def
przypomina polecenie
defn
, ale jest ogólniejsza. Przy jej u;yciu
mo;na definiowa8 funkcje lub dane. U;yjmy s+owa
atom
do utworzenia atomu
i instrukcji
def
do powi1zania atomu z nazw1
visitors
.
(def visitors (atom #{}))
-> #'user/visitors
Aby zaktualizowa8 referencj(, trzeba u;y8 funkcji, na przyk+ad
swap!
.
(swap! r update-fn & args)
Funkcja
swap!
przeprowadza operacj(
update-fn
na referencji
r
i w razie potrzeby
u;ywa przy tym opcjonalnych argumentów
args
. Spróbujmy wstawi8 u;ytkow-
nika do kolekcji
visitors
, u;ywaj1c do aktualizowania funkcji
conj
.
(swap! visitors conj "Janku")
-> #{"Janku"}
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Rozdzia+ 1. • Wprowadzenie
!
39
atom
to tylko jeden z kilku typów referencyjnych dost(pnych w j(zyku Clojure.
Wybór odpowiedniego typu referencyjnego nie jest prosty (zagadnienie to
omawiamy w rozdziale 5., „Stan”).
W dowolnym momencie mo;na sprawdzi8 zawarto98 pami(ci, do której prowadzi
referencja. S+u;y do tego instrukcja
deref
lub jej krótszy odpowiednik,
@
.
(deref visitors)
-> #{"Janku"}
@visitors
-> #{"Janku"}
Teraz mo;na zbudowa8 now1, bardziej rozbudowan1 wersj( funkcji
hello
.
src/examples/introduction.clj
(defn hello
"Wy%wietla powitanie na wyj%ciu, u$ywaj?c nazwy u$ytkownika.
Potrafi stwierdzi7, $e korzysta4e% ju$ z programu."
[username]
(swap! visitors conj username)
(str "Witaj, " username))
Teraz sprawd@my, czy u;ytkownicy s1 poprawnie zapisywani w pami(ci.
(hello "Marku")
-> "Witaj, Marku"
@visitors
-> #{"Jacku" "Janku" "Marku"}
Na Twoim komputerze lista u;ytkowników b(dzie prawdopodobnie inna. Na tym
w+a9nie polega problem ze stanem. Efekty s1 ró;ne w zale;no9ci od tego, kiedy
zasz+y dane zdarzenia. Zrozumie8 funkcj( mo;na na podstawie jej analizy.
Aby zrozumie8 stan, trzeba pozna8 ca+1 histori( dzia+ania programu.
Je9li to mo;liwe, unikaj przechowywania stanu. Je;eli jest to niemo;liwe, dbaj
o to, aby stanem mo;na by+o zarz1dza8. U;ywaj do tego typów referencyjnych,
na przyk+ad atomów. Atomy (i wszystkie inne typy referencyjne w Clojure) s1
bezpieczne przy korzystaniu z wielu w1tków i procesorów. Co lepsze, zapew-
nienie bezpiecze5stwa nie wymaga stosowania blokad, które bywaj1 skompli-
kowane w u;yciu.
Na tym etapie powiniene9 umie8 ju; wprowadza8 krótkie fragmenty kodu
w 9rodowisku REPL. Wprowadzanie wi(kszych porcji kodu odbywa si( podob-
nie. Tak;e biblioteki j(zyka Clojure mo;na wczytywa8 i uruchamia8 z poziomu
9rodowiska REPL. Dalej pokazujemy, jak to zrobi8.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
40
Programowanie w j"zyku Clojure
1.3. Biblioteki j1zyka Clojure
Kod j(zyka Clojure jest umieszczony w bibliotekach. Ka;da biblioteka j(zyka
Clojure znajduje si( w przestrzeni nazw, która jest odpowiednikiem pakietu
Javy. Bibliotek( j(zyka Clojure mo;na wczyta8 za pomoc1 instrukcji
require
.
(require quoted-namespace-symbol)
Je9li programista ;1da biblioteki o nazwie
clojure.java.io
, Clojure szuka pliku
o nazwie clojure/java/io.clj w 9cie;ce ze zmiennej
CLASSPATH
. Zobaczmy, jaki jest
tego efekt.
user=> (require 'clojure.java.io)
-> nil
Pocz1tkowy pojedynczy apostrof (
'
) jest niezb(dny i s+u;y do dos4ownego po-
dawania
(ang. quoting) nazwy biblioteki (podawanie nazw omawiamy w pod-
rozdziale 2.2, „Makra odczytu”). Zwrócona warto98
nil
oznacza powodzenie.
Przy okazji sprawd@, czy mo;esz wczyta8 przyk+adowy kod do tego rozdzia+u
(bibliotek(
examples.introduction
).
user=> (require 'examples.introduction)
-> nil
Biblioteka
examples.introduction
obejmuje implementacj( generowania liczb
Fibonacciego. W j(zykach funkcyjnych jest to tradycyjny program typu „Witaj,
9wiecie”. Liczby Fibonacciego omawiamy szczegó+owo w podrozdziale 4.2,
„»Leniwe« podej9cie”. Na razie upewnij si(, ;e mo;esz uruchomi8 przyk+adow1
funkcj(
fibs
. Wprowad@ poni;szy wiersz kodu w 9rodowisku REPL, a otrzy-
masz 10 pierwszych liczb Fibonacciego.
(take 10 examples.introduction/fibs)
-> (0 1 1 2 3 5 8 13 21 34)
Je9li otrzyma+e9 10 pierwszych liczb Fibonacciego (wymienionych powy;ej),
poprawnie zainstalowa+e9 przyk+adowy kod z ksi1;ki.
Wszystkie przyk+ady sprawdzili9my za pomoc1 testów jednostkowych (testy
znajduj1 si( w katalogu examples/test). Samych testów nie omawiamy w ksi1;ce,
jednak mog1 okaza8 si( przydatnym @ród+em wiedzy. Aby uruchomi8 testy jed-
nostkowe, u;yj instrukcji
lein test
.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Rozdzia+ 1. • Wprowadzenie
!
41
Instrukcje require i use
Po za;1daniu biblioteki j(zyka Clojure za pomoc1 instrukcji
require
elementy
z biblioteki trzeba wskazywa8 za pomoc1 pe+nej nazwy. Zamiast nazwy
fibs
trzeba u;y8 okre9lenia
examples.introduction/fibs
. Uruchom drugi egzemplarz
9rodowiska REPL
8
i wprowad@ poni;szy kod.
(require 'examples.introduction)
-> nil
(take 10 examples.introduction/fibs)
-> (0 1 1 2 3 5 8 13 21 34)
Wprowadzanie pe+nych nazw szybko staje si( k+opotliwe. Mo;esz u;y8 instrukcji
refer
dla przestrzeni nazw i odwzorowa8 wszystkie nazwy z tej przestrzeni na
bie;1c1 przestrze5 nazw.
(refer quoted-namespace-symbol)
Wywo+aj instrukcj(
refer
dla przestrzeni
examples.introduction
i sprawd@, czy
mo;esz bezpo9rednio wywo+a8 funkcj(
fibs
.
(refer 'examples.introduction)
-> nil
(take 10 fibs)
-> (0 1 1 2 3 5 8 13 21 34)
Wygodna funkcja
use
pozwala wykona8 instrukcje
require
i
refer
w jednym kroku.
(use quoted-namespace-symbol)
W nowym 9rodowisku REPL wprowad@ nast(puj1ce instrukcje.
(use 'examples.introduction)
-> nil
(take 10 fibs)
-> (0 1 1 2 3 5 8 13 21 34)
W trakcie pracy z przyk+adowym kodem z ksi1;ki mo;esz wywo+a8 instrukcj(
require
lub
use
z opcj1
:reload
, aby wymusi8 ponowne wczytanie biblioteki.
(use :reload 'examples.introduction)
-> nil
Opcja
:reload
jest przydatna, je9li wprowadzasz zmiany i chcesz sprawdzi8 ich
efekt bez ponownego uruchamiania 9rodowiska REPL.
8
Otwarcie nowego 9rodowiska REPL zapobiega konfliktom nazw mi(dzy utworzonym
wcze9niej kodem a funkcjami o tych samych nazwach z przyk+adowego kodu. W praktyce
nie stanowi to problemu. Zagadnienie to omawiamy w punkcie „Przestrzenie nazw”.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
42
Programowanie w j"zyku Clojure
Znajdowanie dokumentacji
Potrzebna dokumentacja cz(sto jest dost(pna bezpo9rednio w 9rodowisku REPL.
Najprostsz1 funkcj1 pomocnicz1
9
jest
doc
.
(doc name)
U;yjmy funkcji
doc
do wy9wietlenia dokumentacji funkcji
str
.
user=> (doc str)
-------------------------
clojure.core/str
([] [x] [x & ys])
With no args, returns the empty string. With one arg x, returns
x.toString(). (str nil) returns the empty string. With more than
one arg, returns the concatenation of the str values of the args.
Pierwszy wiersz danych wyj9ciowych funkcji
doc
obejmuje pe+n1 nazw( spraw-
dzanej funkcji. W drugim znajduj1 si( argumenty generowane bezpo9rednio
w kodzie. Wybrane cz(sto stosowane nazwy argumentów i ich zastosowanie
omawiamy w ramce „Zwyczajowe nazwy parametrów”. Dalsze wiersze obejmuj1
4aFcuch znaków dokumentacji
, je9li jest on podany w definicji funkcji.
Zwyczajowe nazwy parametrów
NaLcuchy znaków dokumentacji w funkcjach reduce i areduce obejmujJ
szereg krótkich nazw parametrów. Oto niektórych z tych nazw i sposoby
ich stosowania.
Parametr
Zastosowanie
a
Tablica Javy
agt
Agent
coll
Kolekcja
expr
Wyra9enie
f
Funkcja
idx
Indeks
r
Referencja
v
Wektor
val
WartoX@
Nazwy mogJ wydawa@ siA krótkie, jednak jest tak nie bez powodu —
„dobre” nazwy czAsto sJ ju9 „zajAte” przez funkcje jAzyka Clojure! U9y-
wanie dla parametrów nazw identycznych z nazwami funkcji jest dopusz-
czalne, ale uznaje siA to za oznakA zFego stylu. Parametr zasFania wtedy
funkcjA, dlatego jest ona niedostApna, kiedy parametr znajduje siA w za-
siAgu programu. Dlatego nie nale9y nazywa@ referencji ref, agentów
agent, a liczników — count, poniewa9 sJ to nazwy funkcji.
9
Tak naprawd(
doc
to makro j(zyka Clojure.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Rozdzia+ 1. • Wprowadzenie
!
43
`a5cuch znaków dokumentacji mo;na doda8 do funkcji przez umieszczenie go
bezpo9rednio po jej nazwie.
src/examples/introduction.clj
(defn hello
"Wy%wietla powitanie na wyj%ciu, u$ywaj?c nazwy u$ytkownika. "
[username]
(println (str "Witaj, " username))
Czasem nie znasz nazwy elementu, którego dokumentacji potrzebujesz. Funkcja
find-doc
wyszukuje informacje o wszystkich elementach, dla których dane wyj-
9ciowe funkcji
doc
pasuj1 do przekazanego wyra;enia regularnego lub +a5cucha
znaków.
(find-doc s)
Za pomoc1 funkcji
find-doc
mo;na sprawdzi8, w jaki sposób Clojure skraca
kolekcje.
user=> (find-doc "reduce")
-------------------------
clojure/areduce
([a idx ret init expr])
Macro
... Szczegó2y pomini*to ...
-------------------------
clojure/reduce
([f coll] [f val coll])
... Szczegó2y pomini*to ...
Funkcja
reduce
pozwala w skrócony sposób stosowa8 operacje do kolekcji
j(zyka Clojure. Omawiamy j1 w punkcie „Przekszta+canie sekwencji”. Funkcja
areduce
wspó+dzia+a z tablicami Javy, a opisujemy j1 w punkcie „Korzystanie
z kolekcji Javy”.
Du;a cz(98 j(zyka Clojure jest napisana w nim samym, dlatego lektura jego
kodu @ród+owego to pouczaj1ce zadanie. Kod @ród+owy funkcji j(zyka Clojure
mo;na wy9wietli8 za pomoc1 instrukcji
source
z biblioteki
repl
.
(clojure.repl/source symbol)
Wy9wietlmy kod @ród+owy prostej funkcji
identity
.
(use 'clojure.repl)
(source identity)
-> (defn identity
"Returns its argument."
{:added "1.0"
:static true}
[x] x)
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
44
Programowanie w j"zyku Clojure
Oczywi9cie, mo;na te; u;ywa8 interfejsu API Reflection Javy. Metody
class
,
ancestors
,
instance?
i podobne pozwalaj1 sprawdzi8 model obiektowy Javy
i informuj1 na przyk+ad o tym, ;e kolekcje j(zyka Clojure s1 jednocze9nie ko-
lekcjami Javy.
(ancestors (class [1 2 3]))
-> #{clojure.lang.ILookup clojure.lang.Sequential
java.lang.Object clojure.lang.Indexed
java.lang.Iterable clojure.lang.IObj
clojure.lang.IPersistentCollection
clojure.lang.IPersistentVector clojure.lang.AFn
java.lang.Comparable java.util.RandomAccess
clojure.lang.Associative
clojure.lang.APersistentVector clojure.lang.Counted
clojure.lang.Reversible clojure.lang.IPersistentStack
java.util.List clojure.lang.IEditableCollection
clojure.lang.IFn clojure.lang.Seqable
java.util.Collection java.util.concurrent.Callable
clojure.lang.IMeta java.io.Serializable java.lang.Runnable}
Internetow1 dokumentacj( interfejsu API j(zyka Clojure znajdziesz na stronie
http://clojure.github.com/clojure
. W ramce widocznej w prawej cz(9ci tej strony
znajduj1 si( odno9niki do wszystkich funkcji i makr. Po lewej stronie umiesz-
czono odno9niki do artyku+ów na temat ró;nych cech j(zyka Clojure.
1.4. Podsumowanie
W+a9nie zako5czy+e9 szybki przegl1d j(zyka Clojure. Pozna+e9 daj1c1 du;e
mo;liwo9ci sk+adni( tego j(zyka i jego zwi1zki z Lispem, a tak;e zobaczy+e9, jak
+atwe jest wywo+ywanie w Clojure kodu Javy.
Uruchomi+e9 j(zyk Clojure w swoim 9rodowisku, a tak;e napisa+e9 w 9rodowisku
REPL krótkie programy ilustruj1ce programowanie funkcyjne i s+u;1cy do obs+ugi
stanu model referencji. Pora przyjrze8 si( ca+emu j(zykowi.
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Skorowidz
A
agenty, 158
bie;1ca warto98, 159
sprawdzanie poprawno9ci, 160
transakcje, 161
tworzenie, 158
wykrywanie b+(dów, 160
algebra relacji, 110
Apache Ant, 244
atomy, 157
dereferencja, 157
tworzenie, 157
ustawienie warto9ci, 157
B
biblioteki, 20, 40
dos+owne podawanie nazwy, 40
drzewo w+a9ciwo9ci systemowych, 238
znajdowanie dokumentacji, 42
C
Clojure, 15, 23
aktualizacja, 261
aspekty, 23
biblioteki, 20, 40
drzewo w+a9ciwo9ci systemowych, 238
inspector, 238
Lazytest, 286
math.combinatorics, 275
Midje, 286
sekwencje, 87
test, 239
test.generative, 278
cechy j(zyka, 24, 209
czytnik, 46
makra odczytu, 55
edytory kodów, 297
funkcje, 56
czyste, 38
dodawanie sugestii typów, 253
impure, 38
wywo+anie, 56
wy;szego rz(du, 25
Java, 15, 33, 243
dost(p, 243
interfejsy, 183, 255
javadoc, 70
kompilacja AOT, 248
konstrukcja new, 68
korzystanie z kolekcji, 258
mechanizm wywo+a5 zwrotnych, 256
parsery SAX, 255
9rodowisko uruchomieniowe, 34
tworzenie klas, 255
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
302
Programowanie w j"zyku Clojure
Clojure
Java
tworzenie po9redników, 255
tworzenie tablic, 258
wykorzystanie mo;liwo9ci, 247
wywo+ywanie kodu, 68
wywo+ywanie metody, 69
j(zyk funkcyjny, 30
cechy, 30
konstrukcje sk+adniowe, 24, 46
Leiningen, 34, 261
liczby ca+kowite, 248
operatory, 248
Lisp, 15, 24, 27
makra, 28, 201
taksonomia, 216
maszyny JVM, 29
metadane, 77
model czasu, 24
niezmienne struktury danych, 27
obs+uga wyj1tków, 244
kontrolowane wyj1tki, 245
porz1dkowanie zasobów, 245
reagowanie na wyj1tki, 247
optymalizowanie wydajno9ci, 250
dodawanie sugestii typów, 253
u;ywanie typów prostych, 250
pobieranie zale;no9ci, 261
po+1czenie z witryn1, 261
programowanie, 16
funkcyjne, 18, 24, 115
p(tle, 74
regu+y, 120
wspó+bie;ne, 32
protoko+y, 24, 179, 184
przestrze5 nazw, 36, 61, 65
rejestrowanie informacji, 264
rekordy, 193
rozk+adanie struktury, 63
mo;liwo9ci, 65
sekwencje, 29, 81
biblioteka, 87
cechy, 83
Java, 98
manipulowanie, 197
wymuszanie realizacji, 97
wyra;enia listowe, 95
stan, 147
model aktualizacji, 163
model funkcyjny, 149
model referencyjny, 149
sterowanie przep+ywem, 70
instrukcje, 70
makra, 71
rekurencja, 72
9rodowisko REPL, 35
zmienne specjalne, 36
to;samo98, 147
typy referencyjne, 147
tworzenie aplikacji, 269
gra Clojurebreaker, 270
typy danych, 179, 188
cechy, 188
typy referencyjne, 38
atom, 38
warto98, 147
wi1zania, 61
wielometody, 225
wspó+bie;no98, 18, 32, 148
powody stosowania, 148
sytuacja wy9cigu, 149
zakleszczenie, 149
zmienne, 36, 61
cechy, 62
D
definicja pustego +a5cucha znaków, 26
duck typing, 250
F
funkcje, 56
anonimowe, 58
konstrukcja, 59
powody tworzenia, 58
stosowanie, 61
unikanie, 223
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Skorowidz
! 303
bez sprawdzania przepe+nienia, 251
cz(9ciowe wywo+anie, 134
czyste, 38, 116
niezmienne dane, 116
dodawanie sugestii typów, 253
efekty uboczne, 71
funkcje wy;szego rz(du, 25
leniwe, 127
liczba argumentów, 57
listy, 105
+a5cuchy znaków dokumentacji, 42
odwzorowania, 53, 106
tworzenie, 108
operatory matematyczne, 47
predykaty, 52, 56
przejrzyste referencyjnie, 118
memoizacja, 119
rozwini(cie funkcji, 135
implementacja, 135
sekwencje, 83
filtrowanie, 91
predykaty, 92
przekszta+canie, 93
tworzenie, 88
wyra;enia regularne, 100
s+owa kluczowe, 54
wektory, 105
wi1zania, 62
zasi(g leksykalny, 63
wywo+anie, 47, 56
notacja przedrostkowa, 47
notacja wrostkowa, 47
zbiory, 109
z+o;one, 134
H
hermetyzacja, 119
efekty uboczne, 120
Heroku, 292
biblioteka, 293
git init, 293
git push, 294
plik Procfile, 292
polecenie heroku, 293
rejestracja konta, 292
repozytorium git, 293
I
instrukcje
add-points, 171
agent-errors, 160
alias, 233
alter, 152
assoc, 171
atom, 157
binding, 164
clear-agent-errors, 160
commute, 154
concat, 210
cond, 227
condp, 182
conj, 38, 86
cons, 83, 132, 171
def, 38, 61, 218
defmacro, 203
defmethod, 228
defmulti, 175, 228
defn, 57
defonce, 133
defrecord, 27, 54
deref, 39, 150
derive, 236
dir, 279
do, 71, 219
doall, 97
dosync, 33, 150
faux-curry, 135
file-seq, 101
first, 76, 83
fn, 58
for, 75
force, 221
if, 70, 202
import, 67, 199
in-ns, 66, 281
inspect-tree, 238
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
304
Programowanie w j"zyku Clojure
instrukcje
lazy-cat, 129
lazy-seq, 142
lein deps, 261
lein test, 40
let, 212
line-seq, 102
loop, 72
loop/recur, 72
macroexpand, 207
map, 219
memoize, 165
next-counter, 155
partial, 134
partition, 132
prefer-method, 232
println, 116, 203
project, 112
proxy, 176
pst, 37
recur, 72, 120, 130
ref, 156
refer, 41
ref-set, 150
require, 40, 41, 279
reset!, 157
rest, 83
score print-table, 276
select, 112
send, 159
send-off, 161
seq, 101, 258
set, 90
set!, 167, 254
source, 43
start, 163
swap!, 158
take-while, 91
trampoline, 139
unless, 202
use, 41, 66
var, 62
with-open, 102
J
Java, 15, 16, 243
interfejsy, 183
wady, 183
zalety, 183
klasy
BigDecimal, 249
BigInteger, 249
Character, 50
ChunkedSeq, 84
Person, 26
Random, 68
StringUtils, 74
Thread, 33
WidgetFactory, 205
metody egzemplarza, 204
obs+uga, 245
obs+uga wyj1tków, 244
kontrolowane wyj1tki, 244
porz1dkowanie zasobów, 245
sekwencje, 98
kolekcje sekwencyjne, 98
wywo+ywanie kodu, 68
K
kod gry Snake, 169
interfejs GUI, 169, 175
aktualizowanie, 175
defmulti, 175
fill-point, 175
game, 176
game-panel, 175
paint, 175
proxy, 176
tworzenie nowej gry, 176
wy9wietlanie w(;a i jab+ka, 175
model funkcyjny, 169
add-points, 170, 171
assoc, 171
cons, 171
dodawanie punktów, 170
eats?, 172
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Skorowidz
! 305
head-overlaps-body?, 172
lose?, 172
move, 171
point-to-screen-rect, 171
ruch w(;a, 171
sprawdzanie warunków zwyci(stwa, 172
turn, 173
tworzenie nowego jab+ka, 171
tworzenie w(;a, 171
tworzenie zestawu sta+ych, 169
win?, 172
wykrywanie zetkni(cia, 172
zjadanie jab+ka, 172
zmiana kierunku w(;a, 173
model zmiennego stanu, 169, 173
reset-game, 173
update-direction, 174
update-positions, 174
wyd+u;anie w(;a, 174
zmiany pozycji w(;a i jab+ka, 173
konstrukcje sk+adniowe, 24
liczba, 46
BigDecimal, 48
BigInt, 48
ca+kowita, 48
Ratio, 48
wektor, 47
zmiennoprzecinkowa, 48
lista, 46, 47
wywo+ywanie funkcji, 47
+a5cuch znaków, 46, 49
wywo+anie, 50
odwzorowania, 46, 52
sekwencje, 85
rekordy, 52
wywo+ywanie, 54
s+owo kluczowe, 46, 53
symbol, 46, 49
warto98 logiczna, 46
regu+y dzia+ania, 51
warto98 nil, 46
wektory, 46
sekwencje, 84
zbiory, 46
sekwencje, 85
znak, 46
L
Leiningen, 34, 261
pobieranie zale;no9ci, 35
wtyczka lein-noir, 287
leniwe sekwencje, 121, 125
moment realizacji, 127
Lisp, 15, 24
M
makra, 28, 201
amap, 260
and, 207, 216
areduce, 260
assert, 222
bad-unless, 207
bench, 212
binding, 164, 221
chain, 209
comment, 217
cond, 30
czas kompilacji, 203
czas rozwijania makra, 203
declare, 137, 218
definterface, 183
defpartial, 288
defprotocol, 185
defrecord, 28, 193
defstruct, 218
deftype, 189
delay, 220
dosync, 221
dotimes, 250
extend-protocol, 186
extend-type, 186
for, 95
import-static, 220
is, 239
j(zyk szablonów, 210
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
306
Programowanie w j"zyku Clojure
makra
konstrukcje specjalne, 215
lazy-seq, 125
let, 221
letfn, 124
manipulowanie list1, 210
ns, 67
obs+uga kilku konstrukcji, 208
obs+uga szablonów, 211
przechwytywanie symboli, 213
splicing unquote, 211
unquote, 211
przetwarzanie, 203
regu+y stosowania, 202
reify, 198
rozwijanie, 206
rekurencyjne, 207
tworzenie, 212
sprawdzanie, 206
sterowanie przebiegiem programu, 202
tablice Javy, 260
taksonomia, 214
kategorie, 216
time, 212, 221
tworzenie, 203
tworzenie nazw, 212
nazwy lokalne, 214
tworzenie zmiennych, 218
unikanie funkcji anonimowych, 223
unless, 203
upraszczanie, 209
warto9ciowanie argumentów, 203, 206
nak+adki, 221
odraczanie, 220
warunkowe, 216
when, 208
when-not, 202, 208
with-open, 221, 245
with-out-str, 221
wspó+dzia+anie z Jav1, 219
wzorzec projektowy, 205
makra odczytu, 55
dereferencja, 56
funkcja anonimowa, 56
komentarz, 55, 56
metadane, 56
podawanie zmiennych, 56
przytaczanie, 56
syntax-quote, 56
unquote, 56
unquote-slicing, 56
wzorzec wyra;enia regularnego, 56
maszyny JVM, 15, 29
autorekurencja, 124
Clojure, 16
Java, 16
memoizacja, 165
metadane, 77
standardowe klucze, 78
model czasu, 24
N
niezmienne struktury danych, 27
O
optymalizacja TCO, 73, 123
P
pami(8 STM, 32, 151
technika MVCC, 153
transakcje, 151
ACI, 151
aktualizacje, 151
polimorfizm, 231
programowa pami(8 transakcyjna, Patrz
pami(8 STM
programowanie, 16, 18, 31, 97, 148
funkcyjne, 18, 24, 30, 116
autorekurencja, 124
czyste funkcje, 116
definicje rekurencyjne, 121
leniwe podej9cie, 118, 121
leniwe sekwencje, 121, 125
problemy rekurencyjne, 138
prosta rekurencja, 122
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Skorowidz
! 307
regu+y, 120
rekurencja, 118
rekurencja ko5cowa, 123
rekurencja wzajemna, 136
trwa+e struktury danych, 117
wielokrotne wykorzystanie kodu, 119
wspó+u;ytkowanie struktur, 117
wyra;enie listowe, 31
zalety, 119
imperatywne, 31
kod p(tli, 74
prawid+owy proces pisania kodu, 273
sekwencyjne, 97
testowanie kodu, 274
BDD, 286
generowanie danych testu, 279
podstawowe etapy, 278
programowe sprawdzanie poprawno9ci,
280
przeprowadzanie testów, 276, 283
sprawdzanie poprawno9ci danych
wyj9ciowych, 277
sprawdzanie poprawno9ci kodu, 278
TDD, 286
testy jednostkowe, 286
testy regresji, 277
tworzenie danych wej9ciowych, 275
zg+aszanie b+(du, 284
wspó+bie;ne, 148
powody stosowania, 148
wykorzystanie abstrakcji, 180
obs+uga dodatkowych typów, 181
odczyt, 180
zapis, 180
protoko+y, 24, 179, 184
zalety, 184
przestrze5 nazw, 36, 65
clojure.core, 66
clojure.string, 67
funkcje, 68
modyfikacja deklaracji, 264
myapp, 66
user, 36, 65
wi1zania, 65
R
referencje, 150
sprawdzanie poprawno9ci, 156
transakcje, 150
ACID, 151
aktualizowanie informacji, 152
atomowe, 151
izolowane, 151
licznik, 155
pami(8 STM, 151
skoordynowane, 151
spójne, 151
trwa+e, 151
warto98 wewn1trztransakcyjna, 153
w+a9ciwo9ci, 151
zmiana encji, 150
tworzenie, 150
rekordy, 193
dodawanie metod, 195
dost(p do pól, 194
implementacja protoko+u, 195
Note, 193
odwzorowania, 193
Person, 26
tworzenie, 193
rekurencja, 72, 118
autorekurencja, 124
definicje, 121
indukcja, 121
przypadek bazowy, 121
problemy rekurencyjne, 138
prosta rekurencja, 122
przyspieszanie, 143
rekurencja ko5cowa, 123
optymalizacja TCO, 123
rekurencja wzajemna, 136
memoizacja, 144
optymalizowanie, 139
przekszta+canie na autorekurencj(, 138
zast(powanie leniwym podej9ciem, 141
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
308
Programowanie w j"zyku Clojure
S
sekwencje, 29, 81
biblioteka, 86, 87
funkcje, 88
cechy, 83
filtrowanie, 91
funkcje, 91
funkcje, 83
into, 86
Java, 98
kolekcje sekwencyjne, 82, 98
niezmienne, 87
odwzorowania, 85
predykaty, 92
przekszta+canie, 93
funkcje, 93
strumienie, 102
system plików, 101
funkcje, 101
tryb leniwy, 86, 96
stosowanie, 97
zalety, 96
tworzenie, 88
funkcje, 88
wektory, 84
wymuszanie realizacji, 97
wyra;enia regularne, 100
funkcje, 100
zbiory, 85
stan, 147
agenty, 147, 158
bie;1ca warto98, 159
sprawdzanie poprawno9ci, 160
transakcje, 161
tworzenie, 158
wykrywanie b+(dów, 160
atomy, 147, 157
dereferencja, 157
tworzenie, 157
ustawienie warto9ci, 157
model aktualizacji, 163
modele zarz1dzania, 168
referencje, 147, 150
transakcje, 150
tworzenie, 150
wywo+ywane zwrotnie metody, 166
zmienne, 147, 163
I
9rodowisko REPL, 35
zmienne specjalne, 36
T
tworzenie aplikacji, 269
instalowanie kodu, 292
git push, 292, 294
Heroku, 292
plik Procfile, 292
testowanie kodu wyniku, 274
defspec, 282
dir, 279
failures, 284
generate-test-data, 282
generowanie danych testu, 279
in-ns, 281
programowe sprawdzanie poprawno9ci,
280
random-secret, 280
require, 279
score print-table, 276
score-inputs, 278
selections, 275
sprawdzanie poprawno9ci danych
wyj9ciowych, 277
test dla danych wej9ciowych, 276
test-dirs, 283
test-namespaces, 283
test-vars, 283
testy regresji, 277
tworzenie danych wej9ciowych, 275
zg+aszanie b+(du, 284
tworzenie interfejsu, 287
board, 290
defpartial, 288
dodanie stanu, 287
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ
Skorowidz
! 309
framework sieciowy, 287
interfejs gracza, 288
render, 290
session/flash-put!, 290
session/get, 287
session/put!, 287
session/remove!, 290
wynik, 270
exact-matches, 271
frequencies, 271
generowanie, 270
merge-with, 272
score, 273
select-keys, 272
unordered-matches, 272
typy danych, 179, 188
anonimowe egzemplarze, 198
cechy, 188
CryptoVault, 179, 188
definiowanie metod, 189
dost(p do pól, 189
rekordy, 193
tworzenie, 189
typy referencyjne, 38
atom, 38
W
wi1zania, 62
bindings, 63
dynamiczne, 164
modyfikacje na odleg+o98, 164
dynamicznie okre9lany zasi(g, 164
funkcje, 62
zasi(g leksykalny, 63
lokalne, 164
mechanizm rozk+adania struktury, 63
podstawowe, 61
przestrze5 nazw, 65
zmienne, 62
wielometody, 225
account-level, 235
assert-expr, 240
definiowanie, 228
dodawanie implementacji metod, 228
domy9lne dzia+anie, 230
dora@ne taksonomie, 233
dziedziczenie, 236
mechanizm wybierania implementacji, 229
my-print, 228, 231
paint, 175
service-charge, 235
stosowanie, 237
regu+y, 241
wybieranie metod, 229
dla typu kolekcji, 231
na podstawie typu pierwszego
argumentu, 231
rozwi1zywanie konfliktów, 232
wspó+bie;no98, 32
wyra;enie listowe, 94
elementy, 94
Z
zmienne, 36, 61, 163
aliasy, 62
cechy, 62
mechanizm rozk+adania struktury, 63
metadane, 62
rodzaje definicji, 133
specjalne, 164
modyfikacje na odleg+o98, 164
tworzenie, 133
makra, 218
wi1zania, 62
lokalne dla w1tku, 164
podstawowe, 61
Kup ksi
ąĪkĊ
Pole
ü ksiąĪkĊ