F# igang med funktionel programmering

by DotNetNerd 29. December 2007 18:46

F# - brugbar funktionel programmering

For en god uges tid siden dumpede bogen "Expert F#" endelig ind af min brævsprække - noget jeg har glædet mig til i et stykke tid, da jeg har hørt mange spændende ting om sproget. Inspireret af at jeg engang læste at man bør lærer sig et nyt programmeringssprog hvert år synes jeg det var det perfekte næste skridt for mig. Jeg har absolut ingen erfaring med funktionel programmering udover det jeg har rodet med LINQ - hvilket ikke er helt "rigtig" funktionel programmering men rettere funktionel funktionalitet indarbejdet i et Objekt Orienteret sprog.

Idet jeg næppe er den eneste der ikke har rodet med funktionel programmering, da det hovedsageligt har hørt hjemme på universiteterne hidtil, vil jeg skrive en smugle om nogen af de basale ting i funktionel programmering og F#. Hvis du tænker "hvis det hvedsageligt hører hjemme på uni, hvad kan jeg så bruge det til i praksis", så er pointen netop at F# udover at være et funktionelt sprog, også giver mulighed for at tilgå .NET frameworkets mange herligheder, og arbejde imperativt hvis man vil. Jeg tror F# har gode muligheder for at vinde frem netop
af den årsag, da det tilbyder fantastisk ekspressivitet sammen med adgang til de ting vi bruger .NET frameworket til allerede.

Lidt basics

Lidt ligesom der i VB findes option strict og explicit er der i F# "#light", som aktiverer det der kaldes light syntaks. Med andre ord slipper man for at skrive en masse ting og afslute linier manuelt osv. Eller kort sagt, bare skriv det øverst i din kode!

Kommentarer i F# minder langt hen ad vejen om den måde man skriver dem på i C#, med undtagelse af flerlinies kommentarer.

// Her er en enlinies kommentar.

(* Her står der en
flerlinies kommentar *)

///<summary>Xml kommentarer ligner også sig selv som i C#</summary>

Lidt ligesom man har Dim, var o. lign. ord der deklarerer en variabel har man i F# ordet "let" der definerer starten på en funktion. For at illustrere og vise hvordan scope fungerer er her et eksempel:

let powerOfTwo number
  let result = number * number
  result

Her definerer man en funktion der hedder powerOfTwo, som tager et argument "number". Funktionen består af en lokal funktion der er tallet ganget med sig selv. Man kan også se at inferens af typer bruges i meget vid udstrækning og at indrykning bruges til at afgrænse scope ligesom i (Iron)Python.

For at undgå at skulle ud i den helt langt gennemgang af simple typer og operatorer vil jeg nøjes med som udgangspunkt at sige at de langt hen ad vejen er de samme som i C# og ellers er der masser af steder man kan finde oversigter over dem via vores allesammens bedste ven google.

Det er vigtigt at vide at operatorer er unchecked. Operationer der giver overflow kaster altså ikke exceptions men de wrappes istedet. En anden ting der er vigtig at forstå er at de fleste typer er immutable med mindre det explicit angives at de skal være mutable. Det giver en række fordele, da man derved kan være sikker på at en værdi ikke ændres "bag om rykken" på en. Noget der især er rart når man arbejder trådet da man så ikke skal bekymre sig så meget om "concurrent access".

Grundlæggende data strukturer

Fleksible datastrukturer er en af hovedingredienserne i et funktionelt sprog, da de gør det muligt at skrive meget ekspressiv kode til at arbejde med mængder af data.

Tuple:

Tupler bruges til at returnerer flere værdier fra en funktion, som ikke nødvendigvis er af samme type. En tupel angives helt enkelt med en parentes hvori værdierne adskilles af en komma. En funktion der tæller ord kunne for eksempel returnere, totalt antal ord og antallet af unikke ord.

let wordCount = (10, 8)

fst og snd er keywords der bruges til at anvende det første og andet element i en touple - og dermed til at arbejde med par.

let totalWordCount = fst wordCount

En anden mulighed er at decompose tuplen i flere værdier.

let totalWordCount, totalUniqueWordCount = wordCount

Array:

Arrays kender de fleste nok ganske godt så dem vil jeg gå lidt let hen over. En vigtig ting at nævne er dog at arrays er den eneste af de collection strukturer jeg skriver om her der er mutable. Et array i F# defineres således:

