【问题标题】:Merging HList elements合并 HList 元素
【发布时间】:2017-05-10 19:28:44
【问题描述】:

我有一个简单的服务定义

trait Service[-Req, +Rep] extends (Req => Future[Rep]) {
    def apply(request: Req): Future[Rep]
}

以及如何链接服务的方法:

implicit class ServiceOps1[Req, RepIn](service: Service[Req, RepIn]) {
    def -->[RepOut](next: Service[RepIn, RepOut]): Service[Req, RepOut] =
        (req: Req) => service(req) flatMap next
}

我想将我的所有服务(假设它们可以组合)放入HList,然后从HList 构建服务组合。

这是我的Resolver

  trait Resolver[L <: HList, In] {
    type Out
    def apply(l: L): Service[In, Out]
  }

  object Resolver {
    def apply[L <: HList, In](implicit resolver: Resolver[L, In]): Aux[L, In, resolver.Out] = resolver

    type Aux[L <: HList, In, Out0] = Resolver[L, In] { type Out = Out0 }

    implicit def hsingleResolver[I, O, S <: Service[I, O]]: Aux[S :: HNil, I, O] =
      new Resolver[S :: HNil, I] {
        type Out = O
        def apply(l : S :: HNil): Service[I, Out] = l.head
      }

    implicit def hlistResolver[I, O, S <: Service[I, O], T <: HList](implicit res : Resolver[T, O]): Aux[S :: T, I, res.Out] =
      new Resolver[S :: T, I] {
        type Out = res.Out

        def apply(l: S :: T): Service[I, res.Out] = l.head --> res(l.tail)
      }
  }

我有服务

object S extends Service[Int, String] {
    def apply(request: Int): Future[String] =  Future successful request.toString
}

当我尝试解决简单链时

implicitly[Resolver[S.type :: HNil, Int]].apply(S :: HNil)

我得到一个隐含的未找到错误。

【问题讨论】:

    标签: scala shapeless hlist


    【解决方案1】:

    问题在于您的隐式类型签名:implicit def hsingleResolver[I, O, S &lt;: Service[I, O]]: Aux[S :: HNil, I, O]。这里因为S &lt;: Service[I, O],您希望O 是根据S 的类型推断出来的,但不幸的是它不是这样工作的。类型参数列表中的S &lt;: Service[I, O] 子句在推断类型参数时不予考虑。当你调用implicitly[Resolver[S.type :: HNil, Int]] 时会发生什么,编译器会看到S = S.typeI = IntO 是未知的,所以O = Nothing。然后它继续检查 S &lt;: Service[Int,Nothing] 是否为 false 并且隐式搜索失败。

    因此,要解决此问题,您必须使 S &lt;: Service[I, O] 成为隐式搜索/类型推断过程的一部分。例如通过以下方式之一:

    implicit def hsingleResolver[I, O, S](implicit ev: S <:< Service[I,O]): Aux[S :: HNil, I, O] // option 1
    implicit def hsingleResolver[I, O, S]: Aux[(S with Service[I,O]) :: HNil, I, O] // option 2
    

    附带说明:用以下方式定义Resolver 不是更有意义吗?

    trait Resolver[L <: HList] {
      type In
      type Out
      def apply(l: L): Service[In, Out]
    }
    
    object Resolver {
      def apply[L <: HList](implicit resolver: Resolver[L]): Aux[L, resolver.In, resolver.Out] = resolver
    
      type Aux[L <: HList, In0, Out0] = Resolver[L] { type In = In0; type Out = Out0 }
    
      ...
    }
    

    因为In也依赖于L,就像Out一样。

    【讨论】:

      【解决方案2】:

      不知道为什么这被否决了,也许你可以提供一个示例回购。无论如何,这是部分答案,也许这会让你重回正轨。

      1) 在 build.sbt 中启用隐式调试选项:scalacOptions += "-Xlog-implicits"

      2) 为 HNil 定义解析器:implicit def hNilResolver[I]: Aux[HNil, I, HNil] = ???

      3) 在调试输出之后,修复剩余部分:)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-09
        • 1970-01-01
        • 1970-01-01
        • 2021-06-15
        • 1970-01-01
        • 2012-04-28
        相关资源
        最近更新 更多