6

キーワードを使用して、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 (ここで、-> は「依存」を意味します)

4

1 に答える 1

10

この質問は例がないと答えにくい

  • メンバーを持たない相互再帰型がある場合、型は関数について知る必要はありません (したがって、最初に型を定義してから関数を定義できます)。

  • メンバーとして関数を持つ相互に再帰的な型がある場合、メンバーは (型間で) お互いを見ることができ、問題ないはずです。

唯一のトリッキーなケースは、相互に再帰的な型、相互に再帰的な関数があり、いくつかの関数をメンバーとして公開したい場合です。次に、型拡張を使用できます。

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

この場合、簡単なので 2 つの型のメンバーを作成することもできますがcountAcountB関数として記述したいより複雑なコードがある場合は、これがオプションになります。

すべてが 1 つのモジュール (1 つのファイル) に記述されている場合、F# コンパイラは型拡張を標準のインスタンス メンバーとしてコンパイルします (したがって、C# の観点からは通常の型のように見えます)。別のモジュールで拡張機能を宣言すると、それらは F# 固有の拡張メソッドとしてコンパイルされます。

于 2011-08-13T16:21:24.100 に答える