Rekursion puolustus / In Defence of Recursion
Panu A. Kalliokoski
Helsinki Clojure Meetup / Haskell Meetup
ke 30.10.2024
- ilman mitään tekoälygeneroitua sisältöä!
- with no AI generated content!
Mitä rekursio on? | What is recursion?
- Te varmaan tiedätte, mutta…
- You probably know pretty well, but…
(defn even-elements [coll]
(if (empty? coll) []
(cons (first coll)
(even-elements (rest (rest coll))))))
- Funktio, jonka määrittelyssä viitataan funktioon itseensä
- Function whose definition references the function itself
(declare saha-aalto)
(def saha-aalto (concat (range 30) saha-aalto))
- Arvo, jonka määrittelyssä viitataan arvoon itseensä
- Value whose definition references the value itself
- 本当、自分の名前を使っている何でも
Mitkä kielet tukevat rekursiota? | Which languages support recursion?
- LP;EL: kaikki.
- TL;DR: every friggin' one of them.
- On oikeastaan vaikeampaa olla tukematta sitä kuin tukea
- It's basically harder not to support recursion than to support it
- Vaatii ainoastaan tavan viitata nimiin ennen kuin ne on määritelty
- eikä oikeastaan sitäkään…
- Only requires a way to reference names before they have a definition
- and not even that, to be exact…
Miten ohjelmoijat suhtautuvat rekursioon? | What kind of stance do programmers have towards recursion?
- Olen tavannut lähinnä ohjelmoijia, joiden suhde rekursioon on jokin
seuraavista (1–2/5):
- lievä epämukavuus
- ulkopuolisuuden tunne
- I've been mostly meeting with programmers whose relationship with
recursion is one of the following (1–2/5):
- slight discomfort
not my thing really
(jatk./cont.)
- Olen tavannut lähinnä ohjelmoijia, joiden suhde rekursioon on jokin
seuraavista (3–5/5):
- paheksuminen
- ylenkatse
- lämpimät muistot,
vanhat hyvät ajat
- I've been mostly meeting with programmers whose relationship with
recursion is one of the following (3–5/5):
- disapproval
- contempt
- warm memories,
good old times
Miksi rekursiota pitää ja saa käyttää? | Why you should and may use recursion?
- Samat syyt kuin funktionaalisessa ohjelmoinnissa, oikeastaan (1–2/5)
- Yksinkertainen ja helposti ymmärrettävä työkalu
- Erittäin monikäyttöinen
- The same reasons as functional programming in general, actually
(1–2/5)
- It's a simple tool whose semantics are easy to understand
- It's extremely widely applicable
(jatk./cont.)
- Samat syyt kuin funktionaalisessa ohjelmoinnissa, oikeastaan (3–5/5)
- Se kehittää ajattelua
- Joitain ongelmia ei edes voi ratkaista ilman
- Jotkin voi, mutta ei-rekursiivinen ratkaisu on 39 x monimutkaisempi
- The same reasons as functional programming in general, actually
(3–5/5)
- Recursion improves your way of thinking
- Some problems cannot even be solved without it
- Some can, but the non-recursive solution is like 39 x more complex
Vihdoinki jotain koodia! | Finally some code!
(defn long-subs-count [coll threshold]
(count (filter (fn [elem] (> (count elem) threshold)) coll)))
(defn long-subs-count [coll threshold]
(cond
(empty? coll) 0
(> (count (first coll)) threshold)
(inc (long-subs-count (rest coll) threshold))
:else (long-subs-count (rest coll) threshold)))
Entä alun esimerkki? | How about the example at the beginning?
(defn even-elements [coll]
(map first (partition 1 2 coll)))
(defn even-elements [coll]
(cond
(empty? coll) []
(cons (first coll)
(even-elements (rest (rest coll))))))
- erityisellä sanastolla tehdyt määritelmät ovat lyhyempiä mutta
rekursiiviset muistuttavat toisiaan
- special vocabulary solutions are shorter but the recursive ones are
closer to each other
Tällaisessa se alkaa mennä vaikeaksi | In cases like this it gets hairy
(defn elem-surrounded-by [coll surrounder]
(some (fn [[e1 e2 e3]]
(and (= e1 surrounder)
(= e3 surrounder)
e2))
(partition 3 1 coll)))
(defn elem-surrounded-by [coll surrounder]
(cond
(empty? coll) nil
(and (= surrounder (first coll))
(= surrounder (second (rest coll))))
(second coll)
:else (elem-surrounded-by (rest coll) surrounder)))
- Useimmilla on varmaan vähän vaikeuksia lukea ekaa määrittelyä
- Most people probably have a bit hard time reading the first definition
Mites tää? | How about this?
(defn occurrences [data pred?]
(count (filter pred? (flatten data))))
(defn occurrences [data pred?]
(cond
(pred? data) 1
(not (coll? data)) 0
(empty? data) 0
:else (+ (occurrences (first data) pred?)
(occurrences (rest data) pred?))))
- Aika ylivoimaista toteuttaa oikein vakiokirjaston sanastolla
- Quite overwhelming to implement correctly with standard library
Ne jotka on tosi vaivalloisia ilman | Those really toilsome without
(defn match? [pattern haystack]
(or
(and (empty? pattern) (empty? haystack))
(and (or (= (first pattern) (first haystack))
(= (first pattern) \?))
(match? (rest pattern) (rest haystack)))
(and (= (first pattern) \*)
(or (match? (rest pattern) haystack)
(match? pattern (rest haystack))))))
- Joo toki pystyy tekemään käsin pinon epädeterminismiä varten mut miks
- Yeah you sure can manage a manual stack for indeterminism but why
Mites ne mahdottomat? | What about the impossible ones?
(defn splits [vec]
(map (fn [index] [(subvec vec 0 index) (subvec vec index)])
(range 1 (inc (count vec)))))
(defn partitions [vec]
(cond
(empty? vec) [[]]
(empty? (rest vec)) [[vec]]
:else (mapcat (fn [[prefix suffix]]
(map (partial cons prefix) (partitions suffix)))
(splits vec))))
- Joo, Haskellissa on varmasti joku kirjastokutsu joka generoi tämänkin
alilistakuvion…
- Yeah, Haskell surely has a library call that generates this pattern of
sublists…
Miksei rekursiota käytetä (enemmän)? | Why is recursion not used (more)?
- Olen kuullut lähinnä näihin kolmeen kategoriaan kuuluvia syitä:
- tiedon puute
- ennenaikainen optimointi
- estetiikka
- En oo näistä samaa mieltä (ette ehkä yllättyneet)
- I've mostly heard reasons in these three categories
- lack of knowledge
- premature optimisation
- æsthetics
- I don't agree (you might not be surprised)
Tiedon puute | Lack of knowledge
- Esimerkiksi
Eikös se oo tehotonta?
Nykyaikainen ohjelmointi ei harrasta
Meille ei oo opetettu
En oo mikään algoritmisuunnittelija
- For example
Isn't it inefficient?
Modern programming does not involve
We were never taught
I'm not an algorithm designer
Ennenaikainen optimointi | Premature optimisation
- Esimerkiksi
Pino täyttyy
Tää pitää muuttaa häntärekursioksi
Tän thunkit vie muistia
GHC ei osaa soveltaa stream fusionia tähän
- For example
It'll fill the stack
This should be transformed into a tail recursion
The intermediate thunks of this one will use memory
GHC isn't able to apply stream fusion to this
Estetiikka | Æsthetics
- Esimerkiksi
Point-free on paljon tyylikkäämpi
Hieno vakiokirjasto on tehty käytettäväksi
Kollegat nauraa/haukkuu jos teen näin
- For example
Point free is much more elegant
Our esteemed standard library needs to be used
My colleagues will laugh/mock me if I do this
Tarinan opetus | The moral of the story
- Kulje vapaasti, kokeile juttuja, elä pitkään ja menesty
- Go free, try things out, live long and prosper
Kiitos keskittymisestä / Tack för att ni lyssnade / Thank you for focusing
Tiesittekö, että rekursiolla voi generoida kivoja sävelmiä?
Did you know recursion is great for generating nice melodies?