To smooth the integration, the code will have to play nice with existing .NET components written in C#, etc. To this end, I am sometimes using .NET data structures – like List<> – in places where a pure F# implementation might use list, etc. So I decided to practice with some computation expressions that mingle in these other .NET data structures.
Here is a simple example. It splits a string into a tree using various characters and string.Split. It actually does its job using side-effects on the original tree node (Neil dodges rotten tomatoes thrown by the functional programming purists.) For example, splitting the string “a.b:c.d” by colon first and then by dot would result in this tree:

And here is the code. (As always, presented "as-is" and without warranty or implied fitness of any kind; use at your own risk.)
open System.Collections.Generic
open System.Text.RegularExpressions
// This is a simple tree node// which uses List<>.// Think of it as a proxy for// some real-world problem.type Tree =
{ Text : stringmutable Children : List<Tree> option }
// Syntactic sugar.static member Make (s) =
{ Text=s; Children=None }// Splits the text in the node// using string.split and// uses it to create child nodes.let splitter (c:char) =
let a = [|c|]
let f (t:Tree) =
t.Children <- Some(new List<Tree>())
Seq.iter (fun s->t.Children.Value.Add(Tree.Make(s)))
(t.Text.Split(a,System.StringSplitOptions.None))
t
f
// This is almost like a collect,// except it works through the // side-effects in the splitter function.type TreeCollector () =
member this.Bind ((lt:Tree),
(f:Tree->Tree)) =
Seq.iter (fun t->(f t)|>ignore) lt.Children.Value
lt
member this.Return v = v
// Some tests.let splitBar = splitter '|'
let splitColon = splitter ':'
let splitDot = splitter '.'
let treeCollector = TreeCollector()
// Build a tree by bar, colon, then dot.let f0 t = treeCollector {
let! x = splitBar t
let! x = splitColon x
let! x = splitDot x
return x}
// Build a tree by colon, bar, then dot.let f1 t = treeCollector {
let! x = splitColon t
let! x = splitBar x
let! x = splitDot x
return x}
// Simple test print.let printo (t:Tree) =
let rec f s (t:Tree) =
printfn "%s %s" s t.Text
if t.Children.IsSome then
Seq.iter (f (s+" ")) t.Children.Value
f "" tlet t0 = Tree.Make("a0.a1:b0.b1|c0.c1:d0.d1")
let t1 = Tree.Make(t0.Text)
f0 t0 |> ignoref1 t1 |> ignoreprinto t0
printfn ""printo t1
printfn "Done."

No comments:
Post a Comment