Я недавно выбрал шаблон Free Monad, используя cats , пытаясь создать 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", используя американское правописание, мы нашли хороший ответ на этот вопрос, утверждая, что невозможно сделать до интерпретация.
Однако, безусловно, должна быть возможность интерпретировать программу для создания ее оптимизированной версии, а затем интерпретировать ее для получения List[A]
?