pondelok, 3. apríla 2017

Rozvinuté myšlienky

Peniaze slúžia na automatizáciu života

Umožňujú nám vyhýbať sa zložitým životným situáciám alebo problémom a nechať ich na iných. Nepriamo tak rozširujú náš confirmation bias. Vďaka nim sa dokážeme viac vyhýbať "trápeniu" z dosahovania potrieb, ktoré koniec koncov má pozitívny efekt na náš sebarozvoj. Tým, že veci, ktoré chceme, dosahujeme rýchlejšie, telo častejšie vyplavuje dopamín. A ten má podľa mňa vplyv na výkyv nálad a psychické problémy.

Trestáme sa za nesplnené nároky na seba či chyby

Za motiváciou je dopamín (okrem iného). Pričom platí efekt "pamäťového dopamínu", kde sa mozog naučí dopamínovo reagovať na situácie podľa jej častosti a výsledku. To znamená, že čím častejšie sa z opakovanej činnosti budeme cítiť dobre, tým viac mozog uverí tomu, že je to pre nás dobré, a bude to chcieť zažívať znova. Pocity zlosti či sklamania zo seba teda učia mozog zlému pocitu. Tento pocit sa "vďaka" dopamínového pamäťového efektu môže potom dostavovať skôr než situáciu začneme riešiť. A tak sa nám do nej nechce.

Bez predsudkov na motiváciu

Prišiel som na to, že nie je správna cesta myslieť si, že si človek "zaslúži" cítiť sa dobre až po úspechu. Samozrejme, to tiež. Funguje to totiž len do chvíle, kým sa nám darí. Ale keď sa nám prestane dariť, kvôli zlému pocitu nás postupne opustí aj chuť.

Správnou cestou je podľa mňa sa naučiť necítiť negatívne pocity predtým, než sa do niečoho pustíme. Predsudky fuj. Nie však slepo veriť v úspech. Dokonca ideálne je - ak sa to dá - tešiť sa. Ale dá sa to naučiť? Neviem.

Prístupnejšie sa javí lepšie reagovať až po situácii. Napríklad po neúspechu by sme sa nemali trestať a obviňovať sa. Naopak - hľadať to pozitívne, prípadne vysvetľovať, prečo sme sa tak zachovali. Tým, že prestaneme všetko transformovať na "je to moja chyba", a naopak nájdeme niečo pozitívne na našom konaní či aspoň snahe - postupne zmizne pocit "nahovno". A opäť - mozog sa to začne učiť, pričom v ďalšej situácii nám snáď dopamín "zlého pocitu" nevyplaví a už budeme istejší.

Dobrý pocit samozrejme nie je zárukou úspechu, ale myslím si, že je iskrou pre motiváciu. A to je už čo povedať!

sobota, 25. marca 2017

Nezodpovednosť - prejav stratenosti

Prečo sú niektorí ľudia nezodpovední? Každý sa občas na niečo vykašle, no iní sa nedajú "dokopy" po celý život. Je to ich trend, životné krédo - spojené s neviazanosťou, jednorázovými zážitkami, nedokončenými cieľmi.

Pre "nezodpovedných" sú životné ciele často hmlisté alebo príliš nereálne, akoby s nimi neboli stotožnení. Miesto toho bez problémov vezmú tri pôžičky, kúpia si napr. auto aj keď sú bez práce, prípadne prehajdákajú posledný cent z každej výplaty. Alebo nezaplatia nájomné a miesto toho si radšej kúpia drahé topánky... Často len nechápavo žasnem, mne to teda zmysel nedáva. Prečo tak robia?

Dospel som k nasledujúcim myšlienkam. Myslím si, že nezodpovednosť môže vyplývať z pocitu straty vlastnej kontroly nad životom. Z pocitu straty možnosti ho ovládať podľa vlastných predstáv. Nezodpovednosť ako taká je potom iba prejavom - buď straty dôvery vo vlastné schopnosti niečo v živote dosiahnuť, alebo frustrácia a rezignácia z presvedčenia, že sa v živote jednoducho nedá dosiahnuť to, čo človek chce. Akoby všetko unikalo z dosahu, a zároveň provokovalo svojou blízkosťou.

Aj preto si myslím, že pre nezodpovedných sa život proste zdá byť príliš ťažký. Často tak sami seba presviedčajú o opaku, alebo sa možno skôr utešujú dopriavaním si okamžitých pôžitkov. Často totiž majú dojem, že si to "zaslúžia", pretože majú pocit, že vyvíjajú nadštandardné úsilie, ktoré si proste zaslúži odmenu (ďaľší nepriamy dôkaz, že sa im život zdá byť ťažký). Asi aj preto si takíto ľudia často nepripúšťajú, že konajú nezodpovedne.

Na druhej strane - keď sa nám niečo nepodarí, nastane životná zmena alebo sklamanie, môžme prejsť do akejsi formy nevedomého "trucu", akejsi rebélie (ja sa na to môžem vy...; mám to v pi...). Avšak to ešte nie je žiadna katastrofa. Je to akási forma obrannej reakcie. Stane sa to raz. Dvakrát. Občas. Ok...

Nezodpovednosť prichádza, ako jedna z možných evolučných stratégií (inou môže byť dlhodobé premáhanie sa, ktoré vedie k vyhoreniu), keď sme takýmito situáciami už "unavení", keď vnímame, ako naša "snaha" je skoro vždy márna, vďaka čomu si začneme budovať novú životnú teóriu, ktorou konfrontujeme výchovou vštiepeného rodiča v nás, a umlčíme ho. Často sa stáva, že takto utvorená teória je "povoľnejšia" vo viacerých veciach a preto sa dostaví aj pocit akéhosi oslobodenia, neviazanosti a sme "otvorení každej príležitosti".

Avšak, keď taká príležitosť naozaj príde, nie sme schopní sa do nej zahryznúť. Chýba pocit ownershipu (vlastníctva) alebo takej oddanosti, jednoty s danou príležitosťou (odosobnenosť). Stále ju vnímame neviazane, aj keď je možno životnou šancou a dokonca naším životným snom.

Nezodpovednosť je možno jedným riešením strachu z ďaľšieho zlyhania, alebo z bolesti spôsobenej obtiažami života, a neistého výsledku. A tak najistejšie sa začne javiť motto: bez cieľa nie je zlyhanie...

A tak hľadáme šťastie inak. A to v okamžitých pôžitkoch, zábavách, práce len pre peniaze, štúdium len pre papier, krátkodobé vzťahy. Samozrejme u každého sa to môže prejaviť inak, a nie každý, ktorý chodí do práce len kvôli peniazom je nezodpovedný. To je jasné. Pointa je, že taký človek nie je šťastný.

Čo je to zodpovednosť?
Pokúsme sa aspoň laicky a intuitívne zamyslieť nad tým, čo je to zodpovednosť.

Z jedného uhla pohľadu ide o akýsi aspekt činností, a to že sa na nás dá "spoľahnúť". Voľne povedané, že veci nezanedbávame.

Ďaľším rozvinutím "nezanedbávania", je zodpovednosť ako opak ľahtikárskeho myslenia, ktoré nám pomáha určiť si dôležité priority, dokázať sa vzdať okamžitých pôžitkov v prospech vznešenejšieho cieľa.

Taktiež treba poznamenať, že zodpovednosť vzniká len voči niečomu. Či už voči jednej úlohe, alebo voči životu, sľubu, atď.

Ďalej, treba si uvedomiť, že zodpovedne sa môžme chovať, aj keď nám na danej veci až tak nezáleží. Teda myslím si, že zodpovednosť striktne nevyžaduje pocit ownershipu. Zodpovední môžme byť aj v rámci sebaobety (náboženský či morálny predpis), prípadne presvedčenia, že tým ukazujeme svoju "vizitku". Takže aj takáto zištná zodpovednosť je zodpovednosť.

Sme nezodpovední, ak prokrastinujeme?
Z toho, čo som doteraz popísal sa môže zdať, že človeku, konajúcemu nezodpovedne buď na veci nezáleží (či prestalo záležať), alebo ignoruje aj akýsi etický/morálny predpis. Mohlo by sa zdať, že človek je v tomto prípade zbavený rodičovského ja ("svedomie"), a v noci môže pokojne spať.

Avšak existuje aj iný dôvod nezodpovedného konania. Je to akási zotrvačná neschopnosť, aktivovaná chronickou obrannou reakciou, skrytým strachom zo zlyhania. V takom prípade si človek väčšinou uvedomuje, že nie je v poriadku, trápi ho to, ale nevie čo robiť. Tu je príznačná prokrastinácia, klamlivo ako príprava na ťažkú situáciu, ktorá nás čaká. V prokrastinácii zotrvávame stále dlhšie, stále sa necítime byť dostatočne "pripravení"...

