Polyglot

En polyglot er en person som bruker to eller flere språk, og denne kategorien handler om å lære seg og bruke flere, ulike programmeringspråk.

Oz

Oz er et programmeringsspråk som skiller seg ut i mengden! Det er utviklet i et sammarbeid mellom flere universiteter, brukes først og fremst til undervisning, og støtter mange ulike programmeringsparadigmer som logisk programmering, funksjonell programmering, imperativ og objektorientert programmering osv. Det støtter samtidighetsbasert programmering blant annet gjennom bruk av actors, og er spesielt tilrettelagt for å lage distribuerte systemer.

oz

I bunn er Oz et meget enkelt språk med kun noen få datatyper. I tillegg har det en masse “syntaktisk sukker” som gjør språket praktisk. Det er først og fremst inspirert av Lisp, Prolog og Erlang, men har også skapt noe nytt og unikt.

Oz har derfor lenge fristet meg. Jeg har vurdert det som et språk hvor man kan teste ut og eksperimentere med alle mulige slags programmeringsmodeller.

På tide med litt kode

Nedenfor er et komplett Oz-program som skriver ut summen av alle tall fra 0 til 999 som er multipler av 3 eller 5. Det er ikke det korteste programmet jeg kunne ha skrevet, men illustrerer i stedet flere aspekter ved språket.

Oz har såvidt jeg vet ingen vanlige løkker. Det ble derfor naturlig å velge en funksjonell, stream-basert løsning.

I koden får du se hvordan man definerer funksjoner, inkludert en rekursiv funksjon som bygger opp en liste. Du får også se hvordan man bruker høyereordens-funksjoner, hvordan man sender en funksjon som et argument, og hvordan man deklarerer en funksjon in-line i et kallet til FoldL (“fold left”, funksjonen som summerer opp alle tallene).

10 functor
11 import
12    Application
13    System
14 
15 define
16 
17    %% recursive function to create a new list
18    fun {Range From To}
19      if From == To then [From]
20      else From | {Range From+1 To} end
21    end
22 
23    %% function to get value to include in sum
24    fun {Euler1Value X}
25      if X mod 3 == 0 then X
26      elseif X mod 5 == 0 then X
27      else 0 end
28    end
29 
30    %% Variables bound in definition body
31    Values
32    Sum
33  in
34    Values = {Map {Range 0 999} Euler1Value}
35    Sum = {FoldL Values
36                 fun {$ X Y} X + Y end
37                 0}
38    {System.showInfo Sum}
39    {Application.exit 0}
40 end

Du har sett meg bruke map og fold så mange ganger nå at dette bør være helt greit å skjønne. Når du ser noe slikt som {Foo Bar Zot}, så er det et funksjonskall. Foo er funksjonen, og Bar og Zot er argumentene.

Min opplevelse av Oz

Da jeg begyte å studere Oz virket det svært fremmed og nesten uforståelig. Dokumentasjonen var frustrerende; den var skrevet for å lære meg språket grundig, ikke for at jeg raskt skulle kunne komme igang.

Etter hvert begynte jeg derimot å se paralellene til Erlang – spesielt hvordan Erlang håndterer lister. Og da jeg så arven fra Lisp i språket begynte brikkene å falle på plass.

Nå tror jeg det skal gå ganske greit å fortsette med Oz. Det er egentlig et ganske enkelt språk, men med avanserte muligheter.

Hvordan komme i gang

Hovedimplementasjonen av Oz kalles the Mozart Programming System. Det er open source, og tilgjengelig på Unix, Linux, FreeBSD, Windows og Mac OS X.

Jeg lastet det ned på Windows, men fikk det ikke til å virke helt som tiltenkt – GNU Emacs, som er en del av det interaktive miljøet, ville ikke kjøre. Jeg endte til slutt opp med å programmere online i ideone, et kjekt sted hvor man kan kompilere og kjøre programmer i et utall ulike språk.

Mozart-sidene har også den mest komplette dokumentasjonen for Oz. I tillegg finnes det en bok som heter Concepts, Techniques, and Models of Computer Programming. Dette er en lærebok i programmering som bruker Oz til å illustrere alle de ulike aspektene og paradigmene. Sikkert ikke en dum bok å ønske seg til Jul.

GNU Octave

De fleste språkene jeg presenterer her på bloggen er såkalte “general purpose” språk som kan brukes til hva som helst. Men av og til kan det være greit å kjenne til språk som er skreddersydd for en spesifik oppgave; som for eksempel matematiske beregninger.

octave

Med et slikt verktøy kan man løse enkelte oppgaver mye raskere enn man kan i de “vanlige” språkene. De kan f.eks. egne seg godt til å prototype ulike algoritmer, og brukes blant annet til dette innenfor felt som maskinlæring.

Det finnes mange språk og verktøy å velge blant, men noen av de mest kjente er:

MATLAB (Matrix Laboratory) betegnes som et fjerdegenerasjons programmeringsspråk. I MATLAB kan man manipulere matriser, plotte funksjoner og data i flotte grafer, implementere algoritmer, lage brukergrensesnitt, og bruke moduler skrevet i andre språk som for ekssempel C++ eller Java. Språket brukes mye innenfor utdanning.

Mathematica er en programvare for matematiske beregninger (duh!). Det er mye brukt av vitenskapsfolk, ingeniører og matematikere. Mathematica inkluderer et programmeringsspråk som støtter både den funksjonelle og den objektorienterte paradigmen, har et hav av verktøy for visualisering, datamining, bildeprosessering, og mye annet rart, og koster skjorta og en halv arm!

R er et annet programmeringsspråk og miljø for å utføre statistisk analyse, og for å utvikle programvare for slik analyse. I motsetning til MATLAB og Mathematica er R gratis, og kildekoden er tilgjengelig.

Og så har du GNU Octave, det programmeringsspråket ment for numeriske beregninger som denne artikkelen egentlig handler om. Det er også gratis, og har blitt laget for å være kompatibelt med MATLAB; er man “litt forsiktig” når man koder skripts for Octave, så kan de fint kjøres på MATLAB også.

Euler-oppgaven løst i Octave

Denne oppgaven som jeg nå driver og implementerer i ulike språk egner seg selvsagt godt til å løses i GNU Octave. I skjermbildet nedenfor kan du se at jeg har laget et lite skript på fem, seks linjer. Jeg har så kjørt dette fra Octave’s kommandolinje, og programmet har skrevet ut svaret (markert med rød ring).

I tillegg har skriptet plottet hvordan summen vokser etterhvert som vi legger til tall opp mot 1000.

octave

Jeg lar bildet og koden tale for seg selv. Jeg er langt fra noen ekspert på verktøy som dette, og måtte “grave litt” i dokumentasjonen for å løse oppgaven.

