gpt4 book ai didi

scala - Cats Free 基于 Monad 的代数组合

转载 作者:行者123 更新时间:2023-12-02 01:03:08 24 4
gpt4 key购买 nike

假设我有以下用于处理文件系统的代数:

sealed trait Fs[A]
case class Ls(path: String) extends Fs[Seq[String]]
case class Cp(from: String, to: String) extends Fs[Unit]

def ls(path: String) = Free.liftF(Ls(path))
def cp(from: String, to: String) = Free.liftF(Cp(from, to))

以及代数的以下解释器:

def fsInterpreter = new (Fs ~> IO) {
def apply[A](fa: Fs[A]) = fa match {
case Ls(path) => IO(Seq(path))
case Cp(from, to) => IO(())
}
}

现在假设我想构建另一个使用第一个代数的代数。例如:

sealed trait PathOps[A]
case class SourcePath(template: String) extends PathOps[String]

def sourcePath(template: String) = Free.liftF(SourcePath(template))

接下来我想为 PathOps ~> IO 编写一个解释器,它会做这样的事情:

for {
paths <- ls(template)
} yield paths.head

换句话说,我的 PathOps 解释器应该调用 Fs 代数。

我该怎么做?

最佳答案

我假设你想写两个解释器 PathOps ~> Free[Fs, ?]Fs ~> IO,然后将它们组合成一个解释器 PathOps ~> IO

下面是一个可编译的例子。以下是我在此示例中使用的所有导入:

import cats.~>
import cats.free.Free
import cats.free.Free.liftF

这是 IO 和您的代数的模拟实现:

// just for this example
type IO[X] = X
object IO {
def apply[A](a: A): IO[A] = a
}

sealed trait Fs[A]
case class Ls(path: String) extends Fs[Seq[String]]
case class Cp(from: String, to: String) extends Fs[Unit]
type FreeFs[A] = Free[Fs, A]

def ls(path: String) = Free.liftF(Ls(path))
def cp(from: String, to: String) = Free.liftF(Cp(from, to))

这是从您的代码中复制的解释器 Fs ~> IO:

def fsToIoInterpreter = new (Fs ~> IO) {
def apply[A](fa: Fs[A]) = fa match {
case Ls(path) => IO(Seq(path))
case Cp(from, to) => IO(())
}
}

sealed trait PathOps[A]
case class SourcePath(template: String) extends PathOps[String]

def sourcePath(template: String) = Free.liftF(SourcePath(template))

这是您的 for-comprehension 转换为 PathOps ~> Free[Fs, ?]-interpreter:

val pathToFsInterpreter = new (PathOps ~> FreeFs) {
def apply[A](p: PathOps[A]): FreeFs[A] = p match {
case SourcePath(template) => {
for {
paths <- ls(template)
} yield paths.head
}
}
}

现在您可以使用 Free.foldMapFs ~> IO 提升到 Free[Fs, ?] ~> IO 中,并且将其与 PathOps ~> Free[Fs, ?] 组合起来 - 使用 andThen 的解释器:

val pathToIo: PathOps ~> IO = 
pathToFsInterpreter andThen
Free.foldMap(fsToIoInterpreter)

这为您提供了一个来自 PathOps ~> IO 的解释器,它由两个可以单独测试的独立层组成。

关于scala - Cats Free 基于 Monad 的代数组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49235804/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com