HList foldLeft với tuple bằng 0
Tôi đang cố gắng foldLefttrên một HList với một loại bộ tích lũy (HL, Int), đâu HLlà một HList. Chương trình dưới đây không biên dịch. Tuy nhiên, nếu tôi chuyển sang loại bộ tích lũy đơn giản hơn HL(chỉ bằng cách chuyển các dòng đã nhận xét với các dòng ở trên), nó sẽ biên dịch và hoạt động.
Việc bao bọc một HList trong một bộ tuple sẽ phá vỡ độ phân giải ngầm cho leftFolder. Tôi đang thiếu gì?
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)
}
Trả lời
Bạn muốn thực hiện quá nhiều công việc trong một bước duy nhất.
Cố gắng thêm một tham số loại nữa 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)
}
Đọc về hàm ý bị ràng buộc quá mức:
https://books.underscore.io/shapeless-guide/shapeless-guide.html#sec:type-level-programming:chaining (4.3 Chuỗi các chức năng phụ thuộc)
Không tìm thấy tham số ngầm Scala shapeless Generic.Aux trong unpply
Trích xuất giá trị và khóa FieldType từ HList
Làm thế nào để tìm ra loại ở đầu của một HList không định hình
Làm thế nào để suy ra kiểu bên trong của giá trị bản ghi Shapeless với hàm tạo kiểu một ngôi?