合并 HList 元素
Merging HList elements
我有一个简单的服务定义
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)
我收到隐含的未找到错误。
不知道为什么这被否决了,也许你可以提供一个示例 repo。无论如何,这是部分答案,也许这会让您重回正轨。
1) 在您的 build.sbt 中为隐式启用调试选项:scalacOptions += "-Xlog-implicits"
2) 为 HNil 定义解析器:implicit def hNilResolver[I]: Aux[HNil, I, HNil] = ???
3) 根据调试输出,修复剩余部分:)
问题出在你的隐含函数的类型签名上: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.type
、I = Int
和 O
是未知的,因此 O = Nothing
。然后它继续检查 S <: Service[Int,Nothing]
这是错误的并且隐式搜索失败。
因此,要解决此问题,您必须使 S <: Service[I, O]
成为隐式 search/type 推理过程的一部分。例如,通过以下方式之一:
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
.
我有一个简单的服务定义
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)
我收到隐含的未找到错误。
不知道为什么这被否决了,也许你可以提供一个示例 repo。无论如何,这是部分答案,也许这会让您重回正轨。
1) 在您的 build.sbt 中为隐式启用调试选项:scalacOptions += "-Xlog-implicits"
2) 为 HNil 定义解析器:implicit def hNilResolver[I]: Aux[HNil, I, HNil] = ???
3) 根据调试输出,修复剩余部分:)
问题出在你的隐含函数的类型签名上: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.type
、I = Int
和 O
是未知的,因此 O = Nothing
。然后它继续检查 S <: Service[Int,Nothing]
这是错误的并且隐式搜索失败。
因此,要解决此问题,您必须使 S <: Service[I, O]
成为隐式 search/type 推理过程的一部分。例如,通过以下方式之一:
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
.