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:
[Java]
List
add(1); add(2); add(3); add(4);
}};
for (Integer x : lista)
System.out.println(x);
// Można też tak, ale raczej nie bym nie polegał na metodzie toString()
System.out.println(lista.toString());
// lub po prostu:
System.out.println(lista);
[/Java]
Dla odmiany w Ruby’im zrobilibyśmy to tak:
[Ruby]
# 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
[/Ruby]
Zobaczmy teraz, jak zrobilibyśmy to w Scali.
[Scala]
val lista = List(1, 2, 3, 4)
lista.foreach((x: Int) => println(x))
[/Scala]
Brzydko… idziemy dalej. Scala jest językiem funkcyjnym, który ma mechanizm currying. Opuśćmy deklarację typu i nawiasy.
[Scala]
lista.foreach(x => println(x))
[/Scala]
Nadal brzydko… idziemy dalej. Co jest argumentem metody foreach? Sygnatura metody jest następująca:
[Scala]
def foreach(f: A => Unit): Unit
[/Scala]
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:
[Scala]
def println(x: Any) = Console.println(x)
[/Scala]
czyli bierze jakiś argument (nadal patrz: currying, funkcje wyższego rzędu) i zwraca Unit. Zatem typy się zgadzają. Zapiszmy to krócej:
[Scala]
lista.foreach(println)
[/Scala]
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:
[Scala]
lista foreach println
[/Scala]
Piękny zapis, nieprawdaż?
A czy twój ulubiony język zrobi to lepiej?

Nazywam się
Wiktor Gworek
i jestem gospodarzem tego bloga.
[perl]
@lista = (1, 2, 3, 4);
$\ = “\n”;
print for @lista;
[/perl]
Nie wiem czy lepiej, ale też ładnie
No i python, też ładnie
[python]
lista = [1, 2, 3, 4]
for element in lista: print element
[/python]
@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 linijceW perlu to nie jest magia, tych parę użytecznych zmiennych można łatwo zapamiętać
A w pythonie nie trzeba nowej linii
Dobry komentarz napisał także Adrian Olek, że w Ruby‘im wystarcza po prostu:
[ruby]
puts [1, 2, 3, 4]
[/ruby]
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
.
@adriahu
Perl. Każdy język ma parę takich “tajemnic”
.
Python. Jasne, że nie trzeba, ale wtedy w Javie bym zapisał to tak:
[java]
for(Integer x : lista) System.out.println(x);
[/java]
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”?
[...] 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 [...]
Już jest 20:33
hmmm
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.
@Koziołek
Whitespace jest świetny
. Dodajmy jeszcze brainfucka i będziemy w siódmym niebie
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 }
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
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
@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
).
JAVA: for (int x : Arrays.asList(1, 2, 4) System.out.println(x);
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
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…
Perl:
print join (“\n”, @lista);
lub używając ‘zmiennej magicznej’:
$, = “\n”;
print @lista;
Python:
print “\n”.join (lista)
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.
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.
@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ę.
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
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.
@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)
@Mardok
http://clojure.org/
[php]
print_r($lista);
[/php]