Generic Poly2 Folder case for shapeless Hlist

こ雲淡風輕ζ 提交于 2019-12-07 05:29:51

问题


I am trying to transform the following HList

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

to

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

Here is what I have at the moment :

  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)

this works but I would like to make this generic so that it works for any type wrapped in Some without having to write each case


回答1:


First for a literal answer. Note that most of your T type parameters aren't being used. You can use that T to make your function match any element of type 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)
}

Note that you don't even need the none case if you switch the order of arguments in your default.

Also note that you probably want to use the following definition of filtered:

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

This one will have the HNil statically typed as an HNil instead of an HList, which will be useful for pretty much anything you want to do down the line—for example try filtered.length on your original version and then on this one.

You don't even really need a fold for this operation, though—a flatMap will do:

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

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

And then:

val filtered = test.flatMap(filter)

Finally, it's worth noting that this will only work on an HList where the None and Some elements are statically typed as None and Some—a Some[A] for example that's statically typed as an Option[A] will get filtered out. This makes it kind of unuseful (at least I can't see a practical use), but there's just not really any way you can perform this kind of type-level filter if you don't know at compile time whether the Option is empty or not.



来源:https://stackoverflow.com/questions/28591085/generic-poly2-folder-case-for-shapeless-hlist

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