13 kwietnia 2013

Podkreślnik jako substytut parametrów funkcji w Scali

Zacząłem bawić się podkreślnikiem "_" w Scali jako substytut parametrów funkcji.

Jakoś tak się potoczyło, że trafiłem na stronę Wikipedii o literałach funkcyjnych w Scali, na której znalazłem poniższy przykład (zmodyfikowałem go nieznacznie na potrzeby tego wpisu):
List(1, 2, 3, 4).reduceLeft(_ + _)
A pod nim komentarz:

"// Each underscore stands for a new unnamed parameter in the anonymous function.
// This results in an even shorter equivalent to the anonymous function above."


Zwykle tak właśnie u mnie bywa, że drobne rzeczy mają niebagatelny wpływ na moje rozumowanie sprawy i ten, z pozoru błahy, komentarz przypomniał mi o moich dokonaniach w serwisie Coursera w kursie o Scali.

Nie mogę narzekać na ostatnie wyniki z zadań w Functional Programming Principles in Scala.

Idzie całkiem gładko i niezwykle przyjemnie. Nie raz już pisałem o tym szkoleniu i polecam je każdemu - choćby dla poszerzenia horyzontów.

W sekcji Extra Hints do zadań w Week 2: Higher Order Function można było znaleźć taką podpowiedź:

"Most of the solutions for this assignment can be written as one-liners. If you have more, you probably need to rethink your solution. In other words, this assignment needs more thinking (whiteboard, pen and paper) than coding ;-)."

Największym wyzwaniem intelektualnym było wyrażenie exists przez forall, ale coś mi mówiło, że mogę więcej przy definicji funkcji podobnych do poniższej:
def funkcjaZwracajacaFunkcje(arg: Int): Int => Int = e => e + arg
Wywołanie funkcji funkcjaZwracajacaFunkcje zwraca funkcję jednego parametru, który dodawany jest do poprzedniego.
scala> funkcjaZwracajacaFunkcje(5)(4)
res9: Int = 9
Nic odkrywczego, poza podstawową znajomością składni Scali.

I kiedy przeczytałem o podkreślniku jako symbolu zastępczym dla kolejnych parametrów funkcji w 8.5 Placeholder syntax (z książki Programming in Scala, First Edition) wiedziałem już, czego brakowało mi w moich jednolinijkowcach na courserze!

Zamieniłem definicję funkcji na korzystającą z podkreślnika!
def funkcjaZwracajacaFunkcje(arg: Int): Int => Int = _ + arg
To jest znacznie przyjemniejsze dla (mojego) oka. Tu dostrzegam wartość stosowania Scali nad odpowiednikiem w Javie (który nota bene wymagałby zastosowania dodatkowych bibliotek i/lub klas anonimowych!)

2 komentarze:

  1. Nie pamiętam zadania z exists/forall, ale brzmi to jak implementacja uogólnionego prawa De Morgana na kwantyfikatory. Może nie brzmi to najlepiej, ale jeden ze wzorów powyżej stanowi rozwiązanie (nie chcę zdradzać zbyt wiele, chyba, że termin pracy domowej już upłynął).

    OdpowiedzUsuń
    Odpowiedzi
    1. Tak, dokładnie - "This idea can be generalised to quantifiers, so for example the universal quantifier and existential quantifier are duals:" jest rozwiązaniem i przyznam szczerze, że nie znałem tego wcześniej. Widziałem dualizm, ale dopiero kilka godzin ślęczenia dało właściwy rezultat.

      p.s. Niestety, z podkreślnikiem pospieszyłem się z moją euforią - jedynie jedna z implementacji pozwoliła na skrócenie z podkreślnikiem. Pozostałe wołają ów pojedynczy parametr z dwoma funkcjami, np. e => f(e) && g(e), albo funkcja woła inną (opóźnia jej wykonanie), np. e => f(x, y => g(e, y)).

      Usuń