【问题标题】:How to instantiate a generic record with explicit type parameters?如何使用显式类型参数实例化通用记录?
【发布时间】:2017-01-02 11:49:39
【问题描述】:

我想在实例化通用记录时显式提供类型参数。换句话说,给定一个RecordType<'T1, 'T2, 'T3>,我想通过指定这些通用参数来创建一个带有一些固定'T1'T2'T3RecordType<'T1, 'T2, 'T3> 实例。有没有办法在 F# 中做到这一点?

我看到了三种有用的情况:

  1. 当有多个同名泛型类型时实例化记录

    假设我们有以下记录定义:

    type SimpleGenericRecord<'T1, 'T2> = {
        f1 : 'T1 -> 'T2
    }
    
    type SimpleGenericRecord<'T> = {
        f1 : 'T -> 'T
    }
    

    我很容易构造 SimpleGenericRecord&lt;'T&gt; 的实例,它是 最后定义:

    let record = {
        f1 = fun (x: int) -> 0
    } 
    
    let record1 = {
        SimpleGenericRecord.f1 = fun (x: int) -> 0
    }
    

    以下尝试创建SimpleGenericRecord&lt;int, int&gt; 编译错误:

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

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

  2. 记录记录类型

    F# reference 说:

    不要对记录字段使用 DefaultValue 属性。一个更好的 方法是定义具有字段的记录的默认实例 初始化为默认值,然后使用复制和更新 记录表达式以设置与默认值不同的任何字段 价值观。

    根据那条建议,我想定义记录的默认实例,并且由于它们是公共 API 的一部分,因此记录它们的类型。

  3. 有助于类型推断

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

    假设我有:

    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&lt;string&gt;),但在这种情况下,我需要编写特定值的完整类型,例如

    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&lt;string&gt;,它可以推断出值的签名。

【问题讨论】:

  • 你得到什么编译错误?
  • @FyodorSoikin "字段绑定必须采用 'id = expr;' 的形式。

标签: generics f# algebraic-data-types


【解决方案1】:

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

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 评估将立即引发异常,因为它没有延迟

【讨论】:

  • 谢谢。那是一个愚蠢的问题。关于 failwith - 我只是使用它,因为它是众所周知的功能并且具有可以缩小的类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-27
  • 2021-10-22
  • 2011-10-11
  • 1970-01-01
相关资源
最近更新 更多