5

我正在尝试转换以下 HList

Some(C(15)) :: None :: Some(B(55)) :: None :: Some(A(195)) :: HNil

C(15) :: B(55) :: A(195) :: HNil

这是我目前所拥有的:

  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)

这可行,但我想让它通用,以便它适用于 Some 包装的任何类型,而不必编写每个案例

4

1 回答 1

7

首先是字面上的答案。请注意,您的大多数T类型参数都没有被使用。您可以使用它T来使您的函数匹配任何类型的元素Some[T]

trait folderLP extends Poly2 {
  implicit def default[T, L <: HList] = at[T, L]((_, acc) => acc)
}

object folder extends folderLP {
  implicit def some[T, L <: HList] = at[Some[T], L]((t, acc) => t.get :: acc)
}

请注意,none如果您在default.

另请注意,您可能希望使用以下定义filtered

val filtered = test.foldRight(HNil: HNil)(folder)

这个将HNil静态类型化为 anHNil而不是 an HList,这对于您想要做的几乎所有事情都非常有用 - 例如尝试filtered.length您的原始版本,然后尝试这个。

不过,你甚至不需要为这个操作折叠——aflatMap会做:

trait filterLP extends Poly1 {
  implicit def any[T] = at[T](_ => HNil)
}

object filter extends filterLP {
  implicit def some[T] = at[Some[T]](_.get :: HNil)
}

进而:

val filtered = test.flatMap(filter)

最后,值得注意的是,这仅适用于HListandNone元素Some静态类型为Noneand的情况Some——Some[A]例如,静态类型为 an 的Option[A]情况将被过滤掉。这使它有点无用(至少我看不到实际用途),但是如果您在编译时不知道是否Option为空或不是。

于 2015-02-19T03:29:57.553 回答