generics - 如何使用显式类型参数实例化通用记录?

标签 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
    }
    

    我很容易构造 SimpleGenericRecord<'T> 的实例这是
    最后定义:
    let record = {
        f1 = fun (x: int) -> 0
    } 
    
    let record1 = {
        SimpleGenericRecord.f1 = fun (x: int) -> 0
    }
    

    以下尝试创建 SimpleGenericRecord<int, int>
    编译错误:
    let record2 = {
        SimpleGenericRecord<int, int>.f1 = fun (x: int) -> 0
    }
    
    let record3 = {
        SimpleGenericRecord<_, _>.f1 = fun (x: int) -> 0
    }
    

    我知道为两种类型使用相同的记录名称可能不是最好的主意,但是,我认为语言应该给我一种使用这两种类型的方法。
  • 记录记录类型

    F# reference说:

    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.



    按照那条建议,我想定义记录的默认实例,并且由于它们是公共(public) API 的一部分,因此记录它们的类型。
  • 帮助类型推断

    记录类型的通用参数可用于推断记录值的类型。

    假设我有:
    type RecordWithSomeComplexType<'T> = {
        t1 : int -> System.Collections.Generic.Dictionary<int, 'T> // some long type signature
    }
    

    我想实例化它。如果我不提供任何类型注释,记录值将尽可能通用,例如
    let record4 = {
        RecordWithSomeComplexType.t1 = failwith "Intentionally failing"
    }
    

    有类型
    int -> System.Collections.Generic.Dictionary<int, obj>
    

    我可以强制记录为某种类型(例如 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
    }
    

    如果编译器知道我想要 RecordWithSomeComplexType<string> ,它可以推断出值(value)的签名。
  • 最佳答案

    您几乎可以在任何地方添加类型注释

    let record2 : SimpleGenericRecord<_, _> = {
        f1 = fun (x: int) -> 0
    }
    
    // alternative
    let record2 =
      ({
        f1 = fun (x: int) -> 0
      } : SimpleGenericRecord<_, _>)
    

    对于更长的情况,您可以编写别名类型来简化事情
    type Alias<'T> = int -> System.Collections.Generic.Dictionary<int, 'T>
    
    let record4 = {
      t1 = (failwith "Intentionally failing" : Alias<string>)
    }
    

    请注意,record4 评估将立即引发异常,因为它没有延迟

    关于generics - 如何使用显式类型参数实例化通用记录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39155563/

    相关文章:

    java - <? 之间有什么区别?扩展对象> 和 <E 扩展对象>?

    java - 如何使用通配符在 Java 中复制通用集合

    F# - 健全性检查和选项

    F# Seq.sortBy 降序

    从外部类继承的C++嵌套类;不允许不完整的类型

    C# 将泛型类型传递给另一个类

    c# - 我们可以使用通用列表而不是对象数组 C#

    F# R 提供程序 : Method not found: 'RDotNet. REngine RDotNet.REngine.GetInstance

    c# - C# 中的类型安全可区分联合,或 : How to limit the number of implementations of an interface?

    haskell - 将数据构造函数映射到类型