首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >合并HList元素

合并HList元素
EN

Stack Overflow用户
提问于 2017-04-28 16:35:44
回答 2查看 147关注 0票数 1

我有一个简单的服务定义

代码语言:javascript
复制
trait Service[-Req, +Rep] extends (Req => Future[Rep]) {
    def apply(request: Req): Future[Rep]
}

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

代码语言:javascript
复制
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

代码语言:javascript
复制
  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)
      }
  }

我有一项服务

代码语言:javascript
复制
object S extends Service[Int, String] {
    def apply(request: Int): Future[String] =  Future successful request.toString
}

当我试图解出简单的链时

代码语言:javascript
复制
implicitly[Resolver[S.type :: HNil, Int]].apply(S :: HNil)

我发现了一个隐含的没有发现的错误。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-05-10 09:41:55

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

因此,要解决这个问题,您必须将S <: Service[I, O]作为隐式搜索/类型推断过程的一部分。例如,以下几种方式之一:

代码语言:javascript
复制
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不是更有意义吗?

代码语言:javascript
复制
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一样。

票数 1
EN

Stack Overflow用户

发布于 2017-05-08 00:48:42

不知道为什么这会被否决,也许你可以提供一个样本回购。不管怎样,这是个部分答案,也许这能让你重回正轨。

1)为您的build.sbt:scalacOptions += "-Xlog-implicits"中的内嵌启用调试选项

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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43685030

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档