问题
Given the following
case class A(value:Int)
case class B(value:String)
val h:Option[A] :: A :: Option[B] :: Option[A] :: HNil = Some(A(1)) :: A(2) :: Some(B("two")) :: (None:Option[B]) :: HNil
How can I get the following ?
A(1) :: A(2) :: B("two") :: HNil
My attempt below
trait a extends Poly1 {
implicit def any[T] = at[T](_ :: HNil)
}
object f extends a {
implicit def some[T] = at[Option[T]](t => if (t.isDefined) t.get :: HNil else HNil)
}
works for map
h map f
> A(1) :: HNil :: A(2) :: HNil :: B(two) :: HNil :: HNil :: HNil
but fail for flatMap
h flatMap f
> could not find implicit value for parameter mapper: shapeless.ops.hlist.FlatMapper[f.type,shapeless.::[Option[A],shapeless.::[A,shapeless.::[Option[B],shapeless.::[Option[B],shapeless.HNil]]]]]
回答1:
Most likely the only thing you can do is define separate cases for Some and for None:
trait a extends Poly1 {
implicit def default[T] = at[T](_ :: HNil)
}
object f extends a {
implicit def caseSome[T] = at[Some[T]](_.get :: HNil)
implicit def caseNone = at[None.type](_ => HNil)
}
It also means you can't use generic Options in the types, it must be known at compile time whether each element is Some or None:
scala> (Some(A(1)) :: A(2) :: Some(B("two")) :: None :: HNil) flatMap f
res1: shapeless.::[A,shapeless.::[A,shapeless.::[B,shapeless.HNil]]] = A(1) :: A(2) :: B(two) :: HNil
This distinction defines the type of the resulting expression: Some(1) :: HNil flatMap f will have type ::[Int, HNil], but None :: HNil flatMap f will have type just HNil.
This kind of type information can't be figured out at compile time from simple Options: should (x: Option[T]) :: HNil flatMap f have type ::[T, HNil] or HNil? We don't know until we actually run the program and see what the value of x is.
I'm not sure if there's some smart way to do it anyway and get an opaque HList, but at that point you'll abandon exact type information about each element and the length of the list and may as well cast it to a normal List (and maybe use cast from shapeless later if you know what exact type the final result will have)
来源:https://stackoverflow.com/questions/29566279/shapeless-flatmap-hlist-with-option-yielding-hlist