【问题标题】:How to use functors with scala/cats如何在 scala/cats 中使用函子
【发布时间】:2019-04-06 21:32:07
【问题描述】:

喂! :)

能否请人指出一个有用的 scala/cats 教程? 在过去的几天里,我一直在努力让一个类成为函子,我正要在我的显示器上打一个洞。 到目前为止,我找到的所有文档都对我没有帮助。

也许我应该试试 Eta...=D

这是我想变成函子的类。 此外,“show”的行为也不符合我的预期。

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

}

提前致谢

祝你有美好的一天

亚历克斯

更新:

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

}

好的,我现在试试这个:

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

不幸的是,对映射函数的调用看起来有点麻烦:

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

【问题讨论】:

  • 似乎编译得很好。你的问题到底是什么?
  • 安德烈您好,感谢您的回复。我忘了说我想让这个类扩展 cat 的 Functor 并将必要的映射函数放在一个伴生对象中。我希望我能够使用中缀注释调用映射函数,如下所示: fact: Fact[Int] = someFact map someFunction 唉,它不起作用......也许我也是愚蠢的...... =(最好的问候亚历克斯
  • 嗯...如果您想要扩展 Functor,那不是问题。如果您真的尝试实现 Functor,但它没有工作,那么这将是一个问题。目前,我没有看到任何提及 Functor 的内容,除非在一个导入子句中。请提供一个minimal reproducible example 来说明实际问题是什么。
  • 刚刚更新了我的问题...也许现在更清楚了...
  • 在这种情况下,Dmytro Mitin 似乎猜对了您的问题。

标签: scala scala-cats


【解决方案1】:

使用 Cats,您无需扩展 Show、Functor 特征(OOP 方式),而是创建 Show、Functor 的隐式实例(FP 方式)。

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)

以防万一,您的case object Fact extends Show[Fact[_]] 中的Fact[_] 是存在类型,而我的implicit object factFunctor extends Functor[Fact] 中的Fact 是高级类型。

【讨论】:

  • 问题已更新,看起来好像在询问您的回答。因果关系?发生之前的关系?不,从未听说过... xD
  • 这里有两个广告。 1. 不要使用隐式对象,它们有时会破坏隐式解析,始终使用带有显式type签名的implicit valimplicit val factFuntor: Functor[Fact] = new Functor[Fact] { ... } )。 - 2. 澄清一下,这不是猫的东西,它是 typeclass 模式的本质。你的班级不再是F。但是,它确实有一个F 的实例。诀窍在于区分 is a VS has a
  • @AlexanderSchell 正如上面已经提到的:你错过了import cats.syntax.functor._。导入后,您应该可以写fact1.map(_ * 2)
  • @AlexanderSchell 嗯,什么?不,请,如果这解决了您的问题,只需将答案标记为已接受的答案。如果您认为应该将评论部分的内容复制到答案中,请告诉我们,我们可以编辑任何内容。或者自己建议编辑(我不知道,也许这在特定阈值以下不起作用)。
  • @LuisMiguelMejíaSuárez 这是隐式对象有效而隐式 val 无效的示例 gist.github.com/DmytroMitin/ed22c9a84d5c89a46148a073b92052da 这是您无法使用任何类型注释隐式 m 以便代码编译 @987654324 的示例@
猜你喜欢
  • 2018-10-08
  • 2017-05-08
  • 2017-10-11
  • 1970-01-01
  • 2019-12-24
  • 2018-06-09
  • 2019-05-19
  • 1970-01-01
  • 2021-02-25
相关资源
最近更新 更多