niedziela, 12 lipca 2015

Nauka programowania funkcyjnego poprzez synestezję

Pierwsze wnioski po dwóch warsztatach z programowania funkcyjnego wyglądają tak :

I oczywiście pole powierzchnia kółek oraz cześć wspólna jest wzięta z d*** - tudzież na oko - i ma tylko znaczenie symboliczne nie zaś reprezentatywne.

Plan była taki, iż najpierw będzie trochę warsztatów ze scali gdzie ludzie nauczą się jej składni po czym będzie można przejść do praktycznych zastosowań. I jednak nie można przyjść do tych zastosowań bo tematem są zainteresowani ludzie, którzy twierdzą, ze takie konstrukcje jak w scali to widzieli w perlu 20 lat temu. No mają swoje zdanie - ja mam inne ale nie mogę zaprzeczać, że największą trudnością w nauce przy pomocy przykładów, które przygotowałem na warsztaty była własnie składnia scali.

Można popróbować kilku podejść w przyszłości - można uśmiechnąć się w kierunku Javy8 - chociaż po przejściu progu nauki Scali uważam, że to składnia Javy jest trochę okaleczona ale w swym okaleczeniu na tyle spójna, że przystępna do nauki.

Można wrócić do próby nauki scali przy pomocy nauki jakiegoś praktycznego narzedzia jak to było z playem.

A można w końcu wziąć przykład z placówek (hahaha własnie przeglądam tekst po raz drugi i zauważyłem, że zamiast "placówek" napisałem "palcówek" - If yoy know what I min) gdzie efektywność nauki jest chyba największa na świecie - mowa oczywiście o przedszkolach...

Ale zanim co - to jedyny filmik jaki kiedykolwiek wrzuciłem na youtube - było to prawie dwa lata temu kiedy zaczynałem prowadzić pierwsze wykłady z programowania funkcyjnego. Wydaje mi się, że po dwóch latach nauki w końcu mogę pomału zacząć robić to poprawnie.

Co to jest synestezja

https://pl.wikipedia.org/wiki/Synestezja
Synestezja (gr. synaísthesis – równoczesne postrzeganie od sýn – razem i aísthesis – poznanie poprzez zmysły) - w psychologii stan lub zdolność, w której doświadczenia jednego zmysłu (np. wzroku) wywołują również doświadczenia charakterystyczne dla innych zmysłów, na przykład odbieranie niskich dźwięków wywołuje wrażenie miękkości, barwa niebieska odczuwana jest jako chłodna, obraz litery lub cyfry budzi skojarzenia kolorystyczne itp.

To co spróbujemy zrobić to nie będzie taka raczej pseudo-synestezja gdyż jakowoż postaramy się wywołać wrażenia zmysłu matematycznego (który w praktyce nie istnieje) poprzez działanie na zmysł wizualny

Mając np. takie typy

type A
type B
type C

Zazwyczaj przedstawiamy serię abstrakcyjnych przykładów stymulując zmysły matematyczny (i nie wiem czy w praktyce istnieje coś takiego jak zmysł matematyczny ale żym słyszał o czymś takim jak indywidualna inteligencja matematyczna)

val fun1: A => B = ???
val fun2: B => C = ???
val andThen: A => C = fun1 andThen fun2

I to bylibymy jeszcze w stanie wytłumaczyć ale co jak dojdziemy do "ciekawszych konstrukcji"

val twoParamFun: (A, B) => C = ???
val curry: (A, B) => C => A => B => C = ???

Czy żeby już się tak definitywnie popisać  :

trait Functor[F[_]] {
  def map[A, B](fa: F[A])(f: A => B): F[B]
}

Da się ludzi i tak nauczać ale fakt, że "baj default" statystyczny (podkreślam statystyczny) student posadzony do kodu pisze kod proceduralny a nie abstrakcyjny kod modularny może wskazywać, że konkret a nie abstrakcja jest znowu "statystycznym" poziomem podejścia do problemu. a gdyby tak...

type GREEN
type YELLOW
type REED

... i odpowiednio ...

val fun1: GREEN => YELLOW = ???
val fun2: YELLOW => REED = ???
val andThen: GREEN => REED = fun1 andThen fun2
val twoParamFun:(GREEN, YELLOW) => REED = ???
val curry:(GREEN, YELLOW) => REED => GREEN => YELLOW => REED = ???

