【问题标题】:F#: is mutual recursion between types and functions possible?F#:类型和函数之间可以相互递归吗?
【发布时间】:2011-08-13 16:12:43
【问题描述】:

我可以使用and 关键字来设置相互递归的函数定义。我也可以将and 用于相互递归的类型,但是如果类型和函数之间存在相互递归的关系怎么办?我唯一的选择是让函数成为该类型的成员还是我也可以在这里使用类似于and 的东西?

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

// 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 AND MethodDef -> toAbstractInst -> AbstractInstruction(其中 -> 表示“依赖于”)

【问题讨论】:

    标签: f# mutual-recursion


    【解决方案1】:

    这个问题没有例子很难回答

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

    • 如果你有相互递归的类型,作为成员的函数,那么成员可以看到彼此(跨类型),你应该没问题

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

    // 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
    

    在这种情况下,你可以让countAcountB 成为这两种类型的成员,因为这样会更容易,但如果你有更复杂的代码想要编写为函数,那么这是一个选项.

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

    【讨论】:

    • 感谢 Tomas,我在我的问题中添加了一个示例。我现在在想最好只让 toAbstractInst 成为成员,即使我认为它在逻辑上不是 MethodDef 的成员
    • @Keith - 在这种情况下,您可以使 toAbstractInst 成为 let 的私有函数 - MethodDef 的声明函数(如果它没有在其他任何地方使用)。使用带有类型扩展的方法也可以。我猜它也可能是AbstractInstruction 的静态成员(例如FromConcreteInstruction
    猜你喜欢
    • 1970-01-01
    • 2017-06-19
    • 1970-01-01
    • 2012-02-08
    • 2011-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-11
    相关资源
    最近更新 更多