I am trying to transform the following HList
Some(C(15)) :: None :: Some(B(55)) :: None :: Some(A(195)) :: HNil
to
C(15) :: B(55) :: A(195) :: HNil
Here is what I have at the moment :
import shapeless._
case class A(value: Int)
case class B(value: Int)
case class C(value: Int)
trait folderLP extends Poly2 {
implicit def default[T, L <: HList] = at[T, L]((acc, t) => acc)
}
object folder extends folderLP {
implicit def none[T, L <: HList] = at[None.type, L]((t, acc) => acc)
implicit def someDiameter[T, L <: HList] = at[Some[C], L]((t, acc) => t.get :: acc)
implicit def someRatio[T, L <: HList] = at[Some[B], L]((t, acc) => t.get :: acc)
implicit def someWidth[T, L <: HList] = at[Some[A], L]((t, acc) => t.get :: acc)
}
val test = Some(C(15)) :: None :: Some(B(55)) :: None :: Some(A(195)) :: HNil
val filtered = test.foldRight[HList](HNil)(folder)
this works but I would like to make this generic so that it works for any type wrapped in Some without having to write each case
First for a literal answer. Note that most of your
T
type parameters aren't being used. You can use thatT
to make your function match any element of typeSome[T]
:Note that you don't even need the
none
case if you switch the order of arguments in yourdefault
.Also note that you probably want to use the following definition of
filtered
:This one will have the
HNil
statically typed as anHNil
instead of anHList
, which will be useful for pretty much anything you want to do down the line—for example tryfiltered.length
on your original version and then on this one.You don't even really need a fold for this operation, though—a
flatMap
will do:And then:
Finally, it's worth noting that this will only work on an
HList
where theNone
andSome
elements are statically typed asNone
andSome
—aSome[A]
for example that's statically typed as anOption[A]
will get filtered out. This makes it kind of unuseful (at least I can't see a practical use), but there's just not really any way you can perform this kind of type-level filter if you don't know at compile time whether theOption
is empty or not.