Programmeringsparadigmer – ulike måter å tenke på

Jeg har tidligere snakket om betydningen av å beherske både statiske og dynamiske språk. En annen akse blivende polygloter er nødt til å se nærmere på er det vi kaller ulike programmeringsparadigmer.

paradigme_tre

(Språk-treet er selvfølgelig ikke komplett, og kategoriseringen er åpen for diskusjon.)

Om du har omtrent samme bakgrunn som meg er du mest kjent med de imperative språkene, som dominerer software-bransjen. Imperativ (eller befalende om du vil) betyr at vi forteller datamaskinen detaljert hva den skal gjøre – vi manipulerer variabler for å oppnå ønsker resultat.

Jeg tror det er veldig viktig at vi også studerer og lærer oss å beherske de mere deklerative (eller beskrivende) språkene. De tvinger oss til å tenke ganske anderledes når vi skal løse problemer. Om vi til syvende og sist likevel benytter oss av et imperativt språk så vil det vi lærer gi oss nye perspektiv som hjelpe oss til å løse oppgavene våre bedre. Dessuten er det mange språk som befinner seg i flere kategorier samtidig, som støtter f.eks. både objektorientering og funksjonsorientering (som alltid er det glidende overganger).

For å illustrere forskjellene mellom et utvalg paradigmer skal vi se på ulike løsninger for å finne den største, felles divisoren mellom to tall (heretter kalt gcdGreatest common divisor). Og vi begynner med det vi kjenner best…

Imperativ programmering

1 // GCD implementert i C
2 int gcd(int a, int b) {
3   while (a != b) {
4     if (a > b) a = a – b;
5     else b = b – a;
6   }
7   return a;
8 }

Den imperative algoritmen er for anledningen implementert i C, og illustrerer hvordan befalende kode fungerer:

For å beregne gcd av a og b, undersøk om a og b er like. Hvis så er tilfelle, returner en av dem. Hvis ikke, bytt den største av dem med forskjellen mellom dem og repeter.

Funksjonsbasert programmering

1 ; GCD implementert i Scheme
2 (define gcd
3   (lambda (a b)
4     (cond ((= a b) a)
5           ((> a b) (gcd (- a b) b))
6           (else (gcd (- b a) a)))))

I et funksjonelt språk som Scheme legger man vekt på det matematiske forholdet mellom input og output. Lambda-nøkkelordet introduserer en definisjon av en funksjon, og (a b) er funksjonens argumentliste. “cond” er en slags switch/case-konstruksjon. (- a b) er et kall til metoden “-” (minus) med a og b som argumenter. Her er metoden i pseudokode:

Gcd av a og b er definert til å være (1) a når a og b er like, (2) gcd av b og a – b når a er større enn b, og (3) gcd av a og b – a når b er større enn a. For å beregne gcd for to numre, ekspander og forenkle denne definisjonen til avslutning.

Rekursjon er en av hovedvirkemidlene i funksjonsbasert programmering. Samme algoritme kunne man selvsagt ha fått til i imperative språk også, selv om det er vanligere å se den første varianten. Det er derimot mye fra imperativ programmering man ikke gjør i funksjonsbasert. Fraværet av (det vi for enkelhets skyld kan kalle) variabel-manipuleringen gjør at funksjonsbasert kildekode i større grad kan analyseres for korrekthet. Det er også enklere å automatisere enkelte optimaliseringer, som å parallellisere programmer.

Logisk programmering

1 % GCD implementert i Prolog
2 gcd(A,B,G) :- A = B, G = A.
3 gcd(A,B,G) :- A > B, C is A-B, gcd(C,B,G).
4 gcd(A,B,G) :- B > A, C is B-A, gcd(C,A,G).

I et logisk språk spesifiserer vi et sett med axiomer og regler som lar systemet finne løsningen. Det kan være enklere å forstå Prolog-koden om du leser “:-” som “hvis” og “,” som “og”. Her er det samme i pseudokode:

Proposisjonen gcd(a, b, g) er sann om (1) a, b og g er alle like, (2) a er større enn b og det eksisterer et nummer c slik at c er lik a – b og gcd(c, b, g) er sant, eller (3) a er mindre enn b og det eksisterer et nummer c slik at c er lik b – a og gcd(c, a, g) er sant. For å beregne gcd av to numre, søk etter et nummer g (og ulike numre c) slik at man kan bevise at gcd(a, b, g) er sant.

Konklusjon

Valget av imperativ, funksjonell eller logisk programmering får som sagt ikke bare betydning for hvordan koden blir seende ut, men også hvordan utvikleren tenker for å komme opp med en løsning. Å beherske disse måtene å tenke på vil gjøre deg til en bedre problemløser. I tillegg vil du ha flere verktøy å velge blant – noen problemer vil alltid være enklere å løse deklerativt enn imperativt.

En annen ting som er interessant med de deklerative språkene er at vi ikke tvinger datamaskinen til å jobbe på en bestemt måte. Det muligjør implementasjon av forbedringer uten å røre program-koden, f.eks. gjennom å utvikle bedre kompilatorer. Den samme effekten har vi f.eks. når vi benytter LINQ i .net; LINQ er et deklerativt subset av C#/VB.net.

