【问题标题】:Partially applying type parameters部分应用类型参数
【发布时间】:2011-04-03 04:59:43
【问题描述】:

我正在拼命尝试解决以下问题:

trait Access[Res[_]] { def access[C]: Res[C] }

trait CList[C1, A] extends Access[CList[_, A]] // ?!

def test[C1, C2, A](c: CList[C1, A]): CList[C2, A] = c.access[C2]

scalac 只是说:"error: illegal cyclic reference involving trait CList"。如何编译?

【问题讨论】:

    标签: scala higher-kinded-types


    【解决方案1】:

    您可能对类型 lambda 感兴趣。您在答案中使用的部分应用程序实际上是implemented in scalaz。 由于代码的可读性越来越差,他们开始改用 lambdas 类型。有问题的类型可以写成

    ({type λ[α] = CList[α,A]})#λ
    

    这通过在结构类型内部的参数化类型λ 上创建类型投影来实现,从而捕获外部类型参数(在本例中为A)。

    您的答案中描述的有关方差的另一个问题可以通过在Access 中设置Res 参数来解决。

    进行这些更改后,您的代码应如下所示:

    trait Access[+Res[_]] { def access[C] : Res[C]}
    
    trait CList[C, +A] extends Access[({type λ[α] = CList[α,A]})#λ]
    

    【讨论】:

    • 谢谢,看起来好多了。此外,由于在我的真实案例中 CList 的类型参数具有上限,因此具有专用特征 Partial2 并没有真正的帮助(我需要为边界添加类型参数等)
    • 另外,如果您的代码中经常使用 lambda 类型,请考虑以下编译器插件:github.com/non/kind-projector
    【解决方案2】:

    谷歌搜索“部分类型应用程序”我发现这个解决方案由 James Iry 在 scala 辩论列表上发布(http://scala-programming-language.1934581.n4.nabble.com/Partial-type-inference-td2007311.html;经过调整,因此更改了 arg 顺序):

    type Partial2[T[_,_], B] = {
       type Apply[A] = T[A,B]
    }
    trait CList[C1, A] extends Access[Partial2[CList, A]#Apply]
    

    cheese louise,这真的是 2011 年在 scala 中做到这一点的唯一方法吗?!!

    编辑:

    这会因A 中的协方差而失败 :,-(

    trait Access[Res[_]] { def access[C]: Res[C] }
    
    type Partial2[T[_,_], B] = {
      type Apply[A] = T[A,B]
    }
    trait CList[C1, +A] extends Access[Partial2[CList, A]#Apply]
    
    "covariant type A occurs in invariant position"
    

    【讨论】:

      【解决方案3】:

      只是为了更新东西 将此编译器插件添加到您的 sbt 以进行 kind 投影,您将使用 ? 获得不错的语法。
      这将删除看起来凌乱的类型投影样板!
      所以你可以写像 Either[String, ?]

      这样的东西

      addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.7")

      它在下面使用相同的旧类型投影实现


      您也可以在这里找到它:
      https://underscore.io/blog/posts/2016/12/05/type-lambdas.html

      【讨论】:

        【解决方案4】:

        我知道这是一个很老的问题,但无论如何:

        trait AnyAccess {
          type Res[X]
          def access[Z]: Res[Z]
        }
        
        trait AnyCList extends AnyAccess { me =>
          type C
          type A
          // this could be a subtype bound instead, if needed
          type Res[X] = AnyCList { type C = X; type A = me.A }
        }
        case object AnyCList {
          type of[C0, +A0] = AnyCList { type C = C0; type A <: A0 }
        }
        
        case object buh {
        
          def test[C1, C2, A](c: AnyCList.of[C1, A]): AnyCList.of[C2, A] = c.access[C2]
        }
        

        【讨论】:

          【解决方案5】:

          这是一个对我有用的“部分应用类型参数”的方法:

          我有一个类似的功能

          def foo[A, B, C, D, E](...)
          

          这样我只需要提示一个类型参数,编译器就可以推断出其余的。这对我有用:

          object InferType {
            type InferType[A] = Option[A]
            def apply[A]: Option[A] = None
          }
          

          更新 foo 以获取 InferType 类型的附加参数:

          // t parameter is unused in implementation but
          // is used by compiler to infer other type parameters
          def foo[A, B, C, D, E](..., t: InferType[D]) 
          

          用法:

          foo(..., InferType[ConcreteD])
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-11-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-03-08
            • 1970-01-01
            • 2021-09-11
            • 2019-12-19
            相关资源
            最近更新 更多