使用implicit来查找要注入的List类型类的“One”元素

时间:2014-06-05 06:05:14

标签: scala shapeless

以下是代码:

    trait Service[T<: HList] {
      def doStuff(): Unit
    }

    class A
    class B
    class C

    class ServiceAB extends Service[A :: B :: HNil] {
      override def doStuff(): Unit = println("handling a b")
    }

    class ServiceC extends Service[C :: HNil] {
      override def doStuff(): Unit = println("handling c")
    }

    implicit val serviceAB = new ServiceAB
    implicit val serviceC = new ServiceC

    def operate[T, W <: HList](x: T)(implicit service: Service[W]) = {
      service.doStuff()
    }

    operate(new C)

我只是想知道在执行操作(新C)时是否有可能或者我应该在类型级别编码以注入隐式serviceC,因为类C是ServiceC类型类的HList的元素?

非常感谢提前

1 个答案:

答案 0 :(得分:3)

我真的不知道你为什么需要这个:)

所以你的代码可以工作,但如果你明确地传递了类型参数:

operate[C, C :: HNil](new C)

如果您想要相同但隐式,则可以定义类类型:

trait Service[L <: HList, U] { def doStuff(): Unit }

trait lowPriority {
  implicit def otherwise[L <: HList, U] =
    new Service[L, U] {
      def doStuff(): Unit = println("handling otherwise")
    }
}

object Service extends lowPriority {
  implicit def ab[L <: HList, U]
  (implicit e: L =:= (A :: B :: HNil), 
            s: Selector[L, U]) =
    new Service[L, U] {
      def doStuff(): Unit = println("handling a b")
    }

  implicit def c[L <: HList, U]
  (implicit e: L =:= (C :: HNil), 
            s: Selector[L, U]) =
    new Service[L, U] {
      def doStuff(): Unit = println("handling c")
    }
  }
}

def operate[T, W <: HList](x: T)(implicit service: Service[W, T]) = {
  service.doStuff()
}

所以这可以按预期工作:

operate(new C) //> handling c
operate(new A) //> handling a b
operate(new B) //> handling a b

可以使它更通用(所以它会检查你需要的类型是HList,如果不是,则检查哦)(使用Curry-Howard同构,Miles Sabin的解释很棒的文章:http://www.chuusai.com/2011/06/09/scala-union-types-curry-howard/):

import reflect.runtime.universe._

type ¬[A] = A => Nothing
type ∨[T, U] = ¬[¬[T] with ¬[U]]
type ¬¬[A] = ¬[¬[A]]

class A
class B
class C
class D //> additional class for example

trait Service[L <: HList, U] { def doStuff(): Unit }

trait lowPriority {
  implicit def otherwise[L <: HList, U] =
    new Service[L, U] {
      def doStuff(): Unit = println("handling otherwise")
    }
}

object Service extends lowPriority {
  implicit def ab[L <: HList, U]
  (implicit e: (¬¬[U] <:< (A ∨ B)), 
            s: Selector[L, TypeTag[U]]) =
    new Service[L, U] {
      def doStuff(): Unit = println("handling a b")
    }

  implicit def c[L <: HList, U](implicit e: U =:= C, s: Selector[L, TypeTag[U]]) =
    new Service[L, U] {
      def doStuff(): Unit = println("handling c")
    }
  }
}

def operateBi[T, W <: HList](x: T, w: W)(implicit service: Service[W, T]) = {
  service.doStuff()
}

定义HLists类型:

val hl1 = implicitly[TypeTag[A]] :: implicitly[TypeTag[B]] :: HNil
val hl2 = implicitly[TypeTag[C]] :: HNil

operateBi(new C, hl1)
operateBi(new A, hl2)
operateBi(new B, hl1)
operateBi(new D, hl1)

按预期工作。