Scala 定义依赖于自身的半群实例

Scala 定义依赖于自身的半群实例,scala,functional-programming,typeclass,scala-cats,semigroup,Scala,Functional Programming,Typeclass,Scala Cats,Semigroup,。。。或者是Haskell程序员编写Scala代码的失误,第5部分 我在Scala中有以下结构: case class ResourceTree( resources: Map[String, ResourceTree] ) 并且,使用Cats,我想定义它的半群实例 object ResourceTreeInstances { implicit val semigroupInstance = new Semigroup[ResourceTree] { override def

。。。或者是Haskell程序员编写Scala代码的失误,第5部分

我在Scala中有以下结构:

case class ResourceTree(
  resources: Map[String, ResourceTree]
) 
并且,使用Cats,我想定义它的
半群
实例

object ResourceTreeInstances {
  implicit val semigroupInstance = new Semigroup[ResourceTree] {
    override def combine(x: ResourceTree, y: ResourceTree): ResourceTree = {
      ResourceTree(
        x.resources |+| y.resources
      )
    }
  }
这将导致以下错误:

value |+| is not a member of Map[String, ResourceTree]
[error]  Note: implicit value semigroupInstance is not applicable here because it comes after the application point and it lacks an explicit result type
[error]         x.resources |+| y.resource
因此,我的猜测是,由于我正在定义
半群
的实例,Scala编译器无法派生
映射[String,ResourceTree]
半群
的实例。这似乎得到了证实,因为编译了以下实例:

implicit val semigroupInstance = new Semigroup[ResourceTree] {
  override def combine(x: ResourceTree, y: ResourceTree): ResourceTree = {
    dummyCombine(x, y)
  }
}

// FIXME: see if there's a better way to avoid the "no instance of Semigroup" problem
def dummyCombine(x: ResourceTree, y: ResourceTree): ResourceTree = {
  ResourceTree(
    x.resources |+| y.resources
  )
}
我真的希望我错了,因为如果这是在Scala中定义半群实例的正确方法,我将开始考虑放弃使用这种语言进行FP的想法


有更好的方法吗?

以下方法应该可以很好地工作:

import cats.Semigroup
import cats.instances.map._
import cats.syntax.semigroup._

case class ResourceTree(resources: Map[String, ResourceTree]) 

implicit val resourceTreeSemigroup: Semigroup[ResourceTree] =
  new Semigroup[ResourceTree] {
    def combine(x: ResourceTree, y: ResourceTree): ResourceTree =
      ResourceTree(
        x.resources |+| y.resources
      )
  }
关键是错误消息的这一部分:“它缺少显式的结果类型”。Scala中的递归方法必须有显式的返回类型,类似的类型类实例也需要它们,它们依赖于自身(直接或间接地通过
Map
实例和本例中的
+
语法)


一般来说,最好将显式返回类型放在所有隐式定义上。如果不这样做,可能会导致意外行为,如果您仔细考虑并阅读规范(如本例所示),其中一些行为是有意义的,而其中一些在编译器中似乎是错误的。

以下内容应该可以正常工作:

import cats.Semigroup
import cats.instances.map._
import cats.syntax.semigroup._

case class ResourceTree(resources: Map[String, ResourceTree]) 

implicit val resourceTreeSemigroup: Semigroup[ResourceTree] =
  new Semigroup[ResourceTree] {
    def combine(x: ResourceTree, y: ResourceTree): ResourceTree =
      ResourceTree(
        x.resources |+| y.resources
      )
  }
关键是错误消息的这一部分:“它缺少显式的结果类型”。Scala中的递归方法必须有显式的返回类型,类似的类型类实例也需要它们,它们依赖于自身(直接或间接地通过
Map
实例和本例中的
+
语法)

一般来说,在所有隐式定义上都放置显式返回类型是一个好主意。如果不这样做,可能会导致意外行为,如果您仔细考虑并阅读规范(如本例所示),其中一些行为是有意义的,而其中一些似乎只是编译器中的错误。

我对“缺少显式结果类型”感到困惑。我认为它指的是联合收割机操作,而不是类本身。谢谢在Scala中编码时,我禁不住想到我正在编写FP汇编……我被“缺少显式结果类型”弄糊涂了。我认为它指的是联合收割机操作,而不是类本身。谢谢当我在Scala中编码时,我禁不住想到我正在编写FP汇编。。。