简体   繁体   中英

Shapeless flatmap HList with Option yielding HList

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]]]]]

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 Option s 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 Option s: 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)

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