Je tiež zaujímavé sa zamyslieť, kedy ide o prokrastináciu. Nie vždy totiž, keď "nerobíme to čo máme", prokrastinujeme. Mám za to, že o prokrastináciu ide výlučne vtedy, ak z činnosti potom máme výčitky. Ide o akúsi "prípravu", akoby "poslednú večeru" pred tým, ako pôjdeme robiť to, čo máme. A prečo prídu výčitky? Jednoducho preto, že sme sa k "hlavnej činnosti" nakoniec ani nedostali... :(

Záver
Myslím si, že najväčšiu šancu sa z toho nekonečného nezodpovedného kruhu dostať majú tí, ktorí si to uvedomujú. Takže tí "s výčitkami".

Pretože výčitky svedčia o tom, že v niečo stále veríme. Ľudia bez výčitiek sú buď naozaj šťastní (reálne sa to dá), alebo ich umlčali a stali sa z nich ignoranti.

Myslím si, že dôležité je zbaviť sa strachu a predstavy o ťažkosti života. Skúsiť naopak prijať fakt, že život sme v rukách ani nikdy nemali a bola to len ilúzia. Netreba to preto riešiť.

Nehovorím prestať sa snažiť, len znížiť nároky. A znova objaviť záujem. Strach z neúspechu sa ľahšie prekonáva, ak o našej snahe nikomu zatiaľ nepovieme.

THE END

sobota, 28. januára 2017

Naivní blázni

Keď som sám,

cítim jeseň, plody zeme dozreté. Ticho noci strieda šum smutného lístia... Túžba po večnom odpočinku nesplneného sna. Návrat straty.

Vyčerpanosť - a pokoj. Morálka turistu tu neplatí. Stránim sa ísť po vyznačených chodníkoch.

Melanchólia, hudba večného tunela je cestou k môjmu svetu. Každý deň, o krok bližšie. Bosou nohou - mokrým machom - do svetla obklopeného tmou.

Ticho očí je hlboké ako prázdne jazero. Kto som? Naivný, či nevinný? Zatváram dvere vonkajšiemu svetu. Idealista. Chcem, aby bol svet nadprirodzený.

Nebo jasné, či bledé. Tma, rovnaká každú noc. Príležitosťou je predsa každý okamih :) Občas, keď sme sami, pripúšťame dúfanie v akýsi tajný zážitok... A keď si všimneme seba, stáť v postoji skutočného čakania, spojenie naivity a bláznovstva, tak sa zľakneme. Vraciame sa, zmätení vlastnou iracionalitou - nevieme či išlo o hru - do poznaného, smútku.

Blázni

Nakoniec - rád kráčam sám tichým lesom, a smútku si načúvam.. Tvrdia o nás, že sme blázni - keď tancujeme v tichu. No my vieme, že realita je ustálená hladina ničoho.

Našou cestou sú sny; nimi rúbeme hrozné hordy planých ovocných sadov! Veď naša naivita stúpa až na hodnovernosť nádeje, keď sme láskaví, a chápaví. Akési ticho vieme počuť aj v hluku konzumných, ohraničených myšlienok a slov.

Čo každému občas chýba, keď je smutný... Žijeme vo svojom (temnom) lese, každý má svoje trápenia. Blázni vedia, že po prebdenej studenej noci potrebujeme východ hrejivého slnka. Povzbudenie, porozumenie a pohladenie. Jemnosť, a ľudskosť. Záujem, a oporu. Opäť odložiť rolu otroka povinností. Na chvíľu prestať plávať len vpred, a uvedomiť si, že ide predsa len o cestu, vymyslený priestor, a nie istotu, ktorej sa dá držať.

pondelok, 2. januára 2017

Elm vs. Haskell - moje prvé dojmy

V posledných vianočných dňoch som sa trochu pohrával s programovacím jazykom Elm. Ide o funkcionálny jazyk na písanie webových frontendov alebo aj backendov, ktorý kompiluje do Javascriptu. Je zaujímavý hlavne v tom, že jeho syntax a aj spôsob práce je veľmi podobný tomu v Haskelli (o ktorom poviem o chvíľu), a sám je v ňom aj napísaný.

Kód vyzerá nejak takto (verzia 0.16).

Prečo by to človeka malo vôbec zaujímať? Tí, ktorí poznajú funkcionálne programovanie a Haskell, budú určite nadchnutí, a prekvapení. Haskell je totiž statický a silne typový jazyk, ktorého hlavné vlastnosti sú nemodifikovateľnosť dát (immutability), referenčná transparentnosť funkcií, ďalej že funkcie sú sami hodnotami, ktoré si môžme uložiť do premennej, kde je rekurzia veľmi obľúbená technika a že vďaka lenivému vyhodnocovaniu (lazy evaluation) môžme pohodlne pracovať aj s nekonečnými štruktúrami. Väčšinu týchto vlastností má aj Elm, čím sa možno snaží nájsť to ultimátne riešenie na krízu v Javascripte a jeho problémov.

Mám dojem, akoby tie zložitejšie veci v Haskelli sa Elm snažil vypustiť, či nájsť iný, jednoduchší spôsob ako ich riešiť. Napríklad nemáme funktory, alebo monády ako explicitné abstrakcie, a ani typové triedy. To na jednej strane vyvoláva pocit sklamania, že Elm nie je až tak ďaleko čo sa týka typových možností aké má Haskell. Na druhej strane, Haskell vie nielen začínajúcim programátorom pekne zamotať hlavu. 

Keďže Elm je pre programovanie front-endu, pravdepodobne by mal vedieť osloviť Javascriptárov. A keďže Javascript nie je zložitý jazyk, asi by nemal byť ani Elm. Aj z tohto uhlu pohľadu je zaujímavé sledovať, ktoré rysy jazyka Haskell autori Elm-u považujú za dostatočne jednoduché, prípadne akú inú stratégiu volia, keď sa rozhodujú o preberaných vlastnostiach či rysoch.

Elm si myslím zatiaľ určite nezaslúži konečný verdikt, pretože jeho čas ešte pre produkciu ani zďaleka nenastal. V tomto čase je ešte len vo verzii 0.18 a dosť rapídne sa mení. Určite aj to je dôvod, prečo samotný jazyk a jeho hlavná - štandardná knižnica ešte nemá tak veľké portfólio featur. V súčasnosti už existuje množstvo uživateľských komponentov a knižníc, ktoré sa dajú pohodlne nájsť tu. Avšak, keďže na medziverzovú kompatibilitu sa zatiaľ nedá spoľahnúť, veľa používateľských balíčkov v najnovšej verzii Elm-u (0.18) zatiaľ nefunguje. Najpopulárnejšia a najviac fungujúca verzia je v tomto čase 0.16 a postupne sa prechádza na 0.17.

Podpora v jednotlivých IDE je ziatiaľ len základná, ale postačuje. Zvýrazňovanie syntaxe je podporované v IntelliJ IDEA, aj v Eclipse. Netbeans zatiaľ Elm nepodporuje. Ja som používal editor Atom, ktorý má zatiaľ snáď najväčšiu podporu pre Elm. Ak by niekto chcel použiť ViM, tiež má možnosť.

O váš projekt sa stará príkaz "elm-package", cez ktorý si vieme nainštalovať aj odinštalovať ľubovoľný dostupný balíček. Balíčky sa inštalujú do zvláštne pomenovaného podadresára "elm-stuff" a do projektového súboru. Tento má formát JSON, ktorý okrem zoznamu všetkých závislostí a rozsahu povolených verzií, obsahuje metadáta ako názov projektu, verziu, popis, atď.

Okrem programu na správu projektu má Elm aj vlastný REPL - "elm-repl", kde si Elm môžeme vyskúšať v interaktívnom režime. Program "elm-reactor" zas vie vytvoriť lokálny server s voliteľnou IP adresou a portom, pomocou ktorého vieme náš program debugovať.

Samozrejmou súčasťou je Elm kompilátor, ktorý vie vytvoriť či už HTML súbor s výsledným Javascriptom, alebo len čistý Javascript. A tiež Elm že vraj dobre interoperuje s Javascriptom ako takým, je možné ho začleniť do ľubovoľného webového projektu.

Letmé oťukanie


Nemôžem povedať, že som sa Elm kompletne naučil, ani že viem bez problémov programovať v Haskell-i. S Haskellom mám skúsenosti len v rámci voľného času a to tak zhruba rok. S Elm-om som prišiel do styku len tieto Vianoce. Preto moje prvé dojmy určite nepovažujte za kompletnú sadu rozdielov a podobností, skôr tu chcem vypichnúť veci, na ktoré som narazil.

V Elm-e som robil len jeden maličký projektík, a tým je trochu modifikovaná hra Game of Life. Jej zdrojový kód nájdete tu. Modifikácia spočívala v tom, že mriežku mám hexagonovú, a pravidlá hry sú B2/S3,4,5. To znamená, že bunka sa narodí ak má presne dvoch susedov, a prežije ak má od troch do piatich susedov. V iných prípadoch bunka zomrie, alebo ostane mŕtva.

Na mojej niekoľkodňovej ceste, okrem zaujímavej zábavy a vlastne aj úspechu, sa chcem podeliť hlavne s určitými vlastnosťami a rozdielmi, aby som upozornil Haskellákov a trochu uviedol na pravú mieru ich očakávania. Tak sa do toho pusťme.

Rekurzívne dátové typy


V Haskell-i sa často používajú tzv. rekurzívne dátové typy. Napríklad, ak chceme vytvoriť dátovú štruktúru double linked-list. To je taký linked-list, v ktorom každá položka má okrem nasledovníka aj odkaz na svojho predka.

V Haskell-i sa double linked-list dá vytvoriť napr. takto:

  data List a = Cons a (List a) (List a) | Nil

  makelist [] _ = Nil
  makelist (x:xs) prev = let
      cur = Cons x prev (makelist xs cur)

Teda najprv si označíme do premennej cur nový zoznam, pričom ho rekurzívne tvoríme a ako ďalší "prev" prvok v ďalšom rekurzívnom kroku použijeme ten "cur", ktorým sme začali. Toto ide v Haskell-i, bohužiaľ to nejde v Elm-e.

