0

I am trying to represent a tree data-structure in F# using the following type:

type Node = 
 val mutable left: Node option
 val mutable right: Node option
 val mutable value: int 

 new (l, r, v) = {left = l; right = r; value = v}

I can create a tree like this:

let root = new Node (Some (new Node (None, None, 2)), Some (new Node (None, None, 3)), 1)

I now want to traverse using pattern matching. However, i dont know how to pattern match objects. I tried something like this:

let rec traverse r =
  match r with
  | Node (None, None, v) -> printfn "%d" v

and stopped right there because the pattern-matching is wrong.

EDIT: After Petricek's answer, I did not use all his suggestions because I haven't read about discriminated unions and other class features yet. I will implement once i know more about these things. But for time-being, this is how it looks:

type Node = 
 val left: Node option
 val right: Node option
 val value: int 

 new (l, r, v) = {left = l; right = r; value = v}

let (|Node|) (nd: Node) = (nd.left, nd.right, nd.value)

let root = new Node (Some (new Node (None, None, 2)), Some (new Node (None, None, 3)), 1)

let rec traverseLRtR r =
  match r with
  | Node (None, None, v) -> printfn "%d" v
  | Node (left, right, v) -> traverseLRtR left.Value; traverseLRtR right.Value; printfn "%d" v; 

traverseLRtR root

Output is:

2
3
1
badmaash
  • 4,775
  • 7
  • 46
  • 61

1 Answers1

3

Your Node type needs to provide members for reading the left and right fields. The most idiomatic F# way to write such object is to use:

type Node(left:Node option, right:Node option, value : int) =
  member x.Left = left
  member x.Right = right 

I removed the mutable attribute on the fields, because you were not mutating them in your example (but you can use get & set properties to make them mutable, if that's what you want). I also changed the code to use implicit constructor syntax, which is simpler.

As a next step, you can write an active pattern that returns the component of a node:

 let (|Node|) (nd:Node) = (nd.Left, nd.Right)

However, is there any reason (i.e. C# compatibility) why you do not use F# discriminated union? This way, you can define tree data structure really easily and you get pattern matching for free:

type Node = Node of Node option * Node option * int

Then you can construct nodes by writin Node(None, Some ..., 42) and pattern match on them using the pattern you wrote.

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553