Tom*_*ski 4 generics f# algebraic-data-types
我想在实例化通用记录时显式提供类型参数.换句话说,给定一个RecordType<'T1, 'T2, 'T3>,我想创建一个RecordType<'T1, 'T2, 'T3>具有一些固定的实例'T1,'T2并'T3通过指定那些通用参数.有没有办法在F#中做到这一点?
我看到三个有用的案例:
当具有多个具有相同名称的泛型类型时实例化记录
假设我们有以下记录定义:
type SimpleGenericRecord<'T1, 'T2> = {
f1 : 'T1 -> 'T2
}
type SimpleGenericRecord<'T> = {
f1 : 'T -> 'T
}
Run Code Online (Sandbox Code Playgroud)
我很容易构造SimpleGenericRecord<'T>最后定义的实例:
let record = {
f1 = fun (x: int) -> 0
}
let record1 = {
SimpleGenericRecord.f1 = fun (x: int) -> 0
}
Run Code Online (Sandbox Code Playgroud)
在尝试创建SimpleGenericRecord<int, int>给出编译错误之后:
let record2 = {
SimpleGenericRecord<int, int>.f1 = fun (x: int) -> 0
}
let record3 = {
SimpleGenericRecord<_, _>.f1 = fun (x: int) -> 0
}
Run Code Online (Sandbox Code Playgroud)
我知道对于两种类型具有相同的记录名称可能不是最好的想法,但是,我认为该语言应该给我一种使用这两种类型的方法.
记录记录类型
F#参考说:
不要将DefaultValue属性与记录字段一起使用.更好的方法是使用初始化为默认值的字段定义记录的默认实例,然后使用复制和更新记录表达式来设置与默认值不同的任何字段.
根据这条建议,我想定义记录的默认实例,因为它们是公共API的一部分,所以记录它们的类型.
帮助进行类型推断
记录类型的通用参数可用于推断记录值的类型.
假设我有:
type RecordWithSomeComplexType<'T> = {
t1 : int -> System.Collections.Generic.Dictionary<int, 'T> // some long type signature
}
Run Code Online (Sandbox Code Playgroud)
我想实例化它.如果我不提供任何类型的注释,记录值将尽可能一般,例如
let record4 = {
RecordWithSomeComplexType.t1 = failwith "Intentionally failing"
}
Run Code Online (Sandbox Code Playgroud)
有类型
int -> System.Collections.Generic.Dictionary<int, obj>
Run Code Online (Sandbox Code Playgroud)
我可以强制记录属于某种类型(例如RecordWithSomeComplexType<string>),但在这种情况下,我需要写出完整类型的某些值,例如
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
}
Run Code Online (Sandbox Code Playgroud)
如果编译器知道我想要RecordWithSomeComplexType<string>,它可以推断出值的签名.
您可以在任何地方添加类型注释
let record2 : SimpleGenericRecord<_, _> = {
f1 = fun (x: int) -> 0
}
// alternative
let record2 =
({
f1 = fun (x: int) -> 0
} : SimpleGenericRecord<_, _>)
Run Code Online (Sandbox Code Playgroud)
对于较长的情况,您可以编写别名类型以简化操作
type Alias<'T> = int -> System.Collections.Generic.Dictionary<int, 'T>
let record4 = {
t1 = (failwith "Intentionally failing" : Alias<string>)
}
Run Code Online (Sandbox Code Playgroud)
请注意,record4评估会立即引发异常,因为它没有延迟