Göm menyn

Funktionell programmering

Nedan har vi två funktioner; den första, increment5, går igenom en lista och ökar (eng. increment) alla element med 5 medan den andra, first_element, returnerar en lista som består av de första elementet från alla "andra-nivå"-listor. Vi kommer att se fyra alternativa sätt att göra detta på med hjälp av olika aspekter som förekommer i funktionell programmering.

Alternativ 1 - Högre ordningens funktioner

Högre ordningens funktioner går ut på att använda funktioner som in- och utdata och bygger på det faktum att funktioner räknas som första ordningens objekt.

Alternativ 2 - Lambda-funktioner

Små funktioner som endast består av ett uttryck, likt i5 och fe ovan, kan ersättas med så kallade lambda-funktioner. De är temporära funktioner utan namn som typiskt används som argument till högre ordningens funktioner.

Dokumentation

Alt tag

Mer om högre ordningens funktioner

Vi vill ha en funktion combine som kan gå igenom en lista av tal och kombinera dem parvis med hjälp en funktion som vi skickar in. Några exempel på vad vi vill kunna göra är:

  • 0 + 1 + 2 + 3 + 4 = 10
  • 0 - 1 - 2 - 3 - 4 = -10
  • 0 * 1 * 2 * 3 * 4 = 0

Vilket var det svar som vi ville ha. Men hur skulle det fungera om vi vänder ordning på argumenten till den inskickade funktionen?

Alltså att istället för result = func(result, element) så har vi result = func(element, result). Vi testar och ser att vi får fel svar:

Men kan vi göra combine rekursiv istället? Vi måste då bearbeta i omvänd ordning eftersom vi börjar med en hel lista och för varje rekursionssteg minskar den.

Att tänka på vid högre ordningens funktioner

Det gäller att hålla koll på i vilken ordning de enskilda elementen kombineras. Om funktionen vi skickar in är både kommutativ och associativ kan vi i princip kombinera hur som helst, men om den saknar någon av dessa egenskaper är ordningen viktig. Definitionerna av dessa egenskaper:

  • Kommutativ: a + b = b + a
  • Associativ: (a + b) + c = a + (b + c)

Exempel:

  • Addition är både kommutativ och associativ.
  • Subtraktion är varken kommutativ eller associativ.
  • Konkatinering (sammanslagning av strängar eller listor) är associativ men inte kommutativ.

Funktioner som utdata

Vi har sett funktioner som indata, i både combine och with_all. Men vi kan även använda funktioner som utdata.

Exempel:

Det som händer här är att funktionen create_counter returnerar ett closure, d.v.s ett funktionsobjekt som även innehåller information om lokala variabler.

Alternativ 3 - Pythons egna iteratorfunktioner

Den generella funktionen with_all har redan en motsvarighet i Python i funktionen map. Den returnerar dock inte listan direkt.

Dokumentation

Det som funktionerna range och map returnerar kallas iteratorer. De är objekt som innehåller sekvenser som ännu inte är beräknade. En sådan sekvens kan potentiellt vara oändlig, och vi får inte se elementen förrän vi tvingar fram dem, t.ex med funktionen list.

En iterator kan ses som en slags automat ur vilken man kan få ett element i taget. Den i princip enda operationen man kan göra på en iterator är next() som ger nästa element, om det finns. Iteratorer går utmärkt att använda i for-loopar:

Funktionen list ser till att spotta fram hela sekvensen på en gång, i de fall vi behöver detta.

Mer om iteratorfunktioner

Några andra fräna saker som har med iteratorer att göra:

Alternativ 4 - Listbyggare

Listbyggare (eng. list comprehensions) är ett mer kompakt alternativ till funktionen map. Man får en lista direkt och behöver således inte använda funktionen list.

Dokumentation

Blir med hjälp av listbyggare:

Här har vi funktionerna som vi stötte på tidigare skrivna med listbyggare:

Mer exempel på listbyggare

Ett lite klurigare exempel

Nedan ser vi en funktionell implementation av: summan av f(x) för alla tal 0 <= x <= n. Det är en utmärkt lösning som är tydlig och enkelt skriven, men finns det andra sätt att göra det på med hjälp av vad vi har sett idag?

Alt text

Principskiss

Låt oss säga att argumenten som skickas in ska ge upphov till:

Alt text

Hur skulle det kunna se ut?

Alt text

Detta i kod blir då:

Sammanfattning

  • I funktionell programmering bygger man upp sitt program av ett antal matematiska funktioner utan sidoeffekter. Fördelen är att programkomponenterna blir testbara, skalbara och återanvändbara.
  • Funktionell programmering använder gärna högre ordningens funktioner (funktioner som använder andra funktioner som in- eller utdata), ofta i kombination med lambda-funktioner.
  • Python har ett flertal iteratorer inbyggda, som kan hjälpa oss att t.ex. utföra en operation på alla element.
  • Listbyggare är en ännu mer kompakt och flexibel metod att konstruera sekvenser.

Tillhörande quiz

Finnes här


Sidansvarig: Peter Dalenius
Senast uppdaterad: 2016-08-15