Narazil som na to, keď som rozmýšľal o reprezentácii herného plánu. Keď chceme reprezentovať herný plán vo funkcionálnom jazyku, môžme to urobiť niekoľkými spôsobmi. Jeden z obľúbených spôsobov je aplikovať lenivé vyhodnocovanie (lazy evaluation) aj v samotnej dátovej štruktúre. To znamená, že je možné vytvoriť dátovú štruktúru tak, aby dynamicky zväčšovala svoju kapacitu či "dosah" podľa potreby. Napríklad v prípade hry Game of Life, môžme túto dátovú štruktúru zostaviť ako graf vzájomne susediacich políčok:

  data Board = Node
             { w :: Board, nw :: Board
             , n :: Board, ne :: Board
             , e :: Board, se :: Board
             , s :: Board, sw :: Board
             } | Nil

  newBoard = Node
           { w=Nil, nw=Nil, n=Nil, ne=Nil
           , e=Nil, se=Nil, s=Nil, sw=Nil }

  makeWest board =
    let new = newBoard { e = board }
    in board { w = new }

  ...

Takto môžme herný plán rozširovať dokedy chceme, a to ľubovoľným smerom. Využitím techniky Zipperov sa vieme po pláne pohybovať efektívne. Ale toto sa dá len v Haskell-i. Bohužiaľ, v Elm-e to zatiaľ nenapíšeme.

Škaredé nekonzistencie


Ja viem, že ide o nový jazyk, ale niektoré operátory, ktoré existujú v Haskell-i, ako napríklad : a ::, existujú v Elm-e tiež, ale majú vymenený význam. Napríklad, v Haskell-i operátor :: oddeľuje názov funkcie od definície jej typu, a operátor : je konštruktor zoznamu. V Elm-e je to naopak. Príklad:

Haskell:

  prepend :: Char -> String
  prepend x xs = x:xs

Elm:

  prepend : Char -> String
  prepend x xs = x::xs

Hovorím si, že syntax v tomto prípade možno prevzal od Scaly, kde je to tiež takto. Ale je to fuj.

Dátové štruktúry s "automatickými" vlastnosťami


V Haskell-i som často zvyknutý vytvárať dátové typy s užitočnými vlastnosťami, ktoré mi vie Haskell sám odvodiť. Napríklad:

  data Day = Mon | Tue | Wed | Thu
           | Fri | Sat | Sun deriving (Ord)

hodnoty typu Day dokážeme porovnávať, pretože je automaticky odvodený od triedy Ord. V tomto prípade platí Mon < Tue < Wed < ... < Sun. Podobne, existujú triedy Show, Eq, Bounded, a iné. Avšak z tejto featury sa môžme tešiť zatiaľ len v Haskell-i; Elm bohužiaľ vôbec nemá typové triedy. Tie sa však dajú simulovať pomocou record syntaxe, ako sa to popisuje napríklad v tomto článku.

List comprehension


Mnohí list comprehension zrejme poznajú z Pythonu, ktorý funguje aj v Haskell-i (trochu krajšie):

[ (x,y) | x <- 0..10, y <- 0..10 ]

Jedná sa o peknú syntax, ktorú rád využívam, a sklamalo ma, keď som zistil, že Elm ju nepodporuje. Odkazujú sa na Haskell style guide, v ktorom odrádzajú od používania List comprehension a miesto toho navrhujú použiť map či fold. Ale nerozumiem prečo.

Divný List range 


Keď chceme v Haskell-i vygenerovať zoznam v nejakom rozsahu, jazyk nám poskytuje príjemnú syntax, napríklad zoznam prvkov od 1 do 10 vieme zapísať ako:

  [1..10]

prípadne pre len párne čísla ako

  [2,4..10]

Elm na to syntax nemá a tak sme nútení použiť funkciu:

  List.range 1 10

ktorá dokonca ani nemá variant pre krok, takže zoznam párnych čísel sme nútení napísať takto škaredo:

  List.range 1 10 |> filter (\n -> n % 2 == 0)

Sklamanie.

A neexistuje možnosť definovať nekonečné polia. Našiel som len nejaký balíček, ktorý obsahuje "nekonečnú variantu" funkcie repeat, ale nie s krokom. Bolo to trochu sklamanie, ale je možné to samozrejme doprogramovať ručne.

Použitie apostrofov v názvoch premenných


Z Haskell-u som zvyknutý používať apostrofy ako ďaľšie "verzie" premenných rovnakého mena, napr.:

  (w , h)  = (1,2)
  (w', h') = (w+1, h+1)

Všimol som si, že apostrofy sa používajú aj vo väčšine učebníc či kníh o Haskell-i. A čo je najhoršie, Elm to do verzie 0.17 umožňoval použiť tiež. Avšak z mne nepochopiteľného dôvodu zrušil podporu vo verzii 0.18. Že vraj kvôli newbies, že nevedia čo to je apostrof... Chudáci.

Kľúčové slovo where


Mám v Haskell-i vo veľkej obľube písať helper funkcie, ktoré používam len v kontexte jedinej funkcie až ZA hlavné telo. Dôvod je ten, že v prvom rade ma zaujíma čo funkcia robí ako taká, a až potom jej pomocné funkcie. A sme zvyknutí čítať zhora nadol, a nie naopak. Preto napríklad:

  pack [] = []
  pack xs = ys:pack zs 
    where (ys,zs) = span (==head xs) xs

je funkcia, ktorá vytvorí zoznam zoznamov rovnakých položiek. Napríklad pre reťazec "aaabb" vráti funkcia zoznam ["aaa", "bb"]. V Haskell-i je String samozrejme zoznam Char-ov, preto to vyzerá tak dobre. V Elm-e bohužiaľ nie. 

