我正在尝试使用无形'Coproduct进行错误类型聚合.以下是尝试隔离我目前的问题:
import shapeless._
case object F1
case object F2
type F12 = F1.type :+: F2.type :+: CNil
case object F3
case object F4
type F34 = F3.type :+: F4.type :+: CNil
type F1234 = F1.type :+: F2.type :+: F3.type :+: F4.type :+: CNil
def custom(f: Either[F12, F34]): F1234 = // how can I declare the resulting type?
f.fold(_.extendRightBy[F34], _.extendLeftBy[F12])
object F1234Handler extends Poly1 {
implicit def caseF1 = at[F1.type](_ => "got F1")
implicit def caseF2 = at[F2.type](_ => "got F2")
implicit def caseF3 = at[F3.type](_ => "got F3")
implicit def caseF4 = at[F4.type](_ => "got F4")
}
custom(Left(Coproduct[F12](F2))).fold(F1234Handler) // got F2
Run Code Online (Sandbox Code Playgroud)
如何在自定义折叠中声明结果类型而不必重复自己?理想情况下,我不想以我的方式声明F1234,我想通过仅仅创建两个现有类型声明F12和F34的联合来声明它.这样,每当我向这些声明中的任何一个添加另一个失败类型时,我都不需要更新F1234声明.我可以声明类型F1234 = F1.type:+:F2.type:+:F34但我不能声明类型F1234 = F12:+:F34,因为F12的CNil尾部,它被extendBy操作丢弃.
作为LMM的回答表明,部分原因是无形的提供的情况不那么糟糕ExtendBy的是封装了类型的类ExtendLeftBy和ExtendRightBy.因此,如果你真的想要一个返回类型custom,你没有自己计算并手写,你可以使用ExtendBy:
import shapeless._, ops.coproduct.ExtendBy
case object F1
case object F2
type F12 = F1.type :+: F2.type :+: CNil
case object F3
case object F4
type F34 = F3.type :+: F4.type :+: CNil
def custom(f: Either[F12, F34])(implicit ext: ExtendBy[F12, F34]): ext.Out =
f.fold(ext.right(_), ext.left(_))
Run Code Online (Sandbox Code Playgroud)
即使你确实需要使用ExtendLeftBy和ExtendRightBy直接,你可以说服它们具有相同的输出类型多一点干净的编译器Aux类型和一个共享的类型参数.所以不是这个(lmm代码的完整工作版本):
import ops.coproduct.{ ExtendLeftBy, ExtendRightBy }
def custom[ERO, ELO](f: Either[F12, F34])(implicit
el: ExtendRightBy[F12, F34] { type Out = ELO },
er: ExtendLeftBy[F12, F34] { type Out = ERO },
w: ELO =:= ERO
): ERO = f.fold(l => w(el(l)), er(_))
Run Code Online (Sandbox Code Playgroud)
你会写这个:
def custom[Out <: Coproduct](f: Either[F12, F34])(implicit
extL: ExtendRightBy.Aux[F12, F34, Out],
extR: ExtendLeftBy.Aux[F12, F34, Out]
): Out = f.fold(extL(_), extR(_))
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,如果您静态地知道输入类型,那么您只需自己写出返回类型并完全跳过隐式参数业务.只有在使用泛型类型时才需要隐式证据,如下所示:
def custom[A <: Coproduct, B <: Coproduct](f: Either[A, B])(implicit
ext: ExtendBy[A, B]
): ext.Out = f.fold(ext.right(_), ext.left(_))
Run Code Online (Sandbox Code Playgroud)
这适用于任何两个副产品,而不仅仅是F12和F34.