1

... или казусы программиста Haskell, который должен закодировать Scala, часть 5.Определение экземпляра полугруппы, который зависит от себя

I имеет следующую структуру в Scala:

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 не может получить экземпляр для Semigroup из Map[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 на этом языке.

Есть ли лучший способ?

ответ

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

Я был смущен «отсутствием явного типа результата». Я думал, что это относится к операции объединения, а не к самому классу. Благодаря! Я не могу не думать о том, что я пишу сборку FP при кодировании в Scala ... –

Смежные вопросы