Kotlin中的高阶(或递归?)泛型类型参数 [英] Higher order (or recursive?) generic type parameters in kotlin

查看:183
本文介绍了Kotlin中的高阶(或递归?)泛型类型参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为一些高度声明性的代码制作原型,而Kotlin附带的类型推断和安全性大有帮助.目标之一是使主要类型的扩展(子类)易于实现.为了保持丰富的类型推断和表达能力,我发现在定义针对子类的通用扩展函数方面取得了一些成功.所有子类方法的类型信息都没有额外的子类实现,这很好.

I'm prototyping some highly declarative code, and the type inference and safety that comes with Kotlin helps a lot. One of the goals is making extensions (subclasses) of the primary types stupidly easy to implement. In order to maintain rich type inference and expressiveness, I've found some success in defining generic extension functions projected against subclasses. All the type information of subclass methods with none of the extra subclass implementation, it's great.

因此,我试图编写一个丰富的泛型函数,该函数可以维护尽可能多的类型信息.该函数对潜在的递归泛型类型起作用,因此我想改组泛型类型参数.

So I'm trying to write a rich generic function that maintains as much type information as possible. The issue creeps up with the fact that this function operates on potentially recursively generic types, and I want to shuffle the generic type parameters.

没有示例就无法描述.因此请考虑:

This would be impossible to describe without an example. So consider:

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<*>>()

我们希望有一个功能可以有效地做到这一点,除了一般而言

We want a function that effectively can do this, except generically

fun B<A<*>>.doTransitiveThing(c: C<B<*>>) : C<A<*>>
{
    // implement
}

val ca = ba.doTransitiveThing(cb) // Returns C<A<*>>

目标标准:

  • C作为参数并返回C,除非具有不同的泛型类型参数
  • 我想将此行为概括为G所有子类的扩展函数
    • 它必须是扩展函数,以便使用泛型类型,我们可以拥有子类的类型,并确保该参数具有接收者类型的泛型类型参数.
    • 或者换句话说,我们希望为G的子类提供扩展功能,因此在B<A<*>>上调用时,参数必须为C<B<*>>而不是C<G<*>>
    • Takes C as a param and returns C, except with different generic type parameter
    • I'd like to generalize this behavior as an extension function of all subclasses of G
      • It needs to be an extension function so that using generic types we can have the type of the subclass and ensure the argument has a generic type argument of the receiver type.
      • Or in other words, we want an extension function for subclasses of G so the argument must be C<B<*>> instead of C<G<*>> when invoked on B<A<*>>

      这描述了问题的要点.我不确定该语言是否能够支持我想要的内容.我不确定类型擦除是否会导致这种情况的发生,但到目前为止,我仍然找不到它(也许是的话,我可以使用帮助).

      That describes the gist of the problem. I'm not sure the language is capable of supporting what I want. I'm not sure if type erasure is a factor that makes this impossible, but so far I can't find it so (maybe I could use help if it is so).

      以下内容关闭

      fun <
          TargetGenericType, 
          Arg1Type: G<*>, 
          ReceiverType: G<TargetGenericType>, 
          Arg2Type: G<Arg1Type>, 
          ResultType: G<TargetGenericType>
          >
          ReceiverType.doTransitiveThingGeneric(x: Arg2Type): ResultType
      {
          //implement
      }
      val ca2 = ba.doTransitiveThingGeneric(cb)
      

      但是有一些问题

      • 它返回G<A<*>>而不是C<A<*>>.如果它可以返回C并且不丢失类型信息(否则我实际上并没有真正使用此功能),那将是很好的选择
      • 从技术上讲,不能保证ReceiverTypeArg1Type
      • It returns G<A<*>> instead of C<A<*>>. It would be nice if it could return C and not lose type information (otherwise I don't really have a use for this function anyway)
      • There is technically no guarantee ReceiverType is Arg1Type

      想一想,如果以下内容是有效的Kotlin,我认为它可以解决我的问题

      Thinking ahead, if something like the following was valid Kotlin, I think it would address my problem

      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
      }
      

      是否有无法完成的原因?例如作为语言的一项功能添加?我对后勤方面的理由表示同情,但我很好奇原则上是否也可能.

      Is there a reason it can't be done? e.g. added as a feature on the language? I am sympathetic to logistical reasons against, but I'm curious if it is even possible in principle too.

      最后的注释:

      • 它使我想起类型别名,但泛型类型参数本身除外.实际上,在示例中我已经包含了该关键字,以防它有助于消化.不过,这并不是唯一的部分,请注意语法中的<T><U>.
      • 这几乎让我想起了Monads,除了类定义本身之外,如果这可以以一种波浪状,直观的方式来理解的话.
      • 我还不知道如何实现该主体,但是我还没有走那么远,因为我仍在尝试看看是否可以签名:p
      • It reminds me of type aliases except for generic type parameters themselves. In fact I've included that keyword in the example in case it helps to digest. That isn't the only part though, notice <T> and <U> in the syntax.
      • It almost reminds me of Monads as well, except with class definitions themselves if that makes sense in a sort of hand wavy, intuitive way.
      • I have no idea how to implement the body yet, but I haven't gotten that far since I'm still trying to see if the signature is even possible :p

      推荐答案

      我最终要寻找的是高级种类.我试图将其全部强制为一个过度嵌套的类型构造函数.我想完成的操作无法以这种方式实现,而必须使用多个类型参数来完成.功能库 Arrow对更高种类的描述帮助我意识到了这一点.

      Ultimately what I was looking for is 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 helped me realize that.

      在形状为Kind<F, A>的高级类型中,如果A是内容的类型,则F必须是容器的类型.

      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.

      格式错误的高级类型将使用整个类型构造函数来定义容器,从而复制内容Kind<Option<A>, A>的类型.当使用部分应用的类型和嵌套类型时,这种不正确的表示存在很多问题.

      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中的高阶(或递归?)泛型类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