Poznajemy nowe języki: Scala, czyli jak wypisać elementy z listy
Scala. Co to za język?
- Scala została sklasyfikowana jako język funkcyjny, obiektowy, wielo-paradygmatyczny (mam nadzieję, że dobrze tłumaczę),
- statycznie i silnie typowany,
- obecna implementacja bazuje na JVM, niedługo można się spodziwać implementacji na .NET,
- tak!, Scala działa na platformie Java, więc ma dostęp do całego ekosystemu bibliotek Javy,
- nietuzinkową postacią jest sam twórca języka Martin Odersky, który jest współautorem obecnego kompilatora Javy oraz jest współprojektantem obecnych typów generycznych w Javie,
- jest to młody język programowania i posiada wiele ciekawych własności, o których to będę pisał w kolejnych postach,
- więcej: Scala na Wikipedii, strona domowa Scali, wywiad z twórcą języka.
OK, wezmę na warsztat prostą czynność: wypisanie elementów z listy.
Kod w Javie byłby następujący:
Dla odmiany w Ruby'im zrobilibyśmy to tak:
-
# tutaj akurat mamy tablicę
-
lista = %w(1, 2, 3, 4)
-
-
# żeby ładnie było to definiujmy println
-
println = lambda { |x| puts x }
-
-
lista.each &println
Zobaczmy teraz, jak zrobilibyśmy to w Scali.
-
val lista = List(1, 2, 3, 4)
-
-
lista.foreach((x: Int) => println(x))
Brzydko... idziemy dalej. Scala jest językiem funkcyjnym, który ma mechanizm currying. Opuśćmy deklarację typu i nawiasy.
-
lista.foreach(x => println(x))
Nadal brzydko... idziemy dalej. Co jest argumentem metody foreach? Sygnatura metody jest następująca:
-
def foreach(f: A => Unit): Unit
Na potrzebę chwili traktujmy Unit tak samo jak void. Zatem argumentem foreach jest funkcja, która przyjmuje argument A (jakiś nieustalony typ, patrz: currying) i zwraca Unit. Natomiast println jest zdefiniowany tak:
-
def println(x: Any) = Console.println(x)
czyli bierze jakiś argument (nadal patrz: currying, funkcje wyższego rzędu) i zwraca Unit. Zatem typy się zgadzają. Zapiszmy to krócej:
-
lista.foreach(println)
Już lepiej, ale można jeszcze lepiej :). Scala ma bardzo fajną własność, którą nigdzie wcześniej nie spotkałem. Mianowicie w Scali technicznie nie ma operatorów. Wyrażenie 1 + 2 jest tożsame z wywołaniem metody 1.+(2). Jeśli metoda przyjmuję tylko jeden parametr to można pominąć nawiasy oraz kropkę. Zatem:
-
lista foreach println
Piękny zapis, nieprawdaż?
A czy twój ulubiony język zrobi to lepiej?
Nazywam się Wiktor Gworek i jestem gospodarzem tego bloga.
18:30 12-12-2007
Nie wiem czy lepiej, ale też ładnie
18:41 12-12-2007
No i python, też ładnie
18:51 12-12-2007
@adriahu
Perl? Hmmmm... ciekawe, ale widać jaką magię Perla w drugiej linijce :). Gdybym to gdzie indziej zobaczył to pewnie bym się nie domyślił, o co chodzi :). Użyteczna jest konstrukcja
print for.Python? Też ładnie, ale
print elementpowinno się znajdować w następnej linijce ;).18:55 12-12-2007
W perlu to nie jest magia, tych parę użytecznych zmiennych można łatwo zapamiętać
A w pythonie nie trzeba nowej linii 
18:57 12-12-2007
Dobry komentarz napisał także Adrian Olek, że w Ruby'im wystarcza po prostu:
Przy założeniu, że wypisujemy na standardowe wyjście, gdybyśmy chcieli wypisywać gdzieś do logów to wygodniejsze byłoby zastosowanie bloku.
Podejście w Javie, Ruby'im (tym w komentarzu), Pythonie, Perlu jest czysto imperatywne, natomiast w Ruby'im (tym w poście) oraz w Scali jest bardziej funkcyjne.
Kwestia gustu, a o gustach się nie dyskutuje :).
19:00 12-12-2007
@adriahu
Perl. Każdy język ma parę takich "tajemnic" :).
Python. Jasne, że nie trzeba, ale wtedy w Javie bym zapisał to tak:
19:38 12-12-2007
Faktycznie o gustach nie powinno się dyskutować, ale gdy myślę o podejściu funkcyjnym (funkcjonalnym)
od razu przypomina mi się świetny dialekt lispa o nazwie scheme. Czy to nie w tym języku "scałkowano pierwszy raz ruch układu słonecznego"? 
20:33 12-12-2007
[...] Poznajemy nowe języki programowania: Scala, czyli jak wypisać elementy z listyblog.mocna-kawa.com/2007/12/12/poznajemy-nowe-jezyki-scala-c... dodane przez wwiktorr od paru sekund [...]
20:54 12-12-2007
Już jest 20:33
hmmm
21:16 12-12-2007
Rzeczywiście ładne. A teraz prosimy o jakieś bardziej praktyczne zastosowanie. Wypisać listę (10 elementów) można i w whitespace:
http://compsoc.dur.ac.uk/whitespace/count.ws
(jak nie widać nacisnąć ctrl+a)
Na razie widzę ładne rozwiązanie problemów osób, które nie lubią perla/basha i potrzebują śmigać w konsoli, a na pisanie w "zwykłej" javie nie mają czasu. Dobra alternatywa dla Rubiego. Co jeszcze? Silna kontrola typów, plus, statyczne typowanie minus, ale mały.
22:42 12-12-2007
@Koziołek
Whitespace jest świetny :). Dodajmy jeszcze brainfucka i będziemy w siódmym niebie
3:18 12-13-2007
Największe możliwości fajnego zapisu w scali dają call by name i implicits, dzięki nim można bez problemu pisać potem:
1.foo
czy
myif (cond) { foo } myelse { bar }
11:49 12-14-2007
A ja tam wolę Coca Colę - parafrazując "wielkiego poĘtę"
tzn. nie chciałbym kiedyś przeglądać kodu o tak srkóconej postaci, bo - jeśli się dobrze nie znasz - to ciężko coś takiego przeczytać, do czego się odnosi i wogóle... Kurczę, a może jestem zbyt konserwatywny?
Pozdrawiam
18:50 12-14-2007
pitorek: to daj poczytac kod javy osobie "swieckiej" ;). Wiadomo, ze zeby czytac kod trzeba znac (chocby troche) jezyk programowania.
Z innej beczki:
Siedze w jezykach kilka lat, ruby, python, java, c# itd. Niedawno tez odkrylem scale i jak na razie wglebiam sie .. cos czuje, ze znalazlem swoj nowy ulubiony jezyk :).
19:19 12-14-2007
@jau
Nieprawdaż? Jak ja się wgłębiam w Scalę to mam takie miłe uczucie, że to jest to :). Tak samo, jak było z Javą (myślałem: ale ona fajne ;)).
21:35 12-14-2007
JAVA: for (int x : Arrays.asList(1, 2, 4) System.out.println(x);
22:04 12-14-2007
poza tym scala pozwala stworzyc nowy typ danych - stos, gdzie dodawanie elementow bedzie wygladac tak
lista
element
a usuwanie
lista
element
Pokazcie mi drugi jezyk, ktory tak potrafi
23:09 12-14-2007
Z tego co rozumiem (i co chyba jest napisane na Wikipedii) to currying nie polega na ominięciu typu w deklaracji, tylko stworzeniu nowej funkcji, ktora przyjmuje mniej argumentow...
23:59 12-14-2007
Perl:
print join ("\n", @lista);
lub używając 'zmiennej magicznej':
$, = "\n";
print @lista;
Python:
print "\n".join (lista)
9:39 12-27-2007
A mi sie marzy LISP z dobrymi bibliotekami, a tak jestem zdany na rubiego. Ech co by nie mowic o javie to biblioteki ma swietne.
13:21 01-27-2008
Scala ma bardzo fajną własność, którą nigdzie wcześniej nie spotkałem. Mianowicie w Scali technicznie nie ma operatorów. Wyrażenie 1 + 2 jest tożsame z wywołaniem metody 1.+(2)
Podstawa to podstawy. O ile pamiętam w takim języku jak Smalltalk operatory były tak naprawdę metodami, więc nie jest to nic nowego.
Kolejne języki nie wprowadzają tak naprawdę nic nowego poza kompilacjami istniejących już i stosowanych paradygmatów programowania w różnych proporcjach.
Warto byłoby się zastanowić raczej nad pytaniem "Dlaczego scala może ułatwić tworzenie oprogramowania ? Dlaczego miałaby się dobrze przyjąć?" Moim zdaniem heterogeniczne środowiska (powiedzmy Java + Scala) znakomicie podnoszą kłopotliwość tworzenia (złożonych) systemów informatycznych, zwłaszcza w kontekście zespołowej pracy i późniejszego utrzymania.
13:51 01-27-2008
@Tomek
Smalltalk to było dopiero szaleństwo. Metody np:
labirynt go: there :with light :and
Piękne :).
Muszę się zgodzić, że nieheterogeniczne środowiska są trudniejsze w utrzymaniu. Jest także to kwestia ludzi, którzy żeby poznać działanie aplikacji muszą znać kilka języków.
Mnie bardzo podoba się idea (nie weryfikowana jeszcze w praktyce) polyglot programming, gdzie używa się odpowiednich języków/technologii do pracy, np. Ruby on Rails do frontendu, Java jako backend. Czas wszystko zweryfikuje. Ja wierzę w tą ideę.
20:52 01-27-2008
Ja w tę ideę wierzyłem (i nadal trochę wierzę).
Ideę zweryfikowałem na 2 sporych projektach ( 4 m-ce x 4 os), miksując JEE + Adobe Flex 2. Generalnie ujdzie, ale:
w krótkim czasie programista nie jest w stanie być dobry w wiecej niż 1 technologii, mam na myśli bycie rzeczywiście świadomym języka, jego charakterystyki, dobryk praktyk etc.
konieczność przełączania się z języka do języka wybija z rytmu pracy
mimo prób rozdzielenia warstw oprogramowania niestety niektóre rzeczy musisz powielać
integracja bywa trudna, czasochłonna i nie działa zbyt wydajnie
proces budowania lub CI jest zdecydowanie trudniejszy
2:29 02-05-2008
To chyba nie jest currying. Tylko po prostu funkcja println jest takiego typu jakiego jest parametr for'a.
Currying to taki bajer że napisa f x y => x + y montuje funkcję typu int => (int => int). Zamiast int*int => int jak w pascalu, po bożemu.
10:12 02-05-2008
@br
Tak, z rozpędu napisałem, że to currying... co nie zmienia postaci rzeczy, ze currying w Scali występuje ;).
Wyjaśnię przykład br do końca:
f x y => x + y (funkcja bierze 2 argumenty i zwraca ich sume)
succ = f 1 (ukonkretnienie pierwszego argumentu, typ succ to (int => int)
write succ 4 (wypisze 5)
20:49 07-03-2008
@Mardok
http://clojure.org/