Tak sobie siedzę i
myślę, że można by tu coś napisać dla potomności. W szczególności dla
początkujących, a i osobiście samemu podciągnąć się z języka.
Twórca Clojure : Rich Hickey
Postanowiłem więc, że napiszę wstępniaka wzorując się na problemach ze strony
4Clojure
. Strona zawiera zestaw problemów podzielonych na kategorie o różnych
stopniach trudności. Postaram się w każdym nowym wpisie na blogu
rozwiązać kilka z nich. Oczywiście zacznę od najłatwiejszych. Pomysł
poznawania Clojure dzięki przykładom, które mogą być testowane jest
wyjątkowo ciekawy. Nie spotkałem jeszcze czegoś podobnego dla innych
języków. Nie ma jednak tak wspaniale jakby się można było spodziewać.
Często zadania z pozoru trywialne rozwiązuje się dość długo ze względu
na zbyt uproszczoną dokumentację. Aby nie tracić czasu i nie zanudzać
może od razu przejdę do rzeczy.
Problem 1: Nothing but the truth
Zadanie
polega na podaniu w miejscu : ___ wyrażenia, które redukuje się do
postaci prawda/fałsz. Może to być wyrażenie logiczne lub po prostu :
true. Zadania będę oznaczać literą T i numerem, a przykładowe odpowiedzi
literą E i numerem. Odpowiedzi można wpisywać na stronie w polu
tekstowym i kliknąć w przycisk Run. Jeżeli zadanie zostanie rozwiązane
poprawnie, to przy każdym problemie zapali się zielona dioda. Jeżeli
nie, zapali się czerwona. Do testów polecam tę stronę:
try Clojure. Do bardziej zaawansowanych rzeczy będzie potrzebny prawdziwy Clojure z IDE. Polecam także
ściągawkę, która posiada wiele przykładów.
Zaczynamy:
Funkcje
zwracające prawdę lub fałsz w Clojure to : <, >, =, not, not=,
>=, <= oraz wszelkie funkcje kończące się znakiem: ? . Pytajnik
nie ma wpływu na działanie funkcji, to część jej nazwy. Po prostu taka
zasada została przyjęta w nazewnictwie funkcji, które zwracają wartości
logiczne.
nil to odpowiednik znanego
null z innych języków i oznacza wartość nieokreśloną.
E1: true
E2: (= 1 1)
E3: (not false)
E4: (>= 2 1)
E5: (>= 2 2)
E6: (not= 2 3)
E7: (< 1 2 3 4)
E8: (> 4 3 2 1)
E9: (nil? nil)
|
Problem 2: Simple math
Zadanie polega na odgadnięciu liczby, bądź wyrażenia, które spełni warunek:
T1: (= (- 10 (* 2 3)) __)
|
Rozkładając wyrażenie (- 10 (* 2 3)) na postać znaną ze szkoły mam wyrażenie:
10 - (2 * 3)
którego wynik to: 4, stąd, możliwe odpowiedzi:
E1: 4
E2: (* 2 2)
E3: (+ 2 2)
E4: (/ 8 2)
|
To:
(/ 4 1.0) wyrażenie mimo, że wydaje się, że poprawne zwraca fałsz. Co
się dzieje? Otóż wynikiem tego działania nie jest 4 a 4.0 - różny typ
danych. Pierwszy jest wartością całkowitą, drugi przybliżoną - tzw.
zmiennoprzecinkową. Reprezentacje bitowe tych liczb są różne. Aby
równanie było prawdziwe test musiałby wyglądać tak: (== ... ), czyli
zawierać funkcję
==, która porównuje wartości bez zwracania uwagi na typ danych wykonując najpierw konwersję, a potem porównanie.
Problem 3: Intro to Strings
Teraz musimy zgadnąć co zwróci funkcja:
.toUpperCase. Oczywiście funkcja zamienia w tekście małe znaki na duże.
T1: (= __ (.toUpperCase "hello world"))
E1: "HELLO WORLD"
E2: (str "HELLO" " " "WORLD")
E3: (str \H \E \L \L \O \ \W \O \R \L \D)
|
str = funkcja, która łączy wszystkie argumenty w jeden ciąg znaków. Można zapodać liczbę, symbol, znak : \A. Typ
String
w Clojure jest tym samym typem z Javy przeniesionym bez zmian. Działają
więc na nim wszystkie funkcje z Javy. Funkcję Javy można łatwo
rozpoznać po kropce na początku nazwy.
Problem 4: Intro to Lists
Zadanie polega na przekazaniu odpowiednich argumentów do funkcji
list.
Listę
można utworzyć za pomocą polecenia list lub ujmując dane w: '( ) -
nawiasy przed którymi jest apostrof. Słowa zaczynające się dwukropkiem
nazywane są kluczami. Klucze to jeden z podstawowych typów danych, który
ewaluuje się na siebie, tak jak liczba.
T1: (= (list __) '(:a :b :c))
E1: :a :b :c
|
Problem 5: Lists: conj
Funkcja
conj.
Wywołuje się ją podając pierwszy argument jako listę/wektor lub set, a
resztę już jako dowolny typ danych. Zwraca ona nową listę/wektor/set z
dodanymi polami do podanej struktury. Conj nowe elementy listy umieszcza
na jej początku, a do wektora łączy na końcu. W przypadku seta nie ma
znaczenia. Set jest strukturą o nieuporządkowanej kolejności elementów.
Funkcja zwróci wyjątek się jeżeli pierwszy argument nie będzie listą lub
wektorem/setem i nie będzie minimum dwóch argumentów. Co ciekawe,
funkcja porównawcza nie zaprotestuje jeżeli zapodać jej listę i wektor.
Pod względem działania z zewnątrz wektor jest równoważny liście, pod
spodem działa trochę inaczej.
T1: (= __ (conj '(2 3 4) 1))
T2: (= __ (conj '(3 4) 2 1))
E1: '(1 2 3 4)
E1: (list 1 2 3 4)
E3: [ 1 2 3 4 ]
E4: (vector 1 2 3 4)
E5: (vec '(1 2 3 4))
|
Problem 6: Intro to Vectors
Jak wspominałem wcześniej wektory mogą być porównywane bezpośrednio z listami.
Zadanie polega na wypisaniu elementów wektora.
T1: (= [__] (list :a :b :c) (vec '(:a :b :c)) (vector :a :b :c))
E1: :a :b :c
|
Funkcja
vector tworzy wektor z argumentów. Funkcja
vec tworzy wektor z listy.
Problem 7: Intro to Sets
Set,
to lista, w której mogą znajdować się tylko unikalne wartości w losowej
kolejności. W związku z tym nigdy nie należy brać pod uwagę
rozmieszczenia jego elementów. Dla rozróżnienia oznacza się go
okrągłymi klamrami ze znaczkiem number przed pierwszą klamrą: #{ }.
Zadanie polega na odgadnięciu wyniku. Set tworzy się za pomocą funkcji
set z listy lub wektora. Funkcja
union łączy dwa sety w jeden. Kolejność elementów w secie nie ma znaczenia.
T1: (= __ (set '(:a :a :b :c :c :c :c :d :d)))
T2: (= __ (clojure.set/union #{:a :b :c} #{:b :c :d}))
E1: #{:a :b :c :d}
E2: #{:b :a :d :c}
E3: (clojure.set/union #{:a :b} #{:c} #{:d})
|
Problem 8: Sets: conj
Funkcja
conj w zastosowaniu do setów.
T1: (= #{1 2 3 4} (conj #{1 4 3} __))
E1: 2
Brak komentarzy:
Prześlij komentarz