F#:类型和函数之间是否可能相互递归?

F#:类型和函数之间是否可能相互递归?,f#,mutual-recursion,F#,Mutual Recursion,我可以使用和关键字设置相互递归的函数定义。我也可以对相互递归的类型使用和,但是如果类型和函数之间存在相互递归的关系呢?我唯一的选择是使函数成为该类型的成员,还是可以在此处使用类似于和的内容 编辑:添加一个简化的伪示例,我希望它能说明我正在尝试做的事情 // A machine instruction type type Instruction = Add | CallMethod int (* method ID *) | ... // A class representing a metho

我可以使用
关键字设置相互递归的函数定义。我也可以对相互递归的类型使用
,但是如果类型和函数之间存在相互递归的关系呢?我唯一的选择是使函数成为该类型的成员,还是可以在此处使用类似于
的内容

编辑:添加一个简化的伪示例,我希望它能说明我正在尝试做的事情

// A machine instruction type
type Instruction = Add | CallMethod int (* method ID *) | ...

// A class representing a method definition
type MethodDef (fileName : string) =
    member x.Params with get () = ...
    member x.Body with get() =
        let insts = readInstructions fileName
        Array.map toAbstractInst insts

// a more abstract view of the instructions
and AbstractInstruction = AbstAdd | AbstCallMethod MethodDef | ...

// a function that can transform an instruction into its abstract form
let toAbstractInst = function
    | Add -> AbstAdd
    | CallMethod methodId -> AbstCallMethod (somehowResolveId methodId)
    | ...

因此,您可以在这里看到递归关系是非常间接地建立起来的:MethodDef AbstractInst和MethodDef->toAbstractInst->AbstractInstruction(其中->表示“依赖”)

如果没有示例,这个问题很难回答

  • 如果您有没有成员的相互递归类型,那么这些类型不需要了解函数(因此您可以先定义类型,然后定义函数)

  • 如果您有相互递归的类型,并且这些类型的函数是成员,那么这些成员可以(跨类型)看到彼此,您应该不会有问题

唯一棘手的情况是,当您拥有相互递归的类型、相互递归的函数,并且还希望将某些函数公开为成员时。然后可以使用类型扩展:

// Declare mutually recursive types 'A' and 'B'
type A(parent:option<B>) =
  member x.Parent = parent

and B(parent:option<A>) =
  member x.Parent = parent

// Declare mutually recursive functions 'countA' and 'countB'
let rec countA (a:A) =
  match a.Parent with None -> 0 | Some b -> (countB b) + 1
and countB (b:B) =
  match b.Parent with None -> 0 | Some a -> (countA a) + 1

// Add the two functions as members of the types
type A with 
  member x.Count = countA x

type B with 
  member x.Count = countB x
//声明相互递归的类型“A”和“B”
类型A(父项:选项)=
成员x.父=父
和B(父母:选择权)=
成员x.父=父
//声明相互递归的函数“countA”和“countB”
让我们算一算(a:a)=
匹配a.无的父项->0 |某些b->(计数b)+1
和countB(b:b)=
匹配无->0 |部分a->(计数a)+1的b.父项
//将这两个函数添加为类型的成员
A型
成员x.计数=计数a x
B型带
成员x.计数=计数b x
在这种情况下,您可以将
countA
countB
作为这两种类型的成员,因为这会更容易,但是如果您想将更复杂的代码编写为函数,那么这是一个选项


如果所有内容都写在一个模块中(在一个文件中),那么F#编译器将类型扩展编译为标准实例成员(因此从C#的角度看,它看起来就像普通类型)。如果您在单独的模块中声明扩展,那么它们将被编译为特定于F#的扩展方法。

多亏了Tomas,我在问题中添加了一个示例。我现在在想,尽管我不认为它在逻辑上是一个MethodDef@Keith-在这种情况下,您可以将
to abstract
设置为
MethodDef
的私有
let
-声明函数(如果未在其他任何地方使用)。对类型扩展使用这种方法也可以。我猜它也可能是
AbstractInstruction
的静态成员(例如从concreteInstruction
调用