I want to explicitly provide type parameters when I instantiate a generic record. To put in in another words, given a RecordType<'T1, 'T2, 'T3>, I want create an instance of RecordType<'T1, 'T2, 'T3> with some fixed 'T1, 'T2 and 'T3 by specifying those generic parameters. Is there a way to do that in F#?
I see three cases where it's useful:
Instantiating a record when there's more than one generic type with the same name
Assume that we have following record definitions:
type SimpleGenericRecord<'T1, 'T2> = {
    f1 : 'T1 -> 'T2
}
type SimpleGenericRecord<'T> = {
    f1 : 'T -> 'T
}
I easily construct instances of SimpleGenericRecord<'T> which was
defined last:
let record = {
    f1 = fun (x: int) -> 0
} 
let record1 = {
    SimpleGenericRecord.f1 = fun (x: int) -> 0
}
Following attempts to create SimpleGenericRecord<int, int> give
compile errors:
let record2 = {
    SimpleGenericRecord<int, int>.f1 = fun (x: int) -> 0
}
let record3 = {
    SimpleGenericRecord<_, _>.f1 = fun (x: int) -> 0
}
I know that having the same record name for two types might be not the best idea, nevertheless, I think that language should give me a way to use both types.
Documenting record types
F# reference says:
Don't use the DefaultValue attribute with record fields. A better approach is to define default instances of records with fields that are initialized to default values and then use a copy and update record expression to set any fields that differ from the default values.
Following that piece of advice, I would like to define default instances of records and, since they are part of a public API, document their types.
Helping in type inference
Generic parameters of a record type could be used to infer types of record's values.
Assume that I have:
type RecordWithSomeComplexType<'T> = {
    t1 : int -> System.Collections.Generic.Dictionary<int, 'T> // some long type signature
}
and I want to instantiate it. If I don't provide any type annotations, record values will be as as general as possible, e.g.
let record4 = {
    RecordWithSomeComplexType.t1 = failwith "Intentionally failing"
}
has type
int -> System.Collections.Generic.Dictionary<int, obj>
I can force a record to be of a certain type (e.g. RecordWithSomeComplexType<string>), but in that case I need to write full type of certain value, e.g.
let failing = {
    RecordWithSomeComplexType.t1 = 
        failwith "Intentionally failing"  :> int -> System.Collections.Generic.Dictionary<int, string> 
        // I don't want to provide a full type of a value here
}
If compiler knew that I want to RecordWithSomeComplexType<string>, it could infer value's signature.
You can add type annotation pretty much anywhere
let record2 : SimpleGenericRecord<_, _> = {
    f1 = fun (x: int) -> 0
}
// alternative
let record2 =
  ({
    f1 = fun (x: int) -> 0
  } : SimpleGenericRecord<_, _>)
And for the longer case you can write an alias type to ease things
type Alias<'T> = int -> System.Collections.Generic.Dictionary<int, 'T>
let record4 = {
  t1 = (failwith "Intentionally failing" : Alias<string>)
}
Note that record4 evaluation will raise the exception instantly because it isn't delayed
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With