将无形hlist类型F [T1] :: ... :: F [Tn] :: HNil映射到类型T1 :: ... :: Tn :: HNil(类型级别排序)

时间:2014-10-21 20:39:47

标签: scala shapeless type-level-computation

我正在构建一个泛型函数,它接收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[_]的辅助内容,但在我看来,它至少与独立问题一样有用。

2 个答案:

答案 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

...但我现在无法想出通过

制作更好的方法
  • 摆脱包装类;
  • 让Scala推断TCOption

注意:我认为这个答案有点有用,但我不接受它 - 希望有人会提出一个更通用,更好看的解决方案。

答案 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)
}