【问题标题】:Abstract type, variables and typeclasses in ScalaScala 中的抽象类型、变量和类型类
【发布时间】:2018-05-03 12:20:27
【问题描述】:

我正在尝试创建一个依赖于用户输入的类型类。假设我们有一些案例对象:

sealed trait H
case object Ha extends H
case object Hb extends H

和类型类:

trait Foo[A] {
    def bar: String
}

object Foo {
    def bar[A : Foo] = implicitly[Foo[A]].bar

    implicit object FooA extends Foo[Ha.type] {
        override def bar: String = "A"
    }

    implicit object FooB extends Foo[Hb.type] {
        override def bar: String = "B"
    }
}

虽然我使用匹配找到了可行的解决方案:

variableComingFromMainArgs match {
  case "a" => Foo.bar[Ha.type] _
  case "b" => Foo.bar[Hb.type] _
}

我记得我们在 Scala 中有抽象类型,所以我可以将我的案例类更改为:

sealed trait H {
    type T <: H
}

case object Ha extends H {
    type T = this.type
}

case object Hb extends H {
    type T = this.type
}

现在,根据用户对程序的输入,我可以执行类似的操作 val 变量 = Ha println(Foo.bar[variable.T])

但是,由于某种原因,这不起作用,并且该错误对我来说不是很有用:

error: could not find implicit value for evidence parameter of type Foo[variable.T]
        println(Foo.bar[variable.T])

任何想法如果可以克服,如果不能,为什么?

谢谢。

【问题讨论】:

    标签: scala typeclass path-dependent-type abstract-type


    【解决方案1】:

    隐式是编译时构造,因此原则上它们不能直接依赖于用户输入(例如,程序员可以像你一样使用模式匹配来连接它)。

    考虑以下代码。它按预期编译和工作:

    trait H {
        type A
    }
    
    case object Ha extends H {
        override type A = Int
    }
    
    case object Hb extends H {
      override type A = Long
    }
    
    trait Adder[T] {
      def add(a: T, b: T): T
    }
    
    implicit object IntAdder extends Adder[Int] {
      override def add(a: Int, b: Int): Int = a + b
    }
    
    implicit object LongAdder extends Adder[Long] {
      override def add(a: Long, b: Long): Long = a + b
    }
    
    def addWithAdder(input: H)(a: input.A, b: input.A)(implicit ev: Adder[input.A]): input.A = ev.add(a, b)
    
    val x: Int = addWithAdder(Ha)(3, 4)
    val y: Long = addWithAdder(Hb)(3, 4)
    

    让我们关注 addWithAdder 方法。由于路径依赖类型,编译器可以为此任务选择正确的隐式。但是这个方法还是和下面的基本一样:

    def add[T](a: T, b: T)(implicit ev: Adder[T]) = ev.add(a, b)
    

    第一个可以拥有的唯一优势是您可以自己提供所有实例并阻止您的代码用户添加自己的类型(当H 被密封并且所有实现都是最终的)。

    【讨论】:

    • 嗯,很公平.. 我想除了使用我提到的模式匹配之外没有其他解决方法。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多