1

...或具有编写斯卡拉Haskell的程序员的事故,部分5定义取决于本身就是一个半群实例

我在斯卡拉的结构如下:

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

而且,使用Cats,我想定义一个Semigroup它的实例。

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 

所以,我的猜测是,因为我定义Semigroup实例Scala编译器不能为Map[String, ResourceTree]Semigroup获得一个实例。这似乎也印证,因为下面的实例编译:

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 
) 
} 

我真的希望我是错的,因为如果这是定义一个半群在斯卡拉我会开始考虑一个实例的正确方法放弃用这种语言来做FP的想法。

有没有更好的方法?

回答

4

下应该只是罚款:

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实例和|+|语法)也需要它们。

一般来说这是一个好主意,把明确的返回类型上这样做的所有隐式不定义可能会导致意外的行为,其中一些是有道理的,如果你仔细想想,读取规格(在这种情况下, ),其中一些似乎在编译器中很笨拙。

+1

我被“缺乏明确的结果类型”所困惑。我认为它提到了联合行动,而不是这个阶级本身。谢谢!当我在Scala中编写代码时,我不禁想到我正在编写FP汇编... –

相关问题