繁体   English   中英

HList foldLeft,元组为零

[英]HList foldLeft with tuple as zero

我试图在带有(HL, Int)类型的累加器的foldLeft上 foldLeft ,其中HL是 HList。 下面的程序不能编译。 但是,如果我切换到更简单的HL类型累加器(只需将注释行与上面的行切换),它就会编译并且可以工作。

将 HList 包装在元组中会破坏 leftFolder 的隐式解析。 我错过了什么?

package foo.bar

import shapeless.{:+:, ::, CNil, Coproduct, Generic, HList, HNil, Lazy, Poly2}
import shapeless.ops.hlist.{LeftFolder, Reverse}

object StackOverflow extends App {

  trait MyTypeclass[T] {
    def doSomething(t: T): (T, Int)
  }

  implicit lazy val stringInstance: MyTypeclass[String] = (t: String) => (t, 0)
  implicit val hnilInstance: MyTypeclass[HNil] = (t: HNil) => (t, 0)
  implicit def hlistInstance[H, T <: HList](
    implicit
    head: Lazy[MyTypeclass[H]],
    tail: MyTypeclass[T]
  ): MyTypeclass[H :: T] =
    (ht: H :: T) =>
      ht match {
        case h :: t =>
          val (hres, hint) = head.value.doSomething(h)
          val (tres, tint) = tail.doSomething(t)
          (hres :: tres, hint + tint)
    }
  implicit val cnilInstance: MyTypeclass[CNil] = (t: CNil) => ???
  implicit def coproductInstance[L, R <: Coproduct](
    implicit
    head: Lazy[MyTypeclass[L]],
    tail: MyTypeclass[R]
  ): MyTypeclass[L :+: R] = (lr: L :+: R) => ???

  object leftFolder extends Poly2 {
    implicit def caseAtSimple[F, HL <: HList]: Case.Aux[HL, F, F :: HL] =
      at {
        case (acc, f) => f :: acc
      }
    implicit def caseAtComplex[F, HL <: HList]: Case.Aux[(HL, Int), F, (F :: HL, Int)] =
      at {
        case ((acc, i), f) => (f :: acc, i)
      }
  }

  implicit def genericInstance[T, HL <: HList, LL <: HList](
    implicit
    gen: Generic.Aux[T, HL],
    myTypeclass: Lazy[MyTypeclass[HL]],
//    folder: LeftFolder.Aux[HL, HNil, leftFolder.type, LL],
    folder: LeftFolder.Aux[HL, (HNil, Int), leftFolder.type, (LL, Int)],
    reverse: Reverse.Aux[LL, HL]
  ): MyTypeclass[T] = (t: T) => {
    val generic = gen.to(t)
    val (transformed, idx) = myTypeclass.value.doSomething(generic)
//    val ll = transformed.foldLeft(HNil: HNil)(leftFolder)
    val (ll, _) = transformed.foldLeft((HNil: HNil, 0))(leftFolder)
    val reversed = reverse(ll)
    (gen.from(reversed), idx)
  }

  def doSomething[T](t: T)(implicit myTypeclass: MyTypeclass[T]): T = myTypeclass.doSomething(t)._1

  case class Foo(
    str1: String,
    str2: String
  )

  val original = Foo("Hello World!", "Hello there!")
  val result = doSomething(original)
  println(result == original)
}

您希望隐式在一个步骤中完成太多工作。

尝试再添加一个类型参数Out

implicit def genericInstance[T, HL <: HList, Out, LL <: HList](
  implicit
  gen: Generic.Aux[T, HL],
  myTypeclass: Lazy[MyTypeclass[HL]],
  //folder: LeftFolder.Aux[HL, (HNil, Int), leftFolder.type, (LL, Int)],
  folder: LeftFolder.Aux[HL, (HNil, Int), leftFolder.type, Out],
  ev: Out <:< (LL, Int), // added
  reverse: Reverse.Aux[LL, HL]
): MyTypeclass[T] = (t: T) => {
  val generic = gen.to(t)
  val (transformed, idx) = myTypeclass.value.doSomething(generic)
  //val (ll, _) = transformed.foldLeft((HNil: HNil, 0))(leftFolder)
  val (ll, _) = ev(transformed.foldLeft((HNil: HNil, 0))(leftFolder))
  val reversed = reverse(ll)
  (gen.from(reversed), idx)
}

阅读过度约束的隐式:

https://books.underscore.io/shapeless-guide/shapeless-guide.html#sec:type-level-programming:chaining(4.3链接依赖函数)

未应用中未找到 Scala 无形的 Generic.Aux 隐式参数

从 HList 中提取 FieldType 键和值

如何隐式地找出一个无形的HList头部的类型

如何使用一元类型构造函数推断无形状记录值的内部类型?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM