如此处所述
Type-safe way to divide a tuple into multiple tuples
我有一个带有以下签名的方法
def execute[T <: Record](funs: Seq[(Session) => T]): Seq[T]
其中Session
是Slick数据库会话;
def execute[T <: Record](funs: Seq[(Session) => T): Seq[T] = {
db withSession {
session: Session => funs.map(fun => fun(session))
}}
(其中db
是Slick Database
),其他实现添加了日志记录,缓存,多线程等功能。特别是,多线程实现使用funs.grouped(ceil(funs.size / threadCount)).map(funs => Future {})
在几个线程之间划分函数。
我想创建一个接受函数元组的方法版本,以便我可以返回不同类型的值 - 如上面链接的问题所述,我不知道一个好的分割方法将一个元组组合成较小的元组,然后重新组合多线程案例的结果,但该问题的答案是使用Shapeless库的HList
- 但我不清楚为什么我可以创建(Session) => T
函数的多态变体,问题是我所见过的所有多态函数的例子都使用包裹类型参数,例如(Set ~> Option)
每个都包含多态T
,但我正在尝试创建(Session ~> T)
函数,Session
不变,多态T
不是{\ n}包裹在Set
或Option
等等。由于没有足够的无形体验,我无疑以错误的方式看待这个问题。
如何使用Shapeless创建def execute(funs: Seq[(Session) => T]): Seq[T]
函数的多态版本?
答案 0 :(得分:3)
你实际上并不真正需要或想要一个多态函数 - 你可以从Shapeless提供的几个类型类中获得你正在寻找的东西。它看起来有点奇怪,但它并不是那么复杂(请注意我使用的是Shapeless 2.0 - 你可以在1.2.4中做到这一点,但它会变得更加混乱):
import shapeless._, ops.tuple.{ ConstMapper, ToList, ZipApply }
import shapeless.syntax.std.tuple._
def execute[F <: Product, S, O](funs: F)(implicit
cm: ConstMapper.Aux[F, Session, S],
za: ZipApply.Aux[F, S, O],
tl: ToList[O, Record]
): O = db withSession { session: Session =>
funs.zipApply(funs.mapConst(session))
}
我们基本上只是参加我们的会话,通过重复多次来创建一个新元组,因为我们的输入很长,用这个新的会话元组压缩输入元组,然后应用每个压缩的第一部分元素到第二部分。 ToList
部分要求生成的元组的所有元素都是Record
的子类型。
为了完整的工作示例,这里有一些简单的演示定义:
type Session = String
trait Record
case class RecordX(s: String) extends Record
case class RecordY(i: Int) extends Record
def x(s: Session) = RecordX(s)
def y(s: Session) = RecordY(s.size)
object db {
def withSession[T](f: Session => T) = f("foo")
}
它有效!
scala> execute((x _, y _))
res0: (RecordX, RecordY) = (RecordX(foo),RecordY(3))
我们得到一个很好的适当静态类型的元组作为我们的结果。