gpt4 book ai didi

scala - 如何从 HList 创建镜头的 HList

转载 作者:行者123 更新时间:2023-12-02 03:33:30 26 4
gpt4 key购买 nike

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

class Table[TH<:HList, TR<:HList](val hdrs: TH, val rows: Seq[TR])

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

def sort[Elem<:Nat](lens: Lens[R, Elem]) = {
...
table.rows.sortBy(lens.get(_)) //sort the rows of the table using the lens
}

然后我需要将该函数绑定(bind)到表头上的单击事件。在第一次天真的尝试中,我将使用 scalajs-react 构建这样的 html header 。

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方法同上。但这行不通,因为使用 Int 丢失了类型结构信息。名为 ci .确实需要保留所有类型信息,以便编译器知道 HList 的特定字段是 n。列表的第 th 个元素,以便镜头的构造可以在类型级别工作。

所以这当然是使用 shapeless 编程的困难部分。

所需的函数是将我从 HList 的任何子类中带走的函数到 Lenses 的 HList,每个 Lenses 都会为 HList 的特定子类的任何实例选择该元素.

 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`, ... */

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

最佳答案

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

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

关于scala - 如何从 HList 创建镜头的 HList,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25222471/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com