我正在构建一个泛型函数,它接收HList
形式的F[T1] :: ... :: F[Tn] :: HNil
,将其转换为F[T1 :: ... :: Tn :: HNil]
,然后需要将其传递到传入的块中但是,为了使其工作,我需要在F[_]
中提取HList类型。我在Shapeless'hlistconstraints
下找到了一些与之相关的东西:
/**
* Type class witnessing that every element of `L` has `TC` as its outer type constructor.
*/
trait UnaryTCConstraint[L <: HList, TC[_]]
...但这只能用于验证传入的hlist是否确实仅由F[_]
组成;然而似乎没有办法提取_
位以便对自己的hlist说。
我应该在哪里寻找能找到工作的东西?或者我不应该期望找到任何开箱即用的东西,而是自己构建类型计算?
披露:这个问题是Generic transform/fold/map over tuple/hlist containing some F[_]的辅助内容,但在我看来,它至少与独立问题一样有用。
答案 0 :(得分:3)
看起来Sequencer已经这样做了:
import scala.language.higherKinds
class Wrap[TC[_]] {
def foo[L1 <: HList, L2 <: HList](xs: L1)(implicit
seq: Sequencer.Aux[L1, TC[L2]] // L2 is the type we're looking for
): L2 = ???
}
val ret = new Wrap[Option].foo(1.some :: 2.some :: HNil)
// ret now has type Int :: Int :: HNil
...但我现在无法想出通过
制作更好的方法TC
为Option
。注意:我认为这个答案有点有用,但我不接受它 - 希望有人会提出一个更通用,更好看的解决方案。
答案 1 :(得分:0)
为了实现这一点,F
必须至少具有应用能力。一旦确定,就可以像下面的代码中那样:
trait HApplicative[Eff[_], InL <: HList] extends {
type OutL <: HList
def product: InL => Eff[OutL]
}
object HApplicative {
case class HAppAux[Eff[_], InL <: HList, OutL0 <: HList](zipper: InL => Eff[OutL0]) extends HApplicative[Eff, InL] {
type OutL = OutL0
override def product: InL => Eff[OutL0] = zipper
}
implicit def nilHApp[Eff[_]](implicit app: Applicative[Eff]): HApplicative[Eff, HNil] {type OutL = HNil} =
HAppAux[Eff, HNil, HNil](_ => app.pure(HNil))
implicit def consHApp[Eff[_], InH, InT <: HList](
implicit tailHApp: HApplicative[Eff, InT],
app: Applicative[Eff]
): HApplicative[Eff, Eff[InH] :: InT] {type OutL = InH :: tailHApp.OutL} = HAppAux[Eff, Eff[InH] :: InT, InH :: tailHApp.OutL] {
case (inH: Eff[InH]) :: inT => app.map2(inH, tailHApp.product(inT)) {
case (head, tail) => head :: tail
}
}
def product[Eff[_],InL<:HList](inL:InL)(implicit happ:HApplicative[Eff,InL]):happ.OutL = happ.product(inL)
}