"The Grid. A digital frontier. I tried to picture clusters of information as they move through the computer. What did they look like? Ships? Motorcycles? Were the circuits like freeways? I kept dreaming of a world I thought I’d never see. And then, one day, I got in." — Tron: Legacy

2012-11-22

Clojure Elementary 1

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:
T1: (= ___ true)
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