Jeg skulle derimot ønsket at jeg kunne det bedre, og håper jeg får muligheten til å lære mer. For jeg havner rett som det er i situasjoner hvor jeg skulle ønske at jeg enkelt kunne analysere og visualisere en funksjon eller et datasett, men hvor jeg føler det blir litt for tungvindt med et vanlig programmeringsspråk.

Octave laster du ned fra gnu.org. Der finner du også en svær manual, en wiki med mange tutorials, og mye annet snacks.

Fantom

For cirka seks år siden dukket det opp et interessant språk som utviklerne kalte Fan. Det viste seg derimot å være vanskelig å google det navnet, og spåket endret derfor navn til Fantom i 2009. Fantom er en typisk smeltedigel av egenskaper man finner i andre språk, og er ment å være et praktisk verktøy. Det er objektorientert, støtter funksjonell programmering, og har actors – eller støtte for samtidighetsbasert programmering som Joe Armstrong ville ha sagt.

Fantom er fortsatt under aktiv utvikling og endring, men er likevel robust og er brukt i produksjon flere steder.

fantom

Fantom-kode har en Java/C#-lignende syntaks som bør være grei å forholde seg til for de aller fleste. Språket er statisk typet, men har også flere dynamiske features som type inference, implisitt casting, og en dynamic invoke-operator som lar deg kalle en hvilken som helst metode uten statisk kontroll.

Det finnes to ulike typer i Fantom: klasser og mixins. Klasser danner grunnlaget for objekter, og all data i Fantom er objekter, inkludert value types som Int og Bool. Akkurat som Java og C# har Fantom single inheritance, men mixins gir deg mulighet til å utvide objektene på måter Java/C# ikke kan (for eksempel sånn som jeg presenterte i posten om DCI arkitekturen i mars 2010).

Kan kjøre på ulike plattformer

Fantom er laget for å være portabelt, og kan kjøres på Java VM, på .NET CLR, og med JavaScript i en browser. Fantom kompileres til Fantom bytecode, og denne kompileres igjen ned til valgt platform. Per i dag er det Java-runtimen som er mest stabil, og .NET-implementasjonen er mer et proof-of-concept.

Hvordan ser koden ut?

Du begynnes sikkert å bli litt lei av denne oppgaven nå, men jeg skal altså løse Euler-problem nummer 1 i Fantom også. Koden nedenfor viser blant annet hvordan man definerer en klasse med en main-metode, og hvordan lambda-uttrykk ser ut i dette språket. Jeg har valgt en funksjonell, stream-basert løsning denne gangen med bruk av en range, filtrering og aggregering.

10 class Euler1
11 {
12   static Bool MultipleOf(Int n, Int[] dividents)
13   {
14     return dividents.reduce(false) |Bool result, d->Bool|
15     {
16       result.or(n % d == 0)
17     }
18   }
19 
20   static Void main()
21   {
22     echo((1..999)
23       .toList()
24       .findAll |n->Bool| { MultipleOf(n, [3, 5]) }
25       .reduce(0) |Int memo, n->Int| { memo + n } )
26   }
27 }

Måten jeg har implementert MultipleOf-metoden på er både overkill og lite lesbart. Men når du har løst den samme oppgaven fjørti ganger begynner du etterhvert å eksperimentere litt. :)

I linje 16 utnytter jeg det faktum at alt, også boolske verdier, er objekter i Fantom. Jeg kaller derfor metoden “or” for å kombinere to boolske uttrykk. Men frykt ikke, alle de vanlige operatorene du er vandt til, som && og ||, finnes også.

Samtidighet

Samtidighet er det området hvor Fantom skiller seg mest fra Java og C#. Mens Java og C# i bunn og grunn baserer seg på en modell med delt minne mellom tråder, hvor man må synkronisere tilgang til data med locks for å forsøke å unngå deadlocks og race conditions, så tillater ikke Fantom deling av data. Det vil si, Fantom tillater ikke deling av data som kan endres (mutable state).

I stedet har Fantom to alternative teknikker for samtidighetsprogrammering.

Det første er data som ikke kan endres – immutability. Det er dette som har gjort de funksjonelle språkene som f.eks. Clojure og Haskell populære. Ikke-muterende data er bygget inn i Fantom, og kan trygt og effektivt deles mellom tråder.

Den andre teknikken er message passing. Dette er det som har gitt språket Erlang sin fremgang de siste årene. Fantom har et actor API som er bygget på ideen om å sende meldinger mellom asynkrone arbeidere.

Jeg har implementert en løsning til på Euler-oppgaven for å illustrere hvordan man kan bruke actors. Jeg beklager at koden inneholder en del repetisjon, men jeg tror det får frem poenget mitt på en ok måte.

I løsningen nedenfor oppretter jeg fire actors. Den første (summer) tar imot vilkårlige tall, legger dem til en sum som den holder rede på, og returnerer summen. De tre øvrige deler på å finne alle tallene som skal være med i løsningen, og sender disse til summer.

Til slutt spinner jeg inntil de tre arbeiderne er ferdige, og så sender jeg en siste melding til summer for å få tilbake svaret.

10 using concurrent
11 
12 class Euler1
13 {
14   Void main()
15   {
16     pool := ActorPool()
17 
18     summer := Actor(pool) |Int change->Int|
19     {
20       sum := (Int)Actor.locals.get("sum", 0) + change
21       Actor.locals["sum"] = sum
22       return sum
23     }
24 
25     multiplesOf3Actor := Actor(pool) |msg|
26     {
27       for (n:=1; n<1000; ++n)
28         if (n % 3 == 0) summer.send(n)
29       echo(msg); return null
30     }
31 
32     multiplesOf5Actor := Actor(pool) |msg|
33     {
34       for (n:=1; n<1000; ++n)
35         if (n % 5 == 0) summer.send(n)
36       echo(msg); return null
37     }
38 
39     multiplesOf15Actor := Actor(pool) |msg|
40     {
41       for (n:=1; n<1000; ++n)
42         if (n % 15 == 0) summer.send(n * -1)
43       echo(msg); return null
44     }
45 
46     f1 := multiplesOf3Actor.send("All multiples of 3 added!")
47     f2 := multiplesOf5Actor.send("All multiples of 5 added!")
48     f3 := multiplesOf15Actor.send("All multiples of 15 removed!")
49     echo("Done sending startup messages")
50 
51     // Spin-Wait for work to finish
52     while(true)
53       if(f1.isDone.and(f2.isDone.and(f3.isDone)))
54         break
55 
56     echo("The answer is ${summer.send(0).get}")
57   }
58 }

Når jeg kjører koden ser det ut som dette:

C:\code>c:\fantom\bin\fan.exe euler1_with_actors.fan
Done sending startup messages
All multiples of 15 removed!
All multiples of 3 added!
All multiples of 5 added!
The answer is 233168

