【问题标题】:Using Parametric Type in Implicit for Type Classes in Scala在 Scala 中为类型类隐式使用参数类型
【发布时间】:2016-08-19 15:03:37
【问题描述】:

我正在尝试更多地了解 Scala 中的 TypeClasses,并提出了这个示例

trait Cons[T] {
    def cons(t1: T, t2: T):T
}

object Cons {
    implicit object StringCons extends Cons[String] {
        override def cons(t1: String, t2: String): String = t1 + t2
    }

    implicit object ListCons extends Cons[List[_]] {
        override def cons(t1: List[_], t2: List[_]): List[_] = t1 ++ t2
    }

    implicit object IntCons extends Cons[Int] {
        override def cons(t1: Int, t2: Int): Int = Integer.parseInt(t1.toString + t2.toString)
    }
}

def Cons[T](t1: T, t2: T)(implicit c: Cons[T]):T = {
    c.cons(t1, t2)
}

Cons("abc", "def") // abcdef
Cons(1, 2) // 12
Cons(List(1,2,3),List(4,5,6)) // does not work, as the expected type is List[Int]

当我创建ListCons 时,我明确设置了List[_] 的类型,如果我理解正确的话,它是存在类型,相当于Java 通配符,这意味着它是某种类型,我们不在乎。

现在的问题是为什么这不起作用。有没有办法让它工作。或者我可能存在一些根本性的误解。

【问题讨论】:

    标签: scala types


    【解决方案1】:

    Cons(List(1,2,3),List(4,5,6)) 不起作用的原因是,根据类型推断规则,它表示Cons[List[Int]](List[Int](1,2,3), List[Int](4,5,6)),因此它特别需要隐式Cons[List[Int]],而Cons[List[_]] 不是Cons[List[Int]]

    Cons[List[_]] 是一个Cons[List[Int]] 如果Cons 是逆变的(声明为Cons[-T]),但它不能是逆变的,因为它有一个返回T 的方法(除非你用@uncheckedVariance作弊,你不应该)。

    使其工作的正确方法是将ListCons替换为

    implicit def listCons[T]: Cons[List[T]] = new Cons[List[T]] {
        override def cons(t1: List[T], t2: List[T]): List[T] = t1 ++ t2
    }
    

    【讨论】:

      【解决方案2】:

      我添加了一个更高种类的类型,这将使​​您能够捕获您的类型:

      这是我的尝试:

      trait Cons[T] {
        def cons(t1: T, t2: T): T
      }
      
      trait HigherKindCons[M[_]] {
        def cons[T](t1: M[T], t2: M[T]): M[T]
      }
      
      object Cons {
        implicit object StringCons extends Cons[String] {
          override def cons(t1: String, t2: String): String = t1 + t2
        }
      
        implicit object ListCons extends HigherKindCons[List] {
          override def cons[T](t1: List[T], t2: List[T]): List[T] = t1 ++ t2
        }
      
        implicit object OptCons extends HigherKindCons[Option] {
          override def cons[T](t1: Option[T], t2: Option[T]): Option[T] = t1 orElse t2
        }
      
        implicit object IntCons extends Cons[Int] {
          override def cons(t1: Int, t2: Int): Int =  Integer.parseInt(t1.toString + t2.toString)
        }
      }
      
      
      import Cons._
      
      def Cons[T](t1: T, t2: T)(implicit c: Cons[T]):T = {
        c.cons(t1, t2)
      }
      
      def Cons[T, M[_]](t1: M[T], t2: M[T])(implicit c: HigherKindCons[M]): M[T] = {
        c.cons(t1, t2)
      }
      
      
      Cons[String]("abc", "def") // abcdef
      Cons(1, 2) // 12
      Cons(List(1,2,3),List(4,5,6))
      Cons(List("a", "b"),List("c", "d", "e")) // as the expected type is List[String]
      Cons(Some(1), None)
      

      输出:

      res0: String = abcdef
      res1: Int = 12
      res2: List[Int] = List(1, 2, 3, 4, 5, 6)
      res3: List[String] = List(a, b, c, d, e)
      res4: Option[Int] = Some(1)
      

      【讨论】:

        猜你喜欢
        • 2011-08-29
        • 1970-01-01
        • 1970-01-01
        • 2018-01-13
        • 1970-01-01
        • 2018-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多