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彙編... –

相關問題