Her ser du at i dette tilfettet ble multiplesOf15Actor ferdig før multiplesOf3Actor. Det er selvfølgelig overkill å bruke fire tråder til å beregne summen av alle tall som er multipler av 3 eller 5 under 1000, men actor model er en veldig spennende måte å kode på for mange andre problemområder.

Hvordan komme igang

Fantom.org er språkets offisielle side, og her finner du alt du behøver for å komme igang. Under “Docs” finner du utførlige manualer, eksempelkode og full API-dokumentasjon.

Merk at selv om Fantom er et relativt ungt språk så finnes det allerede ganske god editor/IDE-støtte for språket. FantomIDE er bygget på Netbeans, F4 er et annet som baserer seg på Eclipse, og du får støtte for Fantom i TextMate, TextPad, Emacs, Vim og flere andre steder.

Fantom inkluderer også en interaktiv REPL (Fansh), innebygget funksjonalitet for automatisert enhetstesting (Fant), og en egen build-motor som baserer seg på buildscripts skrevet i Fantom. Det har blitt lagt ned mye bra arbeid i dette språket, og det blir spennende å se hvordan det utvikler seg videre.

Nemerle

Nå skal du få møte det jeg oppfatter som det aller mest spennende språket på .NET-plattformen for tiden. Nemerle er som en krysning mellom C# og F#, med Lisp-lignende makro-støtte som en ekstra bonus. Her har du et veldig kraftig verktøy hvor du kan programmere imperative-, objektorienterte- og funksjons-baserte løsninger proppfulle av meta-features. Eller som hjemmesiden sier, et <<Programming language for “special forces” of developers>>.

nemerle

Versjon 1.0.0 ble lansert i mai i år, men arbeidet med språket startet så langt tilbake som i 2003. Programmeringsspråk skapes ofte av én person, enten som noe han gjør privat eller med backing av et firma som f.eks. tidligere Sun eller Microsoft. Andre ganger står det en kommité bak, men det resulterer sjelden i noe bra. Nemerle derimot er skapt av en gruppe utviklere ved University of Wroclaw i Polen, og deres innsats er imponerende.

(At flagget på roboten ble russisk var en glipp.., sorry! Det skulle selvsagt vært det polske.)

Nemerle er sterkt typet, og har kraftig type inference. Utviklere med bakgrunn fra språk som Java eller C# vil kunne kjenne seg igjen, men språket har også mange egenskaper hentet fra funksjonell programmering som tail call optimization, pattern matching, algebraiske datatyper, partial application, tupler osv.

Du finner også såkalte Computation expressions, som så langt jeg har forstått er det samme som monader.

Videre støtter Nemerle streng-interpolering, noe som ikke er vanlig i statisk typede språk. Det har støtte for LINQ, og du kan benytte deg av aspect-oriented programming (AOP). Dessuten har det XML literals, noe du også finner i språk som Scala og Visual Basic .NET.

Generelt sett er språket proppfullt av features, og det virker som om de er satt sammen på en meget behagelig måte. For å vise at Nemerle er et allsidig språk har jeg laget fire løsninger på Euler-oppgaven

En imperativ løsning

La oss først se hvordan et Nemerle-program ser ut, og om vi kan gjøre “vanlig”, imperativ programmering i dette språket.

Nemerle-program består av klasser og/eller moduler (moduler er som statiske klasser). Et program må ha en Main-metode for å kunne kjøres. Merk at using-statements (import av navnerom) er utelatt fra eksemplene.

10 module Program
11 {
12     Main() : void
13     {
14         mutable sum = 0;
15 
16         for (mutable n = 1; n < 1000; n++)
17             when (n % 3 == 0 || n % 5 == 0)
18                 sum += n;
19 
20         WriteLine(sum);
21     }
22 }

I dette eksempelet opprettet jeg en sum-variabel som det er lov å endre (mutable). Nemerle finner selv ut at dette er en integer. Så kjører jeg en for-løkke, gjør en test, og legger tallet til sum om testen var positiv. Ganske rett frem dette her.

Jeg brukte “when” til testen, fordi “if” krever en else-blokk. Det er vanlig med påkrevd else i funksjonelle språk – Clojure er et eksempel på et språk som har det samme skillet.

Range, filter og fold med Labdas

Men la oss glemme for-løkken.., den er gammeldags! Her følger en såkalt stream-basert løsning hvor jeg oppretter en range, filtrerer den, og til slutt aggregerer summen med FoldLeft.

23 module Program
24 {
25     Main() : void
26     {
27         def numbers =
28             NList.Filter ($[1..999], fun (n) { n % 3 == 0 || n % 5 == 0 });
29 
30         def result = NList.FoldLeft (numbers, 0, fun (n, acc) { acc + n });
31 
32         WriteLine(result);
33     }
34 }

Dette illustrerer først og fremst hvordan lambda-uttrykkene ser ut i Nemerle. Ellers har du jo sett denne løsningen ganske mange ganger nå.

Nøstede funksjoner og pattern matching

En ting Nemerle skiller seg litt fra endel andre språk på er muligheten til å definere funksjoner inne i andre funksjoner. I den følgende løsningen har jeg opprettet to funksjoner inne i Main-metoden. Disse bruker pattern matching og rekusjon til å finne summen – en teknikk du også så meg bruke i F#.

35 module Program
36 {
37     Main() : void
38     {
39         def include(n)
40         {
41             n % 3 == 0 || n % 5 == 0
42         }
43         def euler1(n, sum)
44         {
45             | (1000, _)              => sum
46             | (_, _) when include(n) => euler1(n+1, sum+n)
47             | (_, _)                 => euler1(n+1, sum)
48         }
49         WriteLine(euler1(0, 0));
50     }
51 }

List comprehension

Den enkleste løsningen har jeg likevel spart til slutt. Nemerle har støtte for list comprehensions, som er et kraftig verktøy for å opprette filtrerte serier. Jeg kan dermed skrive ut svaret med en ganske leselig one-liner.

52 module Program
53 {
54     Main() : void
55     {
56         WriteLine($[x | x in [1..999], x % 3 == 0 || x % 5 == 0].Sum());
57     }
58 }

Hvorfor bruke tid på Nemerle

Nemerle er et praktisk og godt verktøy som lar deg kombinere objektorientering og funksjonell programmering. I tilleg har du makroene som lar deg utvide syntaksen og kompilatoren ganske enkelt. Nemerle vil derfor egne seg svært godt til å redusere mengden “boilerplate” i større løsninger, og til å lage interne DSL’er.

Sammenlignet med F# er Nemerle trolig enklere å forstå og å komme igang med for programmerere som ikke har vært eksponert for ML-lignende språk tidligere. Nemerle’s minner nemlig mer om C# gjennom bruk av krøllparanteser, klasser og andre syntaks-elementer. Man kan begynne med objekter om man er vandt til det, og gradvis ta i bruk de andre egenskapene etterhvert som man lærer.