Ewentualnie jak ktoś miał dzieciństwo jeszcze przed fejsbukiem

W stronę bardziej abstrakcyjnych konstrukcji

Oto chyba jeden z najbardziej testowalnych kawałków kodu

val f: Int => Int = x => x + 1

Jest tez super re używalny bo moge go zastosować wszędzie tutaj :

List(1, 2, 3) map f
Some(1) map f
Try(1) map f
Future(5) map f

Jak i powymyslać swoje konstrukcje

object Produkt {
  type NiezwykleSpecjalistycznaDomenowaNazwaZeAzDechZapiera = Int => Int
  def zmienCene(f: NiezwykleSpecjalistycznaDomenowaNazwaZeAzDechZapiera) = ???
}

Produkt zmienCene f

Ten tekst jest pogrubiony bo teraz będzie coś bardzo waznego. Dopiero niedawno to załapałem :

type NormalType = Int
type HigherType = List[Int]

val f: NormalType => NormalType = ???
val specialFunction: (NormalType => NormalType) => (HigherType) => HigherType = ???
val fh: HigherType => HigherType = specialFunction(f)

Co tutaj się dzieje? Udało nam się napisać funkcję która zmienia prymitywną, łatwą do testowania, oczywista funkcyjkę na coś - bardziej złożonego, mniej reuzywalnego ale potezniejszegow danym kontekście. Innymi słowy podnieśliśmy funkcję f:Int=>Int do funkcj f:List[Int] => List[Int] stąd też nazwa lift. I dalej kilka takich praktyczniejszych przykładów.

val f = (x: Int) => x + 1


val liftToList = (f: Int => Int) => (la: List[Int]) => la map f
val liftedList = liftToList(f)
liftedList(List(1, 2, 3)) //res3: List[Int] = List(2, 3, 4)


val liftToOption = (f: Int => Int) => (oa: Option[Int]) => oa map f
val liftedOption = liftToOption(f)
liftedOption(Some(1)) //res4: Option[Int] = Some(2)

I patrzcie jaki to ma efekt i co się dzieje z przekazanymi obiektami typu List i Option. A teraz mindfuck - można zmapowac funkcję sama ze sobą (po imporcie scalaz)

val mappedF = f map f
mappedF(1) // res5: Int = 3

val liftToFunction = (f: Int => Int) => (fa: Int => Int) => fa map f
val liftedFunction = liftToFunction(f)
liftedFunction(x => x + 2)(1) // res6: Int = 4

Aż zerknąłem jak to jest zaimplementowane...

/** Wraps a value `self` and provides methods related to `Functor` */
final class FunctorOps[F[_],A] private[syntax](val self: F[A])(implicit val F: Functor[F]) extends Ops[F[A]] {
  ////
  import Leibniz.===

  final def map[B](f: A => B): F[B] = F.map(self)(f)

Wydaje się, że Leibniz to miły człowiek...
W każdym razie lift to by było coś w ten deseń

type GREEN
type YELLOW
type REED

class Shape[A]()

val greenShape = new Shape[GREEN]()
val f: GREEN => YELLOW = ???

val liftToShape: (GREEN => YELLOW) => (Shape[GREEN]) => Shape[YELLOW] = ???

val lifted: (Shape[GREEN]) => Shape[YELLOW] = liftToShape(f)

I na koniec klasyczny argument

"Nie ku*wa wypie*dalać z tym bo kto to będzie utrzymywał jak nikt tego nie zna" - tak... spalmy samochody bo nikt na wiosce nie ma prawa jazdy i tylko syn starosty kiedyś jechał traktorem po grządce ziemniaków.

No jasne, że nie będziemy w punkcie czasu t1 budować dzwigiem jak 98% programistów na rynku umie używać tylko młotka (statystyka wzięta z dupy) ale może by tak się pokusić by w czasie t2 już jakaś załoga umiała ten dźwig obsługiwać a to się nie stanie jak wszyscy do okoła będą optymalizować swoje minima lokalne na Q3 i rzucać tylko cytatami z 7 minutowego managera.

Tudzież zapraszam serdecznie na odbywające się cyklicznie warsztaty i wykłady JUGa gdzie w miłej atmosferze i niejedno kroć darmowym jedzeniu można jakże przyjemnie wchłaniać wiedzę budując lepsze jutro zarówno dla siebie jak i szeroko rozumianej lokalnej społeczności IT.

Brak komentarzy:

Prześlij komentarz