Papers we love: Why Functional Programming Matters

Functioneel programmeren: het is een terugkerend fenomeen met een fanatieke groep aanhangers. Maar waarom zijn ze altijd zo enthousiast? Wat drijft de aanhangers van dit paradigma al sinds de opkomst hiervan? Met het aandragen van deze paper probeer ik hier een klein beetje licht op te werpen. De paper heet Why Functional Programming Matters en komt uit 1984, al is deze een klein beetje herschreven en gepubliceerd in 1989[3].

Het leuke van dit paper is dat hij niet vanuit formeel maar juist vanuit praktisch oogpunt naar functioneel programmeren kijkt. Veel gebruikte argumenten die het functioneel paradigma ondersteunen zijn inherent parallellisme, het kunnen bewijzen van je software en aspecten als referential transparency. Nu wil ik het belang hiervan niet opzij schuiven, maar persoonlijk vind ik dat in de meeste gevallen meer een “nice to have” dan een “must have”. De laatste keer dat ik heb bewezen dat mijn software correct is was op school in het kader van een huiswerk-opdracht.

John Hughes denkt hier ook zo over. In de introductie maakt hij korte metten met deze abstracte redeneringen. Natuurlijk, ook hij geeft aan dat deze belangrijk zijn, maar in zijn ogen is het niet het belangrijkste aspect van het onderwerp. Om zijn liefde voor functioneel programmeren kenbaar te maken kiest hij dan ook voor een interessante aanpak: hij gaat een vergelijking met structured programming trekken.

Structured programming zegt, in het kort, dat je gebruik dient te maken van modulair design, blokken van statements, subroutines en structurele loop-constructies. Dit in tegenstelling tot het hiervoor geldende stramien van een grote spaghetti-codebase vol met JNE/JNZ, meerdere entry-, of return paths en soortgelijke constructies. Dit is erg kort door de bocht en er zijn hier ook bijzonder interessante discussies over gevoerd, maar dit is een onderwerp voor een andere keer.

Hoe dan ook, structured programming was op het moment van publicatie praktisch de ‘mainstream’ manier van werken. Hughes kiest er dan ook voor om enkele, in zijn ogen, krachtige voordelen van functioneel programmeren te laten zien en aan te tonen hoe zij je helpen met modulair design van een codebase. Hughes stelt dat modules wenselijk zijn omdat deze snel ontwikkeld en individueel getest kunnen worden, alsmede hergebruikt wanneer ze generiek zijn. Analoog hieraan is het oplossen van problemen: door deze op te knippen in steeds kleinere deelproblemen kom je automatisch uit op kleinere oplossingen, die samengevoegd de gehele oplossing zullen zijn.

Hiermee wordt ook de focus van de paper duidelijk. Hughes stelt dat functionele talen je op een elegante manier helpen met de compositie van individuele modules. Doordat dit op een vrij abstracte manier mogelijk is, ontstaat er een hele losse, generieke koppeling tussen je componenten.

Ik ga hier niet woordelijk herhalen wat Hughes in de paper allemaal beschrijft. Deze is erg toegankelijk en, opvallend genoeg, totaal niet abstract ingezet. Voorbeelden die hij geeft gaan over higher-order functions, currying, lazy evaluation en oneindige lijsten en worden in verschillende domeinen gedemonstreerd.

Om toch enkele (klassieke) voorbeelden te geven zijn hieronder een paar eenvoudige operaties op lijsten te zien.

Prelude> let list = [1..4]
Prelude> list
[1,2,3,4]
Prelude> map (\x -> x*x) list
[1,4,9,16]
Prelude> foldl (+) 0 list
10
Prelude> foldl (*) 1 list
24

Hierbij voert map een functie uit op ieder element van een lijst en geeft vervolgens een nieuwe lijst met deze waardes terug. Daarnaast is er een reducer, foldl, die drie argumenten accepteert: een functie (de strategie), een initiële waarde (de seed) en een lijst. Deze zal een enkele waarde teruggeven, gecreëerd door de meegegeven strategy. De voorwaarde in dit geval is wel dat de strategie een binary operator is: hij moet dus twee parameters accepteren. Hier kun je dus ook je eigen implementatie aan meegeven:

Prelude> let myfunc = (\x y -> x + y*y)
Prelude> foldl myfunc 0 list
30

Het evalueren zou je ook eventueel handmatig kunnen doen. Dit geeft zoals verwacht hetzelfde resultaat:

Prelude> foldl (+) 0 list == ((((0 + 1) + 2) + 3) + 4)
True
Prelude> foldl myfunc 0 list == ((((0 + 1*1) + 2*2) + 3*3) + 4*4)
True

Ook partial evaluation is vrij eenvoudig te demonstreren:

Prelude> let partialfunc = foldl myfunc 0
Prelude> partialfunc list
30

Ik kan iedereen aanraden deze paper eens een kans te geven. Het bovenstaande is het topje van de ijsberg, in de paper wordt dit veel uitgebreider en vollediger toegelicht. Hughes begint bij de basis: het construeren van een lijst. Dit bouwt hij gedurende zijn verhaal verder steeds op en hiermee licht hij zijn visie op functioneel programmeren toe. Het geeft een goed fundament en is daarmee wat mij betreft dan ook een enorme aanrader om te lezen.


Over deze papers we love: binnen Sogyo hebben we de traditie dat we maandelijks een nieuwsbrief rondsturen. De nieuwsbrief gaat veel over interne feitjes, echter sinds februari 2015 verzorgd Kevin van der Vlist het topic: papers we love. Hij deelt met ons papers die interessant zijn om te lezen en ons kunnen inspireren. De topic is uitgegroeid tot een mooie verzameling die we ook graag hier willen delen.