【问题标题】:Higher kind/type bound puzzler in ScalaScala中更高种类/类型的益智游戏
【发布时间】:2012-10-22 01:50:59
【问题描述】:

当我遇到这个问题时,我正在尝试使用更高级的类型和类型边界。我的用例是我希望能够使用 Request 的任何子类型或 Request 类型本身来参数化 GenericAction 实例。 Action trait 使用默认类型的 Request 扩展 GenericAction trait(在这种情况下,只会生成 Request 的匿名实例)。

trait Request[+A]

trait GenericAction[A, R[_] <: Request[_]]

trait Action[A] extends GenericAction[A, Request]

trait ActionBuilderBase[R[_] <: Request[_], G[_] <: GenericAction[_,R]]

ActionBuilderBase 具有与子特征 ActionBuilder 和 ActionBuilder2 共享的实用方法。 ActionBuilder 生成默认的 Action[A] 和 Request[A] 实例。

trait ActionBuilder extends ActionBuilderBase[Request,Action]

到目前为止一切都很好,但是当我尝试创建另一个扩展 ActionBuilderBase 具有 R 和 GenericAction 子类型的特征时(在这种情况下,将创建 GenericAction 的匿名实例),它无法编译。我猜原因是在第一个 ActionBuilder 的情况下,请求类型已经被“填充”(因为 Action[A] 已经有一个请求类型 == Request),这与下面的示例不同。为了让这个例子起作用,我需要“填写”什么?

//Fails with "GenericAction takes two type parameters, expected: one" - what should the type annotation for GenericAction look like?
trait ActionBuilder2[R[_] <: Request[_]] extends ActionBuilderBase[R,GenericAction]

【问题讨论】:

    标签: scala existential-type higher-kinded-types


    【解决方案1】:

    在这种情况下,如果能写出这样的东西就好了:

    trait ActionBuilder2[R[_] <: Request[_]] extends
      ActionBuilderBase[R, GenericAction[_, R]]
    

    表示您想部分应用GenericAction。不幸的是,这不是有效的 Scala 语法(尽管 Erik Osheim 有 a compiler plugin 可以让您编写非常相似的东西)。

    但是,您可以使用“类型 lambda 技巧”:

    trait ActionBuilder2[R[_] <: Request[_]] extends
      ActionBuilderBase[R, ({ type L[A] = GenericAction[A, R] })#L]
    

    有关其工作原理的详细说明,请参阅 this answer

    【讨论】:

    • @BlakePettersson:是的,人们将其称为“type lambda trick”是有原因的——这是一种丑陋的方式来实现真正应该得到语言更直接。
    猜你喜欢
    • 1970-01-01
    • 2011-03-05
    • 2017-02-17
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-21
    相关资源
    最近更新 更多