Циклическая функция / тип зависимости в F # - PullRequest
2 голосов
/ 06 апреля 2011

У меня вопрос о том, как лучше поступить следующим образом:

У меня есть класс B, у меня есть комбинатор на B, пусть foo: B -> int.

IЯ хочу, чтобы в классе B комбинатор был инкапсулирован как метод, поэтому я добавляю его с расширением типа.

Позже я потом осознаю, что foo довольно дорогой, и хочу кешировать его результат с помощью отложенной оценки

Поэтому я добавляю в систему огромное сцепление, передавая комбинатор как функцию конструктору, а затем инициализируя поле с помощью foo = lazy (foo self) в конструкторе.

т.е.

type foo =
    class
        val x : int Lazy

         new (comb) as self = {x=lazy(comb self);}
     end
 let something (x:foo) = 1

 type foo with
      new() = foo(something)

это, очевидно, кажется неправильным

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

Ни один из них не очень привлекателен, и мне было интересно, пропустил ли я опцию 3

О, и у меня нетбылов состоянии получить let rec и работать с этим совершенно правильно, и я бы не хотел, чтобы «что-то» в вышеприведенном утверждении зависело от функции, которая зависит от функции, которая зависит от функции (глубиной 3).

любой совет был бы оценен

Ответы [ 2 ]

3 голосов
/ 06 апреля 2011

Не думаю, что с вашим текущим дизайном что-то не так. Ключевым моментом является то, что если вы определяете тип Foo, а также расширение для типа в том же файле (и в том же модуле), то F # объединит две части определения в один тип .NET. Таким образом, тот факт, что он определен в двух отдельных частях, является лишь деталью реализации.

Если вы не хотите показывать конструктор, который принимает комбинатор, вы можете пометить его как private. Вместе с несколькими дополнительными изменениями (то есть с использованием неявного синтаксиса конструктора) фрагмент будет выглядеть следующим образом:

type Foo private (comb) as self =
  let x : Lazy<int> = lazy comb self

let something (x:Foo) = 1

type Foo with
  new() = Foo(something)

Если вы хотите сохранить something как отдельную функцию, то это хорошее решение. Многие числовые типы в F # PowerPack следуют этому шаблону (см., Например, определение комплексных чисел )

2 голосов
/ 06 апреля 2011

Я не совсем понимаю, что вы ищете, но я думаю, что это может помочь:

type foo(comb) as self =
    let x = lazy(comb self)
    static member something (x:foo) = 1 
    new() = foo(foo.something)

Тип может быть рекурсивным с собственным статическим членом, так что это более простой способ написания кода.

...