LISP/Clojure

Artikler om LISP og Clojure (som er en LISP)..

Fiat lux

Det er ikke fredag i dag, men likevel, jeg gir dere “Universet, første alpha-versjon”

(ns genesis
    "Book of Genesis, 
    Version 0.0.1-SNAPSHOT")

; Some universal plumbing..
(def darkness 0)
(def light (inc darkness))
(def be identity)

; The main character..
(def God
     (fn [miracle something]
         (condp = miracle
             :create (symbol (name something))
             :see    (if (= something light) :good :evil)
             :say    (println "GOD:" something))))

; In the beginning
(defn in-the-beginning [darkness god]

   ; God created the heaven and the earth.
   (let [heaven (god :create :heaven)
         earth  (god :create :earth) ]
     (assert (and (= heaven 'heaven)
                  (= earth 'earth)))

     ; And God said,
     (god :say
          (pr-str
            ; Let there be light:
            (let [there (be light)]

              ; and there was light.
              (assert (= there light))

              ; And God saw the light,
              (assert (= (god :see light)
                         ; and it was good.
                         :good))

              ; And God divided the light from the darkness.
              (try (/ light darkness)
                   (catch java.lang.ArithmeticException ex
                          (god :say
                               (str "Ah, can't devide by zero, "
                                    "genesis postponed!")))))))))

(in-the-beginning darkness God)
;=> GOD: Ah, can't devide by zero, genesis postponed!
;=> GOD: nil
;=> nil

Brainf*ck

brainfuck_inofficial_logo

Vi utviklere er noen merkelige dyr av og til! Og det er når vi er på vårt aller mest merkelige at vi henter frem programmeringsspråk som brainfuck.

Brainfuck er ikke laget for å være praktisk; det er et fullverdig, Turing-komplett språk, men det er verken forståelig eller spesielt enkelt å bruke til noe fornuftig. Grunnen til at det i sin tid ble laget var at man ville se hvor liten man kunne få en kompilator. Oppfinneren Urban Müller klarte å lage en kompilator for brainfuck til Amiga OS som var på bare 240 bytes.

Jeg har lekt meg litt med brainfuck i det siste. Hvorfor det spør du kanskje? Tja, det er jo noe å lære seg.., en mental utfordring. Millioner av folk over hele kloden bruker jo timevis hver uke på å løse Sudoku – å løse oppgaver i et kryptisk programmeringsspråk er vel egentlig ikke så veldig mye mer spesielt?!

Jeg har til og med installert et integrert utviklingsmiljø for brainfuck – bfdev – hvor jeg kan steppe gjennom instruksjoner, inspisere program-minnet o.l.

bfdev_s

Men jeg har tatt det litt lengre enn som så også – jeg har nemlig implementert min egen brainfuck-tolker. På github finner du nå bf-clj som du kan bruke til å kjøre brainfuck fra Clojure. Igjen har jeg gjort dette fordi det var en mental utfordring.

Så veldig krevende var det heller ikke, men litt spennende å få til i et funksjonelt språk. Det er ikke alltid lett å finne små men utfordrende øvingsoppgaver man kan bruke til å trene programmering, men brainfuck kan i alle fall være en slik. Så jeg anbefaler alle å forsøke å implementere sin egen brainfuck-tolker.

Her har jeg laget en liten video som demonstrerer bf-clj…

En funksjonell Stack-basert kalkulator

NNUG-møtet i Bergen på onsdag ble jeg inspirert til å gjøre en stack-basert kalkulator-kata. Det var nok ikke det som var foreleserens intensjon, men dette var det mest spennende jeg fikk ut av foredraget.

Siden onsdagen har jeg gjort denne kataen tre ganger, i Clojure, med ganske ulike resultat hver gang. Den siste gangen filmet jeg det jeg gjorde, la på litt musikk, og her er resultatet.

Men les gjerne det som står nedenfor først, sånn at du vet hva du går til…

Stack-based Calculator Kata in Clojure from Torbjørn Marø on Vimeo.

Ren og skitten kode

Det som kanskje er litt spesielt er at jeg implementerer kalkulatoren med funksjonell programmering og “rene” funksjoner. Det vil i praksis si at koden ikke kan pushe eller poppe data på/av stacken. Funksjonene må ta inn en stack som parameter, returnere en ny stack tilbake som programmet kan bruke videre, og ellers ikke gjøre noen ting.

Denne implementasjonen illustrerer derfor seperasjonen mellom “ren” kode uten bieffekter og “skitten” kode med bieffekter, slik som jeg snakket om i blogposten hemmeligheten bak funksjonell programmering avslørt.

TDD

I videoen bruker jeg tester som støtte når jeg implementerer den rene delen av programmet. Men dette var som sagt tredje gangen jeg løste oppgaven, og jeg følte meg ganske sikker. Derfor ble testene kanskje ikke så gode, dvs. de drev ikke utviklingen på samme måte som første og andre gangen.

Strengt tatt kunne jeg ha droppet en av testene jeg brukte også, for den var veldig lik en av de andre. Men det oppdaget jeg ikke i farten…

å forstå Clojure-koden

Koden som demonstreres i videoen er egentlig ganske basic, og bør passe for dem som er relativt ferske i Clojure. Her er noen tips som kan gjøre det enklere å følge med.

Den beste datatypen å bruke for å representere en stack i Clojure er en vector. Det er en slags array som er optimalisert for å legge til elementer på enden. Man kan opprette en tom vector slik: [], eller en vector med noen numre slik: [1 2 3 4 5].

For å legge til et nytt element på stacken brukes funksjonen conj. (conj [1 2 3] 4) returnerer en ny vector: [1 2 3 4].

I denne tredje implementasjonen valgte jeg å bruke det som kalles destructuring – en form for pattern matching. Når jeg gjør dette: (let [[x y & r [1 2 3 4]]]) vil x få verdien 1, y får verdien 2, og r får resten av vectoren, altså [3 4] i dette tilfellet. Men om du følger nøye med så ser du at jeg nå plukker elementer fra starten av vectoren, og da ser det mer ut som en kø enn en stack. Trikset er at jeg reverserer stacken før jeg gjør dette, og da går det jo for det samme.

Selve utregningen, evalueringen av pluss, minus, gange og deling, benytter seg av det faktum at i Clojure er data det samme som kode, og kode er det samme som data. Jeg bygger rett og slett opp et Clojure-uttrykk, f.eks. (+ 1 2), som jeg så evaluerer og får resultatet 3.

Bloopers

Alle filmer inneholder feil, også denne. Blant annet implementerte jeg en måte å avslutte programmet på (ved at man sendte kommandoen quit), men jeg tok den aldri i bruk.

Den morsomste feilen er derimot metoden som ble hetende promp! Det skulle selvsagt ha vært prompt.

formater, ikke konkatiner

Mye av det programmene våre gjør er å behandle tekst (og da mener jeg “våre” som i “oss utviklere og alt vi finner på å lage”). Noe av det første vi lærer som ferske hackere er å konkatinere strenger – dvs. å slå sammen to biter med tekst.

Og i forhold til konstruksjon av tekststrenger stopper det der for veldig mange. Du kan egentlig klare deg ganske lenge med enkel konkatinering, men det er ikke alltid det mest elegante!

Siden tidenes morgen (dvs. 50-tallet) har programmeringsspråk inkludert diverse metoder for å formatere tekst. Den aller mest kjente og brukte funksjonen heter printf, og dukket først opp i språket C – men den ble egentlig arvet fra BCPL, hvor den het writef (men hvem har vel egentlig hørt om BCPL?). Siden har printf inspirert andre, og i dag finner du dens etterkommere i nær sagt alle programmeringsspråk.

Format i .Net

Ett av disse språkene er C#, hvor vi kan bruke formatstrenger i mange sammenhenger. Den vanligste bruken er en statisk metode på String-klassen som heter Format. Her er et banalt eksempel:

10 int age = 35;
11 string givenName = "Torbjørn";
12 string surname = "Marø";
13 
14 // Konkatinering på den vanlige måten
15 
16 string displayName = surname + ", " + givenName + " (" + age + ")";
17 
18 // mer elegant med en formatstreng
19 
20 string displayName = String.Format("{0}, {1} ({2})",
21                                    surname,
22                                    givenName,
23                                    age);

Det er mye lettere å innføre feil ved vanlig konkatinering enn ved bruk av format, og det er også (i alle fall for et trent øye) mye lettere å se hva resultatet kommer til å bli når man ser en formatstreng.

String.Format er mye mer avansert enn det kan virke ved første øyekast. Men det er sjelden vi benytt mer enn det mest elementære, og jeg må nesten alltid slå opp i dokumentasjonen om jeg trenger å formatere f.eks. tall eller en dato på en bestemt måte.

I det neste eksempelet bruker jeg Console.Writeline, som også aksepterer en formatstreng. Her har jeg spesifisert at tallet skal formateres som penger, og at datoen skal vises som dagens navn, dagens dato (med ett siffer om mindre enn 10) og månedens navn.

1 double money = 12345.6789;
2 Console.WriteLine("Pris ({0}): {1:C} | {2:dddd dd. MMMM}",
3                   CultureInfo.CurrentCulture,
4                   money,
5                   DateTime.Now);
6 
7 // output: "Pris (nb-NO): kr 12 345,68 | torsdag 7. april"

Format i Clojure (og Java)

I Clojure har vi også en format-funksjon, og en tilsvarende printf-funksjon som tar en formatstreng som input og skriver til standard out. Under panseret bruker disse funksjonene java.util.Formatter, som er inspirert av C’s tradisjonelle printf.

Her er noen eksempler på format i bruk, og strengene de genererer..

10 (format "Hello, %s!" "world")                      ;=> Hello, world!
11 (format "%s = %s" "SomeKey" "SomeValue")           ;=> SomeKey = SomeValue
12 (format "%1$s + %1$s = %2$s" 2 4)                  ;=> 2 + 2 = 4
13 (format "e = %+.4f" 2.718281828459045)             ;=> e = +2,7183
14 (format ":%-20s:" "right padding")                 ;=> :right padding       :
15 (format ":%20s:" "left padding")                   ;=> :        left padding:
16 (format "%b %b %b %b" true false nil "something")  ;=> true false false true
17 (format "#%02x%02x%02x;" 255 0 125)                ;=> #ff007d;
18 (format "%s" (Date.))                              ;=> Thu Apr 07 21:04:29 CEST 2011
19 (format "Offset: %tz" (Date.))                     ;=> Offset: +0100
20 (format "Time zone: %tZ" (Date.))                  ;=> Time zone: CEST
21 (format "%1$tH:%1$tM:%1$tS" (Date.))               ;=> 21:04:29
22 (format "%1$tl:%1$tM %1$tp" (Date.))               ;=> 9:04 pm
23 (format "Unix time: %ts" (Date.))                  ;=> Unix time: 1302203069
24 (format "%1$td/%1$tm-%1$ty" (Date.))               ;=> 07/04-11
25 (format "%1$td. %1$tb %1$ty" (Date.))              ;=> 07. apr 11
26 (format "%1$td. %1$tB %1$tY" (Date.))              ;=> 07. april 2011
27 (format "ISO 8601: %tF" (Date.))                   ;=> ISO 8601: 2011-04-07

(Dette eksempelet ble generert av et Clojure-skript. Hvis du er interesert finner du det her.)

Interpolering

Variabel-interpolering er en lignende teknikk man finner i mange dynamiske språk, som Perl, PHP og Ruby. Her kan tekst-strenger direkte inneholde referanser til variabler eller mer komplekse uttrykk, og språket parser og evaluerer dem og erstatter dem med teksten.

Her er et lite eksempel fra Ruby..

1 given = 'James'
2 surname = 'Bond'
3 
4 puts "My name is #{surname}, #{given} #{surname}."
5 
6 # => My name is Bond, James Bond.

Clojure har også en interpolerings-funksjon i contrib-bibloteket. Den heter <<, og i bruk ser det slik ut:

 1 (ns demo (:use clojure.contrib.strint))
 2 
 3 (let [given "James" surname "Bond"]
 4   (println (<< "My name is ~{surname}, ~{given} ~{surname}.")))
 5 
 6 ; => My name is Bond, James Bond.
 7 
 8 (let [numbers '(1 2 5 9 4 4)]
 9   (println (<< "The sum of ~{numbers} is ~(apply + numbers).")))
10 
11 ; => The sum of (1 2 5 9 4 4) is 25.

Om du trodde regex var uforståelig…

De mest avanserte formateringsmulighetene jeg har sett er dem man har i Common Lisp. Format-strengene kan inneholdet sitt helt eget mini-språk, og hvis du synes at regex er komplisert og uforståelig så vent bare til du ser dette. Formatene kan for eksempel ha kontrollflyt, løkker og rekursjon!

Igjen har clojure en implementasjon av det samme, og den heter cl-format. Dette er bare en liten smakebit..

10 (ns demo (:use clojure.contrib.pprint))
11 
12 (defn print-dogs [n]
13   (cl-format true "~R dog~:[s are~; is~] here." n (= 1 n)))
14 
15 (print-dogs 1) ; => one dog is here.
16 (print-dogs 3) ; => three dogs are here.
17 
18 (cl-format true "Par:~{ <~S,~S>~}" '(A 1 B 2 C 3))
19 
20 ; => Par: <A,1> <B,2> <C,3>

Vil du vite mer om mulighetene kan du ta en titt i Common Lisp HyperSpec (som er den styggeste API-dokumentasjonen jeg noen sinne har sett).

Oppsummering

Den siste tiden, spesielt gjennom å studere Clojure, har jeg liksom gjennoppdaget printf. Når jeg husker på å benytte meg av de kraftige formateringsmulighetene resulterer det ofte i mer elegant kode. Konkatinering er clunky, bruk format!

kjedsommelighetskode

Åååå, som jeg hater influensa!!! Nå ha jeg ligget i sofaen i fem dager og kjedet meg. Men jeg må innrømme jeg har fått til å kode litt. Ikke så mye nyttig nødvendigvis, men jeg har nå fått løst noen Euler-problemer, og knotet litt med ett og annet hobby-prosjekt.

Noe av det aller minst nyttige en kan lage er hello-world-programmer. Og da tenker jeg ikke på den enkle sorten. I et orntlig hello-world-program skal det ikke være så enkelt å se hvordan det faktisk virker. Alt er lov, det eneste kriteriet er at programmets nøyaktige output er teksten “Hello, World!”.

Her er et jeg konstruerte i dag..

10             ;==-----\\
11             ;        \\\
12             ;         \\\\
13 (ns ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
14  ,  hello                                ,,,
15   ,     (:use clojure.repl)                 ,,,
16    ,        (:require clojure.string))         ,,,
17     ,           ((defn                            ,,,
18      ,              Hello-World!  [ by Tormaroe ]    ,,,
19     ,           (println                          ,,,
20    ,        (clojure.string/replace            ,,,
21   ,     (first                              ,,,
22  ,  (dir-fn 'hello))                     ,,,
23 #"-" ", "))) 00 00) ,,,,,,,,,,,,,,,,,,,,
24             ;         ////
25             ;        ///
26             ;==-----//

Ja, det er et gyldig clojure-program. Og selv om det ser tullete ut så går det faktisk an å lære noe av dette også – hvis du klarer å tyde hvordan det virker så vil jeg si du har kommet et godt stykke på vei til å bli en god clojure-utvikler.

Her er en litt annen variant..

 1 ;; a program saying hello to the world
 2 (use '[clojure.string :only (join)])
 3 (let [a (partial subs (slurp *file*))]
 4   (print (join ", " (map #(a % (+ % 5)) [20 33]))))

Klarer du å gjette deg til hva den gjør? Eller hva med den neste..?

 1 (->>
 2   (map #(nth (str %) %2)
 3        '(hash dec nil? apply symbol?
 4               " , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , "
 5               " , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , "
 6               remove-watch comporator print-ctor bit-shift-left chunk-append)
 7        (range))
 8   (apply str)
 9   print)

Litt fornøyd med den faktisk. Og i tre små programsnutter har jeg faktisk klart å vise ganske masse, grunnleggende Clojure.

Disse programmene finner du også på hello-world-tråden på norsk freakforum, sammen med en rekke andre, interessange bidrag i ulike språk.

En universell server (video)

Har du lyst til å se meg kode? Jeg har laget en code cast video jeg håper du vil like, men først litt bakgrunn…

Joe Armstrongs foredrag om Message Passing Concurrency in Erlang på QCon London i fjor forandret meg! Han viste meg en måte å trylle med kode på som inntil da hadde vært helt fremmed for meg. Etter det har Erlang, og deretter Clojure, formet nye mønstre i hjernen min, om hvordan det er mulig å skape fantastiske ting med dynamisk kode.

I presentasjonen lagde Armstrong noe han kalte for en universell server – en server som kunne bli hva som helst, bare ved at man sendte den ulike kommandoer. I min video lager jeg en lignende server i Clojure. Jeg forventer ikke at min video skal gi noen den samme kvasireligiøse a-ha-opplevelsen som Joe gav meg, men kanskje den kan gi deg noen nye ideer…

Jeg hadde veldig lyst til å bruke Daft Punk’s TRON Legacy soundtrack som bakgrunnsmusikk, men jeg turde til slutt ikke å bruke musikk jeg ikke har rettighetene til. Musikken er derfor hentet fra Mevio’s Music Alley. Skru på høytalerne!

The Universal Server from Torbjørn Marø on Vimeo.

Vil gjerne høre hva du synes!

Informatisk julekalender: Luke 9

I dag blir det ikke en helt vanlig luke i kalenderen. I går inspirerte jeg nemlig meg selv såpass ved å fortelle om Alan Turing at jeg ble nødt til å implementere min egen lille Turingmaskin. Folk kaller meg merkelig, men det får nå bare være :)

Denne luken er nok dermed ment for et litt smalere publikum enn vanlig. Det kan f.eks. godt tenkes du ønsker å lese deg opp på turingmaskiner for å få mest utbytte av dette. Jeg planlegger derimot å komme tilbake med en vanlig luke i morgen, så fortvil ikke!

Denne koden er forresten implementert i sånn passe trøtt tilstand, delvis på bussen, så den kan helt sikkert forbedres. Hvis du tror at du kunne klart bedre – og du kan velge programmeringsspråk selv – så utfordrer jeg deg til å dele koden din i kommentarfeltet. Jeg er nemlig veldig interessert i å se andre implementasjoner a turingmaskiner. MEN IKKE POST KODEN DIREKTE I KOMMENTARFELTET, lim heller koden din inn på pastie, Gist eller lignende, og link til koden i kommentaren din her.

Koden min er forresten tilgjengelig i sin helhet som gist her. I denne artikkelen presenteres koden stykkevist og delt..

Hvordan representere en turingmaskin

Jeg valgte selvsagt å bruke Clojure for å implementere min første Turingmaskin. Den er basert på en tabell med regler som består av fem verdier: Hva som står i tapecellen under lesehodet, hvilken tilstand maskinen er i, hva som skal skrives, hvilken retning man skal flytte, og hvilken ny tilstand maskinen skal settes i.

 1 (ns turing.core)
 2 
 3 (comments "The turing machine runs on a table of rules defined by 5-tuples,
 4            implemented here as maps with the following format:"
 5         { :tape value                 ; Given cell under head has value
 6           :state value                ; And machine state has value 
 7           :write value                ; Then write value in cell 
 8           :move value                 ; Move head according to value (:left :right :no) 
 9           :set-state value })         ; And set new machine state to value

Så definerer jeg noen variabler for initiell tilstand, default-verdien til en celle, og det spesielle symbolet for når maskinen skal stoppe.

11 (def *initial-state* "A")
12 (def *empty-cell* 0)
13 (def halt "HALT")

Her følger funksjonen for å finne riktig regel som skal brukes for en gitt tilstand og et gitt symbol under lesehodet på tapen.

15 (defn find-rule
16       "Find the rule for current state and symbol"
17       [symbol state rules]
18       (first (filter (fn [r] (and (= (r :tape) symbol)
19                                   (= (r :state) state)))
20                      rules)))

Og så trenger jeg en litt spesiell funksjon som kan fortelle meg litt om hvilken type bevegelse jeg skal gjøre på tapen. Jeg vil nemlig bruke en vektor (array) til å representere tapen, og vil da få behov for å kjøre litt spesiell kode hvis maskinen ønsker å bevege seg utenfor vektorens størrelse – enten den ene eller den andre veien. Funskjonen skal altså fortelle meg om ny index/posisjon vil bli enten –1 eller går utenfor vektorens lengde.

22 (defn move-type
23       "Return the type of tape move to perform. If the move is to a
24       previously unvisited cell, the tape needs to be expanded, so
25       this function should return :off-left or :off-right."
26       [tape head-position rule]
27       (let [dir (rule :move)]
28         (cond (and (= head-position 0)
29                    (= dir :left))
30                 :off-left
31               (and (= (+ 1 head-position) (count tape))
32                    (= dir :right))
33                 :off-right
34               :else dir)))

Jeg kan nå presentere funksjonen for å gjennomføre en bevegelse på tapen basert på en regel. Funksjonen produserer en ny tape – potensielt med flere celler om det er nødvendig – og oppdaterer også posisjonen.

36 (defn perform-move
37       "Returns a two element vector with new tape and new position"
38       [tape head rule]
39       (let [tape2 (assoc tape head (rule :write))]
40         (case (move-type tape head rule)
41           :off-right [(conj tape2 *empty-cell*)       (inc head)]
42           :off-left  [(vec (cons *empty-cell* tape2)) head      ]
43           :right     [tape2                           (inc head)]
44           :left      [tape2                           (dec head)]
45           :no        [tape2                           head      ])))

Og så har vi endelig ankommet til funskjonen som skjører maskinen. Run starter opp med initiell tilstand og en tom celle. Den finnes så hvilken regel som skal brukes for å gå til neste tilstand (linje 57), utfører operasjonen på tapen (linje 60), og looper (via halerekursjon) inntil den spesielle halt-tilstanden blir satt.

47 (def tableformat "%10s %7s %10s %s%n")
48 
49 (defn run
50       "Run turing machine by given rules and print each step.
51       Initial state is \"A\", empty cell symbol is 0."
52       [rules]
53       (printf tableformat "Sequence" "State" "Position" "Tape")
54       (loop [i 1, state *initial-state*, tape [*empty-cell*], head 0]
55             (printf tableformat i state head tape)
56             (when (not= state halt)
57               (let [rule (find-rule (nth tape head)
58                                     state
59                                     rules)
60                     [tape2 head2] (perform-move tape
61                                                 head
62                                                 rule)]
63                 (recur (inc i)
64                        (rule :set-state)
65                        tape2
66                        head2)))))

Ivrig Bever

Jeg skal nå kunne kjøre turingmaskinen min, og velger da et lite program jeg finner på wikipedia som kalles en 3-state Buzy Beaver. Konseptet om ivrige bevere er veldig akademisk, men den er i alle fall ikke vanskelig å sette opp nå som jeg har implementert turingmaskinen min. Her er kallet til Run som vil kjøre maskinen med bever-reglene.

68 ;; Set up and run Turing table for 3-state Busy Beaver
69 (run [{ :tape 0 :state "A" :write 1 :move :right :set-state "B"   }
70       { :tape 0 :state "B" :write 1 :move :left  :set-state "A"   }
71       { :tape 0 :state "C" :write 1 :move :left  :set-state "B"   }
72       { :tape 1 :state "A" :write 1 :move :left  :set-state "C"   }
73       { :tape 1 :state "B" :write 1 :move :right :set-state "B"   }
74       { :tape 1 :state "C" :write 1 :move :no    :set-state halt  }])

Og her er resultatet:

user=> (require 'turing.core :reload)
  Sequence   State   Position Tape
         1       A          0 [0]
         2       B          1 [1 0]
         3       A          0 [1 1]
         4       C          0 [0 1 1]
         5       B          0 [0 1 1 1]
         6       A          0 [0 1 1 1 1]
         7       B          1 [1 1 1 1 1]
         8       B          2 [1 1 1 1 1]
         9       B          3 [1 1 1 1 1]
        10       B          4 [1 1 1 1 1]
        11       B          5 [1 1 1 1 1 0]
        12       A          4 [1 1 1 1 1 1]
        13       C          3 [1 1 1 1 1 1]
        14    HALT          3 [1 1 1 1 1 1]
nil

Er det ikke vakkert?! ;)

Min tredje state machine DSL

I juni 2009 blogget jeg hvordan man kan implementere en generisk tilstandsmaskin i C#, inspirert av Robert C. Martin’s overgangstabeller fra boken Agile Principles, Patterns, and Practises in C#. Jeg designet også et flytende interface for å konfigurere tilstandsmaskiner – her er et tilbakeblikk på hvordan det så ut:

10   _stateMachine = new StateMachine<State, Event>(State.LOCKED);
11
12   _stateMachine.Configure()
13       .Given(State.LOCKED)
14           .When(Event.COIN)
15               .ThenSetState(State.UNLOCKED).AndRun(unlock)
16           .When(Event.PASS)
17               .ThenSetState(State.LOCKED).AndRun(alarm)
18       .Given(State.UNLOCKED)
19           .When(Event.COIN)
20               .ThenSetState(State.UNLOCKED).AndRun(thankYou)
21           .When(Event.PASS)
22               .ThenSetState(State.LOCKED).AndRun(lockAction);
23

Et halvt år senere presenterte jeg en implementasjon i Ruby, og i en separat blogpost implementerte jeg en forbedret DSL som så ut som dette:

10   @state_machine.transition :if_state_is => :locked
11     :when_event => :coin, :then_set_state => :unlocked do
12     @unlock_called = true
13   end
14   @state_machine.transition :if_state_is => :locked
15     :when_event => :pass, :then_set_state => :locked do
16     @alarm_called = true
17   end
18   @state_machine.transition :if_state_is => :unlocked
19     :when_event => :coin, :then_set_state => :unlocked do
20     @thank_you_called = true
21   end
22   @state_machine.transition :if_state_is => :unlocked
23     :when_event => :pass, :then_set_state => :locked do
24     @lock_action_called = true
25   end

Og nå som jeg har begynt å leke med Clojure er det på tide å se hva jeg kan få til med det språket. Clojure, og Lisp generelt, har nesten ingen begrensninger i forhold til hva man kan få til når man designer en DSL. Jeg har forsøkt å lage en variant som er mere lesbar enn C# og Ruby-variantene, men uten at jeg har gjort noe spesielt avansert.

10 (ns fsm.sample (:use fsm.core))
11
12 (def turnstile (statemachine :locked (      
13
14      Given state :locked, event :coin
15         set state :unlocked, (println ” > Unlocking, you are free to pass.”)
16
17      Given state :locked, event :pass
18         set state :locked, (println ” > You haven’t paid yet. Alarm!!!”)
19       
20      Given state :unlocked, event :coin
21         set state :unlocked, (println ” > Thank you for that extra coin!”)
22
23      Given state :unlocked, event :pass
24         set state :locked, (println ” > Have a nice day! Locking up.”))))

Som du forhåpentlig vis ser er reglene strukturert likt i de tre variantene, og inneholder den samme informasjonsmengden. Men Clojure-varianten skiller seg fra de andre gjennom langt mindre “syntaks”. Hvordan jeg valgte å strukturere setningene er ganske tilfeldig.

Her er et lite eksempel hvor jeg bruker tilstandsmaskinen i en REPL:

CropperCapture[90]

Så hva er det som gjemmer seg bak denne turnstile? Det kan nesten virke som om det er et objekt, men det er det ikke. Det er en funksjon, men denne funksjonen har også en tilstand – den husker hvilken state tilstandsmaskinen den representerer er i. Og da skjønner du kanskje at dette er en closure (les Lispy C# (og hva er en closure) om du ikke vet eller husker hva det er for noe).

statemachine i linje 12 i kodeeksempelet over er altså et kall til en funskjon som tar alle reglene og genererer en closure-funksjon basert på dem. Her følger den komplette funksjonen. Det er nok mye her som vil være vanskelig å forstå om du ikke kan språket, men jeg skal trekke frem noen “høydepunkter” etterpå.

10 (ns fsm.core)
11
12 (defn statemachine [initial-state dsl]
13   {:pre [(> (-> dsl count) 0)
14          (= (-> dsl count (mod 9)) 0)]}
15   (letfn
16     [
17      (new-transition [g e ns a]
18        { :given g, :event e, :new-state ns, :action a })
19
20      (find-transition [state event transitions]                          
21       (first (filter #(and (= (:given %) state)
22                            (= (:event %) event)) transitions)))
23    
24      (perform-transition [transition state]
25        {:pre [(not-empty transition)]}
26        (reset! state (:new-state transition))
27        (eval (:action transition)))]
28
29     (loop [transitions '(), spec dsl]
30       (if (seq spec)
31         (let [[_ _ state _ event _ _ new-state action & more] spec]
32           (recur (cons (new-transition state event new-state action)
33                        transitions)
34                  more))
35
36         (let [current-state (atom initial-state)]
37           (fn [event]
38               (perform-transition (find-transition @current-state
39                                                    event
40                                                    transitions) 
41                                   current-state)))))))

Noe av det første du ser her er Clojure’s støtte for Design by Contract (DbC), eller mer presist preconditions. Linje 13 og 14 sier noe om hva som må være tilfredstilt for at et kall til statemachine-funksjonen skal være gyldig. Linje 13 sier at dsl-argumentet skal inneholde en liste med mer enn ett element. Linje 14 følger opp med å si at antall elementer skal være en multippel av 9. Og hvorfor det? Jo, fordi en regel i syntaksen jeg definerte består av nøyaktig 9 ord/elementer.

For å øke lesbarheten på koden inneholder definisjonen av statemachine-funksjonen tre “interne” funksjoner (linje 17, 20 og 24). Den siste av disse har også en precondition, og den slo faktisk til i REPL-sesjonen du så tidligere. Da jeg sendte eventet :foobar klarte ikke tilstandsmaskinen å finne en overgang, og kastet et assert exception. Ved å bruke preconditions på denne måten slipper jeg å rote til resten av koden med unntakshåndtering.

statemachine-funksjonen starter med å eksekvere en loop i linje 29. Koden plukker de 9 neste uttrykkene fra dsl-spesifikasjonen, og looper sålenge det finnes flere regler. Overgangene samles i verdien transitions. I linje 31 bruker jeg noe som heter destructuring for å plukke ut det som er interessant fra uttrykkene i DSL-listen. Ønsker jeg å endre hvordan jeg skriver reglene er det denne linjen jeg vil måtte endre på.

Når det ikke er flere regler å prosessere opprettes det en verdi for maskinens tilstand (linje 36). Og det eneste som gjenstår da er å opprette og returnere en anonym funksjon (linje 37-41) som representerer tilstandsmaskinen. Denne funksjonen benytter seg av overgangstabellen (transitions) og tilstanden (current-state), og blir dermed en closure. Og ingen andre kan aksessere disse verdiene utenfra, noe som også er ganske kult.

Dette har bare vært en liten smakebit av hva som er mulig å få til av interne DSL’er i Clojure. Og jeg behøvde ikke engang ty til makroer for å få det til. Jeg håper det gav mersmak.

Jeg leker litt med Clojure i .NET

ClojureCLR

Nå har jeg endelig fått testet ut ClojureCLR, dvs. Clojure kjørende på .Net-rammeverket. Det er kjempeenkelt å komme igang – du bare laster ned en zip med bits herfra (anbefaler clojure-clr 1.2.0), pakker det ut et sted, starter et command-vindu og eksekverer Clojure.Main.exe. Hvis du ikke sender med en clojurekildefil som argument startes den interaktive REPL’en (Read Eval Print Loop) hvor du kan leke deg med språket.

CropperCapture[87]

Jeg jobber mye med MSMQ, og da jeg skulle teste ut Clojure i .NET føltes det derfor naturlig å starte med det. Denne blogposten består av noen eksempler på hvordan man kan bruke System.Messaging og meldingskøer fra ClojureCLR – og illustrerer dermed .NET-interopen, og hvordan den eventuelt skiller seg fra Java-interopen i “vanlig” Clojure.

Jeg begynner med en tom fil jeg kaller testqueue1.clj. Det første jeg må gjøre er å laste System.Messaging dll’en, og gjøre klassene jeg har tenkt å bruke tilgjengelige. Det gjør jeg på denne måten:

1 (System.Reflection.Assembly/LoadWithPartialName “System.Messaging”)
2 (import (System.Messaging MessageQueue
3                            MessageQueueTransaction
4                            XmlMessageFormatter))

Jeg har allerede en lokal, transaksjonell kø som heter testqueue, og jeg vil bruke denne fra koden min. Jeg definerer symbolet *queue* til å være en instans av MessageQueue, og setter også Formatter-propertien til en XmlMessageFormatter som håndterer strenger:

6 (def *queue*
7      (doto (MessageQueue. “.\\private$\\testqueue”)
8            (.set_Formatter (XmlMessageFormatter.
9                              (into-array Type [String])))))

Opprettelse av objekter og kall av metoder er akkurat som i Clojure for JVM. Der er ingen spesiell syntaks for properties, i stedet bruker man funksjonene som ligger bak propertiene (get_PropertyName og set_PropertyName). I linje 9 ser du også hvordan jeg konverterer en PersistanceVector om til et array av typen System.Type, som er det konstruktøren til XmlMessageFormatter trenger.

Og nå kan jeg opprette min første funksjon. Denne er en ganske enkel en som returnerer antall meldinger i køen:

11 (defn count-messages []
12       (-> *queue*
13           (.GetAllMessages)
14           (.Length)))

Deretter vil jeg lage én metode for å sende en melding og én metode for å hente ut en melding. Felles for disse to er at jeg trenger å opprette og bruke en transaksjon. For å unngå kodeduplisering lager jeg en “høyereordens funksjon” jeg kaller with-transaction. Den tar som innput en lambda som definerer hva som skjer i transaksjonen.

16 (defn with-transaction [f]
17       (let [transaction (new MessageQueueTransaction)]
18         (.Begin transaction)
19         (let [result (f transaction)]
20           (.Commit transaction)
21           result)))
22
23 (defn send-to-queue [message]
24       (with-transaction
25         #(.Send *queue* message %)))
26
27 (defn receive-one []
28       (with-transaction
29         #(.Receive *queue* (TimeSpan. 0 0 1) %)))

Når jeg utvikler i Clojure bruker jeg den interaktive REPL’en ganske flittig. Typisk jobber jeg i en eller flere tekstfiler samtidig som jeg har en REPL kjørende. I den kan jeg laste filene, og reloade dem når jeg har gjort endringer. REPL’en lar meg test/kjøre funkjonene jeg definerer med ulike innput, eller teste ut kode før jeg skriver den i kildekodefilen. Jeg kan til og med re-definere enkeltfunksjoner underveis om jeg ønsker det.

Nedenfor er et lite eksempel på hvordan jeg kan bruke REPL’en med testqueue1.clj som jeg nettopp har laget. Først laster jeg skriptet. Deretter kaller jeg funksjonene for å telle meldinger, sende melding, og hente ut melding. Legg merke til at jeg velger å lese ut Body-propertien på meldingen jeg leser, selv om receive-one returnerer et Message-objekt.

CropperCapture[88]

Det som skjedde i virkeligheten var at jeg gjorde disse tingene mens jeg definerte funksjonene. Og mellom hver gang jeg gjorde en endring kjørte jeg (require 'testqueue1 :reload) slik at REPL’en ble oppdatert med mine endringer. For et bra innblikk i hvordan det er å jobbe på denne måten anbefaler jeg blogposten Interaktiv programmering: utforsking, læring og produktivitet – skrevet av Thomas Kjeldal Nilsson.

.NET events i ClojureCLR

En annen ting jeg føler jeg bør vise er hvordan man bruker eventer i ClojureCLR. Når man skal bruke meldingskøenes asynkrone funskjonalitet trenger man å sette opp eventhandlere for å motta meldinger. ClojureCLR har en macro som heter gen-delegate for å opprette delegater. I linje 12 nedenfor bruker jeg den til å opprette on-receive-completed. Og i linje 26 ser du hvordan jeg kobler delegatet på eventet. Følgende er plassert i en fil jeg kalte testqueue2.clj:

1 (System.Reflection.Assembly/LoadWithPartialName “System.Messaging”)
2 (import (System.Messaging MessageQueue
3                            MessageQueueTransaction
4                            XmlMessageFormatter
5                            ReceiveCompletedEventHandler))
6
7 (declare handler) ; handler will point to a function later..
8
9 ; generate a delegate of type ReceiveCompletedEventHandler
10
11 (def on-receive-completed
12      (gen-delegate ReceiveCompletedEventHandler
13                    [source async-result]
14                    (let [message (.EndReceive source
15                                               (.AsyncResult async-result))
16                          result (handler message)]
17                      (.BeginReceive source)
18                      result)))
19
20 ; *queue* will have a ReceiveCompleted handler set..
21
22 (def *queue*
23      (doto (MessageQueue. “.\\private$\\testqueue”)
24            (.set_Formatter (XmlMessageFormatter.
25                              (into-array Type [String])))
26            (.add_ReceiveCompleted on-receive-completed)))
27
28 ; function to start receiving, given a specific handler function..
29
30 (defn async-receive [handler-fn]
31       (def handler handler-fn)
32       (.BeginReceive *queue*))

Nedenfor ser du hvordan jeg bruker to REPL’er til å teste ut testqueue2. Det øverste vinduet bruker jeg til å sende endel meldinger. I det nederste vinduet setter jeg opp async-receive til å printe ut alle meldinger som kommer inn. Funksjonskallet avslutter øyeblikkelig. Deretter kommer meldingene fortløpende etterhvert som jeg sender dem.

CropperCapture[89]

For flere detaljer, se CLR-Interop wikisiden på GitHub. Clojure er suverent, og etter å ha kjørt det på Java-plattformen i noen måneder føles det nå som å komme hjem når jeg endelig får benytte .NET-rammeverket. :)

Webutvikling med Clojure

Web_Development

Jeg har begynt å eksperimentere med litt mer seriøs utvikling i Clojure. Jeg har testet ut en “full stack” for webutvikling, og er nå blitt kjent med tilstrekkelig med byggestener for å implementere fullverdige, databasedrevne webløsninger. Gjør deg klar for å bli introdusert til en veldig spennende verden – webutvikling i Clojure er nemlig både gøy og enkelt!

Leiningen

Første byggesten man bør bli kjent med, uavhengig av om man vil bedrive web- eller annen utvikling i Clojure, heter Leiningen. Dette er et kommandolinjeverktøy som hjelper deg å generere filstrukturen for prosjektet ditt, definere og laste ned avhengigheter, samt bygging og deployment. Det baserer seg på Maven, som Java-folket bruker, men er mye enklere å forholde seg til. Dessuten konfigurerer man Leiningen med Clojure-kode, ikke XML.

Når jeg skal starte et nytt prosjekt skriver jeg for eksempel kommandoen “lein new theUltimateBlog”, og leiningen genererer diverse filer for meg – blant annet en project.clj fil hvor jeg kan liste opp avhengighetene mine. Her er en typisk prosjektfil for et webprosjekt:

1 (defproject theUltimateBlog “0.1.0-SNAPSHOT”
2   :description “Yet another blog engine in Clojure”
3   :dependencies [[org.clojure/clojure "1.2.0"]
4                  [org.clojure/clojure-contrib "1.2.0"]
5                  [org.apache.derby/derby "10.6.2.1"]
6                  [ring/ring "0.3.1"]
7                  [compojure "0.5.2"]
8                  [hiccup "0.3.0"]])

Med enkle kommandoer kan jeg nå for eksempel laste ned alle avhengighetene i prosjektet, eller kompilere det. Leiningen kan blant annet produsere en såkalt uberjar, som er en deploymentløsning hvor prosjektet ditt pluss alle avhengighetene (inkludert selve Clojure) pakkes ned i én eksekverbar jar-fil. Dette er ideelt om du trenger å distribuere en applikasjon til klientmaskiner som kanskje ikke har Clojure fra før.

På Github finner du en tutorial med alt du trenger for å komme igang med Leiningen. Det finnes dessuten et alternativt build-verktøy som heter Cake man bør ta en titt på. Cake gir deg større muligheter i forhold til både innebygde oppgaver og til å definere dine egne tasks. Jeg tviler på at jeg tar feil når jeg sier navnet kommer fra Ruby’s Rake.

Ring

Den neste byggeklossen jeg gjorde meg kjent med var Ring. Prosjektet tilbyr webutviklere et stadard grensesnitt for å snakke med webservere, og spiller dermed samme rolle som Rack gjør i Ruby-verden.

Ring har et sett med biblotek for å håndtere ting som session, filopplasting osv., men styrken til Ring er at det er en felles plattform for utvikling av andre webutviklings-rammeverk. Det er dermed mange å velge blant, men jeg har testet ut..

Compojure

Det finnes altså mange rammeverk for webutvikling i clojure – Compojure virker som det mest kjente/omtalte, men man bør også ta en titt på Moustache, Conjure (Rails-inspirert) og Funkyweb. Disse rammeverkene gir deg et høyerenivås API for å definere ting som ruter og controller-logikk.

Her er et eksempel på en meget enkel webapp laget med Compojure og Ring. På roten (“/”) vil den svare med “Hello World”. På alle andre ruter vil den si “Page not found”.

1 (ns hello-world
2   (:use compojure.core, ring.adapter.jetty))
3
4 (defroutes main-routes
5   (GET “/” [] “<h1>Hello World</h1>”)
6   (compojure.route/not-found “<h1>Page not found</h1>”))
7
8 (run-jetty main-routes {:port 8080})

Eksempelet bruker en “embedded” webserver som heter Jetty, og den kjøres opp på port 8080.

I tillegg bør jeg nevne et prosjekt som heter Sandbar, som bygger på og utvider Compojure og Ring med ekstra funksjonalitet og abstraksjoner i forhold til bl.a. autorisering, autentisering og forms validering.

Hiccup

Når en har definert ruter og kontrollere i for eksempel Compojure trenger man en måte å generere dynamisk HTML. Også her finnes det en rekke biblotek man kan benytte. Jeg valgte å teste ut Hiccup, som gir deg en Clojure DSL for å definere HTML som minner mye om Haml i Ruby. For dem som mener det er bedre å kode viewene i HTML direkte finnes det andre prosjekter som for eksempel Fleet, men jeg synes det er ganske interresant å kunne manipulere HTML i form at Clojure-data, og har derfor større tro på Hiccup.

Ta for eksempel dette helt vilkårlige stykke med HTML:

10 <div id=“main”>
11   <h1>Hello World</h1>
12   <p>
13     <a href=http://www.lipsum.com/>Lorem ipsum</a> 
14     dolor sit amet, consectetur adipiscing elit. Nam dictum.
15   </p>
16   Tags:
17   <ul>
18     <li>Tag 1</li>
19     <li>Tag 2</li>
20     <li>Tag 3</li>
21   </ul>
22 </div> 

Nedenfor ser du en liten funksjon som ved hjelp av Hiccup returnerer nøyaktig samme HTML.

19 (defn display []
20       (html
21         [:div#main
22           [:h1 "Hello World"]
23           [:p (link-to "http://www.lipsum.com/" "Lorem ipsum")
24               " dolor sit amet, consectetur adipiscing elit. Nam dictum."]
25           “Tags:” (unordered-list ["Tag 1" "Tag 2" "Tag 3"])]))

Man oppretter og strukturerer HTML ved hjelp av vektorer og keywords. [:b "foo"] omgjøres for eksempel til <b>foo</b>. I tillegg ser du bruk av et par hjelpefunksjoner, link-to som oppretter en HTML-link, og unordered-list som oppretter en liste. Hiccup har mange slike funksjoner, spesielt knyttet til generering av skjema-HTML.

PS: Et tredje biblotek man bør ta en titt på er Enlive, som baserer seg på “selektorer” (ala CSS selectors) og transformering. Og så finnes det faktisk også en Haml-klone, men for meg ser Hiccup bedre ut. 

Og hvis du ønsker den samme styrken når det kommer til CSS kan du bruke cssgen-bibloteket til å kode stylesheets i Clojure.

Databaser

Den siste byggeklossen man normalt behøver for å lage webapps er persistering. I clojure.contrib.sql finner vi grei støtte for å jobbe med relasjonsdatabaser via jdbc. Her er et lite eksempel hvor jeg bruker en Derby-database, oppretter en enkel tabell med to kollonner, inserter et par rader, og til slutt leser dem ut igjen.

10 (ns myFirstDb.core
11     (:use [clojure.contrib.sql :as sql :only ()]))
12
13 (def db {:classname   “org.apache.derby.jdbc.EmbeddedDriver”
14          :subprotocol “derby”
15          :subname     “c:\\temp\\myFirstDb.db”
16          :create      true})
17
18 (defn create-tasks-table []
19       (sql/create-table :task
20         [:description "varchar(255)"]
21         [:state :int]))
22
23 (def *state-open* 0)
24
25 (defn insert-task [description]
26       (sql/insert-rows :task
27         [description *state-open*]))
28
29 (defn main []
30       (sql/with-connection db
31          (create-tasks-table)
32          (insert-task “Buy milk”)
33          (insert-task “Write a blog”)
34          (sql/with-query-results res
35             ["SELECT * FROM task"]
36             (doseq [rec res]
37                (println rec)))))
38
39 ; Output when running main:
40 ; {:description Buy milk, :state 0}
41 ; {:description Write a blog, :state 0}

For et mere komplett eksempel kan du ta en titt på testkoden til bibloteket.

Contrib.sql er egentlig alt man trenger, men det finnes andre abstraksjoner man med fordel kan ta en titt på. clj-record er for eksempel et forsøk på å gjenskape Ruby on Rail’s ActiveRecord i Clojure.

Om du er bitt av NoSQL-basillen finnes det selvsagt diverse Clojure-biblotek for deg også. Congomongo er en wrapper for Java API’et til MongoDB, mens du kan bruke clojure-couchdb om du er glad i Apache CouchDB. Her er litt eksempelkode fra det førstnevnte:

43 (ns my-mongo-app
44     (:use somnium.congomongo))     ; use the congomongo lib
45
46 (mongo! :db “mydb”)                ; setup database to use
47
48 (insert! :robots {:name “robby”})  ; insert some data
49
50 (def my-robot (fetch-one :robots)) ; read some data
51
52 ; my-robot => { :name “robby”,
53 ;               :_id  #<ObjectId> “0c23396f7e53e34a4c8cf400″>,
54 ;               :_ns  “robots” }

Konklusjon

Jeg har nå dratt deg gjennom en komplett liste med byggeklosser du kan bruke for å lage komplette webløsninger i Clojure. Det kan kanskje virke overveldende til å begynne med, men hver liten bit er veldig enkel å forholde seg til, og Clojure har virkelig potensiale til å være en ypperlig plattform for webutvikling. Det er først og fremst språket i seg selv som er årsaken til dette, men mye innsats har også gått inn i å lage praktiske API’er som gjør utviklingen rask samtidig som man fokuserer på det som er viktig.

Det er min vurdering at Clojure kan gjøre deg minst like produktiv som Ruby på dette feltet.

Clojure-prosjekter nevnt i denne posten: Cake | clj-haml | clj-record | Clojure Contrib | Clojure-CouchDB | Compojure | Congomongo | Conjure | cssgen | Enlive | Fleet | Funkyweb | Hiccup | Leiningen | Moustache | Ring | Sandbar.


Alf Kåre Lefdal: Distributed Podcast er også ganske interessant. De tar opp tema som fx. ...

Stian: +1 for 6er til This Developer's Life! Min definitive favoritt. Jeg trengte også...

Torbjørn: Takk for flere tips, Vegard. Deep Fried Bytes ligger på oversikten min fra 2009...

Vegar: Og glemte helt ios: Nsbrief og ideveloper live. Har du hørt på deep fried byt...

Vegar: Mye kjekt her. TDL, hanselminutes og .net rocks ligger i en klasse for seg. Suv...

Torbjørn: Helt enig, arkivet til Software Engineering Radio er en gullgruve om man vet hva...

Einar W. Høst: Jeg synes at det kuleste med se-radio er backloggen av intervjuer... det er noen...

arnab: fantastisk :)...

Olav: Glimrende blogg ! Modellen av hjernens arbeid passer ikke bare på nyskaping: ...

Torbjørn: Ja, flydesign trekkes ofte frem som et eksempel på dette fenomenet. Design av b...

 Hold deg oppdatert

Søk i bloggen

Ferske innlegg

  • NodeJS vs. ASP.NET
  • Pulten min..
  • No ifs and buts
  • Community-fiskebolle på ROOTS 2012
  • Kategorier

  • .net ninja (37)
  • Bøker (18)
  • Diverse prosjekter (37)
  • DSL (10)
  • Erlang (10)
  • F# (5)
  • Hardware (1)
  • Jobb (78)
  • Julekalender (51)
  • kjempekjekt.com (23)
  • LISP/Clojure (34)
  • NDC (4)
  • NNUG / community (63)
  • O/RM & databaser (10)
  • Off topic (118)
  • OO-design/clean code (31)
  • Podcasts (15)
  • Polyglot (82)
  • Ruby (29)
  • Silverlight / RIA (3)
  • Software/verktøy (20)
  • Softwareutvikling (24)
  • Testing / TDD (30)
  • the contiki strip (13)
  • User experience (3)
  • WCF (3)
  • Webutvikling (34)
  • WPF (9)
  • WTF (13)
  • 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