如果我理解正确的话你希望
def toCaseClass[A, R <: HList, L <: HList](implicit
g: Generic.Aux[A, R],
r: Reverse.Aux[L, R]
): L => A = l => g.from(l.reverse)
你只能指定A
进而R
, L
可以推断。
你可以这样做部分应用 https://stackoverflow.com/search?q=%5Bscala%5D%20PartiallyApplied pattern
import shapeless.ops.hlist.Reverse
import shapeless.{Generic, HList, HNil}
def toCaseClass[A] = new {
def apply[R <: HList, L <: HList]()(implicit
g: Generic.Aux[A, R],
r0: Reverse.Aux[R, L],
r: Reverse.Aux[L, R]
): L => A = l => g.from(l.reverse)
}
class A
class B
val a = new A
val b = new B
case class Result(a: A, b: B)
toCaseClass[Result]().apply(b :: a :: HNil)
(没有隐含的r0
类型参数L
无法根据调用推断.apply()
因为L
仅在致电时才得知.apply().apply(...)
)
或更好
def toCaseClass[A] = new {
def apply[R <: HList, L <: HList](l: L)(implicit
g: Generic.Aux[A, R],
r: Reverse.Aux[L, R]
): A = g.from(l.reverse)
}
toCaseClass[Result](b :: a :: HNil)
(这里我们不需要r0
因为L
经呼叫后即可得知.apply(...)
).
如果您愿意,可以将匿名类替换为命名类
def toCaseClass[A] = new PartiallyApplied[A]
class PartiallyApplied[A] {
def apply...
}
或者,您可以定义一个类型类(尽管这有点罗嗦)
trait ToCaseClass[A] {
type L
def toCaseClass(l: L): A
}
object ToCaseClass {
type Aux[A, L0] = ToCaseClass[A] { type L = L0 }
def instance[A, L0](f: L0 => A): Aux[A, L0] = new ToCaseClass[A] {
type L = L0
override def toCaseClass(l: L0): A = f(l)
}
implicit def mkToCaseClass[A, R <: HList, L <: HList](implicit
g: Generic.Aux[A, R],
r0: Reverse.Aux[R, L],
r: Reverse.Aux[L, R]
): Aux[A, L] = instance(l => g.from(l.reverse))
}
def toCaseClass[A](implicit tcc: ToCaseClass[A]): tcc.L => A = tcc.toCaseClass
toCaseClass[Result].apply(b :: a :: HNil)
使用类型类隐藏多个隐式:如何在 Scala 中用另一个方法包装具有隐式方法的方法? https://stackoverflow.com/questions/59175012/how-to-wrap-a-method-having-implicits-with-another-method-in-scala/
您可以在以下位置找到问题的答案类型 宇航员:
https://books.underscore.io/shapeless-guide/shapeless-guide.html#sec:ops:migration https://books.underscore.io/shapeless-guide/shapeless-guide.html#sec:ops:migration(6.3 案例研究:案例类迁移)
请注意IceCreamV1("Sundae", 1, true).migrateTo[IceCreamV2a]
需要一个single类型参数。
你的代码与GraphOps
由于多种原因不起作用。
首先,shapeless.Lazy
不仅仅是一个包装器。它是一个基于宏的类型类处理 https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#first-class-lazy-values-tie-implicit-recursive-knots“发散的隐式扩张”(在斯卡拉2.13 https://github.com/scala/scala/releases/tag/v2.13.0有by-name https://docs.scala-lang.org/sips/byname-implicits.html =>
隐含的,尽管它们不等于Lazy
)。你应该使用Lazy
当你明白为什么你需要它时。
其次,您似乎定义了一些隐式转换(隐式视图,Mat => A
)但是隐式转换的解析比其他隐式转换的解析更棘手(1 https://stackoverflow.com/questions/63964610/implicit-view-not-working-is-my-implicit-def-to-blame 2 https://stackoverflow.com/questions/62630439/in-scala-are-there-any-condition-where-implicit-view-wont-be-able-to-propagate 3 https://stackoverflow.com/questions/62205940/when-calling-a-scala-function-with-compile-time-macro-how-to-failover-smoothly 4 https://stackoverflow.com/questions/62751493/scala-kleisli-throws-an-error-in-intellij 5 https://stackoverflow.com/questions/63002466/what-are-the-hidden-rules-regarding-the-type-inference-in-resolution-of-implicit).
第三,您似乎假设当您定义时
implicit def foo: Foo = ???
def useImplicitFoo(implicit foo1: Foo) = ???
foo1
is foo
。但通常情况并非如此。foo
是在当前范围内定义的并且foo1
将在范围内解决useImplicitFoo
调用站点:
根据类型类设置抽象类型 https://stackoverflow.com/questions/64238219/setting-abstract-type-based-on-typeclass
当使用类型参数进行隐式解析时,为什么 val 放置很重要? https://stackoverflow.com/questions/59391232/when-doing-implicit-resolution-with-type-parameters-why-does-val-placement-matt(之间的差异implicit x: X
and implicitly[X]
)
如此含蓄createConverter
只是不在您调用时的范围内toCaseClass
.
您的代码的固定版本是
trait RunnableGraph[Mat]{
def mapMaterializedValue[A](a: Mat => A): RunnableGraph[A]
}
case class Wrapper[A, B](value: A => B)
implicit class GraphOps[Mat <: HList](g: RunnableGraph[Mat]) {
val ops = this
implicit def createConverter[A, RL <: HList](implicit
r: Reverse.Aux[Mat, RL],
gen: Generic.Aux[A, RL],
): Wrapper[Mat, A] =
Wrapper { l =>
val x: RL = l.reverse
val y: A = gen.from(x)
gen.from(l.reverse)
}
def toCaseClass[A](implicit convert: Wrapper[Mat, A]): RunnableGraph[A] = {
g.mapMaterializedValue(convert.value)
}
}
val g: RunnableGraph[B :: A :: HNil] = ???
val ops = g.ops
import ops._
g.toCaseClass[Result]
Try
import akka.stream.scaladsl.RunnableGraph
import shapeless.{::, Generic, HList, HNil}
import shapeless.ops.hlist.Reverse
implicit class GraphOps[Mat <: HList, R <: HList](g: RunnableGraph[Mat]) {
def toCaseClass[A](implicit
r: Reverse.Aux[Mat, R],
gen: Generic.Aux[A, R]
): RunnableGraph[A] = g.mapMaterializedValue(l => gen.from(l.reverse))
}
case class Result(one: String, two: Int)
val g: RunnableGraph[Int :: String :: HNil] = ???
g.toCaseClass[Result]