F #: is mutual recursion between types and functions possible?

I can use the and keyword to configure mutually recursive function definitions. I can also use and for mutually recursive types, but what if there is a mutually recursive relationship between the type and the function? Is my only way to make a member a member of this type, or can I use something similar to and here too?

Edit: adding a simplified pseudo-example that I hope illustrates what I'm trying to do

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

So, you can see here that the recursive relationships are established quite indirectly: MethodDef ↔ AbstractInst AND MethodDef → toAbstractInst → AbstractInstruction (where → means "depends on")

+6
source share
1 answer

This question is hard to answer without an example.

  • If you have mutually recursive types that have no members, then the types do not need to know about functions (so you can define types first and then functions).

  • If you have mutually recursive types that have functions as members, then the members can see each other (by type), and you should be fine

The only difficult case is when you have mutually recursive types, mutually recursive functions, and you also want to expose some functions as members. Then you can use type extensions:

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

In this case, you can simply make countA and countB members of two types, because it would be easier, but if you have more complex code that you want to write as functions, then this is an option.

If everything is written in one module (in one file), the F # compiler compiles type extensions as standard instance members (so that it looks just like a regular type from the point of view of C #). If you declare extensions in a separate module, they will be compiled as F # -specific extension methods.

+10
source

Source: https://habr.com/ru/post/894982/


All Articles