首页 文章

Scala中的抽象类型,变量和类型类

提问于
浏览
0

我正在尝试创建一个依赖于用户输入的类型类 . 想象一下,我们有一些案例对象:

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中有抽象类型,所以我可以将我的case类更改为:

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 variable = 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])

任何想法,如果这可以克服,如果没有,为什么?

谢谢 .

1 回答

  • 1

    Implicits是编译时构造,因此原则上它们不能直接依赖于用户输入(程序员可以将其连接起来,例如使用模式匹配) .

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

    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 被密封并且所有实现都是最终的时) .

相关问题