gpt4 book ai didi

generics - F# 嵌套泛型类型与实现的类型不兼容

转载 作者:行者123 更新时间:2023-12-05 00:52:56 25 4
gpt4 key购买 nike

背景:

给定 F# 程序中的以下两个声明:

  • 类型 A实现接口(interface)Wrapped<int>
  • 类型 B实现接口(interface)Wrapped<A>

  • 我们说类型 AWrapped<int> 兼容并输入 BWrapped<A> 兼容- 兼容,据我了解,这意味着 A可以传递给需要 Wrapped<int> 的函数.

    问题:

    根据我的编程经验,鉴于上述两个陈述,我希望以下内容也是正确的:
  • 类型 B应该与类型 Wrapped<Wrapped<int>> 兼容

  • 自从 BA作为类型参数,其中 Wrapped<int>应该去, AWrapped<int>是兼容的。

    不是这种情况。以下实现:
    type Wrapper<'a> = abstract member Value : 'a

    type A =
    | A of int

    interface Wrapper<int> with member this.Value = (let (A num) = this in num)

    type B =
    | B of A

    interface Wrapper<A> with member this.Value = (let (B a) = this in a)


    let f (x:Wrapper<Wrapper<int>>) =
    x.Value.Value

    let testValue = f (B (A 1))

    B (A 1) 上有编译错误陈述

    The type B is not compatible with the type Wrapper<Wrapper<int>>



    问题:

    既然我能够在逻辑上实现兼容性跳跃,那么在实现这一点时我做错了吗?或者 F# 是否没有这种“嵌套兼容性”功能,如果是这种情况,是否有特殊原因没有它?

    有一个解决方法:
    type B =
    | B of A

    interface Wrapper<Wrapper<int>> with member this.Value = (let (B a) = this in a :> Wrapper<int>)

    这将消除编译错误,虽然感觉有点不对劲。我问自己“如果我写了一个函数来处理 Wrapper<A> 类型怎么办?(如果我添加更多 Wrapper<A> 实现者)

    最佳答案

    您要求的功能是协变类型。

    协变允许返回类型是子类型,而不是由泛型类型参数精确定义的类型(并不是说这仅适用于接口(interface),不适用于具体类型)。这使您可以垂头丧气IEnumerable<string> :?> IEnumerable<object>string :?> object .

    可以在其他 .NET 语言中进行声明。这是您在 C# 中的示例:

    interface Wrapper<out T> { }
    class A : Wrapper<int> { }
    class B : Wrapper<A> { }

    var b = new B();
    Action<Wrapper<Wrapper<int>>> unwrap = _ => { };
    unwrap(b); //compiles

    F# 不支持声明协变类型,也不强制没有显式声明的类型。其原因主要是协方差导致类型推断退化。

    flexible types 可以在 F# 中实现协方差.
    这是 seq 上的 F# 示例定义为 IEnumerable<out T> 的类型.
    let s = [1..10] 
    let r = s |> Seq.map(fun _ -> s)

    let print1 (v: seq<seq<int>>) = printfn "%A" v
    let print2 (v: seq<#seq<_>>) = printfn "%A" v

    print1 r //does not compile
    print2 r //compiles

    如果泛型参数被标记为协变并使用灵活类型,您就有可能完成这项工作。您可以在 C# 中使用接口(interface)声明并在 F# 中引用程序集。

    还有 mausch/VariantInterfaces它根据命名约定修改程序集以添加协变/逆变声明,因此如果您在单独的程序集中有类型声明,则可以在构建后运行它。

    关于generics - F# 嵌套泛型类型与实现的类型不兼容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41903996/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com