具有选项的无形平面图HList产生HList

时间:2015-04-10 16:24:36

标签: scala shapeless

鉴于以下内容

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

我如何获得以下内容?

A(1) :: A(2) :: B("two") :: HNil

我的尝试

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)         
}

适用于地图

h map f

> A(1) :: HNil :: A(2) :: HNil :: B(two) :: HNil :: HNil :: HNil

但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 个答案:

答案 0 :(得分:1)

您可能做的唯一事情就是为SomeNone定义单独的案例:

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)
}

这也意味着你不能在类型中使用泛型Option,在编译时必须知道每个元素是Some还是{{1} }:

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 将具有类型Some(1) :: HNil flatMap f,但::[Int, HNil]将只具有None :: HNil flatMap f类型。

这种类型的信息无法在编译时从简单的HNil s中找出:Option应该有(x: Option[T]) :: HNil flatMap f类型还是::[T, HNil]?在我们实际运行程序并查看HNil的值是什么之前,我们不知道。

我不确定是否有一些聪明的方法可以做到这一点并得到一个不透明的x,但在那时你将放弃关于每个元素和列表长度的确切类型信息,并可能作为如果你知道最终结果将具有什么样的确切类型,那么将其投射到正常的HList(如果你知道最终结果的确切类型,可以稍后使用List