首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何从HList创建镜头的HList

如何从HList创建镜头的HList
EN

Stack Overflow用户
提问于 2014-08-10 03:56:00
回答 1查看 303关注 0票数 3

我正在编写一个通用的表查看器,应该能够显示任何类型的Seq[Row] where Row <: HList。Table类如下所示:

代码语言:javascript
复制
class Table[TH<:HList, TR<:HList](val hdrs: TH, val rows: Seq[TR])

当有人单击表查看器的某一列时,我希望按该列的顺序重新绘制整个表。为此,我需要能够分配一个函数来对特定列上的表进行排序。使用隐形眼镜似乎是一个合理的选择。

代码语言:javascript
复制
def sort[Elem<:Nat](lens: Lens[R, Elem]) = {
   ...
   table.rows.sortBy(lens.get(_)) //sort the rows of the table using the lens
}

然后,我需要将该函数绑定到表头上的一个单击事件。在第一次幼稚的尝试中,我会使用scalajs-react构建如下的HTML头

代码语言:javascript
复制
def header = {
    tr(for (ci <- 0 to tab.hdrs.runtimeLength) yield 
          th(onclick --> B.sort(hlistNthLens[R,nat(ci)]))(tab.hdrs(ci).toString))
}

这就是在表头上设置一个onClick来调用上面的sort方法。但这不会起作用,因为使用名为ciInt会丢失类型结构信息。我们确实需要保留所有的类型信息,以便编译器知道HList的某个特定字段是列表的第n个元素,这样镜头的构造才能在类型级别工作。

这当然是使用shapeless编程的难点所在。

所需的函数将把我从HList的任何子类带到镜头的HList,每个镜头都会为HList的特定子类的任何实例选择该元素。

代码语言:javascript
复制
 def lenses[H <: HList] = /* return an HList of Lenses, where 
        the first Lens will always select the first element of any 
        instance of `H`, the second will always select the second
        element of any instance of `H`, ... */

(理想情况下,可以将其概括为允许组合这些镜头,以便用户可以选择主要排序顺序,然后选择次要排序顺序。)

EN

回答 1

Stack Overflow用户

发布于 2014-08-11 04:22:54

好了,我想我找到答案了。最初的测试似乎证实了这一点。

代码语言:javascript
复制
scala> :paste
// Entering paste mode (ctrl-D to finish)

import shapeless._
import shapeless.ops.hlist.At
import shapeless.syntax.std.tuple._

final class myHListOps[L <: HList](l: L) {

  import hlistaux._

  def extractors(implicit extractor : Extractor[_0, L,L]) : extractor.Out = extractor()
}

object hlistaux {
  trait Extractor[HF<:Nat, In <: HList, Remaining<: HList] extends DepFn0 { type Out <: HList }

  object Extractor {
    def apply[HL <: HList]
    (implicit extractor: Extractor[_0, HL,HL]):
       Aux[_0, HL, HL, extractor.Out] = extractor

    type Aux[HF<:Nat, In <: HList, Remaining<: HList, Out0 <: HList] = Extractor[HF, In, Remaining] { type Out = Out0 }

    //To deal with case where HNil is passed. not sure if this is right.
    implicit def hnilExtractor: Aux[_0, HNil, HNil, HNil] =
      new Extractor[_0, HNil, HNil] {
        type Out = HNil
        def apply(): Out = HNil
      }

    implicit def hSingleExtractor1[N<:Nat, In<:HList, H ]
    (implicit att : At[In, N]): Aux[N, In, H::HNil, At[In,N]::HNil] =
      new Extractor[N, In, H::HNil] {
        type Out = At[In,N]::HNil
        def apply(): Out = att::HNil
      }


    implicit def hlistExtractor1[N <: Nat, In<:HList, H, Tail<: HList]
    (implicit mt : Extractor[Succ[N], In, Tail],
              att : At[In, N])
    :Aux[N, In, H::Tail, At[In,N]::mt.Out] = {
      new Extractor[N, In, H::Tail] {
        type Out = At[In,N]::mt.Out

        def apply(): Out = {
          att :: mt()
        }
      }
    }
  }
}

// Exiting paste mode, now interpreting.

import shapeless._
import shapeless.ops.hlist.At
import shapeless.syntax.std.tuple._
defined class myHListOps
defined object hlistaux

scala> val l = "Hello"::HNil
l: shapeless.::[String,shapeless.HNil] = Hello :: HNil

scala> val lo = new myHListOps(l).extractors
lo: shapeless.::[shapeless.ops.hlist.At[shapeless.::[String,shapeless.HNil],shapeless._0],shapeless.HNil] = shapeless.ops.hlist$At$$anon$54@12d33d1c :: HNil

scala> lo.head(l)
res0: lo.head.Out = Hello

scala> val m = 42::l
m: shapeless.::[Int,shapeless.::[String,shapeless.HNil]] = 42 :: Hello :: HNil

scala> val mo = new myHListOps(m).extractors
mo: shapeless.::[shapeless.ops.hlist.At[shapeless.::[Int,shapeless.::[String,shapeless.HNil]],shapeless._0],shapeless.::[shapeless.ops.hlist.At[shapeless.::[Int,shapeless.::[String,shapeless.HNil]],shapeless.Succ[shapeless._0]],shapeless.HNil]] = shapeless.ops.hlist$At$$anon$54@5e181eeb :: shapeless.ops.hlist$At$$anon$55@1960690 :: HNil

scala> mo.head(m)
res3: mo.head.Out = 42

scala> mo.tail.head(m)
res4: mo.tail.head.Out = Hello
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25222471

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档