F# interaktiv, pattern matching og active patterns

by DotNetNerd 23. February 2008 17:46

Interaktiv eksekvering

Interaktiv eksekvering er en feature som F# tilbyder der giver mulighed for at afvikle kode som scripts. Dette giver mulighed for at skrive kode på en behagelig måde, hvor man undgår hele tiden at skulle igennem en kode-compile-run cyklus. En almindeligt anvendt teknik er at anvende en scriptfil som "scratch pad", hvor man kan teste små stykker kode løbende.

For at udnytte dette skal man blot åbne F# interactive igennem Tools -> Add-in Manager og lave en fsx fil. Her skriver man så sin kode og når der er en del man ønsker at eksekvere markerer man den og trykker Alt + Enter. Dette gør at man meget hurtigt kan teste sin kode, uden at skulle compile, sætte et breakpoint og debugge indtil man er fremme til det sted i koden man er interesseret i.

Pattern matching

En interessant ting man kan starte ud med at prøve af - f.eks i F# interactive - er pattern matching, som er en feature der ikke er set før i .NET sprog, men som findes i andre miljøer. Pattern matching giver en meget kompakt måde at styre program flow på, lidt i stil med at bruge case sætninger i struktur, men langt mere anvendeligt og kraftfuldt.  Et super simpelt eksempel kan være at man gerne vil afvikle noget kode ud fra hvad værdi en streng har:

let value = "a"

match value with
| "a" -> printfn "The value was an a"
| "b" -> printfn "The value was a b"
| _ -> failwith "Unknown value"

Som det fremgår er syntaksen meget kompakt, og let at læse. Underscoren i den sidste linie betyder at hvilken som helst anden værdi vil blive håndteret, lidt ligesom default i en case hvis man vil sammenligne det med noget man kender fra C#/VB. En vigtig ting man skal vide er at et pattern match altid skal være udtømmende. Det vil sige at det samlet set skal kunne håndtere alle mulige værdier for at det validerer. Desuden afvikles koden ved at værdien matches imod mønstret linie for linie indtil der findes et match. Så hvis man laver et match der udelukker et efterfølgende vil man få en warning idet koden aldrig vil kunne blive ramt.

En anden anvendelse af pattern matching er til at opløst tubler som ses herunder. Nu begynder vi at komme ud i nogen scenarier der viser at pattern matching er mere anvendelige end case sætninger, og at de er stærke i samspil med funktionelle data strukturer.

let value = ("b", "a")

match value with
| ("a", "b") -> printfn "The values were a and b"
| ("b", _) -> printfn "The first value was b"
| _ -> failwith "Unknown value"

Der kan matches på mange forskellige måder men en anden meget anvendt operator :? gør det muligt at matche på typer. Her er det dog vigtigt også at bemærke at dette kræver en box operation, som der fremgår.

let value = "2"

match box value with
| :? System.Int32 -> printfn "The values was an integer"
| :? System.String -> printfn "The value was a string"
| _ -> failwith "Unknown value"

Active patterns

Active patterns er en teknik der gør det muligt at skrive mere advancerede patterns til brug sammen med mere komplekse datastrukturer eller til at lave mere komplek matching. I eksemplet herunder ses et active pattern der matcher ud fra et regular expression og returnerer en option sequence af de værdier der blev matchet ved at eksekvere det angivne regex.

let (|ParseRegex|_|) regex str =
  let regex = new System.Text.RegularExpressions.Regex(regex)    
  let matches = regex.Matches(str)    
  if matches.Count > 0 then        
    Some { for x in matches -> x.Value }    
  else        
    None

Dette active pattern kan derefter bruges på følgende måde sammen med pattern matching til eksempelvis at udskrive alle tal i en streng. Underscoren i deklerationen af dette active pattern betyder at mønstret er ufuldkomment, hvilket vil sige at det kan returnere None.

let PrintNumbers str =
  match str with
  | ParseRegex "\d" st -> Seq.iter(fun x -> printfn "Number found: %s" x) st
  | _ -> printfn "No numbers"

PrintNumbers "b123"

Alternativt kan active patterns bruges over eksempelvis discriminated unions. Et meget anvendt eksempel rundt omkring på nettet har været et discriminated union over et binært træ. Eksemplet kan ses herunder og det representerer helt enkelt et træ, hvor hvert element kan være enten en knude eller et blad - hvor knuder består af 2 elementer.

type BinaryTree<'a> =    
  | Leaf of 'a    
  | Node of BinaryTree<'a> * BinaryTree<'a>

Udfra dette kunne et active pattern eksempelvis bruges til at returnere om en XmlNode er en node eller et blad.

