F # взаимная рекурсия между модулями - PullRequest
2 голосов
/ 25 мая 2010

Для рекурсии в F # из существующей документации ясно, как это сделать, в особом случае, когда это просто одна функция, вызывающая себя, или группа физически смежных функций, вызывающих друг друга.

Но в общем случае, когда группа функций в разных модулях должна вызывать друг друга, как вы это делаете?

Ответы [ 5 ]

7 голосов
/ 25 мая 2010

Я не думаю, что есть способ достичь этого в F #. Обычно можно структурировать приложение так, чтобы этого не требовалось, поэтому, возможно, если вы описали свой сценарий, вы можете получить несколько полезных комментариев.

В любом случае, существуют различные способы обойти проблему - вы можете объявить запись или интерфейс для хранения функций, которые вам нужно экспортировать из модуля. Интерфейсы позволяют также экспортировать полиморфные функции, поэтому они, вероятно, являются лучшим выбором:

// Before the declaration of modules
type Module1Funcs = 
  abstract Foo : int -> int
type Module2Funcs = 
  abstract Bar : int -> int 

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

module Module1 = 
  // Import functions from Module2 (needs to be initialized before using!)
  let mutable module2 = Unchecked.defaultof<Module2Funcs>

  // Sample function that references Module2
  let foo a = module2.Bar(a)

  // Export functions of the module
  let impl = 
    { new Module1Funcs with 
        member x.Foo(a) = foo a }

// Somewhere in the main function
Module1.module2 <- Module2.impl
Module2.module1 <- Module1.impl

Инициализация также может быть выполнена автоматически с использованием Reflection, но это немного уродливо, однако, если вам действительно это нужно часто, я мог бы представить для этого какую-нибудь библиотеку многократного использования.

Во многих случаях это кажется немного уродливым, и реструктуризация приложения, чтобы избежать рекурсивных ссылок, является лучшим подходом (фактически, я нахожу рекурсивные ссылки между классами в объектно-ориентированном программировании, часто довольно запутывающими). Однако, если вам действительно нужно что-то подобное, то экспорт функций с использованием интерфейсов / записей, вероятно, является единственным вариантом.

0 голосов
/ 12 октября 2018

Определенно решение здесь будет использовать сигнатуры модулей. Файл подписи содержит информацию об общедоступных сигнатурах набора элементов программы F #, таких как типы, пространства имен и модули. Для каждого файла кода F # вы можете иметь файл подписи, который имеет то же имя, что и файл кода, но с расширением .fsi вместо .fs.

0 голосов
/ 25 мая 2010

Если бы вы говорили о C # и методах в двух разных сборках, необходимых для взаимно рекурсивного вызова друг друга, я бы вытащил сигнатуры типов, которые они оба должны были знать, в третью общую сборку. Однако я не знаю, насколько хорошо эти концепции соответствуют F #.

0 голосов
/ 25 мая 2010

Я не думаю, что функции в разных модулях могут напрямую ссылаться на функции в других модулях. Есть ли причина, по которой функции, чье поведение так тесно переплетено, должны находиться в отдельных модулях?

Если вам нужно держать их разделенными, один из возможных обходных путей состоит в том, чтобы сделать ваши функции более высокого порядка, чтобы они принимали параметр, представляющий рекурсивный вызов, чтобы вы могли позже вручную «связать узел».

0 голосов
/ 25 мая 2010

Это не поддерживается. Одним из доказательств этого является то, что в Visual Stuido вам нужно правильно упорядочить файлы проекта для F #.

Было бы очень редко recursively вызывать две функции в двух разных модулях.

Если этот случай случится, вам лучше выделить общую часть двух функций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...