0

Aloha! :)

Could please somebody point me to a useful scala/cats tutorial? I’m struggling with making a class a functor for the last few days and I’m about to punch a hole in my display. All the documentation I’ve found up until now was not of help for me.

Maybe I should give Eta a try... =D

Here is the class I would like to turn into a functor. Besides 'show' doesn't behave the way I expected also.

package org.hudelundpfusch.utilites.decisions.data import cats.{Functor, Show} import cats.kernel.Eq import cats.syntax.functor._ import cats.syntax.show._ import scala.reflect.runtime.universe import scala.reflect.runtime.universe._ case class Fact[T <: Any] (name: String, value: T) (implicit private val paramTypeTagT: WeakTypeTag[T]) extends Equals { val paramType: universe.Type = paramTypeTagT.tpe val paramTypeClass: Option[Class[_ <: T]] = if (value != null) { Some(value.getClass) } else { None } def map[A, B](fa: Fact[A])(f: A => B): Fact[B] = Fact[B](fa.name, f(fa.value)) override def canEqual(other: Any): Boolean = other.isInstanceOf[Fact[_]] override def equals(other: Any): Boolean = other match { case that: Fact[_] => (that canEqual this) && name == that.name paramType == that.paramType && paramTypeClass == that.paramTypeClass && value == that.value case _ => false } override def hashCode(): Int = { val state = Seq(name, paramType, paramTypeClass, value) state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b) } override def toString = s"Fact(name=${name}, paramType=$paramType, paramTypeClass=$paramTypeClass, value=$value)" } case object Fact extends Show[Fact[_]] { override def show(t: Fact[_]): String = t.toString } 

Thanks in advance

Have a nice day

Alex

Update:

package org.hudelundpfusch.utilites.decisions.data import cats.{Functor, Show} import cats.kernel.Eq import cats.syntax.functor._ import cats.syntax.show._ import scala.reflect.runtime.universe import scala.reflect.runtime.universe._ case class Fact[T <: Any] (name: String, value: T) (implicit private val paramTypeTagT: WeakTypeTag[T]) extends Functor[Fact] with Equals { val paramType: universe.Type = paramTypeTagT.tpe val paramTypeClass: Option[Class[_ <: T]] = if (value != null) { Some(value.getClass) } else { None } def map[A, B](fa: Fact[A])(f: A => B): Fact[B] = Fact[B](fa.name, f(fa.value)) override def canEqual(other: Any): Boolean = other.isInstanceOf[Fact[_]] override def equals(other: Any): Boolean = other match { case that: Fact[_] => (that canEqual this) && name == that.name paramType == that.paramType && paramTypeClass == that.paramTypeClass && value == that.value case _ => false } override def hashCode(): Int = { val state = Seq(name, paramType, paramTypeClass, value) state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b) } override def toString = s"Fact(name=${name}, paramType=$paramType, paramTypeClass=$paramTypeClass, value=$value)" } 

Okay, I tried this now:

object Fact { implicit val factFunctor: Functor[Fact] = new Functor[Fact] { override def map[A, B](fa: Fact[A])(f: A => B): Fact[B] = Fact[B](fa.name, f(fa.value)) } implicit def factShow[T]: Show[Fact[T]] = new Show[Fact[T]] { override def show(t: Fact[T]): String = this.toString } } 

Unfortunately the call to the mapping function looks a bit cumbersome:

package org.hudelundpfusch.utilites.decisions.data object Fuddel { def main(args: Array[String]): Unit = { val fact1: Fact[Int] = Fact("Fact-1", 23) val fact2 = Fact.factFunctor.map(fact1){x: Int => x * 2} println(s"$fact2") } } 
5
  • 1
    It seems to compile just fine. What's your question exactly? Commented Apr 6, 2019 at 12:36
  • 1
    Hello Andrey Thanks for the reply. I forgot to mention that I wanted to let this class extend cat's Functor and to put the neccessary mapping functions in a companion object. I expected that I would be able to call the mapping functions with infix annotation like so: <code>fact: Fact[Int] = someFact map someFunction</code> Alas, it doesn't work... Maybe I'm too dumb... =( Best regards Alex Commented Apr 6, 2019 at 12:46
  • 1
    Well... If you wanted to extend Functor, that's not a problem. If you actually attempted to implement Functor, and it didn't work, then it would be a problem. Currently, I don't see any mentions of Functor except in the one import clause. Please provide a minimal reproducible example that demonstrates what the actual problem is. Commented Apr 6, 2019 at 12:50
  • 2
    Just updated my question... Maybe it's e little bit more clear now... Commented Apr 6, 2019 at 12:59
  • 1
    In this case, it seems that Dmytro Mitin guessed your problem correctly. Commented Apr 6, 2019 at 12:59

1 Answer 1

6

With Cats you do not extend Show, Functor traits (OOP way), you create implicit instances of Show, Functor (FP way).

http://eed3si9n.com/herding-cats/Functor.html

https://typelevel.org/cats/typeclasses/functor.html

implicit def factShow[T]: Show[Fact[T]] = new Show[Fact[T]] { override def show(t: Fact[T]): String = ??? } // implicit object factFunctor extends Functor[Fact] { // override def map[A, B](fa: Fact[A])(f: A => B): Fact[B] = ??? // } implicit val factFunctor: Functor[Fact] = new Functor[Fact] { override def map[A, B](fa: Fact[A])(f: A => B): Fact[B] = ??? } Show[Fact[Int]].show(Fact("a", 1)) Functor[Fact].map(Fact("a", 1))(_ + 1) import cats.syntax.show._ Fact("a", 1).show import cats.syntax.functor._ Fact("a", 1).map(_ + 1) 

Just in case, Fact[_] in your case object Fact extends Show[Fact[_]] is existential type, and Fact in my implicit object factFunctor extends Functor[Fact] is higher-kinded type.

Sign up to request clarification or add additional context in comments.

20 Comments

The question has been updated, it looks as if it's asking exactly what you answered. Causality? Happens-before relations? No, never heard of that... xD
Two things to ads here. 1. Do not use implicit objects, they sometimes break implicit resolution, always use an implicit val with an explicit type signature instead (implicit val factFuntor: Functor[Fact] = new Functor[Fact] { ... }). - 2. Just as a clarification, this is not a cats thing, it is the essence of the typeclass pattern. Your class is not longer an F. But, it does has an instance of F. The trick is the differentiation of is a VS has a.
@AlexanderSchell As already mentioned above: you're missing the import cats.syntax.functor._. Once imported, you should be able to write fact1.map(_ * 2).
@AlexanderSchell Huh, what? No. Please, if this solved your problem, just mark the answer as the accepted answer. If you think that something from the comment section should be copied into the answer, then please tell us, we can edit anything. Or suggest an edit yourself (I don't know, maybe this doesn't work below certain threshold).
@LuisMiguelMejíaSuárez Here is example where implicit object works and implicit val doesn't gist.github.com/DmytroMitin/ed22c9a84d5c89a46148a073b92052da And here is example where you can't annotate implicit m with any type so that the code compiles gist.github.com/DmytroMitin/0ef4c93b9a58a1f2e1d92f71fbdbfb19
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.