【问题标题】:Scala, getting the type parameters of a KList as an HListScala,将 KList 的类型参数作为 HList
【发布时间】:2014-12-30 03:09:34
【问题描述】:

假设我有一个任意的KList,为了参数,它有类型构造函数Option[_],即;

type Example = Option[Int] :: Option[String] :: HNil

有没有办法可以检索由类型参数组成的 Hlist?

type Params = Int :: String :: HNil

所以,例如,我可以定义某种任意的 getOrElse 方法

getOrElse(ex:Example, default:Params):Params

现在我正在寻找可能是这种形式的东西(或类似于我建议的类型结构可能不可行)。

case class MyOptionList[L <: HList](maybes:L) {
  type Concrete = {somehow the hlist params types as an Hlist}
  def getOrElse(default:Concrete):Concrete = ???

}

【问题讨论】:

    标签: scala shapeless


    【解决方案1】:

    我不是 Miles,但可以通过 Shapeless 的 Comapped 优雅地完成你想做的事情:

    import shapeless._, ops.hlist.Comapped
    
    case class MyOptionList[L <: HList, C <: HList](maybes: L)(
      implicit val comapped: Comapped.Aux[L, Option, C]
    ) {
      def getOrElse(default: C): C = default // Not a useful implementation
    }
    

    然后:

    scala> val x: Int :: HNil = MyOptionList(Option(1) :: HNil).getOrElse(2 :: HNil)
    x: shapeless.::[Int,shapeless.HNil] = 2 :: HNil
    

    请注意,在某些情况下,将约束放在方法上会更方便:

    case class MyOptionList[L <: HList](maybes: L) {
      def getOrElse[C <: HList: ({ type l[x] = Comapped.Aux[L, Option, x] })#l](
        default: C
      ): C = default
    }
    

    这里的用法是一样的,但是你在case类上没有额外的类型参数。如果您想使用这种方法但限制 MyOptionList 的创建以禁止非 Option 成员,您可以在其类型参数列表中使用 L &lt;: HList: *-&gt;*[Option]#λ

    【讨论】:

      【解决方案2】:

      @MilesSabin 可能会给出一个更优雅的答案,但您可以手动递归地构造它,就像许多 Shapeless 内部事物的编写方式一样:

      sealed trait GetOrElse[L <: HList] {
        type Concrete <: HList
        def getOrElse(ex: L, default: Concrete): Concrete
      }
      object GetOrElse {
        implicit def nil = new GetOrElse[HNil]{
          type Concrete = HNil
          def getOrElse(ex: HNil, default: HNil) = HNil
        }
        implicit def cons[H, T <: HList](implicit tl: GetOrElse[T]) =
          new GetOrElse[Option[H] :: T]{
            type Concrete = H :: tl.Concrete
            def getOrElse(ex: Option[H] :: T, default: Concrete) =
              ex.head.getOrElse(default.head) ::
                tl.getOrElse(ex.tail, default.tail)
          }
        def apply[L <: HList](implicit goe: GetOrElse[L])
          : GetOrElse[L]{type Concrete = goe.Concrete} = goe
      }
      
      case class MyOptionList[L <: HList, C](maybes:L)(
        implicit goe: GetOrElse[L]{type Concrete = C}) {
        def getOrElse(default:C):C = goe.getOrElse(maybes, default)
      }
      

      (可能使用类型成员而不是类型参数,但我对这些类型信息何时被吃掉感到困惑,所以我倾向于在任何地方都使用类型参数)

      【讨论】:

      • 像魅力一样工作,非常感谢。我先把它打开一会儿,看看我们能不能从迈尔斯那里得到什么……
      • 这是一个很好的直接实现。如果特拉维斯没有打败我,我也会把你指向Comapped
      猜你喜欢
      • 2016-08-07
      • 2013-05-24
      • 2016-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-22
      相关资源
      最近更新 更多