F# understanding discriminated union

纵饮孤独 提交于 2021-02-19 04:35:13

问题


I've kind of asked this question earlier so sorry for asking a bit similar question again. But unfortunately im not able to really understand how to design a discriminated unions.

so i have bunch of data structures which look like



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

But now i unable to figure out how would i populate my discriminated union similarly i was doing with my simple F# types which are just properties ?.

Can someone help me to explain this ?. I have been reading on discriminated unions but wont say i fully understand them .


回答1:


Discriminated unions are used to represent types with multiple different cases, which roughly corresponds to class hierarchies in object oriented langauges. For example, a base class Shape with two inherited classes for Circle and Rectangle might be defined like this:

type Shape = 
  | Rectangle of (float * float) * (float * float) // Carries locations of two corners
  | Circle of (float * float) * float              // Carries center and diameter

The way you defined your discriminated unions does not really do what you probably intended. Your types Album, Artist and Genre represent just a single concrete type.

You can represent these with either records (which are just like lightweight classes with just properties) or using discriminated unions with a single case, which corresponds to a single class, but has a pretty lightweight syntax, which is the main benefit. For example:

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

To construct an artist together with a few albums, you can write:

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)

If you then create a genre, that will contain a list of albums and possibly a list of artists, so you could write something like this:

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

let rock = Genre("Rock", [pinkFloyd], [darkSide; finalCut])

The question now is, how do you actually want to populate the types. What is your data-source? If you're loading data from a database or from a XML file, you're probably want to write a function that takes some part of the data source and returns Artist or Album and after you load all albums and artists, wrap them inside a Genre and return that as a final result.

PS: It is a bit difficult to answer your questions, because you're not really giving a bigger picture of what you're trying to do. If you can give a small, but concrete example (including the loading of data and their use), then someone can help you to look at the problem from a more functional perspective.



来源:https://stackoverflow.com/questions/9194692/f-understanding-discriminated-union

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!