Циклическая функция / тип зависимости в F#
У меня есть вопрос о том, как лучше поступить следующим
У меня есть класс B, у меня есть комбинатор на B, пусть foo: B -> int.
Я хочу, чтобы в классе 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 ответа
Я не думаю, что с вашим текущим дизайном что-то не так. Ключевым моментом является то, что если вы определяете тип 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 следуют этому шаблону (см., Например, определение комплексных чисел).
Я не совсем понимаю, что вы ищете, но я думаю, что это может помочь:
type foo(comb) as self =
let x = lazy(comb self)
static member something (x:foo) = 1
new() = foo(foo.something)
Тип может быть рекурсивным со своим собственным статическим членом, так что это более простой способ написания кода.