Książka w sposób doskonały wprowadza w tajniki Scali prowadząc czytelnika za rękę - najpierw słów kilka o problemie, aby przedstawić rozwiązanie przez przykłady. Cała książka nafaszerowana jest przykładami i co rusz można trafić na coraz bardziej ciekawe jednolinijkowce. Książka marzenie!
Dzisiaj zobaczyłem kombinację Range, map i foreach do wyrysowania choinki z gwiazdek.
* ** *** **** *****Zanim zadam zadanie, proponuję odświeżenie wiadomości dotyczących programowania funkcyjnego - dzisiaj to Scala, ale w Clojure i F# byłoby baaaardzo podobnie.
Scala udostępnia typ Range, który reprezentuje uporządkowaną serię liczb całkowitych. Korzystamy z metody to do stworzenia obiektu typu Range.
scala> 1 to 5 res0: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5)Range posiada cechę (trait) IndexedSeq, który oferuje metodę map, która z kolei tworzy strukturę danych typu parametru wejściowego i aplikuje funkcję do każdego jej elementu.
scala> scala> (1 to 5) map (_ * 2) res1: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)W Scali mamy również operator (metodę) mnożenia dla typu String, który tworzy ciąg powtarzających się znaków o liczności drugiego parametru.
scala> "1" * 5 res2: String = 11111Ostatnią ważną metodą jest foreach na sekwencji, która wykonuje funkcję z efektem ubocznym, np. wypisanie na ekran (println), dla każdego elementu bez dbania o zwracany wynik.
scala> (1 to 5) foreach { e => println(e.toString * 3) } 111 222 333 444 555Z tą wiedzą możesz spróbować rozwiązać malutkie zadanko. Zamień "XXX" na właściwe wykonanie funkcji w poniższym jednolinijkowcu, aby wyświetlić choinkę z gwiazdek.
scala> XXX map XXX foreach XXX * ** *** **** *****Jeśli tego typu zadania i sposób nauki języka Scala przystają do Twoich oczekiwań, 9 lipca (wtorek) na MIMUWie organizuję scalania - naukę Scali przez grupowe rozwiązywanie krótkich zadań programistycznych. Gorąco zachęcam do udziału!
Nieco alternatywne podejście (spoiler) przy użyciu strumieni. I podobne rozwiązania w Javie... 8.
OdpowiedzUsuńWreszcie rysowanie "diamentu", wyższy poziom trudności.
świetny pomysł ze strumieniami. na to bym nie wpadł :)
UsuńCzy to jest dobre rozwiązanie tzn akceptowalne? Jestem początkujący w scali (spoiler)
OdpowiedzUsuńTen komentarz został usunięty przez autora.
UsuńMyślę, że akceptowalne :))
OdpowiedzUsuńDla porównania załączam swoje
Dodam jeszcze swoją propozycję rozwiązania, wydaje mi się, że będzie to najbardziej funkcyjne podejście, bo funkcja z efektem ubocznym jest wywoływana tylko raz:
OdpowiedzUsuńdef christmasTree(size:Int) = (1 to size).map("*" * _).mkString("\n")
println(christmasTree(5))
Wydaje mi się jednak, że gdybym miał pracować nad taką choinką w projekcie komercyjnym, wolałbym, żeby była napisana tak:
for (i <- 1 to 5) {
println("*" * i)
}
To chyba będzie najłatwiejsze to naprawiania, zmieniania, refaktoryzowania ;)
Cześć Marcin,
UsuńRozwiązanie podoba mi się i właśnie o coś takiego chodziło. Brawo!
Odnośnie imperatywnej wersji, to jej łatwość "naprawiania, zmieniania, refaktoryzowania" jest jedynie kwestią gustu (piękno jest w oku posiadacza) i trzymania się podejścia (funkcyjne vs imperatywne). Wybieram funkcyjne rozwiązanie, bo zwraca wartość, z którą można *coś* zrobić później w innym miejscu aplikacji - jest po prostu bardziej uniwersalne do ponownego użycia.