7

如此处所述

将元组划分为多个元组的类型安全方法

我有一个带有以下签名的方法

def execute[T <: Record](funs: Seq[(Session) => T]): Seq[T]

Slick数据库会话Session在哪里;该方法的基本实现是

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库的HLists - 但是我不清楚如何创建(Session) => T函数的多态变体,问题是所有我见过的多态函数的示例使用包装类型参数,例如(Set ~> Option),每个都包装一个 polymorphic T,但我正在尝试创建一个(Session ~> T)函数,其中Session不变且多态T不包含在SetorOption等等。由于对Shapeless没有足够的经验,我无疑以错误的方式看待这个问题。

如何使用 Shapeless 创建def execute(funs: Seq[(Session) => T]): Seq[T]函数的多态版本?

4

1 回答 1

5

您实际上并不真正需要或不想要一个多态函数——您可以从 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))

我们得到了一个很好的适当的静态类型元组作为我们的结果。

于 2014-03-26T21:07:15.080 回答