Problem with cyclic dependencies between types and functions from different files in F#

前端 未结 1 376
终归单人心
终归单人心 2021-01-14 03:40

My current project uses AST with 40 different types (descriminated unions) and several types from this AST has cyclic dependency. The types are not so big, therefore I put

相关标签:
1条回答
  • 2021-01-14 03:55

    As mentioned in the comments, there is no way to split functions (or types) with cyclic dependencies between multiple files. Signature files are useful mainly for documentation purposes, so they won't help.

    It is hard to give some advice without knowing what exactly the dependencies are. However, it may be possible to refactor some part of the implementation using functions or interfaces. For example, if you have:

    let rec process1 (a:T1) = 
      match a with
      | Leaf -> 0
      | T2Thing(b) -> process2 b
    
    and process2 (b:T2) = 
      match b with 
      | T1Thing(a) -> process1 a
    

    You can modify the function process1 to take the second function as argument. This makes it possible to split the implementation between two files because they are no longer mutually recursive:

    // File1.fs
    let process1 (a:T1) process2 = 
      match a with
      | Leaf -> 0
      | T2Thing(b) -> process2 b
    
    // File2.fs
    let rec process2 (b:T2) = 
      match b with 
      | T1Thing(a) -> process1 a process2
    

    If you can find some more clear structure - e.g. two blocks of functions that contain logically related functions and need to access each other, then you can also define an interface. This doesn't make much sense for the example with just two functions, but it would look like this:

    type IProcess2 = 
      abstract Process : T2 -> int
    
    let process1 (a:T1) (process2:IProcess2) = 
      match a with
      | Leaf -> 0
      | T2Thing(b) -> process2.Process b
    
    let rec process2 (b:T2) = 
      let process2i = 
        { new IProcess2 with 
            member x.Process(a) = process2 a }
      match b with 
      | T1Thing(a) -> 
        process1 a process2i
    

    Anyway, these are just some general techniques. It is difficult to give a more precise advice without knowing more about the types you're working in. If you could share more details, perhaps we could find a way to avoid some of the recursive references.

    0 讨论(0)
提交回复
热议问题