let (|Node|Leaf|) (node : #System.Xml.XmlNode) =    
  if node.HasChildNodes then        
    Node (node.Name, { for x in node.ChildNodes -> x })    
  else        
    Leaf (node.InnerText)

Dette kunne så bruges til at lave forskellige matches, og eksempelvis rekursivt udskrive noderne indenteret ligesom i xml dokumentet.

let PrintXml node =    
  let rec PrintXml indent node =        
    match node with        
    | Leaf (text) -> printfn "%s%s" indent text        
    | Node (name, nodes) ->            
      printfn "%s%s:" indent name            
      nodes |> Seq.iter (PrintXml (indent + "    "))    
  PrintXml "" node

Givet et xml dokument over ansatte i en lille IT virksomhed kunne man så benytte funktionen til at udskrive indholdet pænt sådan her.

let doc =    
  let xmlDoc = new System.Xml.XmlDocument()    
  let text = "
<employees>    
  <programmers>
    <junior>10</junior>
    <senior>8</senior>
  </programmers>
  <designers>3</designers> 
</employees>"
  xmlDoc.LoadXml(text)    
  xmlDoc
PrintXml (doc.DocumentElement :> System.Xml.XmlNode)

Tags:

Feed-Me.dk release og Lang.NET inspiration

by DotNetNerd 22. February 2008 19:49

Feed-me.dk release 

Det seneste års tid er jeg i stor stil røget med på rss bølgen, og er begyndt at abonnere på en række feeds for at følge med i diverse nyheder - især inden for .NET udvikling. Jeg er dog tit løbet på det problem at der er feeds som indimellem indeholder nogle virkelig interessante indlæg, men som desværre hovedsageligt drukner i personlige historier, som jeg er knap så interesseret i. Jeg har derfor nu lavet en service som jeg stiller gratis til rådighed på http://www.feed-me.dk, hvor det er mulige at sammensætte et feed der er kombineret af andre feeds, og filtreret ud fra nøgleord man indtaster som har ens interesse. Man kan desuden selv vælge om man vil have feedet i RSS eller Atom format, ved at angive dette som en del af url'en i et REST format. Eksempelvis har jeg lavet et udviklings feed som kan ses her: http://www.feed-me.dk/feed.svc/UdviklingsDemo/rss - hvor url'en viser at det sammensatte feed er navngivet UdviklingsDemo og at jeg vil se den i rss format.

Da servicen er gratis håber jeg at brugerne er så flinke at holde øje med mine google reklamer, og klikker på dem de synes er interessante, og eventuelt bruge den søgebar jeg har inkluderet i bunden. Ideen er at jeg vil give 20% af de penge jeg eventuelt tjener til kræftens bekæmpelse, idet det er en sygdom jeg selv har haft tæt inde på livet. Skulle du finde servicen interessant men synes der mangler en eller anden feature må du meget gerne skrive om dit ønske, da jeg gerne udvider den. Som det tydeligt fremgår af siden er jeg ikke den store designhaj, men pointen er også klart at lave en teknisk velfungerende løsning, så det er heller ikke mange minutter der er spildt på design.

Lang.NET

En af de nyheder jeg senest er faldet over ved at abonnere på blogs rundt omkring er, at der for nylig blev afholdt Lang.NET symposium (http://langnetsymposium.com/talks.asp), hvorfra der er udgivet en række interessante webcasts. En af de casts jeg især synes var interessant var Eric Meijer der talte om Volta. Jeg synes det er et virkeligt interessant eksperiment, og håber da meget det kan udvikle sig til et alternativ til den måde man udvikler applikationer på idag. Kort fortalt går Volta ud på at man koder en applikation som single tier, og vilta frameworket kan så ved hjælp af MSIL rewriting splitte applikationen i flere lag, lave asynchronous kald og sørge for at oversætte koden så den kan afvikles i det miljøet tilbyder i et givent scenarie. Noget der især virker som sort magi på mig er tanken om at frameworket kan omdanne kode i et CLR sprog til javascript - dette har naturligvis sine begrænsninger men er alligevel ganske fascinerende.

Udover Volta var der også andre interessante taler af blandt andet danske Anders Hejlsberg, der talte om C# 3.0 og kort kommer ind på nogen af de ting de har på tegnebrættet til version 4.0 eller hvad den nu kommer til at hedde. Også F# som jeg har rodet lidt med i fritiden her på det sidste var der et par taler omkring - hvor den ene dog mest omhandlede parsere og leksere, som er en af de ting F# tilbyder nogle specielle features til at understøtte.

Tags: , ,

Who am I?

My name is Christian Holm Nielsen, 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.

Month List