Если вам нужно определить два типа, которые являются взаимно рекурсивными (что означает, что они могут ссылаться друг на друга), то вам нужно поместить их в один файл и использовать синтаксис type ... and ...
.
В вашем примере это означает, что Genre
и Album
должны быть определены следующим образом:
// Start a definition block using 'type' as normal
type Genre() =
let mutable name = String.Empty
let mutable albums = [new Album()]
member x.Name
with get() = name
and set (value) = name <- value
member x.Albums
with get() = albums
and set ( value ) = albums <- value
// Continue single type definition block using 'and'
and Album() =
let mutable genre = new Genre()
let mutable albumId = 0
let mutable artist = new Artist()
member x.Genre
with get() = genre
and set (value) = genre <- value
member x.AlbumId
with get() = albumId
and set ( value ) = albumId <- value
member x.Artist
with get() = artist
and set ( value ) = artist <- value
Однако ваш пример использует F # в очень C # -стиле, поэтомукод на самом деле выглядит не очень элегантно и может не дать вам многих преимуществ функционального программирования.
Если бы я хотел представить структуру, которую вы используете, то, вероятно, я бы не добавил ссылку на жанр в тип Album
.Когда вы помещаете список альбомов в Genre
, вы всегда сможете восстановить жанр при обработке структуры данных (т. Е. Превратить ее в какую-то другую структуру, например, запись F #, которую можно передать в данные).связывание).Преимущество F # в том, что он позволяет писать домен в несколько строк, но это работает только для функциональных типов.
Используя различимые союзы с одним регистром, вы можете написать:
// Type aliases to make code more readable
type Name = string
type AlbumID = int
// Simple type definitions to represent the domain
type Artist = Artist of Name
type Album = Album of AlbumID * Artist
type Genre = Genre of Name * Album list