Кошки Scala: проблема с имплицитами при попытке использовать синтаксис `===` для признака `Eq`

#scala #scala-cats

#скала #scala-кошки #scala #кошки scala

Вопрос:

Алоха! 🙂

Я не в восторге от того, что все время бегаю на форумы stackoverflow, чтобы получить помощь с другой странностью, которую scala / cats бросила на меня. Проблема в том, что, похоже, нет действительно полезной документации, только некоторые бесполезные — по крайней мере, для меня — строки repl.

Не мог бы кто-нибудь из вас указать на какую-нибудь полезную документацию? Какой-то реальный код? Не только строки в repl?

Здесь я просто попытался работать с эквалайзером scala / cats и показывать классы типов… Что, черт возьми, я делаю не так?

Класс:

 package org.hudelundpfusch.utilites.decisions.data

import cats.Show
import cats.kernel.Eq

case class Fact[ T <: Any](name: String, value: T)
  extends Equals {

  override def canEqual(that: Any): Boolean = that match {
    case _: Fact[_] => true
    case _          => false
  }

  override def equals(other: Any): Boolean = other match {
    case that: Fact[_] =>
      (that canEqual this) amp;amp;
        name == that.name amp;amp;
        value == that.value
    case _ => false
  }

  override def hashCode(): Int = {
    val state = Seq(name, value)
    state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a   b)
  }

  override def toString = s"Fact(name=$name, value=$value)"

}

case object Fact {

  implicit val factEq: Eq[Fact[_]] = Eq.fromUniversalEquals[Fact[_]] // Neither of this works

//  implicit def factEq: Eq[Fact[_]] = new Eq[Fact[_]] {
//    def eqv(x: Fact[_], y: Fact[_]): Boolean = (x != null, y != null) match {
//      case (true, _)  => x.equals(y)
//      case (_, true)  => y.equals(x)
//      case _          => true
//    }
//  }

  implicit def factShow[T]: Show[Fact[T]] = (t: Fact[T]) => t.toString // Example calls for 'implicit val factShow[Fact[_]]' but that doesn't work

}
  

И большой сюрприз:

 package org.hudelundpfusch.utilites.decisions

import cats._
import cats.data._
import cats.syntax._
import cats.implicits._
import cats.implicits.eq
import com.typesafe.scalalogging.LazyLogging
import org.hudelundpfusch.utilites.decisions.data.Fact
import org.hudelundpfusch.utilites.decisions.data.Fact._
// Tried to import everything that came to my mind to make the stuff working

object Fuddel
  extends App
    with LazyLogging {

  logger.info("Let's start to fuddel!")
  this.fuddel()
  logger.info("Enough with fuddling!")

  def fuddel(): Unit = {
    val fact1: Fact[String] = Fact[String]("FactName", "FactValue")
    println(s"${fact1.show}")
    val fact2: Fact[String] = Fact[String]("FactName", "FactValue")
    println(s"${fact2.show}")

    println(s"${fact1.equals(fact2)}")
    println(s"${fact1 == fact2}")
//    println(s"${fact1 === fact2}") // Not resolved...According to the repl example this should work with implicits imported
    println(s"${fact1 eq fact2}") // False? Oh joy! Thanks to the great repl example!
  }

}
  

Итак, пожалуйста, есть ли какая-либо документация, не являющаяся бесполезной?

Заранее спасибо

Удачного дня, чем у меня

Алекс

Комментарии:

1. Я сочувствую вашему разочарованию, но сомневаюсь, что вы получите полезные ответы на этот вопрос. Вообще говоря, StackOverflow отлично подходит для конкретных ответов на конкретные проблемы с кодом, но не предназначен для предоставления ответов на запросы «дайте мне лучшую документацию».

Ответ №1:

1. Это здесь компилируется просто отлично (я удалил ваше имя пакета и зависимость от регистрации):

 import cats.Show
import cats.kernel.Eq

case class Fact[ T](name: String, value: T) extends Equals {

  override def canEqual(that: Any): Boolean = that match {
    case _: Fact[_] => true
    case _          => false
  }

  override def equals(other: Any): Boolean = other match {
    case that: Fact[_] => true // TODO: replaced, irrelevant
    case _ => false
  }

  override def hashCode(): Int = {
    val state = Seq(name, value)
    state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a   b)
  }

  override def toString = s"Fact(name=$name, value=$value)"
}

case object Fact {
  implicit def factEq[A]: Eq[Fact[A]] = Eq.fromUniversalEquals[Fact[A]]
  implicit def factShow[T]: Show[Fact[T]] = (t: Fact[T]) => t.toString
}
  

Обратите внимание на универсальную количественную оценку вместо подстановочного знака в factEq[A] . Затем в Fuddel.scala :

 import cats.syntax.show._
import cats.syntax.eq._
import Fact._

object Fuddel
  extends App {

  this.fuddel()

  def fuddel(): Unit = {
    val fact1: Fact[String] = Fact[String]("FactName", "FactValue")
    println(s"${fact1.show}")
    val fact2: Fact[String] = Fact[String]("FactName", "FactValue")
    println(s"${fact2.show}")

    println(s"${fact1.equals(fact2)}")
    println(s"${fact1 == fact2}")
    println(s"${fact1 === fact2}")
    println(s"${fact1 eq fact2}")// must be false, different instances
  }

}
  

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


2. Я бы рекомендовал прочитать Уэлша, Гурнелла «Scala с кошками». Scaladoc тоже хорош, но вы не сможете эффективно ориентироваться в нем, пока не прочтете вводную главу об организации пакетов и последствий в cats библиотеке.

Комментарии:

1. Привет, Андрей, еще раз спасибо. Мне просто интересно, стоит ли продолжать пытаться. Я никогда не видел языка, который доставлял бы мне столько проблем с поиском полезной документации. Приятного вечера С наилучшими пожеланиями, Алекс

2. Я счел это стоящим. В настоящее время я не могу предложить язык, который лучше интегрирован со всеми материалами, вдохновленными ct. Если бы у меня был такой язык, я бы поделился им. Я не чувствую, что нахожусь в правильном положении, чтобы критиковать чужие усилия по документированию.