【问题标题】:Scala typeclass and implicit puzzleScala 类型类和隐式谜题
【发布时间】:2014-09-10 16:30:34
【问题描述】:

下面的最后一行语句产生错误: “类型不匹配;发现:TestExpandableWithLibrary.this.library.type(具有基础类型 org.typeclass.Library)需要:V”

这是我尝试进行隐式转换的地方。我简单地使用 typeclass 函数的前一行确实可以正常工作。

关于如何解决它的任何想法?

package org.typeclass

///////////////////////////////////////////////////////////////////////////////
// the domain objects

case class Book(bookName: String)

case class Library(libraryName: String, books: Set[Book])

object Library {
  def apply(libraryName: String, bookNames: String*): Library =
    Library(libraryName, bookNames.map(Book(_)).toSet)
}

case class TreeClass(nodeName: String, children: Seq[TreeClass])

///////////////////////////////////////////////////////////////////////////////
// the typeclass definition

trait Expandable[T, V, R] {
  def expandWith(template: T, values: V): R
}

object Expandable {

  def expandWithF[T, V, R](template: T, values: V)(implicit ev: Expandable[T, V, R]): R =
    ev.expandWith(template, values)

  implicit class ExpandableItem[T, V, R](val template: T) extends AnyVal {
    def expandWithM(values: V)(implicit ev: Expandable[T, V, R]): R =
      ev.expandWith(template, values)
  }
}

///////////////////////////////////////////////////////////////////////////////
// a typeclass implementation

object ExpandableImpls {

  implicit object ExpandableTreeClass extends Expandable[TreeClass, Library, TreeClass] {
    def expandWith(template: TreeClass, library: Library): TreeClass = {
      val parentName = s"${template.nodeName}.${library.libraryName}"
      val children = library.books.map(book => TreeClass(s"${parentName}.${book.bookName}", Seq.empty)).toSeq
      TreeClass(parentName, children)
    }
  }

}

//@RunWith(classOf[JUnitRunner])
class TestExpandableWithLibrary /*extends FlatSpec*/ {

  import Expandable._
  import ExpandableImpls._

  val library = Library("test", "black", "white")
  val root = TreeClass("parent", Seq.empty)

  val useF = expandWithF(root, library) // this works

  val useM = root.expandWithM(library) // this doesn't work!

}

【问题讨论】:

    标签: scala implicit-conversion typeclass


    【解决方案1】:

    问题在于您需要将后两个类型参数放在扩展方法上的隐式类上——因为它们将被推断为Nothing,因为它们在构造函数中没有被引用论据。

    implicit class ExpandableItem[T](val template: T) extends AnyVal {
      def expandWithM[V, R](values: V)(implicit ev: Expandable[T, V, R]): R =
        ev.expandWith(template, values)
    }
    

    这应该可以正常工作。

    【讨论】:

    • 不要粗鲁,但也许理想情况下,编译器可以给我一些线索,告诉我我要去哪里漂泊。类型推断 = Dragons Be Here!
    • @satyagraha:我同意这个错误可能会更好。内化规则是一个好主意,即如果您想要推断类型参数,它应该出现在参数中的非泛型位置。
    • 发现了这个可能有帮助的工具:blog.cppcabrera.com/posts/scala-wart-remover.html(当然需要注释掉有问题的语句才能完成编译)
    猜你喜欢
    • 2018-11-21
    • 2017-01-30
    • 2011-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-30
    • 2016-08-02
    相关资源
    最近更新 更多