fredag 9. desember 2011 Julekalender 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>>.
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...
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.
Men la oss glemme for-løkken.., den er så 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å.
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 }
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 }
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.
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!