用于无形Hlist的通用Poly2文件夹案例

Jea*_*ean 5 generics scala fold hlist shapeless

我正在尝试转换以下HList

Some(C(15)) :: None :: Some(B(55)) :: None :: Some(A(195)) :: HNil
Run Code Online (Sandbox Code Playgroud)

C(15) :: B(55) :: A(195) :: HNil
Run Code Online (Sandbox Code Playgroud)

这就是我现在所拥有的:

  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)
Run Code Online (Sandbox Code Playgroud)

这是有效的,但我想使这个通用,以便它适用于包含在Some中的任何类型,而无需编写每个案例

Tra*_*own 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)
}
Run Code Online (Sandbox Code Playgroud)

请注意,none如果切换参数的顺序,甚至不需要这种情况default.

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

val filtered = test.foldRight(HNil: HNil)(folder)
Run Code Online (Sandbox Code Playgroud)

这个将HNil静态输入为一个HNil而不是一个HList,这对你想要做的任何事情都很有用 - 例如尝试filtered.length你的原始版本,然后在这个版本上.

你甚至不需要折叠这个操作,但是 - 它flatMap会做:

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

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

然后:

val filtered = test.flatMap(filter)
Run Code Online (Sandbox Code Playgroud)

最后,值得注意的是,这只会HListNoneSome静态输入元素的位置上起作用,NoneSome-a Some[A]例如静态输入Option[A]将被过滤掉.这使得它有点无用(至少我看不到实际用途),但是如果你不知道在编译时是否Option为空或者没有任何方法可以执行这种类型级别的过滤器不.