Typeclass ops:启用查找参数

问题描述

我是Typeclass模式的新手,并且在scala中是隐式的,下面是我测试该模式的代码片段,但我不知道为什么compareB方法无法为参数找到隐式值wrapper ,即使这样,我也声明了一个IntWrapper [Int]类型的隐式字段。

有人知道在typeclass中如何解析隐式吗?以及为什么下面的代码无法编译?

谢谢

trait IntWrapper[T]{
  def test: Boolean
}

trait ProductComparator[T] extends Serializable{
  def compare(p1 : T,p2: T): Boolean
}

object ProductComparator{

  def apply[A](implicit cmp: ProductComparator[A]) : ProductComparator[A] = cmp


  implicit def w: IntWrapper[Int] =
    new IntWrapper[Int] {
      override def test: Boolean = true
    }

  implicit def CompareB[T <: Product,Repr <: HList,KRepr <: HList](implicit gen: LabelledGeneric.Aux[T,Repr],keys: Keys.Aux[Repr,KRepr],wrapper:  IntWrapper[Int]) : ProductComparator[T] =
      new ProductComparator[T] {
        override def compare(p1: T,p2: T): Boolean = {
          p1.productArity == p2.productArity
        }
      }

}


case class Emp(a: Int,b: Int)

object Demo extends App{
  val comparator = implicitly[ProductComparator[Emp]]
}

解决方法

通常将类型为TC[A]的隐式对象放到TC的伴随对象或A的伴随对象中。

所以转移

implicit def w: IntWrapper[Int] =
  new IntWrapper[Int] {
    override def test: Boolean = true
  }

ProductComparator的伴随对象到IntWrapper的伴随对象

object IntWrapper {
  implicit def w: IntWrapper[Int] =
    new IntWrapper[Int] {
      override def test: Boolean = true
    }
}

然后代码应编译。

或者,您也可以按照 @TomerShetah 的建议导入w

Where does Scala look for implicits?

定义时

implicit val foo: Foo = ???

def bar(implicit foo1: Foo) = ???

(在您的示例中,foowbarCompareBFooIntWrapper[Int]) 您通常不应该假设foo1foofoo在当前范围内定义,foo1将在bar呼叫站点范围内解决。如果它在范围内或其他隐式范围内,则可以为foo

When doing implicit resolution with type parameters,why does val placement matter?

Setting abstract type based on typeclass

Reverse HList and convert to class?

,

问题是范围。在该行中:

val comparator = implicitly[ProductComparator[Emp]]

方法:

def apply[A](implicit cmp: ProductComparator[A]): ProductComparator[A] = cmp

将被调用,其中AEmp。可以创建该隐式的是CompareBCompareB需要更多的隐式。前两个来自进口。因此,它们在范围内。变量w是在object ProductComparator上定义的,因此它不在您定义val comparator的范围内。

要将其添加到范围中,您有几个选择:

  1. 将其导入:

    import ProductComparator.w
    
  2. implicit def w: IntWrapper[Int]移动到与trait IntWrapper[T]相同的范围,这使得:

import shapeless.ops.record.Keys
import shapeless.{HList,LabelledGeneric}

trait IntWrapper[T]{
  def test: Boolean
}

implicit def w: IntWrapper[Int] =
  new IntWrapper[Int] {
    override def test: Boolean = true
  }

trait ProductComparator[T] extends Serializable{
  def compare(p1 : T,p2: T): Boolean
}

object ProductComparator{

  def apply[A](implicit cmp: ProductComparator[A]) : ProductComparator[A] = cmp

        implicit def CompareB[T <: Product,Repr <: HList,KRepr <: HList](implicit gen: LabelledGeneric.Aux[T,Repr],keys: Keys.Aux[Repr,KRepr],wrapper:  IntWrapper[Int]) : ProductComparator[T] =
          new ProductComparator[T] {
            override def compare(p1: T,p2: T): Boolean = {
              p1.productArity == p2.productArity
            }
          }

}

case class Emp(a: Int,b: Int)

object Demo extends App{
  val comparator = implicitly[ProductComparator[Emp]]
}

要了解有关Scala在哪里寻找隐式信息的更多信息,请阅读Daniels brilliant post