Подтвердить что ты не робот

Укладка монадических эффектов в Free Monad в Scala

Я изучаю свободную монаду в Scala, и я собрал простой пример алгебры, который я могу поднять в Free monad, используя кошек.

Здесь моя алгебра

sealed trait ConsultationOp[A]
object consultation {
  case class Create(c: Consultation) extends ConsultationOp[Unit]
  case class Get(s: ConsultationId) extends ConsultationOp[Option[Consultation]]
}

И я могу использовать его как

def app = for {
  c <- consultation.Create(Consultation("123", "A consultation"))
  _ <- consultation.Get(c._id)
} yield ()

def interpreters = ConsultationInterpreter or UserInterpreter
app.foldMap(interpreters)

Если подстановка с ConsultationOp до Free выполняется неявно.

(там много деталей отсутствует, полная рабочая реализация здесь: https://github.com/gabro/free-api)

Пока все хорошо, но что, если мне нужно извлечь необязательное значение, возвращаемое consultation.Get.

Первое, что приходит в голову, это трансформатор монады, т.е. что-то вроде

def app = for {
  c <- consultation.Create(Consultation("123", "A consultation")).liftM[OptionT]
  d <- OptionT(consultation.Get(c._id))
  _ <- doSomethingAConsultation(d)
} yield ()

но он выглядит уродливым, и он не чувствует себя хорошо.

Какой прославленный путь - если таковой имеется - укладывания монадических эффектов при использовании свободной монады?

4b9b3361

Ответ 1

Обычно я вижу повторяющиеся в этих случаях: использовать траверс, поэтому вы можете изменить свой код по строкам:

import cats.syntax.traverse._
import cats.instances.option._

// ...

def app = for {
  c <- consultation.Create(Consultation("123", "A consultation"))
  d <- consultation.Get(c._id)
  _ <- d.traverseU(doSomethingAConsultation(_))
} yield ()

Какой, имхо, намного чище, чем альтернатива трансформатора монады. Обратите внимание, что вам может понадобиться еще один import и немного изменить код, я его не пробовал, но концепция такова: используйте траверс.