找不到参数元组的隐式值
Posted
技术标签:
【中文标题】找不到参数元组的隐式值【英文标题】:could not find implicit value for parameter tupler 【发布时间】:2016-11-07 17:20:51 【问题描述】:在下面的代码中,我试图创建一个 HList 列表,但我在该代码的最后一行遇到编译时错误:
◾找不到参数 tupler 的隐式值: shapeless.ops.hlist.Tupler[shapeless.HList] ◾没有足够的参数 元组方法:(隐式元组: shapeless.ops.hlist.Tupler[shapeless.HList])tupler.Out.未指定 值参数元组。
object Problem extends App
def combinations[T](n: Int, ls: List[T]) =
import shapeless._
import HList._
def prepareHListR(t: Int, result: HList): HList = t match
case t if (t == 0) => result
case _ => prepareHListR(t - 1, rotateLeft(t - 1, ls) :: result)
prepareHListR(n, HNil)
def rotateLeft[A](i: Int, xs: List[A]) =
val rot = if (i > 0) i else xs.length + i
xs.drop(rot) ++ xs.take(rot)
println(combinations(3, List('a, 'b, 'c, 'd, 'e, 'f)))
输出:
List('a, 'b, 'c, 'd, 'e, 'f) :: List('b, 'c, 'd, 'e, 'f, 'a) :: List(' c, 'd, 'e, 'f, 'a, 'b) :: HNil
接下来我需要做的是创建这些列表的元组,如下所示:
(List('a, 'b, 'c, 'd, 'e, 'f), List('b, 'c, 'd, 'e, 'f, 'a), List('c , 'd, 'e, 'f, 'a, 'b))
我正在尝试:
combinations(3, List('a, 'b, 'c, 'd, 'e, 'f)).tupled
然而,这种方法在 REPL 上运行良好:
scala> import shapeless._
import shapeless._
scala> import HList._
import HList._
scala> val hlist = List(1, 2, 3) :: List(4, 5, 6) :: List(7, 8, 9) :: HNil
hlist: shapeless.::[List[Int],shapeless.::[List[Int],shapeless.::[List[Int],shapeless.HNil]]] = List(1, 2, 3) :: List(4, 5, 6) :: List(7, 8, 9) :: HNil
scala> val t =hlist.tupled
t: (List[Int], List[Int], List[Int]) = (List(1, 2, 3),List(4, 5, 6),List(7, 8, 9))
对我来说,这似乎是 type parameter 的一个问题,但由于我对 Scala 和 Shapeless 的了解有限,我无法理解它。
非常感谢任何帮助! TIA。
【问题讨论】:
对,您可能缺少一个类型参数(以及一个隐含的证据)。如果您可以提供一个完整的示例(包含导入和所有定义),那么诊断会更容易。 @TravisBrown 感谢您的回复。我已经用工作代码和进一步的解释更新了帖子。 【参考方案1】:这里有几个相关的问题,但重要的一点是元组的大小取决于仅在运行时才知道的值(这是一个问题)。 HList
版本有效,但这只是因为您丢弃了类型。您最终会得到静态类型为 HList
的东西,您几乎无法对它做任何事情(运行时的模式匹配除外),而且这通常不是您想要的。
您可以编写一个版本,为您提供一个不错的静态元组类型结果,但它需要更多的工作,并且它对您的 n
参数施加了限制。首先你需要一个自定义类型类:
import shapeless._, ops.tuple. Last, Prepend
trait Rotated[N <: Nat, A] extends DepFn1[List[A]]
object Rotated
type Aux[N <: Nat, A, Out0] = Rotated[N, A] type Out = Out0
implicit def rotated0[A]: Aux[nat._1, A, Tuple1[List[A]]] =
new Rotated[nat._1, A]
type Out = Tuple1[List[A]]
def apply(l: List[A]): Tuple1[List[A]] = Tuple1(l)
implicit def rotatedN[N <: Nat, A, OutN, LA](implicit
rotN: Aux[N, A, OutN],
last: Last.Aux[OutN, LA],
ev: LA <:< List[A],
prep: Prepend[OutN, Tuple1[List[A]]]
): Aux[Succ[N], A, prep.Out] =
new Rotated[Succ[N], A]
type Out = prep.Out
def apply(l: List[A]): prep.Out =
val resultN = rotN(l)
val lastList = ev(last(resultN))
prep(resultN, Tuple1(lastList.drop(1) ++ lastList.take(1)))
您可以通过多种方式编写它。上面的版本是现成的,但可能是合理的。
现在您的 combinations
方法如下所示:
def combinations[T, O <: HList](n: Nat, ls: List[T])(implicit
rotN: Rotated[n.N, T]
): rotN.Out = rotN(ls)
然后用法正是您要求的:
scala> combinations(3, List('a, 'b, 'c, 'd, 'e, 'f))
res0: (List[Symbol], List[Symbol], List[Symbol]) = (List('a, 'b, 'c, 'd, 'e, 'f),List('b, 'c, 'd, 'e, 'f, 'a),List('c, 'd, 'e, 'f, 'a, 'b))
scala> combinations(2, List('a, 'b, 'c, 'd, 'e, 'f))
res1: (List[Symbol], List[Symbol]) = (List('a, 'b, 'c, 'd, 'e, 'f),List('b, 'c, 'd, 'e, 'f, 'a))
现在您要返回元组,但代价是无法执行以下操作:
scala> val x = 4
x: Int = 4
scala> combinations(x, List('a, 'b, 'c, 'd, 'e, 'f))
<console>:20: error: Expression x does not evaluate to a non-negative Int literal
combinations(x, List('a, 'b, 'c, 'd, 'e, 'f))
^
但是,如果您认为这是一个合理的约束——如果您想要一个在编译时可用的元组,则需要以一种在编译时可用的方式指定该大小。
【讨论】:
以上是关于找不到参数元组的隐式值的主要内容,如果未能解决你的问题,请参考以下文章
Scala 类型参数化,Shapeless - 找不到参数 Generic 的隐式值