poniedziałek, 18 kwietnia 2016

Lista nieoczywista

To jest taki pierwszy z brzegu obrazek procesora ściągnięty z netu. Po co on tutaj jest? Ano aby pokazać, że wszystkie dyskusje o paradygmatach programowania sprowadzają się w ostateczności do tego jakie napięcie pojawi się o tam na tych "nuszkach".

Dla procesora te dyskusje z cyklu, który język lepszy itd są niezrozumiałe bo on widzi i tak tylko 10100010111 czy coś podobnego. Zaś dla ludzi sytuacja jest inna. Dla ludzi poczciwych jak ty i ja być może bardziej abstrakcyjne spojrzenie pomoże ogarnąć szersze przestworze cyfrowych konstrukcji. W końcu po to są metafory aby rozumieć coś nowego w kontekście czegoś starego. A jeśli metafora pomoże zmniejszyć ilość spalonych dolarów na produkcji to tym lepiej. To zobaczmy pierwszą metaforę dla Listy - dla czegoś czego używamy od zawsze i zazwyczaj sie kojarzy z przypadkiem "Lista produktów" albo Lista Userów, a teraz inaczej...

Lista jako alternatywa dla...

Option lub Optional lub Maybe w zależności od języka. Dokładnie tak. Bardzo często spotykam się z porównaniem Option do takiego obiektowego-ifa czy czegoś w tym stylu. Raczej mało osób kojarzy wchodzi rozmyślaniami w system typów i konsekwencje sprowadzenia opcjonalności do wyniku obliczeń

Krótka notka odnośnie nulla i Optional. W przypadku zapoznawania kogoś z koncepcją Optional w Javie8 pojawia się czasem pytanie "no ale co gdy Optional będzie nullem". Wtedy mamy do czynienia z objawem debilizmu lub geniuszu - już tłumaczę. W Javie7 null jest prostym sposobem zasygnalizowania, że czegoś nie ma i ten null może to być częścią interfejsu jak to :"jak nie będzie wyniku to zwracam nulla" - podobno po to ten null powstał. Gdy już mamy do dyspozycji Optional , który jednocześnie jawnie sygnalizuje "możliwośc braku" a umiejętnie użyty oszczędza nam do tego narzutu checked-exception - to wtedy zwracanie nulla gdzie w typie jest Optional jest oznakiem niedowładu mózgu ... albo wyjątkowej wiedzy bo podobno Optional w Javie8 wcale miał nie być takim Optional jako Optional bo nie jest serializable, puste czy nie puste to jedna klasa a architekci z oracla podobno toczą pianę jak ktoś wspomni, że chciałby użyć tego jako typu pola w klasie. Ale mimo wszystko - jak już w sygnaturze metody ktoś dał Optional a ktoś inny zwrócił null - to raczej mamy do czynienia z objawą szaleństwa aniżeli geniuszu.

Natomiast jest to trochę niecodzienna percepcja Optionala widzieć go jako taką małą Listę - albo w drugą stronę - percepcja Listy jako takiego dłuższego Optionala . Po raz pierwszy się z tym spotkałem w kursie FP in Haskell gdzie Erik Meijer wspomniał, że lubi używać List zamiast Maybe (w haskellu jest Maybe a zamiast Some jest Just - dzięki czemu można stosować polski żart Just(5) - ale Gimby pewnie nie znajo...) bo w Maybe może sobie przechować tylko jedną potencjalną wartość - i to jest dosyć ciekawe Lista jako struktura przechowująca n opcjonalnych wartości.

Taki kodzik sobie zobaczmy :

type HTML=String

case class User(login:String, email:String)

val extractEmail:User=>String= _.email
val displayEmail: String => HTML = email =>
      s"""
         |<h1> EMAIL </h1>
         |<span> ${email} </span>
       """.stripMargin

Jest tam i User (byśmy mogli rzec, iż jakoś "biznesowo" jest) jak i dwie banalne pokazowe funkcje aby zbudować mały ciąg przekształceń. I patrz, i patrz jak ten kod jest do siebie podobny :

//option
def findUser(login:String):Option[User]=Some(User("Roman","donjuan17@wp.pl"))
findUser("Roman").map(extractEmail).map(displayEmail).getOrElse("""<h1>Nie ma takiego zioma</h1>""")

//list
def findUserList(login:String):List[User] = List(User("Roman","donjuan17@wp.pl"))
findUserList("Roman")
.map(extractEmail).map(displayEmail).headOption.getOrElse("""<h1>Nie ma takiego zioma</h1>""")

taka nowa ciekawa perspektywa co nie? Lista jako 0..n opcjonalnych elementów. Ale można na Listę spojrzeć jeszcze z innej strony.

Efekt - ale czego ?!?

Mamy takie dwie proste funkcje :

val addThree:Double=>Double= _ +3
val timesTwo:Double=>Double = _*2

Możemy je zastosować :

W kontekście efektu opcjonalności :

Option(1.0).map(addThree).map(timesTwo)

W kontekście efektu błędu :

Try(1.0).map(addThree).map(timesTwo)

W kontekście efektu czasu :

Future(1.0).map(addThree).map(timesTwo)

I mogę sobie coś takiego zastosować na liście :

List(1.0).map(addThree).map(timesTwo)

Składnia podobno ale czy to jest jakiś efekt ta lista? A jeśli jest to efekt to efekt ku*wa czego?

A wybierz se co chcesz

y=f(x)

Co jest tak niesamowitego w tej linijce powyżej, że ma własne formatowanie i italica? Otóż funkcja aby była funkcją musi mieć jeden wynik. No i zazwyczaj ma - findUser i jest user. albo 2+2=4 ale jaki jest wynik czegos takiego : 0=x^2-4 ?

Math.pow(2,2)-4
Math.pow(-2,2)-4

Nie ma jako takiego "jednego rozwiązania" - gdybyśmy chcieli znaleźć wszystkie możliwe rozwiązania (nie licząc krzywych wymiarów zapętlonie-zespolonych) to kod moglibyśmy napisać tak :

def allSqrts(v:Int)=List(-Math.sqrt(4),Math.sqrt(4))
allSqrts(4) //res12: List[Double] = List(-2.0, 2.0)

I cały dowcip polega na tym, że tam gdzieś jest dobra odpowiedź ale ja nie wiem która - i w sumie przez chwilę nie chcę wiedzieć.

allSqrts(4).map(addThree).map(timesTwo) //List[Double] = List(2.0, 10.0)

Może wezmę pierwszy, może większy, może mniejszy - to zależy od kontekstu (jak zwykle). A te wszystkie metody z rodziny fold czy reduce, które np. liczą sume zysku to tak abstrakcyjnie patrząc wszystkie polegają na tym, aby przejść od stanu nie-determinizmu do pewnej określonej wartości.

Czyli patrząc na coś takiego :

sealed trait SchrodingerCat
case object Alive extends SchrodingerCat
case object Dead extends SchrodingerCat

val catStates=List(Alive,Dead)

Może warto przeredagować paragraf z poprzedniego punktu =>

W kontekście efektu braku determinizmu :

List(1.0,2.0,3.0).map(addThree).map(timesTwo)

Brak komentarzy:

Prześlij komentarz