简体   繁体   中英

to[List] on a generic HList after Partition

So I'm trying to do something like this:

@ import shapeless._
import shapeless._
@ case class A(); case class B(); case class C()
defined class A
defined class B
defined class C
case class Stuff(a: List[A], b: B, c: List[C])

@ def stuffs[H <: HList](hl:H)(
  implicit
  pb:Partition[H,B],
  pa:Partition[H,List[A]],
  pc:Partition[H,List[C]],
  tl: ToTraversable[H, List]
  ):List[Stuff] =
  hl.filter[B].to[List].map {
   b =>
     Stuff(
       a = hl.filter[List[A]].to[List].flatten,
       b = b,
       c = hl.filter[List[C]].to[List]flatten
     )
  }
Compilation Failed
Main.scala:374: could not find implicit value for parameter ts: shapeless.ops.hlist.ToTraversable[pb.Prefix,List]
hl.filter[B].to[List].map {
               ^
Main.scala:377: could not find implicit value for parameter ts: shapeless.ops.hlist.ToTraversable[pa.Prefix,List]
     a = hl.filter[List[A]].to[List].flatten,

I understand that some evidence is required for the to[List] in the result of hl.filter[B] , hl.filter[List[A]] , and hl.filter[List[C]] which would be pb.Prefix , pa.Prefix , and pc.Prefix , but those cannot be used on the same argument list, so not sure what can be done here

Update based on Jeremy's response:

well this works:

@ def stuffs[H <: HList, Prefix <: HList, Suffix <: HList]  (hl:H)(
    implicit
    pb:Partition.Aux[H,List[A],Prefix, Suffix ],
    prefixToTraversable: ToTraversable[Prefix, List]
    ) = hl.filter[List[A]].to[List]
defined function stuffs
@ stuffs(List(A()) :: List(A()) :: B() :: HNil)
res30: List[List[A]] = List(List(A()), List(A()))

@ def stuffs[H <: HList, Prefix <: HList, Suffix <: HList]  (hl:H)(
    implicit
    pb:Partition.Aux[H,B,Prefix, Suffix ],
    prefixToTraversable: ToTraversable[Prefix, List]
    ) = hl.filter[B].to[List]
defined function stuffs
@ stuffs(List(A()) :: List(A()) :: B() :: HNil)
res33: List[B] = List(B())

but this doesn't, which makes sense (it's still weird that it allows to define the function but it fails when trying to use it):

@ def stuffs[H <: HList, Prefix <: HList, Suffix <: HList]  (hl:H)(
    implicit
  pa:Partition.Aux[H,List[A],Prefix, Suffix ],
    pb:Partition.Aux[H,B,Prefix, Suffix ],
    prefixToTraversable: ToTraversable[Prefix, List]
    ) = (hl.filter[List[A]].to[List], hl.filter[B].to[List])
defined function stuffs
@ stuffs(List(A()) :: List(A()) :: B() :: HNil)
Compilation Failed
Main.scala:375: could not find implicit value for parameter pb: shapeless.ops.hlist.Partition.Aux[shapeless.::[List[cmd1.A],shapeless.::[List[cmd1.A],shapeless.::[cmd1.B,shapeless.HNil]]],cmd1.B,Prefix,Suffix]
stuffs(List(A()) :: List(A()) :: B() :: HNil)
      ^

then I tried this:

@ def stuffs[H <: HList, PA <: HList, SA <: HList, PB <: HList, SB <: HList]  (hl:H)(
    implicit
  pa:Partition.Aux[H,List[A],PA, SA ],
  pb:Partition.Aux[H,B,PB, SB ],
  prefixToTraversableA: ToTraversable[SA, List],
  prefixToTraversableB: ToTraversable[SB, List]
    ) = (hl.filter[List[A]].to[List], hl.filter[B].to[List])
Compilation Failed
Main.scala:380: could not find implicit value for parameter ts: shapeless.ops.hlist.ToTraversable[pa.Prefix,List]
  ) = (hl.filter[List[A]].to[List], hl.filter[B].to[List])
                            ^
Main.scala:380: could not find implicit value for parameter ts: shapeless.ops.hlist.ToTraversable[pb.Prefix,List]
  ) = (hl.filter[List[A]].to[List], hl.filter[B].to[List])
                                                   ^

That last snippet makes sense to me, so why does not work?

If you need to use the output types of a shapeless proof, you can use the proof's corresponding Aux type with an additional type parameter to get a proof for that output type in the same parameter list:

def stuffs[H <: HList, Prefix <: HList, Suffix <: HList](implicit
  pb: Partition.Aux[H, B, Prefix, Suffix],
  traversablePrefix: ToTraversable[Prefix, List]
  ....
)

Most proof types have an Aux type for just this purpose.

Your last attempt was quite close. @Jeremy was right about needing type variables for the output types of the Partition operations. You also need to specify the output types of the ToTraversable operations to determine the element type of the results of the conversions,

import shapeless._
import ops.hlist._, ops.traversable._

case class A()
case class B()
case class C()
case class Stuff(a: List[A], b: B, c: List[C])

def stuffs[H <: HList, PA <: HList, SA <: HList, PB <: HList, SB <: HList, PC <: HList, SC <: HList](hl:H)
  (implicit
    pa: Partition.Aux[H, List[A], PA, SA],
    pb: Partition.Aux[H, B, PB, SB],
    pc: Partition.Aux[H, List[C], PC, SC],
    prefixToTraversableA: ToTraversable.Aux[PA, List, List[A]],
    prefixToTraversableB: ToTraversable.Aux[PB, List, B],
    prefixToTraversableC: ToTraversable.Aux[PC, List, List[C]]
  ): List[Stuff] = {
    val as: List[A] = hl.filter[List[A]].to[List].flatten
    val bs: List[B] = hl.filter[B].to[List]
    val cs: List[C] = hl.filter[List[C]].to[List].flatten 
    bs.map(Stuff(as, _, cs))
  }

val hl = List(A(), A()) :: B() :: List(C()) :: B() :: List(C(), C()) ::HNil
val ss = stuffs(hl)
val expected =
  List(
    Stuff(List(A(), A()), B(), List(C(), C(), C())),
    Stuff(List(A(), A()), B(), List(C(), C(), C()))
  )

assert(ss == expected)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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