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 : string
mutable 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 "" t
let t0 = Tree.Make("a0.a1:b0.b1|c0.c1:d0.d1")
let t1 = Tree.Make(t0.Text)
f0 t0 |> ignore
f1 t1 |> ignore
printo t0
printfn ""
printo t1
printfn "Done."
No comments:
Post a Comment