【问题标题】:Scala add extension method when the type params have a common type当类型参数具有公共类型时,Scala添加扩展方法
【发布时间】:2022-01-01 01:52:36
【问题描述】:

我有一个类型 Foo[+A, +B] 和一个类型 Bar[+B]。我想像这样将扩展方法bar添加到Foo

implicit class FooSyntax[A](foo: Foo[A, Bar[A]]) {
   def bar: A = ???
}

所以扩展方法只适用于BBar[A]的情况。因此,以下所有内容都应该编译——

trait Fruit
trait Apple  extends Fruit
trait Banana extends Fruit
def foo0: Foo[Apple, Bar[Banana]] = ???
def foo1: Foo[Apple, Bar[String]] = ???
def foo2: Foo[Apple, Bar[Apple]]  = ???
def foo3: Foo[Apple, List[Apple]] = ???

foo0.bar // Fruit
foo1.bar // Object
foo2.bar // Apple

对于我的用例,我希望能够在没有 FooSyntax 的情况下使用隐式要求来执行此操作,这样该方法始终可用并且易于发现,但是只有在满足类型条件时才可以调用它.这就是我到目前为止所做的——

trait Foo[+A, +B] {
    def bar[C <: A](implicit evA: A <:< C, evB: B <:< Bar[C]): C
}

不用说,这是行不通的。

【问题讨论】:

  • 我希望该方法始终可用以便更好地发现,但只有在满足条件时才可以调用它。

标签: scala functional-programming type-level-computation


【解决方案1】:
trait Foo[+A, +B] {
  def bar(implicit ev: FooBar[A, B]): ev.Out
}

trait Bar[+B]

trait FooBar[-A, -B] {
  type Out
}

object FooBar {
  type Aux[A] = FooBar[A, Bar[A]] { type Out = A }

  implicit def x[A]: FooBar.Aux[A] =
    new FooBar[A, Bar[A]] {
      override type Out = A
    }
}

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
【解决方案2】:

您需要做的就是从C 中删除绑定的类型,并留下隐含的证据来完成它的工作。

trait Bar[+B]

trait Foo[+A, +B] {
  def bar[C](implicit ev1: A <:< C, ev: B <:< Bar[C]): C = ???
}

那么你可以这样做(如预期的那样)

foo0.bar // Fruit
foo1.bar // Object
foo2.bar // Apple

可以看到代码运行here

【讨论】:

  • 为什么在scala 2.13.x 中不起作用?
  • @JohnyTKoshy 啊,我的错。我忘了 Scastie 默认使用 Scala 3。嗯,类型推断算法在3.0.0中得到了改进,看来旧版本不能做你想做的了。
  • 这不是我的问题。 OP 可能正在使用3.0.0。我在2.13.x 中尝试了同样的方法。无论如何,谢谢。
  • 是的,我正在努力让它在 Scala 中工作 2.13.7
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-16
相关资源
最近更新 更多