Ale k veci - Elm neumožňuje niekoľkonásobné definície funkcie. Takže žiadne také, že máme definíciu pre prázdne pole, a potom pre neprázdne. A po druhé, Elm nemá kľúčové slovo where :(((( Elm obsahuje jedine syntax let, takže funkcia pack v Elm-e musí vyzerať takto (a musíme použiť extra balíček, pretože span nie je štandardná funkcia):

  import List exposing (head)
  import List.Extra exposing (span)

  pack xs = let
     (ys, zs) = span (== head xs) xs
    in ys::(pack zs)

ktorú však nemôžme použiť na String, pretože ako som už povedal, v Elm-e String nie je pole Char-ov ( :( ):

  pack (String.toList "aaabb")  
                  ==  [['a','a','a'], ['b','b']]

Dôsledkom je napr., že v Elm-e nemôžme napísať niečo ako

  "ahoj " ++ "svet"

ale len

  String.append "ahoj " "svet" 

Sklamanie.

Infixová syntax binárnych funkcií


Tí, ktorí poznajú Haskell, iste poznajú aj tzv. infixový tvar binárnych funkcií, akou je napr. div či mod. Tieto príklady patria bohužiaľ k nie celkom pekným, napr. operátor / je už rezervovaný na delenie desatinných čísel, a Haskell nepodporuje automatickú konverziu z celých čísel na desatinné. Avšak, keďže sme normálne zvyknutí používať operátor delenia ( / ) v infixovom tvare, Haskell nám to umožňuje, a to dokonca pre každú binárnu funkciu tak, že ju uzavrieme do spätných apostrofov, napr.:

  4 `div` 2     == 2 

Elm túto syntax nepodporuje, avšak aspoň zavádza operátor celočíselného delenia //, takže v Elm-e bude príklad vyzerať takto:

  4 // 2        == 2 

Elm tiež nemá často používanú funkciu mod (zvyšok po delení), a miesto toho má operátor %, to je napríklad pekné.

Prevádzanie vecí do Stringu


Haskell má triedu Show, ktorá umožňuje pre ľubovoľný typ definovať funkciu show, zodpovednú za prevod hodnoty tohto typu na String. Funkcia show je podľa mňa notoricky známa a veľmi používaná funkcia. Avšak v Elm-e neexistuje. Miesto toho existuje mega-všeobecná implementácia toString v balíčku Core.Basics, implementovaná v natívnom Javascripte  (nájdite si ju pomocou CTRL+F, pod názvom "function toString()").

Neexistujú všeobecné funkcie zip, map


Neviem prečo, ale v Elm-e neexistuje funkcia zip. Miesto toho má Elm definované rôzne verzie funkcie map. Našťastie zip sa dá v Elm-e napísať ako

  zip = List.map2 (,)

pričom map2 je funkcia:

  map2 : (a->b->c) -> List a -> List b -> List c

Existujú aj funkcie map3, map4, ... až do map8.

Tieto mapy, foldy a iné podobné funkcie existujú aj pre iné dátové štruktúry, napríklad pre asociatívne pole (mapu) Dict.

Záver


To, čo som uviedol v tomto príspevku bolo hlavne o tom, čo mi udrelo do očí v rámci implementácie hry Game of Life, a tiež len z hľadiska samotného porovnania programovania v Haskell-i a Elm-e. Neriešil som ani performance, ani všetky možné iné vlastnosti. Je možno škoda, že som neuviedol ako pekne je Elm pripravený na prácu s obrázkami, animáciami, a dokonca aj komunikáciou medzi serverom a klientom cez rôzne bežne používané protokoly.

Veľmi tiež vyzdvihujem tzv. "Elm architecture", ktorá od verzie 0.18 "núti" programátora písať programy v patterne podobnom MVC, ktorý však má časti Model, Update a View (a Subscriptions), takže je to skôr MUV(S) :)

Sám som veľmi zvedavý na ďalší progres Elm-u, a som zvedavý aký "tábor" programátorov si Elm vlastne "ochočí". Mám dojem, že snahou je, aby šlo hlavne o Javascriptárov, u ktorých je známe, s akou obľubou používajú a hlavne píšu stále nové a nové frameworky, aby to už konečne prestali robiť...

Elm teoreticky môže mať na to (až za nejaký čas) unifikovať a spojiť tie najsilnejšie featury web developmentu takým spôsobom, že pritiahne veľa ľudí a svojimi názormi a striktnosťou poučí zblúdilých. Môže byť smerodatný.

Počul som niečo aj o TypeScripte, ktorý prináša typy do Javascriptu (okrem iného), a tiež je veľmi populárny. Nikdy som však v TypeScripte nerobil, keďže vlastne ani nie som front-end vývojár, a možno by som takéto články vlastne ani nemal písať. Elm ma zaujal hlavne kvôli jeho spojitosti s Haskellom - "najfunkcionálnejším jazykom na svete" - a zaujímalo ma, ako môže vyzerať taký Haskell na front-ende. A mám z toho veľmi dobrý dojem.

Výhodou je tiež parádna interoperabilita s Javascriptom, ktorý môžme do Elm-u rovno includovať, aj keď vlastne neviem, či sa jedná o hack alebo nie. A možnosť v Elm-e písať komponenty do Reactu, a tiež jeho už existujúce komponenty na animáciu a interakciu, ktoré sú vďaka funkcionálnemu prístupu úžasne jednoducho použiteľné.

Na použitie v produkcii si myslím musíme ešte dosť počkať, a to hlavne kvôli stále ešte rapídnemu vývoju samotného jazyka a neustálemu porušovaniu spätnej kompatibility. Na hranie je to však super.

utorok, 1. novembra 2016

Hodnota človeka

Akú hodnotu má človek? Dá sa vôbec hodnota človeka vyjadriť kvantitatívne? Niekto by mohol tvrdiť, že človek má nevyčísliteľnú hodnotu. Iný by si mohol spočítať celkovú sumu cien jeho orgánov na čiernom trhu. Ďalší by mohol napríklad tvrdiť, že hodnotu človeka bude možné určiť až po smrti, ako súčet váh užitočných a neužitočných vecí, ktoré počas svojho života spravil. Keď vyjde kladné číslo, človek bol “užitočný”, a vyhráva ten, kto má najviac. Podobných “teórií” môže vzniknúť niekoľko, a samozrejme každá reprezentuje “pravdu” len vo svojom vlastnom kontexte.

Koho to zaujíma?

Prečo by sme sa však mali pýtať túto otázku? Pýtajú sa ju všetci? Myslím si, že otázku vlastnej hodnoty sa snažil niekedy zodpovedať každý. Navyše mám dojem, že nepoznám človeka, ktorý by sa snažil zistiť odpoveď všeobecne. Pretože – opakujem – záleží na kontexte.

Ako som spomínal, hodnota ľudských orgánov môže nadobudnúť konkrétne čísla, taktiež si našu "sumu" vieme odvodiť napríklad z ceny liekov, ako priamu úmeru dôležitosti aspektov života a chorôb (ich opak), ktoré sa dajú liečiť. Ak by sme sa nechali zmiasť touto „metrikou“, na naše zdesenie zisťujeme, že dôležitosť aspektov života v podstate určuje trh, pretože ten priamo vplýva na ceny liekov. Ceny liekov zoraďujú dôležitosť aspektov ľudského života podľa toho, ktoré choroby sú „najdrahšie“, a tým pádom by sme sa im mali snažiť "najviac" vyhnúť.

Avšak snaha o filozofické odpovede, či dumanie nad "hodnotou človeka" podľa mňa nemôže vyústiť vo všeobecné závery. Som presvedčený o tom, že človek, ak premýšľa o “hodnote človeka”, premýšľa skoro výlučne o vlastnej hodnote, možno o vlastnom postavení, či o úrovni svojho (ne)úspechu konkrétnej roly alebo rolí, ktoré v živote zastáva.

Aby sme sa mohli pohnúť ďalej, je treba povedať, že som presvedčený o tom, že človek má nevyliečiteľnú potrebu byť úspešný vo svojej role. Je to fakt, a veľmi zaujímavý. Totiž – význam toho „objavu“ si uvedomíme až vtedy, keď začneme skúmať chovanie človeka, ktorému sa darí, alebo ktorému sa nedarí.

Miera úspechu = miera hodnoty?

Človek, ktorý je vo svojich rolách viditeľne úspešný, málokedy pochybuje o svojej vlastnej hodnote. Väčšinou mu naopak sebavedomie rastie, a nemusí nevyhnutne prerásť v aroganciu. Avšak, môže sa objaviť negatívny efekt, ktorým je tlak. Tlak nepoľaviť a tlak udržať si svoju pozíciu, lepšie povedané „úroveň“.

Naopak človek, ktorému sa nedarí, je podľa mňa oveľa zaujímavejší na „skúmanie“. Mám dojem, že práve jednou z fáz prejavov pocitu neúspechu je pýtať sa, „akú má človek hodnotu?“. Takéto všeobecné otázky sú často nie až tak všeobecné. Možno sú spôsobené neochotou priznať si úpadok úspechu vykonávania vlastnej role v danej situácii.

Tu je – na vlastné prekvapenie – možnosť vzniku pozitívneho efektu, ktorým je boj. Človek sa väčšinou veľmi neochotne zmieri s tým, že sa mu nedarí, teda s vlastnou neschopnosťou, a preto s tým najprv bojuje, odmieta priznať si ju. Pocit neschopnosti totiž vedie k pocitu neužitočnosti, a pocit neužitočnosti vedie k otázke vlastnej hodnoty... Človek hľadá presvedčenie, že jeho existencia nie je podmienená úspechom role, ktorú hraje.

Ako spoločnosť vníma neúspech

Dnešná spoločnosť, aj keď sa navonok tvári inak, neumožňuje spokojný život s prijatím vlastnej neschopnosti. To, ako sa máme dobre – či už koľko zarábame peňazí, alebo akých máme priateľov, či v akej kvalite života všeobecne žijeme – závisí výlučne od našich vlastných schopností a „skillov“. Všeobecne od schopnosti byť úspešný v rolách, ktoré hráme. Či si to vedome pripúšťame, je otázka. Čo je však isté, že podvedome to každý vie. A zistí to hneď vtedy, keď ho rodičia prestanú „pridržiavať“ a na naše plecia sa nahrnie bremeno zodpovednosti, „reálny svet“.

Role však nemusia byť len o tom, ako zodpovednosť zvládnuť. Existujú aj „nečestné“ role, ktorých úspech vlastne priamo závisí na schopnosti vyhnúť sa zodpovednosti, prípadne "oblafnutie" zodpovednosti rôznymi technikami podvodu, klamstiev, atď. Sú to väčšinou roly ľudí, ktorí prestali veriť vo vlastnú schopnosť presadiť sa v „čestných“ rolách, a reprezentujú určitú formu vzdoru a postoj „život je aj tak nahovno“, prípadne „život je aj tak nefér“, atď.

Nechcem však zachádzať do úplných detailov, tieto veci zrejme nehovoria nič nové. Radšej by som sa zamyslel, čo robiť, ak sa cítime byť neúspešní, ak strácame pocit „vlastnej hodnoty“.

Zváženie možností - ako nebyť "nahovno"

Je možné, že niektorí by v takýchto prípadoch mohli poskytnúť radu – „stretni sa s priateľmi, ktorí Ťa povzbudia“. Prípadne v opačnom extréme, „nefňukaj a radšej na sebe makaj“. Prvý prípad vychádza z pocitu prijatia nášho zlyhania, druhý z jeho odmietania. Ako sa teda „správne“ zachovať?

V prvom rade musím povedať, že „makanie na sebe“ bez vnútornej motivácie môže spôsobiť nenávisť a odpor k sebe samému, a o to viac, keď nám to nepôjde, čím sa v podstate „potvrdí“ naša neschopnosť.

Naopak, chronická lenivosť či sebaľútosť často vyžaduje pravidelné uisťovanie sa u iných ľudí, že vlastne „nie sme leniví“ a radi obviňujeme naše okolie z každého nášho neúspechu. Vychádza často zo skrytého malého sebavedomia, ktoré nám však iní ľudia bohužiaľ navrátiť nedokážu.

Tým chcem povedať, že ani jeden z prístupov nie je vždy ten najlepší. Situácia sa môže ešte zhoršiť, keď prejdeme do spomínanej apatie typu „život je nahovno“. Záleží od mnohých faktorov, kedy takýto postoj človek nadobudne. Mám dojem, že záleží hlavne na trpezlivosti, ktorú človek so sebou má pri hraní svojej role (a teda sile osobnosti človeka). Prípadne môže ísť aj o zúfalstvo, keď úspech v našej role je zmarený externou udalosťou, napríklad stratou či sklamaním (tiež tu hraje rolu sila osobnosti človeka).

Táto otázka však nemá správnu odpoveď. Hranie určitej životnej role často nie je otázkou výberu, napriek tomu, že jej užitočnosť pre nás môže byť otázna. Väčšinu rolí si naopak volíme sami, a je to často pocit zviazanosti, ktorý umožňuje globalizovať náš neúspech až k pochybovaniu o vlastnej hodnote.

Užitočné, či pohodlné?

Čím rolu dlhšie budujeme, tým väčší vzťah k nej máme, a tým dlhší je preto „pád“, ktorý cítime pri zlyhaní. Hlbšie prepracovaná rola vyjadruje naše skúsenosti, ktoré potvrdzujú naše schopnosti. Preto sa na takúto rolu viac viažeme, či zvykáme, a tým menej sme potom schopní orientovať sa mimo nej. Keďže úspech hrania role chápeme ako náš vlastný úspech, tak logicky príchodzí neúspech musí byť našim vlastným neúspechom.

Možno najužitočnejšie sa preto môže zdať nesnažiť sa radšej viazať na žiadnu rolu, prípadne vyhýbať sa hraniu konkrétnej role, zmeniť rolu a nadobúdané skúsenosti naberať "pomimo". Čiastočne to ide, ale nie vždy a väčšinou nie jednoducho. Z časti je to dané globálnymi definíciami rolí samotnou spoločnosťou, ale častejšie našimi vlastnými hodnotami, princípmi či názormi. Naviac, človek je tvor „hravý“. Hranie hier je vlastne jednou z evolučných stratégií života samého, a je podľa mňa našou prirodzenosťou, tak ako každého živého tvora.

Snáď lepšou stratégiou je podvoliť sa hraniu, možno aj viac doslovne, a dokázať sa znova postaviť na nohy. Páči sa mi jedno staré príslovie: Nie je hanbou spadnúť, ale nepokúsiť sa postaviť.

To znamená začať cielene budovať svoju osobnosť a svoje schopnosti. A neúspech či úspech brať ako jednu z foriem "feedbacku", teda spätnej väzby, ktorá je objektívne najlepšia pre naše ďalšie zdokonaľovanie sa.

Poznanie svojich nedostatkov nám umožní sa zlepšovať systematicky. Schopnosti nemajú binárnu formu (mám / nemám), ale existujú rôzne úrovne. Človek je v niečom lepší, v niečom inom horší. Užitočný pohľad je napríklad takýto: spadol som, OK, nie som prvý ani posledný. V čom bol problém? Retrospektíva. Aha, takže začnem pracovať na zlepšení, nech to znamená čokoľvek (ak neviem ako, skúsim si zistiť ako).

Záver

Tu, ako ste si určite všimli, hrá neuveriteľne dôležitú úlohu motivácia. Vnútorná motivácia. Inak povedané, človek musí chcieť „sám od seba“. Dobrou správou je, že aj na vnútornej motivácii sa dá pracovať. Mne napríklad dáva motiváciu presvedčenie, že na svete neexistujem pre nejaký špecifický dôvod. Preto odo mňa nikto nemôže chcieť, aby som plnil jeho predstavy, nech sa v jeho očiach budem zdať akokoľvek divný. Ľudia robia často systematické chyby vo vlastnom zmýšľaní, a "racionalite" či pohľade na svet, takže vážnosť skoro ľubovoľného "hodnotenia" iných voči mojej osobe môže byť nanajvýš do určitej miery pravdepodobná.

Je preto lepšie nebyť ovca, a mať vo veciach jasno. Kvantitatívna "hodnota človeka" neexistuje bez kontextu, a preto sa ňou nemá zmysel zaoberať. Nikto nevie, čo pre "vesmír" znamenáme. Už len preto je možno užitočnejšie byť pokorný a zvedavý, než arogantný ignorant.

nedeľa, 19. júna 2016

Alan Turing: čoho sú počítače neschopné?

Možno je to už aj desať rokov, odkedy sme sa v škole učili o Turingových strojoch. Pamätám si, ako nám vtedajší profesor Hudák na TUKE povedal:
"Alan Turing konečne dobre definoval pojem algoritmus."
Turing "že vraj" nejak dokázal, čo je a čo nie je možné vypočítať na počítačoch, teda definoval "vypočítateľnosť", po anglicky "computability".O tom je jeho najdôležitejší článok "On Computable Numbers, with an Application to the Entscheidungsproblem".

O týchto veciach existuje mraky materiálov, v dnešnej dobe je vypočítateľnosť už akýsi alias na tzv. "recursion theory", ktorú zas rozvinuli Alonzo Church a Stephen Kleene; v dnešnej dobe je to oblasť stále aktívne rozvíjaná a skúmaná.

Je dôležité uvedomiť si vtedajšiu dobu - 30-te roky minulého storočia, nikto ani nesníval ako by také počítače mohli vyzerať a ako by mali fungovať. A odrazu prišli, zdanlivo z ničoho nič, nápady, ktoré sa nielen uchytili, ale tvoria základný princíp fungovania počítačov dodnes.

V tomto blogposte sa však zameriam na Turingov článok, k nemu mám asi najbližšie a je dá sa relatívne rýchlo pochopiť. Predpokladám však, že čitateľ už vie čo sú Turingove stroje a ako fungujú.

Pôvod Turingovho "stroja"


Keď sa tak zamyslím, nikdy mi nebolo jasné, ako taká vypočítateľnosť vlastne "vyzerá", akú má povahu, čo to je. Na druhej strane, keď sa človek pozrie na Turingov stroj, uvidí - "áno, nejaká 'podobnosť' s normálnymi počítačmi tam je" a na vypočítateľnosť sa zabudne. Hehe, ale nie :)

Stroj vykonáva inštrukcie podľa dobre definovaných pravidiel, pričom každá inštrukcia je elementárna, a v jednom čase stroj vie vykonať len jednu inštrukciu. Činnosť tohto aj keď abstraktného stroja je definovaná vlastne naozaj dosť mechanicky a intuitívne, vôbec nie matematicky (to až neskôr), takže je aj ľahko pochopiteľná.

Vlastne, Turingov stroj funguje podľa princípov, ktoré veľmi nápadne pripomínajú vlastnosti algoritmu:
  • Turingov stroj (algoritmus) je popísaný ako postupnosť krokov,
  • ktorých počet je konečný,
  • kroky sú deterministické (jednoznačné),
  • elementárne (nedeliteľné),
  • celkovo rieši určitú všeobecnú triedu problémov,
  • s nejakým výsledkom

Myslím si však, že sa Turing svojim abstraktným strojom snažil mechanickým spôsobom popísať skôr človeka - matematika, a nie reálny stroj. Odtiaľ tie jeho nápady - v rámci riešenia "Entscheidungsproblem" (o ktorom poviem o chvíľu) sa snažil intuitívne a mechanicky popísať prácu človeka pri počítaní.

Nekonečná páska, rozdelená na štvorčeky. Do každého štvorčeka môže stroj napísať jeden symbol, alebo ho prepísať alebo prečítať. Pripomína to skôr štvorčekovaný zošit, než pamäť. "Hlava", ktorá číta a zapisuje symboly do tohto zošita je vlastne abstraktná ľudská hlava, v ktorej náš humanoidný stroj "počíta", len na základe jasne daných pravidiel. Sám Turing, v diskusii o povahe vypočítateľných čísel na str. 249-250 a ďalej (originál) veľmi podrobne vysvetľuje, že tento "stroj" musí vedieť pracovať iba s konečným počtom symbolov a mať iba konečný počet "stavov mysle" (states of mind). Dôvodom je, že inak (ak by ich počet bol nekonečný), by niektoré symboly, rovnako ako aj niektoré stavy mysle, boli nekonečne "blízko seba", čím by sme ich vlastne od seba nevedeli zreteľne odlíšiť. Tým vlastne skryto uvádza podobnosť s človekom, tiež pracujeme iba s konečným počtom symbolov, a aj keď to vtedy Turing nevedel, naša neurónová sieť v mozgu má tiež konečný počet neurónov, ktoré nadobúdajú určitý stav jasnej povahy.

Turing sa umelou inteligenciou zaoberal v jeho druhom najslávnejšom článku, Computing Machinery and Intelligence, odkiaľ je napríklad známy aj Turingov test.

Ale späť k vypočítateľnosti.

Aký problém to riešil?


Ide o to čo chcel ukázať - je to už aj v názve jeho článku: "with an application to Entscheidungsproblem". Z nemčiny sa to dá preložiť ako "problém rozhodnutia". Je to jeden z problémov, ktoré popísal nemecký matematik David Hilbert v roku 1928. Matematici aj toho pána určite poznajú, je tiež veľmi známy (okrem iného aj jeho bojom voči latinskému ignoramus et ignorabimus).

Hilbert chcel vedieť, v jednoduchosti, či existuje nejaký všeobecný postup na robenie matematických dôkazov. Pár rokov pred definovaním problému (rok 1910,1912, a 1913) bola totiž napísaná veľmi dôležitá kniha Principia Mathematica (3 diely v uvedených rokoch), game-changer, ktorej snahou bolo len pomocou matematickej logiky (axiómov a "mechanických" logických pravidiel) popísať celú dovtedy známu matematiku. Podarilo sa to (výsledkom je tá kniha) - a zaujímavosťou je, že každá známa veta v tej knihe bola dokázaná len "mechanickým" aplikovaním logických pravidiel na axiómy. Nič viac nebolo treba.

Je dosť jasné, že aj vďaka tejto knihe sa naskytla otázka, či by mohol existovať všeobecný postup na dokázanie akéhokoľvek výroku v matematickej logike, efektívne - dokázať akýkoľvek matematický teorém alebo vetu, napísanú pomocou matematickej logiky, len pomocou samotnej matematickej logiky - aplikovaním jej pravidiel, a to hlavne pre budúce, nové, teorémy.

Kým neprišiel Turing so svojim článkom (a samozrejme pár mesiacov pred ním Alonzo Church), bol dovtedy k tejto téme známy "len" Gödelov teorém nekompletnosti, v ktorom Gödel dokázal dve veci. Po prvé, že je možné v každom konzistentnom (nerozporuplnom) matematickom systéme (rozšírenom o prirodzené čísla) nájsť taký teorém, ktorý je síce pravdivý, ale nevieme to pomocou tohto systému dokázať. Teda ten systém, tá matematická teória, je v tomto duchu "nekompletná". Po druhé, dokázal, ako dôsledok, že každý takýto systém nevie dokázať vlastnú konzistenciu.

Poznámka: Dá sa síce vytvoriť aj "kompletná" teória, ale tá už naozaj nebude "konzistentná", teda bude rozporuplná (budeme z nej vedieť odvodiť protichodné výroky - nezmysly). A keďže v matematike nechceme nezmysly, volíme radšej nekompletnosť.

Dobre, takže vieme, že matematická logika nevie "dokázať samu seba". OK (Hilbertovi to vlastne trvalo o dosť dlhšie prijať tento fakt než mne :). To by však stále nemuselo brániť tomu, ako už popísal Hilbert, že by aj tak mohol existovať všeobecný postup, ktorým by sme vedeli rozhodnúť, či matematický teorém je alebo nie je dokázateľný, a keď je, vedeli by sme podľa neho "mechanicky" odvodiť dôkaz. To by "stačilo".

A čo teda dokázal (v 9-iatich krokoch)?


TLDR; Turing teda dokázal - že NIE, žiadny taký algoritmus či postup neexistuje. A nasleduje jeho skrátený postup, bez obšírnejších detailov:

Krok 1

Najprv vymyslel mechanický stroj, ktorý vie na základe určitých pravidiel počítať všetko, čo človek (intuitívne) - ten slávny "Turingov stroj". Zatiaľ všetko len intuitívne.

Krok 2

Potom vymyslel "univerzálny" stroj, ktorý vie vykonávať ľubovoľný Turingov stroj, vrátane toho práve vymysleného "univerzálneho stroja".

Krok 3

Nasledovala drobná odbočka - ukázal ako sa dá ľubovoľný Turingov stroj popísať len jediným svojim unikátnym prirodzeným číslom (aj keď potencionálne veľkým, napr. 313325317)

Krok 4

To mu umožnilo dokázať, že Turingove stroje tvoria spočitateľnú množinu (po anglicky "enumerable" alebo "countable"). Na to použil dôkaz podobný ako použil Cantor, keď spočitateľnosť popisoval - dôkaz známy ako "diagonal process".

Tento dôkaz je kritický, na ktorom stojí celý jeho ďalší článok. Jeden z krokov dôkazu bolo vlastne určiť, či nejaký Turingov stroj "je uspokojujúci" (satisfactory), teda či bude navždy počítať a nezastaví (obdoba tzv. "halting problemu" ako ho v roku 1958 definoval Martin Davis, kde naopak išlo o to, či niekedy zastaví).

Myšlienkový postup je jednoduchý. Predstavme si stroj, ktorý to bude robiť za nás (postačí mechanicko-humanoidný Turingov stroj). Keďže má ísť o všeobecný postup, tak ten stroj musí overiť, či každý stroj zastaví.

Tento stroj bude mať na vstupe postupne všetky stroje za sebou - veď máme nekonečnú pásku. A tak začne overovať. Overí prvý, druhý, atď., až kým nepríde sám k sebe (on je tiež súčasťou vstupu). Lenže na to, aby vedel povedať, či sám niekedy zastaví, musí vedieť povedať, či zastaví jeho "rekurzívny brat" - teda on sám. Ako to však zistí? Nám je asi jasné, že nikdy nezastaví, ale jemu samému nie - on nemá ten nadhľad, pretože pracuje výhradne mechanicky a len so symbolmi na páske. K rozhodnutiu musí dôjsť len pomocou nich.

Nemá teda inú možnosť než overovanie realizovať tak, že overovaný stroj "spustí" a "počká", či začne počítať. A tak spustí rekurzívne aj sám seba a bude sa vlastne "pozorovať" z o úroveň vyššej reality. Lenže rekurzívny brat robí tú istú činnosť - teda overuje, či všetky stroje zastavia. Takže nevyhnutne aj ten dôjde k samému sebe, a teda stroj efektívne síce nikdy nezastaví, ale nikdy o tom sám nebude vedieť rozhodnúť.

Teda - vo všeobecnosti sa proste nedá zostrojiť Turingov stroj (alebo algoritmus), ktorý by vedel rozhodnúť, či ľubovoľný Turingov stroj (na vstupe) zastaví.

Z toho odvodil, že napríklad sa tiež nedá zostrojiť taký stroj, ktorý by zistil, či niekedy nejaký stroj vypíše na pásku nejaký symbol (napr. číslicu 0).

Krok 5

Ďalej sa zaoberal vypočítateľnými číslami a vypočítateľnosťou ako takou. Doteraz definoval všetko to, čo je vypočítateľné Turingovým strojom ako vypočítateľné "sekvencie", či reťazce ("computable sequences"). Aby sa dostal bližšie k matematickej logike (a k "entscheidungsproblemu"), musel lepšie definovať vzťah medzi vypočítateľnými sekvenciami a vypočítateľnými číslami ("computable numbers").

Turing (znova intuitívne) definuje, že vypočítateľné čísla sú také, ktoré vieme vyčísliť - teda keď vieme zapísať postupne všetky cifry tohto čísla a len prostredníctvom konečných symbolov (napr. číslic). Nemusíme ich vedieť vypísať všetky v konečnom čase, ide len o to, aby sme sa v priebehu výpočtu "nezasekli" na niečom, čo by nám bránilo v ďalšom výpočte a teda vo vyčíslení ďalšej cifry.

Keďže medzi vypočítateľné čísla patria aj prirodzené čísla (máme všeobecný postup na ich výpočet - napr. Peanove axiómy), a máme všeobecný postup na popis Turingovho stroja ako prirodzeného čísla, je jasné, že by aj všetky Turingove stroje mali byť vypočítateľné (pozor - nielen spočitateľné, ale aj vypočítateľné - sú to dva pojmy).

Avšak, háčik je v tom, že nás zaujímajú len "uspokojujúce" stroje, pretože jedine tie niečo počítajú a sú validné aj syntaxou. Ale bohužiaľ - nevieme nájsť ani stroj, ktorý by vedel tieto stroje "vyčísliť" (efektívne teda ani všetky "rezultatívne" algoritmy), pretože by potom musel existovať všeobecný postup na zistenie, či je daný stroj "uspokojujúci", a ten podľa kroku 4 nemáme.

A tak Turing našiel aj číslo, ktoré nie je vypočítateľné. Nech sa to číslo skladá len z číslic 0 a 1, s tým, že jeho n-tá cifra bude rovná 1, ak n je číslo "uspokojujúceho" Turingovho stroja, a 0 ak nie. A podľa kroku 4 to všeobecne vypočítať nevieme. Tým pádom sme síce dobre definovali ako to číslo vypočítať, ale napriek tomu sa vypočítať nedá (na Turingovom stroji). Výsledok je teda taký, že vypočítateľné čísla nezahŕňajú všetky "definovateľné" čísla.


Krok 6

Ďalej pomocou matematickej logiky definoval prirodzené čísla (Peanove axiómy), čo mu umožnilo využiť matematickú logiku (predikátovú) na definíciu tzv. vypočítateľných funkcií ("computable functions").

Vo všeobecnosti vypočítateľné funkcie môžu mať aj argumenty, ale nie v doméne reálnych čísel (keďže reálne čísla nie sú vypočítateľné), ale znova iba vypočítateľných čísel (tzv. "computable variables").

Nasleduje niekoľko formálnych teorémov o vypočítateľných funkciách, vrátane konvergencie vypočítateľných čísel. Z toho sa dozvedáme, že napríklad číslo  je vypočítateľné, číslo e (Eulerova konštanta) je vypočítateľná, ďalej všetky algebraické čísla, logaritmické funkcie, goniometrické funkcie, atď.

Krok 7

V ďalšom kroku našiel takú "sústavu" Turingovych strojov, ktoré dokazujú ľubovoľnú formulu matematickej logiky (sústavu vypočítateľných funkcií). Popísal ich síce len intuitívne, ale dostatočne. Intuitívne predpokladal nejakú formu, akou sa výroky matematickej logiky prevedú na symboly, ktoré "pochopí" Turingov stroj.

Na vstupe mal byť výrok (A) a tiež jeho negácia (B), a tento stroj by mal teda vedieť dokázať buď (A) alebo (B). Keďže predpokladáme konzistentný systém matematickej logiky, iná "pravda" ani nie je - buď výrok platí, alebo neplatí. Stroj mal pracovať tak, že systematicky aplikoval pravidlá matematickej logiky  na (A) a aj na (B) a keď narazil v rámci odvodzovania na axióm, tak tým pádom úspešne našiel dôkaz platnosti (A) resp. neplatnosti (B) výroku.

Krok 8

Keďže je jasné, že Turingov stroj vieme vyjadriť ako prirodzené číslo, a prirodzené čísla práve doplnil k matematickej logike (ako mal aj Gödel v teoréme nekompletnosti), musí sa dať cez matematickú logiku popísať aj samotný Turingov stroj. A našiel takýto popis.

Krok 9

Nakoniec napísal takú matematickú formulu (predikát), ktorá obsahuje popis nejakého konkrétneho Turingovho stroja a vyjadrenie, že tento stroj niekedy počas svojho behu vypíše na pásku nejaký symbol (napr. číslicu 0). Tento predikát nazval vtipne ako Un(M), pričom asi mal na mysli skratku "Undecidable".

Keďže v kroku 7 bol nájdený taký stroj, ktorý dokazuje matematické teorémy, dáme mu na vstup tento teorém. No ale neslávne zisťujeme, že na jej dokázanie by sme tým museli zistiť, či stroj na vstupe niekedy vypíše symbol 0 na pásku, čo podľa kroku 4 - opäť - nie je možné.

Teda, nie je, minimálne v určitých prípadoch - teda vo všeobecnosti - možné rozhodnúť o ľubovoľnom matematickom teoréme či je alebo nie je dokázateľný len pomocou Turingovho stroja (ktorý reprezentuje všetky "všeobecné postupy"), a teda efektívne - nie je možné nájsť všeobecný postup na dokázanie ľubovoľného matematického teorému. Teda "Entscheidungsproblem" nemá riešenie.

Záver

Od Turingovho článku ubehlo už dosť veľa času. Bezprostredné pokračovanie malo formu skôr opráv (Turing, Emil Post, Donald W. Davies, ...). Ďalej sa ukázalo, že Entscheidungsproblem nie je vôbec jediným problémom, ktorý nemá riešenie (ako napríklad ani Hilbertov desiaty problém ho nemá).

Postupne sa v priebehu ďalšieho rozvoja "teórie vypočítateľnosti" definovali triedy vypočítateľnosti - ako miera "vyjadrovacej sily", ktorou systém (napríklad programovací jazyk alebo iný abstraktný stroj či formalizmus) disponuje (viď napr. Turing completeness).

Tak vzniklo mnoho ďalších abstraktných strojov, ktoré ešte lepšie približujú reálne počítače a tým umožňujú ich pohodlnejšie teoreticky skúmať, napr.:



A tak sa postupne našli súvislosti medzi dokazovaním, vypočítateľnosťou a jej komplexitou (triedy P, NP, atď.) a jazykmi. Celé to začalo naberať dnešné rozmery. Teória vypočítateľnosti je však stále aktívne skúmanou oblasťou.

Záver 2.0


V hlave mi celú tú dobu od školy vŕtalo - čo to vlastne znamená "dobre definoval algoritmus". Teraz mi to už jasnejšie je, konečne som si poriadne prečítal jeho článok v rámci knihy od relatívne známeho človeka, Charlesa Petzolda, s názvom 
The Annotated Turing: A Guided Tour Through Alan Turing's Historic Paper on Computability and the Turing Machine.

Keďže som čítal už aj jeho (tiež známu) knihu Code: The Hidden Language of Computer Hardware and Software, vedel som, čo môžem čakať. Intelektuálne "rozmaznávanie" do špiku kosti... Problematika vysvetlená tak, že sa človek môže pohodlne posadiť, a nerobiť si absolútne starosti s tým, že o počítačoch a matematike nič nevie. Musím povedať, že je to jedna z ďalších úžasných kníh, ktorá mala presne ten efekt, aký som očakával.

Kniha prechádza postupne celým Turingovym článkom On computable numbers, with an application to the Entscheidungsproblem, vydaným Proceedings of the London Mathematical Society, 2nd series, Vol. 42 (1936), pp. 230-265. Kde je to vhodné, autor Turinga "preruší" a doplní pár odstavcov, niekedy strán, ako doplňujúce vysvetlenie a občas aj akúsi prípravu na to, čo bude nasledovať. 

V knihe je okrem samotného článku rozobraná detailne celá história okolo Entscheidungsproblem, ľudsky vysvetlený význam Gödelových viet (teorém úplnosti predikátovej logiky a dva teorémy neúplnosti) a ich dôsledky. Samozrejme nechýbajú útržky z Turingovho života a tiež ďalších matematikov ako David Hilbert, Bertrand Russel, Kurt Gödel, Georg Cantor, Richard Dedekind, Gottlob Frege, Alonzo Church, Stephen Kleene, John von Neumann, a ďaľších.

Knihu naozaj odporúčam, človek aspoň trochu pochopí o čom to celé je, ale možno dôležitejšie, hlavne sa nad tým zamyslí...


štvrtok, 12. mája 2016

Princípy dobrého designu

Dobrý design (čohokoľvek) je pojem, ktorý podľa môjho názoru súvisí jednak s pojmom "krása", ale zároveň je spojený s efektivitou technickej realizácie (zachováva "dobré" vlastnosti z technického pohľadu). Design (bez straty na všeobecnosti), po slovensky "návrh", je takým "rozhraním" alebo interfejsom medzi tým, čo treba, a tým, čo je komfortné a príjemné.

Krása je pojem, ktorý ide skôr do umenia, fantázie, bláznovstva, odlišnosti; je to niečo, čím sú posadnutí vizionári, rojkovia a umelci. Na druhej strane technická efektivita je spojená s minimom (orientovaná na presne definovanú funkcionalitu), výkonnosťou, škálovateľnosťou a akousi "čistotou". A dobrý design je spojenie týchto dvoch vecí dohromady.

Dobrý design nemusí byť úplne minimalistický, ale musí spĺňať nasledujúce body:
  • Rieši presne definované problémy (nič viac a nič menej) - ("čo" riešime),
  • Je krásny, v individuálnom zmysle ("ako" riešime).
Cestu k dobrému designu by som rád prirovnal k ceste aplikovaním zaujímavej fantázie a dobrých rozhodnutí, ktoré odzačiatku až do konca v rámci nej robíme.

Vytváranie a hodnotenie sú dve rozdielne veci

Spojenie požiadaviek spomenutých v predchádzajúcom odstavci je dosť pochybné. A to už len z nasledujúcich dôvodov:

  • "Presne" definovaný problém je vtedy, ak neexistuje viac možností jeho pochopenia 
  • Ďalej, ako už bolo povedané, "krásno" je veľmi individuálne.

Aj keď daný problém máme definovaný, často býva, že na jeho technickú realizáciu môže existovať viac riešení, alebo aj žiadne riešenie. "Krásota" designu je teda snáď daná výberom toho najvhodnejšieho riešenia pre daný problém, avšak intuitívne cítim, že aj niečoho viac.

Keď hovorím o "výbere najvhodnejšieho riešenia", evokuje to dojem, že máme pred sebou (pre predstavu) papiere riešení a ide len o to ukázať prstom, "ktoré" berieme (na strojníckej priemyslovke sme to označovali ako "varianty riešenia" a museli sme ich vypracovať niekoľko, z ktorých sme si na základe našich ďalších úvah museli jeden variant vybrať).

Avšak vypracovanie jednotlivých variantov nie je úplne to isté, ako keď už nejaké máme a hodnotíme ich. Vypracovanie vyžaduje kreativitu (fantáziu), motiváciu a akýsi občasný proces hodnotenia rozpracovaného výtvoru (či už pocitový alebo na základe vedomostí), keď sa na to priebežne pozeráme. Mohli by sme ten občasný proces chápať ako občasné "spojenie s realitou", kde kontrolujeme, či ideme "dobrým smerom" (spĺňa to zatiaľ požiadavky? Vyhovuje to "pravidlám"?)

Teda aj kreatívny proces má akési striedajúce sa fázy. Pustíme "rádio fantázie", ktorá predstavuje akési náhodné fluidum rôzne strelených nápadov v ktorých sa rôzne pohybujeme. Tento "pohyb" ďalej rôzne ovládame - či už obmedzíme alebo nasmerujeme, akoby sme otáčali volantom idúceho auta. To je podľa mňa to intuitívne a tajomné "priebežné kontrolovanie". Určite je iného druhu, než vyhodnocovanie hotových variantov riešenia. A myslím si, že je to ten najdôležitejší prvok kreatívneho procesu, pretože vedie cestou rozhodnutí, ktoré v rámci designu robíme.

Každopádne, schopnosť dobre "priebežne kontrolovať"  je úzko spätá so skúsenosťami, znalosťou pravidiel, princípov a tiež odborných vedomostí. Ide to teda skôr do toho chladného logického, analytického a nekreatívneho, zatiaľ čo to "kreatívne" ide skôr do emočného, pocitového. Teda striedajú sa ľavá a pravá hemisféra mozgu, kde kreatívna časť odpovedá skôr tej pravej, a analytická skôr tej ľavej.

Ako vyzerá dobrý design?

Hodnotenie skutočnosti, či ide o dobrý design je podľa mňa čisto empirická záležitosť. Pocit krásy pretrvá prvý pohľad len vtedy, ak vec obstojí aj v použiteľnosti. A použiteľnosť musí pretrvať (prirodzene) relatívne dlhodobo. Podľa mojich skúseností dobrý design vyzerá nejak takto:
  • vytvára dojem spojenia do seba zapadajúcich, osobitých, jasne odlíšiteľných prvkov
  • preferuje jednoduchosť, prehľadnosť, pochopenie
  • opakujúce sa mechanizmy explicitne identifikuje a zjednocuje do samostatných celkov
Keďže som programátor, tak dosť už rečí vo všeobecnosti. Zúžime trošku ten pojem na problémy v programovaní.

Inverzia - "výzor" ako cieľ

Dnešná doba sa z hľadiska programovacích trendov začala trochu viac hýbať. Každým rokom pribúda čoraz viac technológie a možností, v ktorých sa programátor stráca. Včera bolo "in" OOP, dnes je to funkcionálne programovanie, prípadne rôzne pokusy spojiť obe paradigmy. Myslím si však, že hľadanie dobrého designu neskončí nikdy, je jedno v akej paradigme sa pohybujeme. Je mi tiež jasné, že "there is no silver bullet in software development", ako už popísal Fred Brooks.

Aj napriek tomu však možno stojí za úvahu skúsiť nájsť akési viac všeobecné princípy (výsledky Googlu sú naozaj bohaté aj na túto tému), ktoré by reflektovali výzor designu popísaný v predošlej kapitolke.

V skratke zopakujem - dobrý design, ako spojenie krásy a akejsi "technickej dokonalosti", v zmysle troch spomenutých bodov sa dá popísať už existujúcimi princípmi v doméne programovania. Tieto princípy považujem ako dostatočne všeobecné, ktorých dodržiavanie zlepšuje design celkovo. Háčik je v tom, že podstata každého z nich je viac či menej vágne definovaná a spolieha sa na skúsenosti a schopnosti človeka - designéra.

Riešenie komplexného problému nás môže "odlákať" od myšlienok na dobrý design, pretože proces jeho zlepšovania je v podstate ďalším problémom, a človek nevie robiť niekoľko veci naraz. Preto som zástancom akejsi "priebežnej kontroly" (o ktorej som hovoril už vyššie), ktorá bude viac menej rutinná. Jej podstatou by mali byť práve takéto všeobecné princípy, ktoré si znovu-pripomíname ako určitú "mantru". Ich "automatické" aplikovanie nás tak priveľmi neodláka od riešenia pôvodného problému, to je môj dojem.

Taktiež, aplikovanie určitej "šablóny" nemusí byť klišé, v programovaní to vedie k dobre rozpoznateľným patternom (vzorom), ktoré sú esenciálne pri zlepšovaní designu a párovom programovaní. (poznámka: jednou z takých "šablón" je aj code style, ktorý si väčšinou firmy ako-tak definujú a je to dobrá vec).

Tak poďme konečne k tým slávnym princípom:
  • YAGNI (You Aren't Gonna Need It)
  • KISS - (Keep It Simple Stupid)
  • DRY - (Don't Repeat Yourself)

YAGNI

Tento princíp je podľa mňa ten najdôležitejší a myslím si aj najlepšie pochopiteľný (a najmenej dodržiavaný - žeby slabá vôľa?). Radí nám, že nemáme vytvárať nové funkcie v programe, keď ich práve teraz nepotrebujeme. Dodržanie tohto princípu:
  • Drží softvér vždy iba minimálne rozpracovaný. A to čo je rozpracované, je vždy jasne definované, niečo čo treba teraz.
  • Núti odkladať rozhodnutia na neskôr. Je veľmi dôležité nechať si otvorené možnosti do maximálnej doby aká je možná (požiadavky sa môžu (a budú) meniť) (Lean Software Development)
  • Drží nás pri zemi, design riadený požiadavkami a nie naopak (typu "to sa bude hodiť keď budeme v budúcnosti robiť XYZ!"). V praxi to bohužiaľ často vyzerá tak, že pridanie novej technológie je oveľa jednoduchšie než možnosť sa jej zbaviť. Takže pozor na to...
  • Udržuje nízky technický dlh (ehm.. skôr bráni jeho zvýšeniu)
Nie je to presne to, čo potrebujeme aby sme vedeli odhadnúť kedy bude práca hotová?

KISS

Tento princíp je bohužiaľ najviac vágny zo všetkých troch. Ak by sme sa ho mali striktne držať, tak to bude dosť závisieť na tom, kto si čo predstaví pod pojmom "jednoduché". Nedá sa to veľmi zovšeobecniť, a dodržanie tohto princípu vyžaduje buď znalosť ďalších X princípov ako riešiť - zjednodušiť určité veci v konkrétnych prípadoch, alebo designér musí mať skúsenosti a taký ten "cit", kedy sa ešte pýtať "dá sa to aj jednoduchšie?" a kedy s tým už prestať.

Čo si o designe myslia slávnejší ľudia než som ja?
  • Einstein si myslí, že: "Keep it simple, as simple as possible, but not simpler" (narážka na použitie princípu Occam's razor, ktorý radí vybrať si takú hypotézu s pomedzi niekoľkých, rovnako pravdepodobných, ktorá vyžaduje najmenej predpokladov)
  • C.A.R. Hoare zas (trochu podpichovačne): "There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies."
Radšej by sme mohli urobiť skôr výčet toho, čo nie je jednoduchý design:
  • Over-engineering (needless complexity)
  • Nízka kohézia (kód je neusporiadaný, zodpovednosti sú "porozhadzované" a nejasné - kód nemá "myšlienku")
  • Tesný coupling (príliš veľa závislostí na konkrétnych implementáciách, opak princípu SDP (Stable Dependencies Principle))
Jednoduchosť je relatívny pojem, spätý s kontextom, alebo pohľadom na vec. Musíme vždy vedieť, aký je cieľ, požiadavka. A s tým súvisia aj kompromisy, ktoré často musíme vykonať. Napríklad, ak je cieľ "best performance ever", tak prehľadnosť a "čistota" často musia spraviť kompromis, a naopak.

DRY

Skoro ma láka povedať, že toto je jeden z princípov patriacich do Zenu. Hľadať v kóde repetitívnosť sa totiž dá občas prirovnať k riešeniu Zenového koanu, alebo ide o činnosť, keď meditujeme podľa Vipassany. Pomenúvame a identifikujeme. A zažívame AHA-efekty.

Hlavným nástrojom, ktorý nám pomáha v tejto činnosti je abstrakcia. Vo všeobecnosti je abstrakcia pojem vlastne priamo určený na eliminovanie opakujúceho sa (či zložitého) kódu. A málokto si to uvedomuje.

Už len jednoduchý for cyklus je abstrakciou (ktorú snáď poznáte všetci); keby neexistovala, mali by sme veľa if-ov za sebou, podľa toho, aké maximálne N by bolo. Samozrejme v rámci hĺbky "rozjímania" nad koanom DRY sa dá ísť až do výšin teórie kategórií, a exotických zigohistomorfických prepromorfizmov, ale väčšinou nemusíme :)

Hlavný princíp je "zgrupovať" súvisiace kódy, potom v rámci nich zgrupovať zdieľané funkcie a nahrádzať ich jedinou, alebo aj celú vec refaktorovať. Často (v rámci OOP) pomôže aj aplikovanie nejakého vhodného patternu, či dvoch.

Ako na nový design


Aj návrh návrhu má svoje YAGNI, KISS a DRY. Treba začať vždy tou najlacnejšou a najdôležitejšou vecou - API. Použitie. Má to niekoľko výhod:
  • Ujasníte si problém, prípadne identifikujete viac problémov.
  • Zmena API je v tomto bode neuveriteľne lacná
  • Krásne funguje párové programovanie
  • Hotové API je niečo ako "zadanie", "špecifikácia", na ktoré sme ako školáci boli zvyknutí a ktoré v Agile nedostaneme len tak (iba pracnou komunikáciou - user story).
  • Často nás to privedie k zamysleniu, aha-efektom a objaveniu nových súvislostí   
Tvorba API sa môže striedať s návrhom algoritmov či dátovou reprezentáciou. Nič nie je úplne oddelené, všetko má svoje prieniky.

Návrh API sa mi najviac osvedčil, keď som postupoval intuitívne - v princípe jeho použitia. Nezačal som robiť interface, ale kód, ktorý niečo "robí". S neexistujúcim API. Nemusí ísť vôbec o TDD (aj keď to k tomu smeruje), pretože použitie často môže používať príliš nedomyslené veci a sústredenie sa na pravidlá TDD v tejto fáze by nás iba "dekontextovalo". Kód, ktorý som písal, bol pseudo-kód, kde som vyjadroval len to, čo práve robím a aby to bolo pochopiteľné (aj prípadnému sparring-partnerovi).

Ako už vieme, zmena kontextu je rušivý element, ktorý ak je častý, znižuje IQ. Takže na začiatok žiadne pravidlá (okrem YAGNI, KISS a DRY), máme (teda skoro) free svet a navrhujeme to ako nám to "príde" fajn. Keď nás už nič nenapadá, vrátime sa kritickým okom a skontrolujeme zvyšné princípy (kohézia, coupling, SOLID, atď.)

Toto všetko sa dá riešiť už v tejto prvotinnej fáze, pri návrhu API v notepade alebo na papier, kde je všetko zadarmo.

Keď bude nejaký nástrel API, pri implementácii už budeme odbremenení od mnohých rozhodnutí (zázračne sme okúsili blahodárne výsledky použitia YAGNI v predchádzajúcej fáze).

Záver

Keď sa na to celé pozerám, použil som dosť pojmov, takže dobrý design asi nebude úplne "trivka" :) Na druhej strane, cieľ je vcelku jednoduchý, až zenový:
Princípmi:
  • Riešiť jednu, iba tú dôležitú, myšlienku v čase
  • Písať, kontrolovať a upravovať kód dovtedy, kým tá myšlienka nebude biť do očí