Scala, код с free monad не компилируется, если в операции есть параметр с типом содержащим F[_]

Разбираюсь с free monad, но не получается понять как правильно написать код, если один из классов принимает например fs2.Stream.

Пример кода:

import cats.effect.{Async, IO, IOApp}
import cats.free.Free
import cats.syntax.all._
import cats.{Monad, ~>}
import dev.free.A._

object Example extends IOApp.Simple {
  override def run: IO[Unit] = {
    val stream =
      fs2.Stream.emit[IO, String]("example").through(fs2.text.utf8.encode)
    write("/a/b/c", stream).foldMap(compiler)
  }

  private def compiler: ActionA ~> IO = new (ActionA ~> IO) {
    override def apply[A](fa: ActionA[A]): IO[A] = {
      fa match {
        case Write(path, data) => data.through(fs2.text.utf8.decode).compile.string.flatMap { s =>
          IO.println(s"$path; $s")
        }
      }
    }
  }

}

object A {
  sealed trait ActionA[A]

  case class Write(path: String, data: fs2.Stream[_, Byte]) extends ActionA[Unit]

  type Action[A] = Free[ActionA, A]

  def write(path: String, data: fs2.Stream[_, Byte]): Action[Unit] = Free.liftF[ActionA, Unit](Write(path, data))
}

Ошибка при компиляции:

Example.scala:35:44
_$2 takes no type parameters, expected: 1
  def write(path: String, data: fs2.Stream[_, Byte]): Action[Unit] = Free.liftF[ActionA, Unit](Write(path, data))

Все проблемы из за того что не указан тип эффекта для fs2.Stream в Write и я не понимаю как это сделать.


Ответы (1 шт):

Автор решения: Bleser

Вот этот код работает.

import cats.effect.{Async, IO, IOApp}
import cats.free.Free
import cats.syntax.all._
import cats.{Monad, ~>}
import dev.free.A._

object Example extends IOApp.Simple {
  override def run: IO[Unit] = {
    val stream =
      fs2.Stream.emit[IO, String]("example").through(fs2.text.utf8.encode)
    write("/a/b/c", stream).foldMap(compiler)
  }

  private def compiler: ActionA ~> IO = new (ActionA ~> IO) {
    override def apply[A](fa: ActionA[A]): IO[A] = {
      fa match {
        case o: Write[IO] => o.data.through(fs2.text.utf8.decode).compile.string.flatMap { s =>
          IO.println(s"${o.path}; $s")
        }
      }
    }
  }

}

object A {
  sealed trait ActionA[A]

  case class Write[F[_]](path: String, data: fs2.Stream[F, Byte]) extends ActionA[Unit]

  type Action[A] = Free[ActionA, A]

  def write[F[_]](
             path: String,
             data: fs2.Stream[F, Byte]
           ): Action[Unit] = Free.liftF[ActionA, Unit](Write[F](path, data))
}
→ Ссылка