如何在接口实现中保留未实现的泛型类型参数?

rob*_*kuz 1 generics f#

假设我有以下通用接口

type IStorageX<'a, 'b> =
    abstract Make: 'a -> 'b
    abstract From: 'c -> 'b
Run Code Online (Sandbox Code Playgroud)

以下2种类型

type SomeInput<'a> = {value : 'a}

type SomeThing = {value: string}
    with interface IStorageX<int, SomeThing> with
        member this.Make x = {value = sprintf "%A" x}    
        member this.From (x:SomeInput<'a>) = {value = sprintf "%A" x.value}    
Run Code Online (Sandbox Code Playgroud)

如何使F#理解member From应该允许任何类型的输入(只要它SomeInput)?

我在某种程度上试图尝试的是

type IStorageX<'a, 'b, 'c> =
    abstract Make: 'a -> 'b
    abstract From: 'c -> 'b

type SomeThing = {value: string}
    with interface IStorageX<int, SomeThing, SomeInput<'a>> with
                                                     //^^--- unrealized generic param here
        member this.Make x = {value = sprintf "%A" x}    
        member this.From x = {value = sprintf "%A" x.value}    
Run Code Online (Sandbox Code Playgroud)

但是这也没有编译,因为我可能没有在未实现的接口上使用泛型类型参数.

我能做到的唯一方法就是这样

type SomeThing = {value: string}
    with interface IStorageX<int, SomeThing, SomeInput<int>> with
        member this.Make x = {value = sprintf "%A" x}    
        member this.From (x:SomeInput<'a>) = {value = sprintf "%A" x.value}    
Run Code Online (Sandbox Code Playgroud)

那就是完全制定所有通用参数.这当然不起作用,因为我必须为每种类型的SomeInput实现它们...

有关如何做到这一点的任何想法?

谢谢

PS:我能够非常快速地使用SRTP定义解决方案.但是我想要一个基于接口的解决方案,因为SRTP在某种程度上是不好的,F#land中的每个人都像"不,不,不!讨厌的男孩!"

kvb*_*kvb 5

对于您来说,从实现方面和消费者方面准确地包含您正在努力实现的内容的更多细节将非常有帮助 - 如果没有这一点,很难推断出最佳惯用解决方案是什么.建立你的第二个例子,似乎你希望你能做的就是采取

type IStorageX<'a, 'b, 'c> =
    abstract Make: 'a -> 'b
    abstract From: 'c -> 'b
Run Code Online (Sandbox Code Playgroud)

让你的类型SomeThing实现IStorageX<int, SomeThing, SomeInput<'a>>任何'a,但没有办法做到这一点 - 类型无法forall 'a.I<'a>在.NET类型系统中实现.但是,您可以提供一种方法,而不是实现接口:

type SomeThing = 
    {value:string}
    member this.AsStorage() = { 
        new IStorageX<int,SomeThing,SomeInput<'a>> with 
            member this.Make x = {value = sprintf "%A" x}    
            member this.From (x:SomeInput<'a>) = {value = sprintf "%A" x.value}
    }
Run Code Online (Sandbox Code Playgroud)