如何在不限于一个文件的情况下在 F# 中实现访问者模式?

How to implement a visitor pattern in F# while not being restricted to one file?

以下代码示例演示了 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"

这编译得很好,但由于使用了 and 关键字,我们只能在一个文件中实现所有类型 IVisitable。这个关键字似乎是允许相互类型引用所必需的。

有没有一种方法可以让我们不局限于一个文件来实现这个模式?

(我不是征求您是否应该在 F# 中使用此模式的意见)

编辑:我问这个问题是因为访问者模式在与 C# 代码进行互操作时是相关的。

模式匹配应该可以用一小部分复杂性和开销实现相同的目标。以我个人的经验,这是在 F# 中实现访问者模式的最佳方式。

type Visitor = A of int | B of int

match a with 
| A x -> 1 * x
| B x -> 2 * x

然后对于一些可能的 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();
    }
}

如果您确实需要为 C# 互操作使用 OO 模式,我认为解耦类型的最佳方法是使用泛型:

module VisitorPattern =

    type IVisitor<'T> =
        abstract Visit : 'T -> unit

    type IVisitable<'T> =
        abstract InvokeVisit : IVisitor<'T> -> unit

module Visitors =

    open VisitorPattern

    type ObjectA () =
        interface IVisitable<ObjectA> with
            member this.InvokeVisit (visitor : IVisitor<ObjectA>) =
                visitor.Visit this

    type ObjectB () =
        interface IVisitable<ObjectB> with
            member this.InvokeVisit (visitor : IVisitor<ObjectB>) =
                visitor.Visit this