Funktionaalista ohjelmointia tavalliselle koodaajalle, osa 4: Monadi

Orangit
Orangit
Published in
4 min readMay 10, 2022

--

Joku voisi luulla, että tämä neljäs osa on ollut pitkään kirjoituksessa. Se on totta. Ajastaan jäljessä se ei kuitenkaan ole, koska päähahmomme on aina ajankohtainen. No niin, se siitä. Sitten asiaan.

Jos ei vielä ole alkanut hirvittää, niin nyt viimeistään alkaa. Monadi, tuo varmaan kaikkien aikojen pelätyin design pattern, on edessä.

Älä säikähdä jos et tajua heti kaikkea. Tämä on vaikea.

Lisäksi lupasin kirjoittaa tähän numeroon jouluteeman. Kaikkea sitä pitääkin luvata. Mutta olkoon. Sankarimme on tällä kertaa Joulupukki. Tämä pukki antaa lahjoja vain sellaisille lapsille, jotka ymmärtävät monadit.

Monadeista tykkäävä pukki.

Muistatteko flatMapin viime kerralta? Jos ette, niin kiireen vilkkaa lukemaan edellinen jakso.

Tulitte takaisin? Hyvä.

Monadi koostuu seuraavista osista:

  1. Joku funktori (monadit ovat aina myös funktoreita)
  2. Pure-operaatio
  3. Bind-operaatio

Rakennamme siis itse monadin. Omin käsin tekemällä oppii parhaiten.

Otetaan joku simppeli funktori. Vaikka joulupukin säkki.

Kaikki monadit ovat funktoreita, mutta kaikki funktorit eivät ole monadeja. Joulupukin säkki on funktori, koska sinne voi laittaa tavaroita (lahjapaketteja) ja suorittaa operaatioita niille.

Pure-operaatio on yksinkertainen. Se on kaikilla monadeilla hyvin samantapainen. Sen tarkoitus on “kääriä” tavallinen alkio (vaikkapa lahjapaketti) funktoriin (säkkiin).

pure paketti => säkki, joka sisältää paketin

Paketin sisältävä säkki

Pure-funktio siis ottaa syötteenään jonkin esineen. Se voi olla mikä tahansa. Tässä tapauksessa se on lahjapaketti. Se voisi olla vaikka numero 4. Tai kirjain “k”. Tai merkkijono “monadit on parasta!”

Lopputulos on aina samankaltainen: meille palautuu syötteenä otettu olio, joka on laitettu sisään funktoriin, eli tässä tapauksessa säkkiin.

Joulupukki tykkää lahjasäkkiesimerkeistä. Nyt pukki on iloinen.

Ilahtunut pukki

Otetaanpa vähän tylsempi, mutta koodaajalle tutumpi esimerkki. Otetaan lista. [] <- tuo on tyhjä lista. Kaikki varmaan jo tiesivätkin, että lista on funktori. No mitäpä sinne listaan laitettaisiin? No laitetaanpa vaikka numeroita! Jos haluaisin vaikkapa sellaisen 1-alkioisen listan, joka sisältää numeron 4, niin mitä tekisin!

Oikein! Komentaisin konetta: pure 4, ja saisin takaisin listan, jossa on nelonen eikä mitään muita numeroita: [4]

Joulupukki ei tykkää numerolistaesimerkeistä. Pukki alkaa suuttua.

Pukin päreet alkavat palamaan

Siirrytään siis nopeasti eteenpäin.

Kolmas osa monadista on bind-funktio. Se on ylivoimaisesti vaikein. Mutta ennen kuin tuskastut, tadaa — minun on myönnettävä että olen hiukan huijannut sinua. Olet nimittäin oppinut bindin jo viime jaksossa! Koska arvaa mitä?

bind on sama kuin flatmap!

Joulupukin säkki -esimerkissä flatmapin funktiotyyppi olisi

flatmap : (a -> m b) -> m a -> m b

Eli : flatmap ottaa syötteekseen 1) funktion, joka ottaa alkion, tekee sille jotain ja laittaa sen säkkiin, ja 2) funktorin (tässä tapauksessa lahjasäkin) jossa on alkioita (lahjoja), ja palauttaa yhden ison säkin, josta löytyvät kaikki kohdan 1) funktorin generoimat lahjat!

Otetaan esimerkki. Lahjasäkissä on kaksi villasukkaa.

Parin villasukan lahjasäkki

Pikku Kaino-Riepu haluaisi joululahjaksi neljä PlayStationia. Miten Kaino-Rievun pitäisi käyttää flatmap-funktiota tähän säkkiin, jotta lahjasäkin sisältö muuttuisi hänen haluamakseen?

muutaVillasukkaKahdeksiPlaystationiksiJaLaitaNeSäkkiin on se funktio, jonka Kaino-Riepu keksii.

Kaino-Rievun keksimä funktio

Innosta täristen Kaino-Riepu antaa flatmapille parametreiksi 1) loitsun muutaVillasukkaKahdeksiPlaystationiksiJaLaitaNeSäkkiin, sekä 2) säkin jossa on kaksi villasukkaa. Maa järisee ja tanner tömisee! Ja lopputulos on:

Säkki täynnä pleikkareita!

Neljä pleikkaria! Jipii! Kaino-Riepu pelaa koko jouluyön aamuun asti.

Joulupukki on tyytyväinen.

Todella tyytyväinen joulupukki

Kaino-Riepu ja sinä olette ymmärtäneet monadin.

Jälki-istunto

Ai etkö vielä tajunnut? Otetaan nyt uudestaan oikein hitaasti. Tämä lähtee nyt aivan alkeista. Osa tästä materiaalista on käyty aikaisemmissa osissa.

Ajatellaan, että meillä on tietorakenne, joka sisältää jotain muita tietorakenteita. Arkikielenä siis vaikka säiliö, joka sisältää kananmunia.

Säiliö, joka sisältää kananmunia, on toiselta nimeltään kennosto. Niissä on yleensä kuusi munaa.

Kennosto on funktori. Jokaiselle kennostoon laitetulle esineelle, tässä tapauksessa kananmunalle, voi tehdä saman asian. Vaikka kertoa sen kylkeen kirjoitettu numero kahdella.

Mapataan kananmunia kennostossa

Tämän operaation nimi on map.

Mutta jos haluat muuttaa alkioiden määrää, sepä ei enää mapilla onnistukaan. Kokeilepa tehdä komento map ??? kananmunakennosto, siten, että ??? paikalla on valitsemasi funktio tyyppiä A -> B. Jos tämä notaatio ei tässä vaiheessa ole tuttu, niin aloita alusta.

Yritä tehdä haluamallasi ??? :llä tämä temppu:

Temppujen temppu?

Yritä pari kertaa, mutta älä kuluta yrittämiseen liian paljon aikaa. SE ON NIMITTÄIN MAHDOTONTA! Buhahahahaa!

map ei ole tarpeeksi vahva loitsu

funktori ei ole tarpeeksi vahva tietorakenne

tarvitaan monadi

tarvitaan flatMap

Tule tekemään joulupukki iloiseksi ja hankkimaan vahvuutta koodaustaitoihisi! Etsimme uusia koodaajia, joille lisää oppiminen on intohimo.

--

--