let myArray = [|1;2;3;4;5|]

En anden funktion der er værd at nævne er at man kan definere et litteral byte array som:
let myArray = "MAGIC"B // Det svarer til [|77uy; 65uy; 71uy; 73uy, 67uy|]

Array slicing som ellers er en ting man godt kan savne lidt i andre .NET sprog kan desuden laves således.

let slicedArray = myArray.[1 .. 3]

List:

List i F# er en implementation af en singularly linked list som er en struktur der læses hurtigt hvis man læser elementerne igennem fra
start til slut.
 
let oneHalfOfTheFamily = ["Claus";"Lena";"AC"]
let anotherHalfOfTheFamily = ["Allan";"Janni";"Peter";"Jacob"]
let bothHalvesOfTheFamily = oneHalfOfTheFamily @ anotherHalfOfTheFamily

Her set man to lister blive oprettet og smeltet sammen. Det er vigtigt at huske at lister er immutable, så efter dette er sket er værdierne af de to første lister uændrede.

Set:

Sets indeholder ordnede lister hvor der kun kan være 1 af hver værdi, og sets er case sensitive. Et eksempel illustrerer meget godt hvordan den bruges.

let myset = Set.of_list ["BAC";"ABC";"ABC"]

Vil give en Set<string> med indholdet ["ABC";"BAC"]

Sets kan laves til lister eller laves fra lister ved hjælp af to_list og of_list

Option:

Options bruges til at beskrive en struktur der enten har en værdi eller er None. Keywordet her er "Some" og kan bruges således.

let childAndParents = [ ("Jens", Some("Ib", "Hanne"));"Jonas", None]

Options har funktioner som get der returnerer værdien af en some option og is_option der returnerer true for en some option.

Sequence:

Sequences er en abstraktion over datastrukturer der kan læses sekventielt og er alt der implementerer IEnumerable, som man kender det fra andre .NET sprog. I F# har sekvenser deres eget keyword som er seq. Det vil sige alle typer der er IEnumerable kan arbejdes med som sekvenser, det inkluderer arrays, lists osv. En smart F# feature er at man kan beskrive ranges af værdier i sekvenser på følgende måde.

let myNumbers = seq {0 .. 5}

Som vil give en sequence af værdier fra 0 til 5. Denne liste er lazy således at værdierne ikke genereres før de skal bruges. Dette er meget vigtigt hvis man skal arbejde med rigtigt lange sekvenser. Man kan desuden definere et interval i sevensen således.

let myNumbers = seq {1 .. 2 .. 6}

Som vil give værdierne [1;3;5]

Eller man kan definere en sequence ud fra f.eks. et for expression:

let powersOfTwo = seq { for i in 0 .. 10 -> i*i }

List og Seq indeholder desuden en række funktioner som eksempelvis map, iter, filter, to_array og of_array. De først nævnte gør det nemt at arbejde med strukturerne ved at passe en funktion ind.

