【问题标题】:How to create a Functor for an ADT used in a cats Free Monad如何为猫 Free Monad 中使用的 ADT 创建 Functor
【发布时间】:2021-08-13 02:41:03
【问题描述】:

我正在 cat.free.Free Monad 库的帮助下使用案例类编写 DSL。 DSL 将由接收消息的 Actor 进行解释,因此每个 Actor 必须首先使用 Free.resume 解包命令。

这在六年前使用 scalaz where we also used the resume function 也很有效,但是免费 monad 的 Functor 是 easy to create,因为我们使用了带有额外函数参数的案例类,可以映射到诸如 k下面。

case class GetResource[Rdf <: RDF, A](
   uri: Rdf#URI,
   k: NamedResource[Rdf] => A) extends LDPCommand[Rdf, A]

但是当前的cats.scala.Free on the cats Free Monad web page 的例子并没有这样的论点。确实,当通过自然转换使用 Free Monads 的解释时,这些效果很好。我用一个案例类尝试了with a super simple DSL

sealed trait LDPCmd[A]:
    def url: Uri

case class Get[T](url: Uri) extends LDPCmd[Response[T]]

然后我可以为此编写a simple Script,它可以按预期工作in the tests using the natural transformation interpretation

但是使用基于 Actors 的解释,我现在需要解开 free monad 中的每个命令,这些命令使用 Free 的 resume 函数发送给不同的 Actor。这需要一个仿函数。但是我不清楚仿函数在哪里可以得到控制。即,我在 ???位置在这里

given CmdFunctor: cats.Functor[LDPCmd] with 
    def map[A, B](fa: LDPCmd[A])(f: A => B): LDPCmd[B] = fa match 
        case g: Get => ???

【问题讨论】:

  • 添加了 Scala 3 标签

标签: scala scalaz scala-cats scala-3


【解决方案1】:

问题在于您的数据类型:Get[T] 不使用 T,因此无法有意义地映射它,除了无操作:g: Get =&gt; Get[B](g)

【讨论】:

  • 为什么会有问题? Functor 定律成立,所以这是一个非常好的 Functor。 cat 包含相同数据类型的通用版本实际上非常有用:Const。 typelevel.org/cats/datatypes/const.html
  • 是的,但我不想要一个 const 仿函数 :-) 我想用它来构建一个在某个位置获取一些数据的脚本,就像在 example function I gave 中一样。它适用于解释的自然转换方法,但我需要构建一个使用函子的方法。
  • 也许我只需要添加额外的参数...
【解决方案2】:

答案似乎又回到了将额外功能添加到案例类中。在猫聊天频道 Rob Norris 写道:

Free[F, *] 的经典编码只有当 F 是一个函子时才是一个单子,所以对于每种情况,你都需要额外的 Blah => A 成员。然后我们发现您可以使用 Free[Coyoneda[F, *], *] 并免费获得该机器。然后我们想出了如何将它烘焙成 Free,所以大多数时候你不需要做任何事情。 但是,如果您需要逐步完成计算,则确实需要其中一种编码,因为在这种情况下 F 仍然需要是 Functor。

他指向的代码是SimMessageSocket.scala

sealed trait Step[+A]
  case class Send[A](m: BackendMessage, k: Unit => A) extends Step[A]
  case class Expect[A](h: PartialFunction[FrontendMessage, A]) extends Step[A]
  object Step {
    implicit val FunctorStep: Functor[Step] =
      new Functor[Step] {
        def map[A,B](fa: Step[A])(f: A => B): Step[B] =
          fa match {
            case Send(m, k) => Send(m, k andThen f)
            case Expect(h)    => Expect(h andThen f)
          }
      }
  }

【讨论】:

    猜你喜欢
    • 2018-08-22
    • 2019-11-27
    • 2019-11-12
    • 2021-09-04
    • 2012-01-29
    • 2011-11-05
    • 2020-03-26
    相关资源
    最近更新 更多