Shapeless flatmap HList with Option yielding HList

折月煮酒 提交于 2019-12-23 12:34:34

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!