Reputation: 640
so i have got a type Genre with Property Name on it.
Im creating a list of Genre Names like below.
let genres = new Genre()
[ genres.Name <- "Disco";
genres.Name <- "Jazz";
genres.Name <- "Rock"; ] |>ignore
Wondering if there is more succint way of creating this ?.
Upvotes: 0
Views: 257
Reputation: 92026
Slightly more terser:
type Genre = Genre of string
let genres = List.map Genre ["Disco"; "Jazz"; "Rock"]
printfn "%A" genres
Prints [Genre "Disco"; Genre "Jazz"; Genre "Rock"]
.
Upvotes: 1
Reputation: 243041
The code in your example creates just a single Genre
object and then creates a list of unit
values. A unit
value is a bit like void
in C# - it is the result of perfroming an expression that does not return anything, but has a side-effect. In your case, the side-effect is modifying the Name
property of the single instance (that's what the <-
operator does), so you end with a single genres
value whose Name
is "Rock"
.
There are numerous ways to change the code to do what you want - to start with what you wrote:
let genre = new Genre()
genre.Name <- "Disco"
This creates a single genre
value, so you could create values genre1
, genre2
and genre3
and then turn them into a list using:
let genres = [ genre1; genre2; genre3 ]
That would be quite a lot of repetition. If you have a default constructor for Genre
that takes the name, you can just write Genre("Disco")
. If you don't, you can use F# object initialization syntax and specify the value of the property during the construction as Genre(Name="Disco")
. Note you can also omit new
if the object does not implement IDisposable
.
Now you can construct a list like this:
let genres = [ Genre(Name="Disco"); Genre(Name="Jazz"); Genre(Name="Rock") ]
Now, you can start using functional features like List.map
(as suggested by Daniel) or F# list comprehension syntax to make the construction even shorter. In this case, I would probably prefer list comprehension and I'd write:
let genres = [ for name in ["Disco"; "Jazz"; "Rock"] -> Genre(Name = name) ]
This does the same thing as List.map
, but using an F# syntax that has been designed for this purpose.
EDIT: Aside, using mutable properties in F# is not always the best way to go. You could try solving the same problem using F# records, which give you an easy way to create copies with modified properties. For example:
// A genre has a name and an era
type Genre = { Name : string; Era : string; }
// Create a template with the basic properties set
let template = { Name = "Default"; Era = "Twentieth century" }
// Create a list of 20th century genres
let genres = [ { template with Name = "Disco" }
{ template with Name = "Jazz" }
{ template with Name = "Rock" } ]
Unlike in the previous case, records are immutable and so you don't risk the confusion that is caused when you create a mutable object and then mutate it. Here, you get a list of three different objects (that are created by copying the template
).
Upvotes: 8
Reputation: 25516
I think the simplest way would be to use a construcotr which did the assignment for you, then you could write
let genres = Genre("Disco")::Genre("Jazz")::Genre("Rock")::[]
Upvotes: 2