Hvordan komme igang

Nemerle er støttet gjennom en extension i Visual Studio 2008. 2010-støtten er i beta, men fungerte greit nok for meg. Man får farger, IntelliSense, designtime hints og sikkert andre features jeg ikke har oppdaget. Du finner også støtte for Nemerle til SharpDevelop (om du er på Linux, eller foretrekker open source).

Jeg tror det vil være svært enkelt for et team med C#-utviklere å konvertere til å bruke Nemerle. Man kan selvfølgelig bruke språket på enkeltdeler; .NET-løsninger kan fint blande prosjekter skrevet i ulike språk. Men med Nemerle kan man i tillegg inkludere C#-kode i Nemerle-prosjekter – noe lignende har jeg aldri sett før.

Dessuten tilbyr Nemerle-teamet en C#-til-Nemerle converter. Hva med å kjøre den på din eksisterende kodebase, og se hva som kommer ut i andre enden?

Du finner Nemerle på nemerle.org. Språket har også en brukbar wiki med ganske mye informasjon, linker til API-dokumentasjon og tutorials.

Som sagt synes jeg Nemerle er et veldig spennende språk, og jeg anbefaler deg å ta det i nærmere ettersyn!

Unlambda

“The effect of reading an Unlambda program is like having your brains smashed out by a Lisp sexp wrapped around an ENIAC. You won’t find anything like it west of Alpha Centauri.” – The Hitch-Hacker’s Guide to Programming

unlambda

Unlambda beskrives som et mareritt som har blitt virkelig. Det er med vilje designet for å gjøre programmeringen vanskelig og smertefull – eller utfordrende og underholdende, om du lærer deg å like denslags. Å skrive Unlambda-kode er vanskelig, men å lese Unlamdba-kode er praktisk talt umulig!

Det dreier seg her om et funksjonelt programmeringsspråk ala Scheme. I slike språk utgjør funksjonen den viktigste byggestenen, og i Unlambda er funksjonen faktisk det eneste man har å jobbe med. Matematisk kan man si at kjærnen i Unlambda er en implementasjon av Lambda Calculus, men uten selve Lambda-operatoren.

Unlambda er altså ikke ment å være et praktisk anvendelig språk. I stedet demonstrerer det svært ren, funksjonell programmering. Man kan ikke ha variabler, og har ingen vanlige operatorer eller datatyper. Alt man har er noen få innebygde funksjoner som hver tar én annen funksjon som parameter, og returnerer en ny funksjon. For å gjøre det ekstra kryptisk (og elegant) består hver funksjon av kun et tegn. Språket har ingen syntaks utover dette.

Hvorfor skal man bruke tid på Unlambda?

Det som skremmer meg med Unlambda er at det er et språk jeg sålangt ikke klarer å forstå. Jeg tror derimot at om man jobber litt med det, og begynner å skjønne hvordan man bruker det, så har man forstått noe svært sentralt innen funksjonell programmering. Man vil sansynligvis stå bedre rustet til å utføre små mirakler i Haskell, i Lisp-dialektene eller tilsvarende språk.

Har du først og fremst en praktisk tilnærming til programmering er altså dette språket sansynligvis ikke noe for deg. Men om du liker en utfordring, og har tro på at all kunnskap kan berike deg, så er Unlambda noe av det mest spesielle du kan lære.

Hvordan ser det ut?

Jeg beklager, men jeg har ikke klart å lage et program som løser Euler-oppgave 1. Men jeg tviler på at det har noe nå si. Følgende “lånte” Unlamda-program kalkulerer og skriver i stedet ut Fibonacci-tall i form av linjer med stjerner.

