Έχουν δημοσιευτεί
Κυριακή, 27 Σεπτεμβρίου 2009 2:54 μμ
από το μέλος
PALLADIN
Ένα από τα πολύ δυνατά χαρακτηριστικά μιας functional γλώσσας, είναι η δυνατότητα να δημιουργούμε internal DSLs κάνοντας compose combinators.
Ένα τέτοιο παράδειγμα, είναι μια regex engine που έγραψα σε F#.
Κάποιες βασικές ιδέες της υλοποίησης:
- lazy computations for backtracking
- combinators for regex composition
- parametric polymorphism: Generic "named capture variables" and input sequences
- Unions + Active Patterns: pattern matching and value extraction
Ακολουθεί ένα sample
#r "FSharp.PowerPack.dll"
#load "RegEx.fs"
open System
open RegEx
// example from http://www.martinfowler.com/bliki/ComposedRegex.html
type extractTags = NumberOfPoint of int | NumberOfNights of int | HotelName of string
let numberOfPoints = toInt >> NumberOfPoint
let numberOfNights = toInt >> NumberOfNights
let hotelName = toString >> HotelName
let scoreKeyword() = string "score" => !+ space()
let numberOfPoints = !+ digit() |> group numberOfPoints
let forKeyword() = space() => string "for" => space()
let numberOfNights = !+ digit() |> group numberOfNights
let nightsAtKeyword() = spaces() => string "nights" => spaces() => string "at" => spaces()
let hotelName() = !+ any() |> group hotelName
let pattern = scoreKeyword() => numberOfPoints => forKeyword() => numberOfNights => nightsAtKeyword() => hotelName() => endOfLine()
let text = List.reduce (fun acc value -> acc + "\r\n " + value)
[ "score 400 for 2 nights at Minas Tirith Airport";
"score 500 for 6 nights at Athens Airport";
"score 200 for 3 nights at London Airport" ] + "\r\n"
let result = patternMatch pattern text
// pattern match
match result with
| Success ( (NumberOfPoint(points) :: NumberOfNights(nights) :: HotelName(name) :: _) :: _ ) -> printfn "Points: %d, Nights %d, Hotel name: %s" points nights name
| Failure -> ()
let replacePattern = function
| [NumberOfPoint(points); NumberOfNights(nights); HotelName(name)] -> sprintf "score %d for %d nights at %s" (points * 2) (nights * 3) (name + " ok")
| _ -> failwith "Expected extraction pattern: score {NumberOfPoint} for {NumberOfNights} nights at {HotelName}"
let replacedResult = patternReplace pattern text replacePattern |> Array.of_seq |> (fun (chars : array<char>) -> new String(chars))