powersOfTwo.iter(fun number -> Printf.printf "Number = %s\n" (number)

Functionelle værdier

En anden vigtig bestantdel i et funktionelt sprog er naturligvis muligheden for at arbejde med funktionerne. En række metoder som for eksempel map og iterate der findes på blandt andet List og Sequence tager imod en funktion som argument. Map bruges til at omforme alle elementer i strukturen og iterate bruges til at iterere strukturen og udføre funktionen på hvert element. En funktion kan som shorthand skrives som:

let namesWithH = Names.Filter(fun name -> name.StartsWith("J"))

Man har desuden mulighed for at "pipe" funktioner, sådan at en funktion kaldes med retur værdien fra den forrige funktion. Piping er en god
måde at gøre kode mere let læseligt på da det kan læses fra højre mod venstre og ikke indefra ud som man ellers tit ender med at skulle.


let PrintNamesWith prefix =
  NamesWith(prefix) |> List.iter(fun name -> Printf.printf "Name = %s\n" (name))


Man kan også arbejde med sammensatte funktioner og partiel applikation. Disse to teknikker viser hvor fleksibelt sproget er når man arbejder med funktioner.

let getNames s = String.split [';'] s
let countNames = getNames >> List.filter(fun (name:string) -> name.StartsWith("M")) >> List.length
let NameCount = countNames "Mia;Christian;Mig"

Eksmeplet viser hvordan man givet en funktion "getNames", kan definere en ny funktion countNames, som er en sammensætning af denne, List.filter og List.length - som derved kan bruges til at tælle antallet af navne i en semikolon separeret streng. F# har en meget powefull engine til at sammensætte effektive funktioner på denne måde.


let shift (x, y) (x1, y1) = (x1+x, y1+y)
shiftright = shift(1,0)

Dette eksempel viser helt enkelt at man kan definere en ny funktion ved at kalde en anden funktion med kun nogen af de argumenter den kræver. Dette giver mulighed for at være meget beskrivende i sin kode ved at lave en række partielle funktioner der løser specifikke opgaver på baggrund af en mere generel funktion.

Konklusion

Jeg håber ovenstående givet et godt indblik i nogle af de mest basale strukturer og teknikker der anvendes i F# i forbindelse med funktionel programmering. Som tidligere nævnt er F# ikke et "rent" funktionelt sprog så man kan også arbejde med imperativ programmering i sproget. Det kan være det bliver et emne jeg tager op senere. Selvom jeg er ny indenfor funktionel programmering synes jeg hurtigt man får et indtryk af hvor ekspressiv kode man kan skrive og at det er vejen frem især hvis man skal kode en applikation til et trådet miljø.

Tags:

Opsætning af IIS 7.0 og Windows Communication Foundation i Vista

by DotNetNerd 16. December 2007 14:50

Jeg opdagede idag at det er knap så "lige ud af boksen" som man kunne ønske sig at afvikle ASP.NET og Windows Communication Foundation services under Vista og IIS 7. Man kan kun undre sig over at ihvertfald ASP.NET ikke automatisk installeres ved installation af IIS, men det er åbenbart ikke tilfælder. Det lykkedes dog efter at have rodet lidt at få det til at virke og jeg vil derfor lige skrive en guide hvis andre skulle støde på samme problem. 

Installation af IIS og ASP.NET på Windows Vista

For at kunne afvikle en ASP.NET applikation skal man først installere IIS og den tilhørende ASP.NET komponent. Dette kræver administrator rettigheder og gøres ellers ved at:

  • Gå til kontrolpanel -> Programmer og funktioner.
  • Herfra vælger du "Slå windows funktioner til eller fra" i sidemenuen til venstre i vinduet.
  • Vælg internet Information Service og udvid punktet.
  • Udvid "værktøjer til webmanagement" og "kompatibilitet med IIS 6 management".
  • Vælg "Kompatibilitet med IIS-metabase og IIS 6-konfiguration".
  • Udvid også "World wide web services" og Funktioner til programudvikling.
  • Vælg ASP.NET checkboksen.

Du kan nu afvikle ASP.NET applikationer ved at oprette dem på almindeligvis via IIS management værktøjet - eller bruge default sitet ved at smide det i inetpub/wwwroot.

Installation af WCF service modellen

For at kunne afvikle en Windows Communication Foundation service skal service modellen registreres.

Dette gøres ved at:

  • Åben en kommandoprompt med admin rettigheder.
  • Gå til %Windows%\Microsoft.Net\Framework\v3.0\Windows Communication Foundation\
  • Check status ved at skrive ServiceModelReg -vi og se om service modellen allerede er installeret.
  • Er den ikke installeret skriv ServiceModelReg -i og så skulle modellen blive installeret.

Og nu kan du så også afvikle en Windows Communication Service.

Lige for en god ordens skyld skal det siges at for at hoste en WCF service under IIS 7 skal man blot smide en svc fil med følgende indhold i roden af sitet.

<%@ ServiceHost Language="C#" Debug="true" Service="Syndication.FeedService" %>

Hvor servicen skal pege på klassen der implementerer din service. Dll'en skal ellers bare ligge i en bin mappe som den plejer.

Tags: , ,

Silverlight del 3 - ready, set, draw

by DotNetNerd 2. December 2007 16:56

I sidste blogindlæg om silverlight nåede jeg lige kort at berøre Path elementet, som har en Path.Data collection bestående af Geometry elementer som tegnes.

Der findes 4 basale typer geometry elementer som er:

  • RectangleGeometry
  • EllipseGeometry
  • LineGeometry
  • PathGeometry

De 3 første fungerer på samme måde som de tilsvarende elemeter jeg gennemgik i sidste blogindlæg, og RectangleGeometry blev ligeledes berørt i eksemplet på at bruge Path.

PathGeometry

PathGeometry er et meget komplekst element der kan bestå af en række segmenter, som findes i 7 forskellige typer:

  • LineSegment
  • PolyLineSegment
  • ArcSegment
  • BezierSegment
  • PolyBezierSegment
  • QuadraticBezierSegment
  • PolyQuadraticBezierSegment

Disse elementer kan tilføjes til et PathFigure element - som der så igen kan være flere af i et PathGeometry element.
PathFigure har en StartPoint property som beskriver hvor der tegnes fra og derefter tegnes de tilføjede segmenter efter hinanden. Som altid siger et eksempel mere end 1000 ord. 


<Canvas Name="Canvas1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480">
 <Path Name="Car" Stroke="Green" Canvas.Left="100" Canvas.Top="100" StrokeThickness="1">
  <Path.Data>
   <PathGeometry>
    <PathFigure StartPoint="50,50">
     <LineSegment Point="100,100" />
     <ArcSegment Point="150,150" Size="20,20" />
     <BezierSegment Point1="250,300" Point2="200,50" Point3="0,0" />
     <ArcSegment Point="50,50" Size="20,20" />
    </PathFigure>
   </PathGeometry>
  </Path.Data>
 </Path>
</Canvas>

Som det fremgår kan man tegne virkeligt komplekse ting med meget enkle midler. 

Geometri elementer som strenge

En smart feature er at Geometries kan beskrives som strenge, hvilket tillader en væsentligt mere kompakt syntaks. Læsevenligheden kan man tilgengæld godt stille spørgsmålstegn ved, men det kan være det bliver lettere når man bliver lidt mere rutineret.

Jeg vil undgå at gennemgå alle kommandoer, da der alligevel allerede findes omfattende sites hvor man kan slå den slags ting op, men vil da give et eksempel på nogen af de mest brugte ved at tegne den ovenstående figur igen ved hjælp af en kommandostreng.

M angiver StartPoint og er derved altid angivet. Ved at slutte med Z kan man iøvrigt sørge for at figuren lukkes - dette svarer til at sætte propertien IsClosed="True" på PathFigure.
L angiver at der skal tegnes en linie hen til et punkt.
A angiver at der skal tegnes en arc ud fra formlen "A radiusX radiusY grader IsLargeArc Clockwise x,y".
C angiver at der skal tegnes et beziersegment ud fra formlen "C punkt1X,punkt1Y punkt2X,punkt2Y x,y".

Alle kommandoer kan desuden skrives som lowercase hvilket bevirker at de fortolkes relativt til nuværende punkt frem for som absolute koordinater.

For at tegne den figur vi havde tidligere kan vi derfor gøre følgende.

<Path Name="Car" Stroke="Green" Canvas.Left="100" Canvas.Top="100"
 Data="M 50,50 L 100,100 A 20,20 0 0 0 150,150 C 250,300 200,50 0,0 A 20,20 0 0 0 50,50" StrokeThickness="1" />

Dette virker nok knap så intuitivt at læse, men da man nok oftest vil arbejde med et værktøj som expression blend er det smart at have en kompakt syntaks, da man derved også begrænser hvor meget ens XAML skal fylde.

Clipping ved hjælp af Geometries

Geometries kan ikke kun bruges til at tegne elementer, men også til at beskære andre elementer.  Dette gøres ved at sætte et hvilket som helst elements Clip element til et Geometry element. For eksempel kan en Ellipse beskæres af en anden ellipse således.

<Ellipse Width="250" Height="150" Fill="Orange" Stroke="Black" StrokeThickness="3">
  <Ellipse.Clip>
   <EllipseGeometry RadiusX="150" RadiusY="200" />
  </Ellipse.Clip>
 </Ellipse>

Dette giver især spændende muligheder hvis man f.eks arbejder med billeder eller video, hvor det også er muligt at benytte denne teknik. Derved kan man lade en film afspille i hvilken som helst form man kan tænke sig, eller man kan lade alle billeder på ens side blive beskåret ens så der er endnu en måde at lave et custom design på.

Tags:

Who am I?

My name is Christian Holm Diget, and I work as an independent consultant, in Denmark, where I write code, give advice on architecture and help with training. On the side I get to do a bit of speaking and help with miscellaneous community events.

Some of my primary focus areas are code quality, programming languages and using new technologies to provide value.

Microsoft Certified Professional Developer

Microsoft Most Valuable Professional

Month List