kotlin 中的高阶(或递归?)泛型类型参数
Higher order (or recursive?) generic type parameters in kotlin
我正在制作一些高度声明性代码的原型,Kotlin 附带的类型推断和安全性很有帮助。目标之一是使主要类型的扩展(subclasses)非常容易实现。为了保持丰富的类型推断和表现力,我发现在定义针对 subclasses 投影的通用扩展函数方面取得了一些成功。 subclass 方法的所有类型信息和额外的 subclass 实现的 none,太棒了。
所以我正在尝试编写一个丰富的通用函数来维护尽可能多的类型信息。问题是这个函数对潜在的递归泛型类型进行操作,我想打乱泛型类型参数。
没有例子就无法描述。所以考虑:
open class G<in T>
class A<in T> : G<T>()
class B<in T> : G<T>()
class C<in T> : G<T>()
val ba = B<A<*>>()
val cb = C<B<*>>()
我们想要一个可以有效地做到这一点的函数,除了一般性的
fun B<A<*>>.doTransitiveThing(c: C<B<*>>) : C<A<*>>
{
// implement
}
val ca = ba.doTransitiveThing(cb) // Returns C<A<*>>
目标标准:
- 将
C
作为参数和returns C
,除了不同的通用类型参数
- 我想将此行为概括为
G
的所有子 class 的扩展函数
- 它需要是一个扩展函数,以便使用泛型类型我们可以获得子类型class并确保参数具有接收者类型的泛型类型参数。
- 或者换句话说,我们想要
G
的子 class 的扩展函数,因此在 C<B<*>>
上调用时参数必须是 C<B<*>>
而不是 C<G<*>>
=20=]
这描述了问题的要点。我不确定该语言是否能够支持我想要的东西。我不确定类型擦除是否是使这成为不可能的一个因素,但到目前为止我找不到它(如果是这样,也许我可以寻求帮助)。
以下接近
fun <
TargetGenericType,
Arg1Type: G<*>,
ReceiverType: G<TargetGenericType>,
Arg2Type: G<Arg1Type>,
ResultType: G<TargetGenericType>
>
ReceiverType.doTransitiveThingGeneric(x: Arg2Type): ResultType
{
//implement
}
val ca2 = ba.doTransitiveThingGeneric(cb)
但是有一些问题
- 它return是
G<A<*>>
而不是C<A<*>>
。如果它可以 return C
并且不丢失类型信息就好了(否则我真的没有用这个功能)
- 技术上无法保证
ReceiverType
是 Arg1Type
提前考虑,如果像下面这样的东西是有效的 Kotlin,我认为它会解决我的问题
fun <
TargetGenericType,
ReceiverBaseType<T>: G<T>,
typealias ReceiverType = ReceiverBaseType<TargetGenericType>,
ParamBaseType<U>: G<U>,
typealias ParamType = ParamBaseType<ReceiverBaseType<*>>,
ResultType: ParamBaseType<TargetGenericType>
>
ReceiverType.doTransitiveThingHigherOrderGeneric(x: ParamType): ResultType
{
//implement
}
是否有无法完成的原因?例如添加为语言的功能?我同情反对的后勤原因,但我很好奇这在原则上是否也可能。
最后的笔记:
- 这让我想起了类型别名,除了泛型类型参数本身。事实上,我已经在示例中包含了该关键字,以防它有助于理解。这不是唯一的部分,请注意语法中的
<T>
和 <U>
。
- 它几乎也让我想起了 Monad,除了 class 定义本身,如果它以一种手摇式、直观的方式有意义的话。
- 我还不知道如何实现正文,但我还没有走那么远,因为我仍在尝试查看签名是否可行 :p
最终我要找的是 higher kinds. I was trying to force it all into one single overly nested type constructor. The manipulations I wanted to accomplish cannot be achieved that way, and must be done using multiple type parameters. The functional library Arrow's description of higher kinds 帮助我意识到这一点。
In a Higher Kind with the shape Kind<F, A>
, if A
is the type of the content then F
has to be the type of the container.
A malformed Higher Kind would use the whole type constructor to define the container, duplicating the type of the content Kind<Option<A>, A>
. This incorrect representation has large a number of issues when working with partially applied types and nested types.
我正在制作一些高度声明性代码的原型,Kotlin 附带的类型推断和安全性很有帮助。目标之一是使主要类型的扩展(subclasses)非常容易实现。为了保持丰富的类型推断和表现力,我发现在定义针对 subclasses 投影的通用扩展函数方面取得了一些成功。 subclass 方法的所有类型信息和额外的 subclass 实现的 none,太棒了。
所以我正在尝试编写一个丰富的通用函数来维护尽可能多的类型信息。问题是这个函数对潜在的递归泛型类型进行操作,我想打乱泛型类型参数。
没有例子就无法描述。所以考虑:
open class G<in T>
class A<in T> : G<T>()
class B<in T> : G<T>()
class C<in T> : G<T>()
val ba = B<A<*>>()
val cb = C<B<*>>()
我们想要一个可以有效地做到这一点的函数,除了一般性的
fun B<A<*>>.doTransitiveThing(c: C<B<*>>) : C<A<*>>
{
// implement
}
val ca = ba.doTransitiveThing(cb) // Returns C<A<*>>
目标标准:
- 将
C
作为参数和returnsC
,除了不同的通用类型参数 - 我想将此行为概括为
G
的所有子 class 的扩展函数- 它需要是一个扩展函数,以便使用泛型类型我们可以获得子类型class并确保参数具有接收者类型的泛型类型参数。
- 或者换句话说,我们想要
G
的子 class 的扩展函数,因此在C<B<*>>
上调用时参数必须是C<B<*>>
而不是C<G<*>>
=20=]
这描述了问题的要点。我不确定该语言是否能够支持我想要的东西。我不确定类型擦除是否是使这成为不可能的一个因素,但到目前为止我找不到它(如果是这样,也许我可以寻求帮助)。
以下接近
fun <
TargetGenericType,
Arg1Type: G<*>,
ReceiverType: G<TargetGenericType>,
Arg2Type: G<Arg1Type>,
ResultType: G<TargetGenericType>
>
ReceiverType.doTransitiveThingGeneric(x: Arg2Type): ResultType
{
//implement
}
val ca2 = ba.doTransitiveThingGeneric(cb)
但是有一些问题
- 它return是
G<A<*>>
而不是C<A<*>>
。如果它可以 returnC
并且不丢失类型信息就好了(否则我真的没有用这个功能) - 技术上无法保证
ReceiverType
是Arg1Type
提前考虑,如果像下面这样的东西是有效的 Kotlin,我认为它会解决我的问题
fun <
TargetGenericType,
ReceiverBaseType<T>: G<T>,
typealias ReceiverType = ReceiverBaseType<TargetGenericType>,
ParamBaseType<U>: G<U>,
typealias ParamType = ParamBaseType<ReceiverBaseType<*>>,
ResultType: ParamBaseType<TargetGenericType>
>
ReceiverType.doTransitiveThingHigherOrderGeneric(x: ParamType): ResultType
{
//implement
}
是否有无法完成的原因?例如添加为语言的功能?我同情反对的后勤原因,但我很好奇这在原则上是否也可能。
最后的笔记:
- 这让我想起了类型别名,除了泛型类型参数本身。事实上,我已经在示例中包含了该关键字,以防它有助于理解。这不是唯一的部分,请注意语法中的
<T>
和<U>
。 - 它几乎也让我想起了 Monad,除了 class 定义本身,如果它以一种手摇式、直观的方式有意义的话。
- 我还不知道如何实现正文,但我还没有走那么远,因为我仍在尝试查看签名是否可行 :p
最终我要找的是 higher kinds. I was trying to force it all into one single overly nested type constructor. The manipulations I wanted to accomplish cannot be achieved that way, and must be done using multiple type parameters. The functional library Arrow's description of higher kinds 帮助我意识到这一点。
In a Higher Kind with the shape
Kind<F, A>
, ifA
is the type of the content thenF
has to be the type of the container.A malformed Higher Kind would use the whole type constructor to define the container, duplicating the type of the content
Kind<Option<A>, A>
. This incorrect representation has large a number of issues when working with partially applied types and nested types.