Tips til Java og .Net-utviklere

Om du er Java-utvikler, eller C#-utvikler som meg, så skal du være klar over at du har tilgang til funksjonsbaserte språk på favorittplattformen din også. Scala på Java-plattformen er et språk som kombinerer objektorientering og funksjonsbasert programmering. Fra Microsoft har vi fått F#, en variant av ML som støttes fullt ut i Visual Studio 2010 – på samme måte som Scala kombinerer også F# den funksjonelle og den objektorienterte paradigmen.

Hvis du vil ha et språk som er “renere” kan du velge Clojure – en moderne (2007) Lisp-dialekt som kjører på både .Net og Java-plattformen. Er du interessert i logiske språk kan du ta en titt på P#, som gir deg Prolog i .net. Prolog Cafe er tilsvarende for Java.

For komplette lister over språk på Java Virtual Machine og Common Language Infrastructure, se her og her.

Denne blogposten var inspirert av boken Programming Language Pragmatics, hvor kodesnuttene også er sakset fra.

Kategorier: .net ninja, Polyglot.
RSS feed for kommentarene. Tilbaketråkk.

3 kommentarer til “Programmeringsparadigmer – ulike måter å tenke på”

  1. Bjarte Says:

    Interessant post. Jeg liker slike oversikter som gir grunnlag for videre undersøkelser :) Jeg er i ferd med å finne meg et passende funksjonelt språk å leke med. Tror jeg heller mot F#, men er åpen for alternativer :)

  2. Torbjørn Says:

    Jeg tror jeg skal være forsiktig med å anbefale hva du skal velge. Begynte selv først å se på Haskell, som ser omtrent ut som Scheme minus parantesene (usikker på om jeg liker koden best med eller uten). Etter at jeg fikk øynene opp for Erlang har jeg derimot skippet Haskell. Erlang er et veldig interessant språk – det er funksjonsbasert, men har lånt aller mest fra Prolog, så det er en slags bastard.

    Er du veldig glad i .NET, og har lyst å få noe praktisk ut av det du lærer så raskt som mulig, er sikkert F# et av de bedre valgene. Min begrunnelse for å ikke velge det er at jeg vil ha et \”rent\” språk som tvinger meg å følge paradigmen – da tror jeg at jeg lærer mest.

  3. Ameth Says:

    Det er ikke akkurat enten-eller: http://augustss.blogspot.com/search/label/BASIC (BASIC-implementasjon i Haskell)

    Hvis det er Haskell valget faller på er dette en ganske god nybegynnerguide: http://learnyouahaskell.com/

Skriv en kommentar

Tillatte tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


Einar W. Høst: Det er jo læringen som gjør det morsomt! Se også http://norvig.com/21-days...

Pagliacci: OBS! tl;wr. Det er vel akuratt det jeg sliter med med min læring innenfor pr...

Torbjørn: La oss anta to ulike definisjoner av Template Method pattern - de to ytterpunkte...

Lars-Petter: Hei igjen. Siden du inviterer til å ta diskusjonen i bloggen, og har tatt deg t...

Torbjørn: Lars-Petter: Det er én måte å se det på. Det er absolutt fortsatt Template M...

Lars-Petter: Hei. Har du ikke i prinsippet her gått over fra Template Method (arv) til Strat...

Christian Abildsø: I alle fall i C#, så føles dette som kode som blir mer fleksibel men vanskelig...

Torbjørn: Hei Henrik, og takk for tilbudet. Ble oppmerksom på Rasberry Pi for under en uk...

Henrik Sandaker Palm: Ang. større hobby prosjekt. Du er som er en slik rakker på programmering har j...

Øivind Nilsen: Slutt å bruke mobilnummeret mitt som eksempel !...

Mulig relaterte linker

 Hold deg oppdatert

Søk i bloggen

Ferske innlegg

  • En historie om programmering
  • Template Method del 4: Multippel arv
  • Template Method Intermesso
  • Template Method del 3: Bare funksjoner
  • Kategorier

  • .net ninja (37)
  • Bøker (17)
  • Diverse prosjekter (35)
  • DSL (10)
  • Erlang (10)
  • F# (5)
  • Hardware (1)
  • Jobb (77)
  • Julekalender (51)
  • kjempekjekt.com (23)
  • LISP/Clojure (33)
  • NNUG / community (60)
  • O/RM & databaser (10)
  • Off topic (116)
  • OO-design/clean code (30)
  • Podcasts (14)
  • Polyglot (77)
  • Ruby (27)
  • Silverlight / RIA (3)
  • Software/verktøy (20)
  • Softwareutvikling (21)
  • Testing / TDD (30)
  • the contiki strip (13)
  • User experience (3)
  • WCF (3)
  • Webutvikling (32)
  • WPF (9)
  • WTF (12)
  • Last ned Wallpaper

    Programmeringsbloggens tøffe skrivebordsbakgrunn med snippets fra ulike språk laster du ned her!

    Abonner via epost

    Om du vil kan du få alle nye blogposter tilsendt til din epost. Abonner nå, det er kjempeenkelt!

    Meta