首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何降低约束HList

如何降低约束HList
EN

Stack Overflow用户
提问于 2016-12-15 11:03:50
回答 2查看 379关注 0票数 1

如何修复下面的代码以使其工作?

代码语言:javascript
复制
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?

更新:

请考虑我的问题的更充分的例子:

代码语言:javascript
复制
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
}

更新:

代码语言:javascript
复制
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)
  }

}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-12-20 10:22:06

这工作:

代码语言:javascript
复制
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)
}
票数 0
EN

Stack Overflow用户

发布于 2016-12-15 15:36:08

从某种意义上说,LUBConstraint.<<:类型是非建设性的,因为很明显,所有HList成员都有某种类型,但不能从中派生任何东西。

要使用reduceLeft方法,需要专门的LeftReducer操作提供程序。您可以在您的方法中直接要求它。

代码语言:javascript
复制
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

更新

如果您需要直接的证据,说明您的结果将是某种结果类型,则可以使用附加的类型参数,但这需要通过类型化的Maker模式分离类型参数。

代码语言:javascript
复制
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)
  }
}

现在

代码语言:javascript
复制
Foo.foo[Int](1 :: 2 :: 3 :: HNil)
Foo.foo[Double](1.0 :: 2.0 :: 3.0 :: HNil)

仍然会产生正确的结果,而

代码语言:javascript
复制
Foo.foo[Double](1 :: 2 :: 3 :: HNil)

将在编译时失败。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41162574

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档