Я думаю, что определение типа только с помощью type somename
не будет работать в F #.Компилятору F # необходимо сгенерировать некоторый тип .NET из объявления, а спецификация F # не определяет явно, что должно происходить для фантомных типов.
Вы можете создать конкретный тип (например, с type somename = ReadOnlyDummyValue
) в реализациифайл (.fs) и скрыть внутренности типа, просто добавив type somename
в файл интерфейса (.fsi).Таким образом, вы приближаетесь к фантомному типу - пользователь вне файла не увидит внутренности этого типа.
Другой привлекательной альтернативой будет использование интерфейсов.Это звучит логично для меня, потому что пустой интерфейс, вероятно, самый простой тип, который вы можете объявить (и он не вводит никаких фиктивных идентификаторов).Пустой интерфейс выглядит следующим образом:
type CanRead = interface end
type CanWrite = interface end
В данном случае интересно то, что вы также можете создавать унаследованные интерфейсы:
type CanReadWrite =
inherit CanRead
inherit CanWrite
Затем вы можете написать функцию, которая может приниматьзначения типа Ref<CanRead, int>
, но также и значения типа Ref<CanReadWrite, int>
(поскольку эти значения также поддерживают чтение):
let foo (arg:Ref<#CanRead, int>) = // ...
Это кажется чем-то полезным.На самом деле мне было бы интересно, можно ли это сделать и в OCaml (потому что он опирается на поддержку F # для интерфейсов и наследования).