Задержка реализации методов интерфейса?

Я программировал в F # в течение нескольких лет, и там "проблема", которая беспокоила меня в течение некоторого времени, и я не смог ее решить. Это не ошибка, я думаю, что это дизайнерское решение, но в любом случае проблема заключается в следующем: есть ли способ задержать (может быть, это не правильное слово для этого) реализацию интерфейсов?, то есть не выполнять их в начальном определении, но позже, возможно, в том же файле после того, как я внедрил модуль для типа. Я объясню с упрощенным примером: Предположим, что у меня есть следующая структура данных:

    type 'T MyCollection =
        (*type definition*)
        interface IEnumerable<'T> with
            member this.GetEnumerator () =
                (* I don't want to implement it here 
                   because I still don't have the module
                   with a toSeq function *)

Если бы я реализовал метод прямо там, мне пришлось бы также реализовать все функции как методы этого типа, а затем модуль был бы просто "прокси" для вызова методов. Таким образом, я создаю структуру данных OO-first, а затем создаю модуль (перегруженный аннотациями типа), чтобы обеспечить функциональное использование. Я бы предпочел написать функционально-первую структуру данных (более чистую, так как вывод типа может работать лучше), а затем создать OO-оболочку, чтобы обеспечить лучшую поддержку intellisense для таких языков, как С#. Этот подход соответствует тому, что нам предлагает руководство по проектированию для F #, но интерфейсы не могут быть реализованы нигде, кроме первоначального определения типа. Это ограничение заставляет меня написать всю структуру данных с членами. Я искал примеры, и я обнаружил, что реализация списка в FSharp.Core list делает именно то, что я хочу, но я не могу этого сделать. компилятор мне не позволит. Я почти уверен, что это дизайнерское решение, возможно, чтобы не поощрять плохие практики, я не знаю, но я не считаю свое желание быть плохой практикой. Также я хорошо знаю линейную природу компилятора fsharp.

Пожалуйста, если кто-то из вас знает, как делать то, что я хочу, я буду рад, если вы скажете мне. Кроме того, если кто-то из вас знает, почему я не должен следовать этому подходу, я тоже буду рад узнать. Должна быть причина, почему это не проблема для кого-либо еще.

Спасибо заранее.

Ответ 1

Я полностью согласен с тем, что это неудачная проблема. Трюк, который используется в исходном коде 'a list в библиотеке F # Core, заключается в определении реализации интерфейса в расширении типа. Компилятор не жалуется, когда вы добавляете членов к типу таким образом, но он говорит, что добавление реализации интерфейса таким образом устарело. Однако это не мешает вам это делать. Следующие компиляции отлично подходят для меня:

open System.Collections
open System.Collections.Generic

type MyCollection<'T> =
  { Data : 'T list }
  interface IEnumerable<'T> 
  interface IEnumerable 

let getEnumerator { Data = d } = 
  (d :> seq<_>).GetEnumerator()

type MyCollection<'T> with 
  interface IEnumerable<'T> with
    member this.GetEnumerator() = getEnumerator this
  interface IEnumerable with
    member this.GetEnumerator() = (getEnumerator this) :> _

То, что это устарело, немного неудачно. Мне очень нравится этот стиль, и я использую его, когда это имеет смысл. Вы можете начать обсуждение этого вопроса на голосовании пользователя F # и, возможно, его можно вернуть в обычную принятую функцию: -)