F#理解歧视联盟

net*_*x01 2 f#

我之前有点问过这个问题,很抱歉再次提出类似的问题.但不幸的是,我无法真正理解如何设计一个受歧视的工会.

所以我有一堆看起来像的数据结构

type Artist( artistId : int, name : String ) = do if name = null then nullArg String.Empty new(artistId: int) = Artist(artistId) member x.ArtistId = artistId member x.Name = name

and Genre() = let mutable name = String.Empty let mutable genreId : int = 0 let mutable description = String.Empty let mutable albums = List.empty member x.Description with get() = description and set( value ) = description <- value
member x.Albums with get() = albums and set ( value ) = albums <- value

and Album() = let mutable title = String.Empty let mutable albumId = 0 let mutable genreId = 0 let mutable artistId = 0 let mutable price : decimal = Decimal.Zero let mutable albumArtUrl = String.Empty let mutable genre = new Genre() let mutable artist = new Artist(artistId) member x.Title with get() = title and set (value) = title <- value member x.Genre with get() = genre and set (value) = genre <- value member x.AlbumId with get() = albumId and set ( value ) = albumId <- value member x.GenreId with get() = genreId and set ( value ) = genreId <- value member x.ArtistId with get() = artistId and set ( value ) = artistId <- value member x.Price with get() = price and set ( value ) = price <- value member x.AlbumArtUrl with get() = albumArtUrl and set ( value ) = albumArtUrl <- value member x.Artist with get() = artist and set ( value ) = artist <- value

enter code here

I tried defining the above as a Discriminated union based on suggestions by some of F# guru's

which i defined like below

type Name = string type AlbumId = int

type Artist = | ArtistId of int | Artist of Name

type Album = | Title of string | Price of decimal | Album of AlbumId * Artist | AlbumArtUrl of string

type Genre = | GenreId of int | Genre of Name * Album list

enter code here
Run Code Online (Sandbox Code Playgroud)

但现在我无法弄清楚我将如何填充我的歧视联盟同样地使用我的简单F#类型,这只是属性?

有人可以帮我解释一下吗?我一直在阅读有歧视的工会,但不会说我完全理解它们.

Tom*_*cek 7

被区分的联合用于表示具有多个不同情况的类型,其大致对应于面向对象语言中的类层次结构.例如,基类Shape具有两个继承的类CircleRectangle可能这样被定义:

type Shape = 
  | Rectangle of (float * float) * (float * float) // Carries locations of two corners
  | Circle of (float * float) * float              // Carries center and diameter
Run Code Online (Sandbox Code Playgroud)

你定义你受歧视的工会的方式实际上并不是你想要的.你的类型Album,ArtistGenre表示只是一个单一的具体类型.

您可以使用任一记录(这些记录就像具有属性的轻量级类)或使用具有单个案例的区分联合来表示这些,这对应于单个类,但具有非常轻量级的语法,这是主要的好处.例如:

type Name = string  
type Price = decimal
type AlbumId = int  
type ArtistId = int  

type Artist = Artist of ArtistId * Name 
type Album = Album of AlbumId * Name * Price * Artist
Run Code Online (Sandbox Code Playgroud)

要与几张专辑一起构建艺术家,您可以写道:

let pinkFloyd = Artist(1, "Pink Floyd")

let darkSide = Album(1, "The Dark Side of the Moon", 12.0M, pinkFloyd)
let finalCut = Album(2, "The Final Cut", 11.0M, pinkFloyd)
Run Code Online (Sandbox Code Playgroud)

如果你然后创建一个类型,它将包含一个专辑列表和可能的艺术家列表,所以你可以写这样的东西:

type Genre = Genre of Name * Artist list * Album list 

let rock = Genre("Rock", [pinkFloyd], [darkSide; finalCut])
Run Code Online (Sandbox Code Playgroud)

现在的问题是,你如何真正想要填充类型.你的数据来源是什么?如果您正在从数据库或XML文件加载数据,您可能想要编写一个函数来获取数据源的某些部分并返回,Artist或者Album在您加载所有相册和艺术家之后,将它们包装在一个Genre并返回这是最后的结果.

PS:回答你的问题有点困难,因为你并没有真正全面了解你想要做的事情.如果您可以提供一个小的但具体的示例(包括加载数据及其使用),那么有人可以帮助您从更具功能性的角度来看待问题.

  • @ netmatrix01如果你想使用相互递归的类型,那么你通常需要变异和类.但是,如果你的"专辑"存储在"流派"中,你真的需要将"专辑"的引用存储到"流派"吗?当您列出指定类型的专辑时,您将始终知道类型名称.同样,当您显示特定相册时,如果您浏览对象结构,您将始终知道该类型.所以,我想我可能会尝试避免这种应用程序中的递归结构. (3认同)