The following code sample demonstrates an implementation of the visitor pattern in F#
module VisitorPattern
type IVisitor =
abstract Visit : ObjectA -> unit
abstract Visit : ObjectB -> unit
and IVisitable =
abstract InvokeVisit : IVisitor -> unit
and ObjectA =
interface IVisitable with
member this.InvokeVisit (visitor: IVisitor) =
visitor.Visit(this)
and ObjectB =
interface IVisitable with
member this.InvokeVisit (visitor: IVisitor) =
visitor.Visit(this)
type MyVisitor =
member this.Visit (a : ObjectA) =
printfn "Visited object A"
member this.Visit (b : ObjectB) =
printfn "Visited object B"
This compiles fine, but we are limited to have all the types implementing IVisitable
in one file, due to the use of the and
keyword. This keyword seems to be necessary to allow for the mutual type references.
Is there a way to implement this pattern in such a way that we are not restricted to one file?
(I'm not asking for opinions on whether you should use this pattern in F#)
EDIT: I'm asking this question because the Visitor Pattern is relevant when doing interop with C# code.
Pattern matching should accomplish the same goal with a fraction of the complexity and overhead. In my personal experience this is the best way to implement a visitor pattern in F#.
type Visitor = A of int | B of int
match a with
| A x -> 1 * x
| B x -> 2 * x
then for some possible C#
private static void Main()
{
Visitor a = Visitor.A(7)
switch(a){
case Visitor.A x:
x.Item * 1;
break;
case Visitor.B x:
x.Item * 2;
break;
default:
throw new ArgumentOutOfRangeException();
}
}