【发布时间】:2020-05-12 09:16:58
【问题描述】:
我最近使用cats 选择了Free Monad 模式,试图创建一个可以在执行前“简化”的DSL。例如,假设我创建了一种与列表交互的语言:
sealed trait ListAction[A]
case class ListFilter[A](in: List[A], p: A => Boolean) extends ListAction[List[A]]
case class ListMap[A, B](in: List[A], f: A => B) extends ListAction[List[B]]
type ListProgram[A] = Free[ListAction, A]
在执行使用这些操作构建的任何程序之前,我想通过将后续过滤器转换为单个过滤器并将后续映射转换为单个映射来优化它,以避免多次迭代列表:
// Pseudo code - doesn't compile, just illustrates my intent
def optimise[A](program: ListProgram[A]): ListProgram[A] = {
case ListFilter(ListFilter(in, p1), p2) => optimise(ListFilter(in, { a: A => p1(a) && p2(a) }))
case ListMap(ListMap(in, f1), f2) => optimise(ListMap(in, f2 compose f1))
}
这是否可以使用 Free Monad,通过在添加到程序时检查最后一个操作或通过如上所述的优化?非常感谢。
以下是我用来创建程序的代码:
trait ListProgramSyntax[A] {
def program: ListProgram[List[A]]
def listFilter(p: A => Boolean): ListProgram[List[A]] = {
program.flatMap { list: List[A] =>
Free.liftF[ListAction, List[A]](ListFilter(list, p))
}
}
def listMap[B](f: A => B): ListProgram[List[B]] = program.flatMap { list =>
Free.liftF(ListMap(list, f))
}
}
implicit def syntaxFromList[A](list: List[A]): ListProgramSyntax[A] = {
new ListProgramSyntax[A] {
override def program: ListProgram[List[A]] = Free.pure(list)
}
}
implicit def syntaxFromProgram[A](existingProgram: ListProgram[List[A]]): ListProgramSyntax[A] = {
new ListProgramSyntax[A] {
override def program: ListProgram[List[A]] = existingProgram
}
}
例如:
val program = (1 to 5).toList
.listMap(_ + 1)
.listMap(_ + 1)
.listFilter(_ % 3 == 0)
编辑:在我的同事使用美式拼写搜索“Free Monad optimize”后,我们发现a good answer 对这个问题断言不可能在之前 解释这个问题。
但是,肯定可以解释程序以生成它的优化版本,然后解释它以检索我们的List[A]?
【问题讨论】:
-
“肯定可以解释程序以生成它的优化版本” - “执行前”如何?关键是你不能在不调用函数的情况下解释
flatMap。 -
是的,我现在看到了。我将探索其他工具来实现我想要的。感谢您的帮助。
标签: scala scala-cats free-monad