Как уже упоминалось в комментариях, нет способа разделить функции (или типы) с циклическими зависимостями между несколькими файлами. Файлы подписей полезны в основном для целей документирования, поэтому они не помогут.
Трудно дать какой-то совет, не зная, каковы именно зависимости. Однако может оказаться возможным рефакторинг некоторой части реализации с использованием функций или интерфейсов. Например, если у вас есть:
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
Вы можете изменить функцию process1
, чтобы принять в качестве аргумента вторую функцию. Это позволяет разделить реализацию между двумя файлами, поскольку они больше не являются взаимно рекурсивными:
// 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
Если вы можете найти более четкую структуру - например, два блока функций, которые содержат логически связанные функции и нуждаются в доступе друг к другу, тогда вы также можете определить интерфейс. Это не имеет большого смысла для примера с двумя функциями, но это будет выглядеть так:
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
Во всяком случае, это всего лишь некоторые общие приемы. Трудно дать более точный совет, не зная больше о типах, с которыми вы работаете. Если бы вы могли поделиться более подробной информацией, возможно, мы могли бы найти способ избежать некоторых рекурсивных ссылок.