如何修复下面的代码以便它可以正常工作?
object Foo {
object sum extends Poly {
implicit def caseFoo = use((f1: Int, f2: Int) => f1 + f2)
}
def foo[L <: HList : <<:[Int]#λ](l: L): Int = {
l.reduceLeft(sum)
// Error: could not find implicit value for parameter reducer: shapeless.ops.hlist.LeftReducer[L,com.struct.Foo.sum.type]
// l.reduceLeft(sum)
// Error: not enough arguments for method reduceLeft: (implicit reducer: shapeless.ops.hlist.LeftReducer[L,com.struct.Foo.sum.type])reducer.Out.
// Unspecified value parameter reducer.
}
}
此外。如何更改它以减少任何数字的HList?
更新
请考虑我的问题的更全面的例子:
import shapeless._
trait Bar {
def foo: Int
}
case class Foo[L <: HList](l: L) extends Bar {
object sum extends Poly {
implicit def caseFoo[A: Numeric] = use((f1: A, f2: A) => f1 + f2)
//Error: type mismatch;
//found : A
//required: String
}
override def foo(implicit reducer: LeftReducer[L, sum.type]): Int = reducer(l)
//Error: type mismatch;
//found : reducer.Out
//required: Int
}
更新
package com.test
import shapeless.ops.hlist.LeftReducer
import shapeless.{HList, HNil, Poly}
trait Bar {
def foo: Int
}
case class Foo[L <: HList](list: L) extends Bar {
import Numeric.Implicits._
object sum extends Poly {
implicit def caseFoo[A: Numeric] = use((f1: A, f2: A) => f1 + f2)
}
class MkFoo[T] {
def apply(l: L)(implicit reducer: LeftReducer.Aux[L, sum.type, T]): T = reducer(l)
}
override def foo: Int = (new MkFoo[Int]())(list)
// Error: could not find implicit value for parameter reducer: shapeless.ops.hlist.LeftReducer.Aux[L,Foo.this.sum.type,Int]
}
object Testing {
def main(args: Array[String]): Unit = {
val b:Bar = Foo(1 :: 2 :: 3 :: HNil)
println(b.foo)
}
}
答案 0 :(得分:2)
LUBConstraint.<<:
类型具有非建设性意义,因为只有所有HList
成员都有某种类型,但无法从中获取任何内容。
要使用reduceLeft
方法,您需要专门的LeftReducer
操作提供程序。您可以直接在您的方法中使用它。
import shapeless._, ops.hlist._
object Foo {
import Numeric.Implicits._
object sum extends Poly {
implicit def caseFoo[A: Numeric] = use((f1: A, f2: A) => f1 + f2)
}
def foo[L <: HList](l: L)(implicit reducer: LeftReducer[L, sum.type]): reducer.Out =
reducer(l)
}
Foo.foo(1 :: 2 :: 3 :: HNil) // res0: Int = 6
Foo.foo(1.0 :: 2.0 :: 3.0 :: HNil) // res1: Double = 6.0
如果您需要直接证据,您的结果将是某种结果类型,您可以使用其他类型参数,但需要通过键入的制作者模式分离类型参数
object Foo {
import Numeric.Implicits._
object sum extends Poly {
implicit def caseFoo[A: Numeric] = use((f1: A, f2: A) => f1 + f2)
}
def foo[T] = new MkFoo[T]
class MkFoo[T] {
def apply[L <: HList](l: L)(implicit reducer: LeftReducer.Aux[L, sum.type, T]): T = reducer(l)
}
}
现在
Foo.foo[Int](1 :: 2 :: 3 :: HNil)
Foo.foo[Double](1.0 :: 2.0 :: 3.0 :: HNil)
仍会产生正确的结果。
Foo.foo[Double](1 :: 2 :: 3 :: HNil)
将在编译时失败
答案 1 :(得分:0)
这有效:
package com.test
import shapeless.{::, Generic, HList, HNil, Lazy}
trait Bar {
def foo: Int
}
case class Foo[L <: HList](list: L)(implicit ev: SizeCalculator[L]) extends Bar {
override def foo: Int = ev.size(list)
}
object Testing {
def main(args: Array[String]): Unit = {
val b: Bar = Foo(1 :: 2 :: 3 :: HNil)
println(b.foo)
}
}
sealed trait SizeCalculator[T] {
def size(value: T): Int
}
object SizeCalculator {
// "Summoner" method
def apply[A](implicit enc: SizeCalculator[A]): SizeCalculator[A] = enc
// "Constructor" method
def instance[A](func: A => Int): SizeCalculator[A] = new SizeCalculator[A] {
def size(value: A): Int = func(value)
}
import Numeric.Implicits._
implicit def numericEncoder[A: Numeric]: SizeCalculator[A] = new SizeCalculator[A] {
override def size(value: A): Int = value.toInt()
}
implicit def hnilEncoder: SizeCalculator[HNil] = instance(hnil => 0)
implicit def hlistEncoder[H, T <: HList](
implicit
hInstance: Lazy[SizeCalculator[H]],
tInstance: SizeCalculator[T]
): SizeCalculator[H :: T] = instance {
case h :: t =>
hInstance.value.size(h) + tInstance.size(t)
}
implicit def genericInstance[A, R](
implicit
generic: Generic.Aux[A, R],
rInstance: Lazy[SizeCalculator[R]]
): SizeCalculator[A] = instance { value => rInstance.value.size(generic.to(value)) }
def computeSize[A](value: A)(implicit enc: SizeCalculator[A]): Int = enc.size(value)
}