1 ```s``s``sii`ki
2   `k.*``s``s`ks
3  ``s`k`s`ks``s``s`ks``s`k`s`kr``s`k`sikk
4   `k``s`ksk

Som du ser er det mest brukte tegnet i dette programmet “backquote”. Dette er rett og slett Unlambdas apply-funksjon. S står for substitution, k kalles constant generator, og i er identity-funksjonen som bare returnerer sitt argument uendret. R skriver ut en ny linje, og .* skriver ut en stjerne.

Her ser du hvordan det ser ut når jeg kjører det med Java-implementasjonen av Unlambda (den fortsetter å kjøre i det uendelige antar jeg, men jeg trykket Ctrl-C for å stoppe den):

C:\unlambda-2.0.0\java>java unlambda.Execute fib.unl

*
*
**
***
*****
********
*************
*********************
**********************************
*******************************************************

Tar du utfordringen?

Siden jeg feiget ut og ikke klarte å løse den vanlige adventsoppgaven, så har vi jo egentlig en utfordring her. Kjempekudos til førstemann som poster løsningen i en kommentar!

hvordan kommer man i gang?

Det første man må gjøre er å lese det som står på den ofisielle websiden til The Unlambda Programming Language. Deretter kan man laste ned Unlambda versjon 2, som inkluderer implementasjoner i C, Java, Perl, Scheme med flere, samt eksempel-programmer og noen verktøy for Unlambda-utviklere. Og så er det bare å klø seg i hodet og forsøke å få ting til å virke :-)

Haskell

Haskell er en tungvekter. Haskell er vakkert, elegant og matematisk, og samtidig anvendelig i den virkelige verden. Haskell kan gjøre deg mer produktiv, og kan resultere i kode som er mer fleksibel og derfor bedre egnet for et langt liv med mange endringer. Og Haskell’s kompilator og sterke typing tillater ikke noe tull, men hjelper deg til å skrive feilfri kode.

haskell

Ingressen inneholder noen sterke påstander. Jeg har ikke nok erfaring til å garantere at de er riktige, men de som bruker Haskell skryter i alle fall noe voldsomt av språket sitt. De sier at det er gøy å lære og å jobbe med Haskell. At det vil utvide hjernen din, og raskt gjøre deg til en bedre programmerer også i andre språk. Dette høres ut som gode grunner til å ta en titt.

De stolte Haskellanerne sier også at språket egner seg bra til å løse real-world problems, men at det kan ta mange måneder med studie før man når et nivå hvor det blir realistisk.

For Haskell er vanskelig! Enhver kompetent programmerer kan lære det, men det kan kreve mer tid og motivasjon enn man tror. For de fleste av oss innebærer Haskell at vi må lære en ny måte å tenke på – det er ikke bare snakk om en ny syntaks for gamle konsepter og teknikker. Til å begynne med kan dette være frustrerende, og enkle oppgaver kan virke nesten umulige å løse.

Personer uten tidligere programmeringserfaring vil faktisk kunne lære det raskere, fordi det er færre ting man må “glemme”.

Hva er Haskell, og hvor kommer det fra?

Haskell er resultatet av et forsøk på å samle det beste fra diverse funksjonelle programmeringsspråk. Det er en åpen standard definert av en komité, og første versjon kom i 1990. Den gjeldende versjonen er Haskell 2010.

Haskell er altså et funksjonelt språk, et rent funskjonelt språk for å være presis. Men det er også imperativt, for rent betyr ikke nødvendigvis det du tror. Haskell er veldig fleksibelt, og kan også støtte ting som objektorientering, aspekter og logisk programmering.

Haskell er lazy (for de som vet hva det er), har pattern matching og list comprehensions, og et sterkt, statisk typesystem. Jeg kunne sagt mye mer, men uansett hva jeg sier vil noen komme og si at jeg har missforstått Haskell helt, så nå er det…

…På tide å se litt kode

Igjen har jeg implementert en løsning for Euler problem 1hvordan finne summen av alle tall mindre enn 1000 som er delelige på 3 eller 5. Jeg har delt programmet opp i mindre biter for at det skal bli lettere å fordøye. Her er første “chunk”, som definerer modulen Main, importerer funksjonen range som jeg trenger senere, og definerer min første funksjon:

10 module Main where
11 
12     import Ix (range)
13 
14     zero :: Integer -> Bool
15     zero x = x == 0

Den første funksjonen heter zero. Linje nummer 14 er en typedeklarasjon, og er ikke påkrevd. Den sier rett og slett at zero er en funksjon som tar inn en Integer og returnerer en Bool. Selve implementasjonen følger på linje 15; den sier at resultatet av zero x, hvor x altså er en Integer, er det samme som x == 0, altså True hvis x er 0, og False hvis x er noe annet enn 0.

Neste funksjon kan brukes til å sjekke om et tall er delelig på 3 eller 5:

17     multipleOf3or5 :: Integer -> Bool
18     multipleOf3or5 x =
19         let modX = mod x
20             multipleOf = zero . modX
21             in multipleOf 3 || multipleOf 5

multipleOf3or5 illustrerer flere Haskell-features. Let lar meg definere et par verdier som jeg kan bruke videre i funksjonen. Definisjonen av modX er et eksempel på partial application – mod er nemlig en funksjon som tar to parametre, men jeg har bare “sendt inn” ett. Jeg har dermed fått laget meg en ny funksjon (altså modX) som tar én parameter.

Jeg har snakket om denne teknikken et par ganger tidligere, i posten komponere funksjoner i F# og i curry-oppskrifter for sultne utviklere.

For å lage multipleOf-funksjonen i linje 20 bruker jeg Haskell’s dot-operator (.), som komponerer en ny funksjon fra to andre. Å si multipleOf = zero . modX er det samme som å si multipleOf x = zero (modX x). Altså er multipleOf nå en funksjon som først sender sine argumenter til modX-funksjonen, og så tar resultatet av dette og sender inn til zero-funksjonen.

Det bør nå være mulig å forstå hvordan multipleOf3or5 virker. Videre har jeg laget en høyereordens-funksjon som filtrerer en liste med tall og til slutt summerer de filtrerte tallene:

23     sumWhere :: (Integer -> Bool) -> [Integer] -> Integer
24     sumWhere f lst = sum $ filter f lst

Først har vi typedeklerasjonen av sumWhere som basically sier at funksjonen først har en parameter som er en funksjon som tar inn en Integer og returnerer en Bool (som f.eks. multipleOf3or5). Deretter har den et parameter som er en liste av Integer. sumWhere skal til slutt returnere en Integer.

Selve implementasjonen bruker et dollartegn for å unngå å måtte bruke paranteser (Haskell har lært fra Lisp at utviklere flest ikke skjønner denslags). Men sum $ filter f lst kunne i stedet ha blitt skrevet som sum (filter f lst). Listen filtreres altså på funksjonen f, og resultatet av dette sendes til funksjonen sum.

Og da gjenstår det bare å koke det jeg har laget sammen for å beregne løsningen på oppgave:

26     euler1 :: Integer
27     euler1 = sumWhere multipleOf3or5 $ range (1,999)

euler1 er – alt etter hvordan du ser det antar jeg – en Integer eller en funksjon som evaluerer til / returnerer en Integer. Jeg tar en range fra 1 til 999, og bruker sumWhere til å filtrere og summere listen vha. multipleOf3or5.

Denne kodesnutten har så vidt skrapet i overflaten på hva Haskell er, men forhåpentligvis gir det et lite inntrykk av hva du vil møte.

Hvordan komme i gang

Den mest kjente implementasjonen av Haskell heter The Glasgow Haskell Compiler (GHC), og funker på Windows, Linux, Mac og mange andre steder. Den er ekstremt rask, har god støtte for concurrency og paralell programmering, og inkluderer blant annet støtte for Software Transactional Memory (STM). GHC laster du ned herfra.

De to mest populære ressursene for å lære språket er bøkene Learn You a Haskell og Real World Haskell. Begge er gratis tilgjengelig online, men du kan også kjøpe dem i dødt tre om du foretrekker det.

Ellers er haskell.org stedet du ønsker å starte for å utforske språket. Det kan være litt tøft i starten, men hold ut – det er verdt det. Lykke til!

F#

Har du hørt at programmer som er kodet etter den funksjonelle paradigmen ofte er kortere og er enklere å teste, og gjør det mye enklere å utnytte prosessorkraften på maskinen? Spennende, men hvilket språk skal man bruke da? F# er ett alternativ.

fsharp

På Universitetet i Edinburg utviklet man tidlig på 70-tallet et programmeringsspråk man kalte ML. Språket støttet både imperativ og funksjonell programmering. F# er en moderne implementasjon av ML, først utviklet av Don Syme ved Microsoft Research for 10 år siden. Nå er språket i versjon 2, mens versjon 3 er i preview. Det er tilgjengelig i Visual Studio, og distribueres som et fullverdig språk på .NET-plattformen.

F# er et sterkt typet språk. Det her såkalte immutable types – data som ikke kan endres – som brukes til funksjonell programmering, men også mutable types som kan brukes til objektorientering. I F# kan man benytte alle biblotekene en som .NET-utvikler er vandt til å ha tilgang til, men måten du koder og tenker på er ganske anderledes.

Eh, hva er denne funksjonelle programmeringen for noe egentlig?

Funksjonell programmering (FP) er når man lager programmer som er som evaluering av matematiske funksjoner, og man forsøker å unngå tilstand og data som kan endres på underveis i programmet. Man legger altså vekt på å evaluere funksjoner, og mindre vekt på endring av variabler.

FP har sine røtter i lambda calculus, en formell beskrivelse av funksjonsdefinisjoner, evaluering av funksjoner, og rekursjon. Et par relaterte blogposter som utdyper betydningen av FP er programmeringsparadigmer – ulike måter å tenke på og hemmeligheten bak funksjonell programmering avslørt.

Litt kode

Jeg vil nå vise en hel rekke ulike løsninger på Euler problem nummer 1 implementert i F#. Selv om jeg har blogget litt om F# tidligere så er jeg helt nybegynner, og her er den første løsningen jeg kom opp med gjennom å google meg frem til funksjoner jeg kunne bruke:

10 let Euler1a =
11     Seq.unfold       (fun x -> Some(x, x+1)) 0
12     |> Seq.takeWhile (fun x -> x < 1000)
13     |> Seq.filter    (fun x -> x % 3 = 0 || x % 5 = 0)
14     |> Seq.fold      (fun x acc -> x + acc) 0
15     |> System.Console.WriteLine

Seq.unfold genererer en uendelig sekvens med tall. Jeg sender så sekvensen gjennom en rekke funksjoner for å begrense, filtrere, summere, og til slutt skrive ut resultatet.

Jeg fant derimot raskt ut at jeg kunne forenkle løsningen. Sekvenser kan lages enklere, og jeg behøver ikke bruke fold for å summere tall.

17 let Euler1b =
18     seq { 0 .. 999 }
19     |> Seq.filter(fun x -> x % 3 = 0 || x % 5 = 0)
20     |> Seq.sum
21     |> System.Console.WriteLine

Faktisk viste det seg også at Seq-bibloteket inneholdt en funksjon som jeg kunne bruke til å filtrere og summere i én operasjon, og da så det til slutt slik ut:

23 let Euler1c =
24     seq { 0..999 }
25     |> Seq.sumBy (fun x -> if x%3=0 || x%5=0 then x else 0)
26     |> System.Console.WriteLine

Men F# egner seg også til å implementere sett-baserte løsninger som dem jeg beskrev i denne bloggposten. I løsningen nedenfor oppretter jeg to sett med multipler av 3 og multipler av 5. Disse finner jeg unionen av, endrer settet til en sekvens, summerer og skriver ut.

28 let Euler1d =
29     (set {0..3..999}, set {0..5..999})
30     ||> Set.union
31     |> Set.toSeq
32     |> Seq.sum
33     |> System.Console.WriteLine

Jeg forsøkte også det andre alternativet av sett-løsninger hvor jeg legger sammen summen av alle 3-multipler og 5-multipler, og trekker fra summer av alle 15-multipler:

35 let Euler1e =
36     (seq {0..3..999} |> Seq.sum) +
37     (seq {0..5..999} |> Seq.sum) -
38     (seq {0..3*5..999} |> Seq.sum)
39     |> System.Console.WriteLine

Den neste løsningen er en rekursiv funksjon som bygger opp en sum basert på pattern matching. Løsningen er inspirert av bowlingkata-algoritmen jeg viste i blogposten Likheter mellom F# og Erlang. Jeg bruker et såkalt match expression med tre ulike muligheter: Hvis n er 1000 skal sum inneholdet svaret, og det returneres. Hvis ikke sjekker jeg om n er delelig på 3 eller 5, og hvis så er tilfelle så legger jeg n til sum, øker n med 1, og kaller funksjonen rekursivt. Hvis tallet ikke er delelig på 3 eller 5 skal det ikke inkluderes, og jeg kjører videre uten å endre sum.

43 let rec Euler1f n sum =
44     match n with
45         | 1000                          -> sum
46         | _ when n % 3 = 0 || n % 5 = 0 -> Euler1f (n+1) (sum+n)
47         | _                             -> Euler1f (n+1) sum
48 
49 System.Console.WriteLine (Euler1f 0 0)

Til slutt har jeg laget en forbedret pattern matching ved å bruke et såkalt active pattern. Denne teknikken brukes for å partisjonere data – i dette tilfelle splitte alle tenkelige tall i to grupper basert på om de er multipler av 3 eller 5 eller om de ikke er det. Selve match-uttrykket blir dermed renere.

56 let (|Multiple|NotMultiple|) n =
57     if n % 3 = 0 || n % 5 = 0 then Multiple else NotMultiple
58 
59 let rec Euler1g n sum =
60     match n with
61         | 1000        -> sum
62         | Multiple    -> Euler1g (n+1) (sum+n)
63         | NotMultiple -> Euler1g (n+1) sum
64 
65 System.Console.WriteLine (Euler1g 0 0)

Hvorfor bruke tid på F#

Jeg vil ikke at du absolutt skal lære deg F#, men jeg mener det er viktig at du lærer deg minst ett språk med fokus på funksjonell programmering. Og om du allerede har .NET-erfaring er F# da et naturlig valg. Er du Java-utvikler er det kanskje mer sansynlig at du vil gå for å lære deg Scala eller Clojure (som forresten begge finnes for .NET også).

Men nå snakker vi altså om F#, som er et modent språk, supportert av Microsoft, og som egner seg godt til praktisk utvikling av forretningsprogramvare. Visual Studio-støtten, og F#-støtten man finner i andre verktøy som f.eks. LinqPad, er også et stort pluss for dem som allerede bruker disse.

Jeg har derimot ikke inntrykk av at F# har fått den utbredelsen man kunne forvente. Det kan være flere grunner til dette, men ett av dem er nok at C# og VB.NET – de mest utbredte språkene på .NET – også har fått brukbar støtte for funksjonell programmering vha. Linq og lambda-uttrykk. F# har derimot endel egenskaper man ikke finner i disse andre språkene, og det er absolutt verdifullt å studere disse.

Hvordan komme igang

Har du Visual Studio 2010 har du allerede F# på maskinen, og det er bare å sette igang. På MSDN finner du all informasjon du behøver om språket og API’ene, samt flere guider, tutorials og videoer. På Visual F# Developer Center finner du siste nytt og community-relatert informasjon. Lykke til!

Cobra

Programmeringsspråket du skal få møte i dag har mye til felles med Boo, språket jeg fortalte om i går. Cobra er nemlig også laget for .NET og Mono, og syntaksen er Python-inspirert (men Ruby-utviklere vil også kunne føle seg som hjemme). Det har både statisk og dynamisk binding, og er generelt sett en smeltedigel som forsøker å kombinere det beste fra mange andre språk.

cobra

Hvorfor bruke tid på Cobra?

Cobra er utviklet med fokus på å øke kvaliteten i koden din. For det første er enhetstester førsterangs borgere i Cobra. De lever som en naturlig del av metode-definisjonene, og kjøres som en del av kompileringen.

Men i tillegg til normale tester støtter språket også kodekontrakter, inspirert av Eiffel. Dette innebærer at du kan deklarere invarianter, pre- og post-conditions som objekter og metoder må tilfredstille. Kontraktene blir en del av grensesnittet til klassene, og brudd på en kontrakt under kjøring resulterer i exceptions.

Ønsker man optimal ytelse kan både tester og kontrakter enkelt elimineres når man kompilerer for produksjon.

Andre interessante egenskaper er compile-time nil-tracking. Skal noe kunne være en nil (eller null om du vil) i Cobra så må det deklareres eksplisitt. Er du lei av å bli overrasket av NullReferenceException når du kjører programmet ditt? Da kan dette være noe som hjelper deg.

Cobra tilbyr også utvidet informasjon når et problem oppstår. Man kan f.eks. velge å få generert en HTML-formatert post-mortem rapport når programmet kræsjer.

Et eksempel

Jeg tipper du ikke lar deg overraske av at jeg skal bruke Cobra til å finne summen av alle positive heltall under 1000 som er multipler av 3 eller 5. Klassen nedenfor implementerer et komplett program som skriver ut løsningen.

Euler1-klassen inneholder to metoder: main, som kjøres når programmet eksekveres, og validNumber, som inneholder både tester og en liten precondition.

10 class Euler1
11     shared
12         def main
13             """
14             Finds the sum of all numbers from 1 
15             below 1000 that are multiples of 3 or 5.
16             """
17             sum = 0
18             for n in 1:1000
19                 if .validNumber(n)
20                     sum += n
21             print sum
22 
23         def validNumber(n) as bool
24             require
25                 n > 0
26             test
27                 assert .validNumber(6)
28                 assert .validNumber(10)
29                 assert not .validNumber(1)
30                 assert not .validNumber(8)
31             body
32                 return n % 3 == 0 or n % 5 == 0

Noen bekymringer

Cobra har vært under utvikling i mange år nå, men virker fortsatt litt uferdig. Det skal blant annet støtte mixins, men dette virker ikke som det skal. Støtten for anonyme metoder og lamda er heller ikke så bra enda. På den andre siden har det blitt laget en Cobra add-in for Visual Studio 2010, men denne har jeg ikke forsøkt.

Jeg er litt usikker på hvor aktiv utviklingen egentlig er. Jeg ser det stadig gjøres små bugfikser, men gjeldende release er over ett år gammel. Det er også endel som ikke er oppdatert på websidene, men diskusjonsforumet er i alle fall aktivt.

Tenker man at Cobra kan være noe å satse på bør man derfor vurdere disse tingene nærmere.

Hvordan komme i gang

Cobra finner du på cobra-language.com. Der kan du laste ned språket, og så er det rimelig enkelt å komme igang. Dokumentasjonen er brukbar, men som sagt inneholder den både hull og enkelte ting som har gått ut på dato.

Det er likevel interessant å teste ut et språk hvor Design by Contract-teknikken har fått en så sentral plass. Microsoft er jo i ferd med å levere støtte for dette i sine egne språk på .NET-plattformen, og det kan være lurt å lære seg dette som et suplement til testdrevet utvikling basert på enhetstester.

Boo

Er du interessert i å lære et .NET-språk som er mer elegant og enklere å skrive enn C# og VB.NET, og som i tillegg gir deg samme mulighet for å utvide selve språket som det Lisp gjør? Da kan Boo være et bra valg!

Boo er et objektorientert, statisk typet språk med en syntaks inspirert av Python. Det så dagens lys i 2003, og har vært under aktiv utvikling siden det. Gjeldene release ble sluppet i januar 2011.

Boo kjører altså på .NET-plattformen (og Mono), og man har tilgang til det meste av hva man er vandt til i rammeverket, som generics, linq osv, og man kan benytte alt man har av eksisterende .NET-biblotek. Ofte bruker man Boo til deler av prosjekt – der hvor Boo’s styrker kommer til sin rett.

Disse styrkene er blant annet en behagelig syntaks (selv om ikke alle vil være enige i det), og kraftig type inference og automatisk type casting som gjør at den sterke typingen ikke går i veien for deg, og er mer behagelig å jobbe med. Dessuten får du literals (enklere syntaks) for lister, arrays og dictionaries, du trenger bare bruke klasser når du trenger det (funksjoner lever fint for seg selv), og du kan bruke duck-typing (en form for dynamisk typing) når du måtte ha behov for det.

boo

Alt dette er vel og bra, men Boo har mer! Fokuset under utviklingen av Boo har vært på å lage en fleksibel og utvidebar kompilator. Dette gjør at man kan utvide selve språket gjennom å lage ting som meta-metoder og makroer som kjører under selve kompileringsprosessen. Disse teknikkene gjør blant annet at man kan unngå det vi ofte kaller for boilderplate code. Det gjør også Boo til et glimrende verktøy for å lage domenespesifike språk, noe Ayende Rahien beskrev i boken DSLs in Boo: Domain-Specific Languages in .NET.

Jeg har selv fått benyttet Boo på denne måten i et par prosjekter, og synes det fungerer ganske bra.

På tide med litt kode

Som vanlig har jeg implementert en løsning (eller rettere sagt flere løsninger) på Project Euler problem nummer 1hvordan man summerer opp alle tall opp til 1000 som er delelige på 3 eller 5. Dette vil ikke demonstrere noen makro eller meta-features, men gi et første inntrykk av hvordan Boo-kode ser ut, og hva man kan gjøre.

 1 """A simple, imperative Boo solution to Euler problem #1"""
 2 
 3 class Euler1:
 4   static def Solve():
 5     sum = 0
 6     for i in range(1, 1000):
 7       if i % 3 == 0 or i % 5 == 0:
 8         sum += i
 9     return sum

I koden over deklarerer jeg en klasse jeg kaller Euler1. Den har en statisk metode som heter Solve. Her kjører jeg en for-løkke over en range og legger til et tall i sum-variabelen hvis det er delelig på 3 eller 5.

Du bør ha lagt merke til et par ting: For det første bruker Boo indentering til å definere strukturen i koden, akkurat slik Python gjør det. Dessuten har jeg ikke deklarert noen typer her (bortsett fra selve Euler1 da), Boo-kompilatoren skjønner fint at sum er en int, at i er en int, og at Solve dermed også returnerer en int. Ingen grunn til at jeg skal måtte påpeke det.

For å kjøre koden min skriver jeg følgende:

11 print Euler1.Solve()

Siden Solve er en statisk metode trenger jeg ikke opprette en instans av Euler1, men kaller bare metoden direkte på klassen. Print er faktisk en makro som ekspanderer til System.Console.WriteLine(..) under kompilering.

Her følger en alternativ implementasjon som benytter seg av Sum-funksjonen i System.Linq:

1 import System.Linq.Enumerable
2 
3 def Euler1Filter(it as int):
4   if it % 3 == 0 or it % 5 == 0:
5     return it
6 
7 print range(1, 1000).Sum(Euler1Filter)

En range er nemlig en IEnumerable<Int32>, og jeg kan dermed kalle Sum på denne, slik .NET-utviklere er vandt til, og sende inn en funksjon som parameter. Denne funksjonen blir kalt for hvert element i sekvensen. Legg merke til at jeg har gjort noe litt rart i Euler1Filter-funksjonen.., jeg returnerer kun hvis elementet skal være med. Jeg antar Boo er smart nok til å returnere en default-verdi (dvs. 0) når elementet ikke matcher.

Til slutt har jeg gjort en løsning som benytter det Boo kaller for en Generator Expression (jeg ville kalt det en list comprehension):

10 import System.Linq.Enumerable
11 
12 def include(i as int):
13   return i % 3 == 0 or i % 5 == 0
14 
15 def euler1Range():
16 """ Function returns a Generator Expression """
17   return x for x in range(1, 1000) if include(x)
18 
19 print euler1Range().Sum()

Hvorfor bruke tid på Boo

Bakgrunnen for Boo er først og fremst en frustrasjon over syntaksen til C#. Hvis du deler denne, og synes språk som Python er mere elegante, så er Boo noe du bør se på.

Men styrken til Boo ligger i makroene. Du kan utvide språket med nye kodeord og strukturer som gjør at du kan forme det til å passe dine behov, og gjøre din kode enklere. Dette er kanskje ikke for hvem som helst, men seriøse utviklere bør være klar over hva de eventuelt går glipp av om de ikke bruker makroer.

Hvordan komme i gang

Boo finner du på boo.codehaus.org. Det du kan begynne med er å lese Boo-manifestet (pdf), skrevet av språkets skaper i 2004-2005.

Jeg har slitt litt med at noe av dokumentasjonen på Boo er utdatert, og det kan være litt vanskelig å navigere på siden for å finne det man er ute etter. Men det finnes et relativt stort community rundt Boo, og det skal være mulig å finne den hjelpen man trenger om man forsøker.

Euphoria

Euphoria er et akronym for noe så spesielt som End-User Programming with Hierarchical Objects for Robust Interpreted Applications. Dette prosedyrebaserte språket ble orginalt utviklet for Atari, og første release kom i 1993. I 2006 ble det open source, og i dag er det et språk som kan kjøre på Windows, Linux, FreeBSD og OS X.

euphoria

Euphoria har en syntaks som skal være lett å både lære og lese. Engelske ord foretrekkes fremfor kryptiske tegn. Jeg får rett og slett litt BASIC-assosiasjoner. Det har også bare fire innebygde datatyper: atom, sequence, integer og object.

I tillegg til enkelhet vektlegger språket rask utvikling. Det er i utgangspunktet et tolket språk, som f.eks. Python og Ruby, men kan også kompileres til C-kode. Du kan dessuten pakke kildekode sammen med en tolker for å lage selvstendige, kjørbare programmer.

Euphoria har også en meget effektiv garbage collector, og det skrytes av at Euphoria er et av de raskeste tolkede språkene som finnes. Av andre ting som er verdt å nevne har Euphoria en debugger, enkel wrapping (eller tilgang til) C-bibloteker, og en enkel, innebygget database.

Det er flere paraleller til Lua her, som jeg presenterte i går.

Og så skal vi se hvordan koden ser ut

Som vanlig setter jeg igang med å implementere et program som finner summen av alle multipler av 3 eller 5 under 1000, uten å vite noe spesielt om språket på forhånd. API-dokumentasjonen var ganske bra, men det var litt problematisk likevel. Euphoria skal være god på sekvenser, og har et rikt sekvens-biblotek, men funksjonene har ikke de navnene jeg forventer.

Etter litt knoting frem og tilbake kommer jeg frem til følgende løsning:

10 include std/io.e
11 include std/math.e
12 include std/sequence.e
13 
14 function multiplesOf(integer n)
15   return series(0, n, ceil(1000 / n))
16 end function
17 
18 function negate(integer x, object ignored)
19   return x * -1
20 end function
21 
22 procedure main()
23   sequence mults_3 = multiplesOf(3)
24   sequence mults_5 = multiplesOf(5)
25   sequence mults_15 = apply(
26                         retain_all(mults_3, mults_5),
27                         routine_id("negate"))
28 
29   ? sum({mults_3, mults_5, mults_15})
30 end procedure
31 
32 main()

Med litt forklaring bør koden være grei å forstå: Jeg løser oppgaven som et sett-problem, med algoritmen som summerer alle multipler av 3 og alle multipler av 5, for så å trekke fra snittet av disse to, som er alle multipler av 15.

retain_all(a, b) gir meg en sekvens med alle tallene fra b som også er i a. apply(a, routine_id) sender alle elementene i sekvens a til rutinen, og gir meg en sekvens med resultatet – dette tilsvarer altså det som andre steder heter map eller eventuelt select.

Til slutt bygger jeg en ny sekvens som består av de tre sekvensene jeg har laget, og sender denne til den innebygde sum-funksjonen, som summerer alt sammen. Spørsmålstegnet printer ut svaret.

Det rareste er at jeg må bruke routine_id og en streng for å sende en funksjons-referanse til apply. Funksjoner er altså ikke førsterangs borgere i Euphoria. Språket har heller ikke anonyme funksjoner eller lambda-uttrykk såvidt jeg kan se.

Hvorfor bruke tid på Euphoria?

Euphoria er ikke objektorientert. Det støtter ikke funksjonell programmering på en god måte. Det har en enkel syntaks som likevel føles “bråkete”. Så hvilken verdi har det?

På OpenEuphoria-forumet leser jeg at Euphoria er et lett språk å lære seg, og at det resulterer i mere lesbar kode enn mange andre språk. Og at man kan løse problemer raskere. Sammenlignet med tolkede språk som f.eks. Python har det mye bedre performance, og er også lett å pakke til en frittstående fil.

Men for å være ærlig føles det litt som å ta en tidsmaskin tilbake til en tid før internett, til et sted hvor noen ikke hadde fått med seg hva som finnes av andre språk der ute. En verden hvor BASIC hadde dødd ut, C var vanskelig, og det egentlig ikke fantes noen andre alternativer. Det var en interessant reise, for all del, og språket kan nok brukes til mye rart. Men jeg tviler på at jeg kommer til å gjøre det.

Jeg er redd jeg kan ha sløst bort tiden din i dag, og at Euphoria blir den store taperen blant språkene jeg presenterer. Jeg lover mye mere spenstige språk i fortsettelsen!

Hvordan komme igang

Er du likevel interessert i å prøve ut Euphoria kan du ta turen til OpenEuphoria.org. Der kan du laste det ned for din foretrukne plattform, og lese så mye dokumentasjon som du bare måtte orke.


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