根据抽象类型成员搜索类型
Search for types based on their abstract type members
我有以下类型定义:
trait Content
trait Wrapper {
type ContentType
}
final case class Foo(param: String) extends Content
final case class Bar(param: String) extends Content
final case class FooWrapper(foo: Foo) extends Wrapper { type ContentType = Foo }
final case class BarWrapper(bar: Bar) extends Wrapper { type ContentType = Bar }
在运行时给定一个内容值,我想 return 将其包装在相应的包装器类型中。我使用 Shapeless 尝试了以下操作:
def fetchWrapper[N, G <: Wrapper](
implicit
gen: Generic.Aux[G, N :: HNil],
// this also compiles, as an alternative to Generics.Aux
// =:= :G#ValueType =:= N
) = ...
它有效,但前提是我明确提供类型参数:fetchWrapper[Foo, FooWrapper]
。我如何利用隐式解析来概括事物,以便我可以为给定内容派生出正确的包装器?
我正在考虑在 shapeless book 的 random number generator 部分使用相同的推导技术生成包装器的实例(即如果我有一个隐式 Bar :: HNil
在范围内),但我一开始甚至找不到正确的包装器类型。
Generic
可以轻松帮助将 Wrapper
子类型转换为 Content
子类型,但反之亦然。
试试类型class
trait ContentToWrapper[C <: Content] {
type Out <: Wrapper { type ContentType = C }
}
object ContentToWrapper {
implicit val foo: ContentToWrapper[Foo] { type Out = FooWrapper } = null
implicit val bar: ContentToWrapper[Bar] { type Out = BarWrapper } = null
}
def fetchWrapper[C <: Content](implicit ctw: ContentToWrapper[C]): ctw.Out = ???
如果你使 Wrapper
密封你可以导出类型 class
import shapeless.{Coproduct, Generic, HList, Poly1, poly}
import shapeless.ops.coproduct.ToHList
import shapeless.ops.hlist.CollectFirst
object ContentToWrapper {
implicit def mkContentToWrapper[C <: Content, WC <: Coproduct, WL <: HList](implicit
generic: Generic.Aux[Wrapper, WC],
toHList: ToHList.Aux[WC, WL], // there is CollectFirst for HList but not for Coproduct
collect: CollectFirst[WL, WrapperSubtypePoly[C]]
): ContentToWrapper[C] { type Out = collect.Out } = null
trait WrapperSubtypePoly[C] extends Poly1
object WrapperSubtypePoly {
implicit def cse[C, A <: Wrapper { type ContentType = C }]:
poly.Case1.Aux[WrapperSubtypePoly[C], A, A] = poly.Case1(identity)
}
}
测试:
val w1 = fetchWrapper[Foo]
w1: FooWrapper
val w2 = fetchWrapper[Bar]
w2: BarWrapper
我有以下类型定义:
trait Content
trait Wrapper {
type ContentType
}
final case class Foo(param: String) extends Content
final case class Bar(param: String) extends Content
final case class FooWrapper(foo: Foo) extends Wrapper { type ContentType = Foo }
final case class BarWrapper(bar: Bar) extends Wrapper { type ContentType = Bar }
在运行时给定一个内容值,我想 return 将其包装在相应的包装器类型中。我使用 Shapeless 尝试了以下操作:
def fetchWrapper[N, G <: Wrapper](
implicit
gen: Generic.Aux[G, N :: HNil],
// this also compiles, as an alternative to Generics.Aux
// =:= :G#ValueType =:= N
) = ...
它有效,但前提是我明确提供类型参数:fetchWrapper[Foo, FooWrapper]
。我如何利用隐式解析来概括事物,以便我可以为给定内容派生出正确的包装器?
我正在考虑在 shapeless book 的 random number generator 部分使用相同的推导技术生成包装器的实例(即如果我有一个隐式 Bar :: HNil
在范围内),但我一开始甚至找不到正确的包装器类型。
Generic
可以轻松帮助将 Wrapper
子类型转换为 Content
子类型,但反之亦然。
试试类型class
trait ContentToWrapper[C <: Content] {
type Out <: Wrapper { type ContentType = C }
}
object ContentToWrapper {
implicit val foo: ContentToWrapper[Foo] { type Out = FooWrapper } = null
implicit val bar: ContentToWrapper[Bar] { type Out = BarWrapper } = null
}
def fetchWrapper[C <: Content](implicit ctw: ContentToWrapper[C]): ctw.Out = ???
如果你使 Wrapper
密封你可以导出类型 class
import shapeless.{Coproduct, Generic, HList, Poly1, poly}
import shapeless.ops.coproduct.ToHList
import shapeless.ops.hlist.CollectFirst
object ContentToWrapper {
implicit def mkContentToWrapper[C <: Content, WC <: Coproduct, WL <: HList](implicit
generic: Generic.Aux[Wrapper, WC],
toHList: ToHList.Aux[WC, WL], // there is CollectFirst for HList but not for Coproduct
collect: CollectFirst[WL, WrapperSubtypePoly[C]]
): ContentToWrapper[C] { type Out = collect.Out } = null
trait WrapperSubtypePoly[C] extends Poly1
object WrapperSubtypePoly {
implicit def cse[C, A <: Wrapper { type ContentType = C }]:
poly.Case1.Aux[WrapperSubtypePoly[C], A, A] = poly.Case1(identity)
}
}
测试:
val w1 = fetchWrapper[Foo]
w1: FooWrapper
val w2 = fetchWrapper[Bar]
w2: BarWrapper