F #: возможна ли взаимная рекурсия между типами и функциями? - PullRequest
6 голосов
/ 13 августа 2011

Я могу использовать ключевое слово 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 (где -> означает «зависит от»)

1 Ответ

10 голосов
/ 13 августа 2011

На этот вопрос сложно ответить без примера

  • Если у вас есть взаимно рекурсивные типы, которые не имеют членов, то типам не нужно знать о функциях (поэтому вы можете сначала определить типы, а затем функции).

  • Если у вас есть взаимно рекурсивные типы, которые имеют функции в качестве членов, то члены могут видеть друг друга (по типам), и у вас все будет в порядке

Единственный сложный случай - это когда у вас есть взаимно рекурсивные типы, взаимно рекурсивные функции, и вы также хотите представить некоторые функции в качестве членов. Тогда вы можете использовать расширения типа:

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

В этом случае вы можете просто сделать countA и countB членами двух типов, потому что это будет проще, но если у вас есть более сложный код, который вы хотите написать как функции, то это вариант .

Если все написано в одном модуле (в одном файле), то компилятор F # компилирует расширения типов как стандартные члены экземпляра (так что с точки зрения C # это выглядит как обычный тип). Если вы объявите расширения в отдельном модуле, они будут скомпилированы как специфичные для F # методы расширения.

...