How to convert between monad stacks with transformers in scalaz 7

I struggle with understanding monad stacks and monad transformers with Scalaz7 . I feel like I'm pretty close to the answer, but just can't plunge into any particular step.

The following code looks on disk for the ffmpeg binary, then creates an executable command to run, then executes this command, and then does something trivial with the output.

 object Encoder { def findFfmpeg: OptionT[IO, String] = { OptionT[IO, String](IO { List("/usr/local/bin/ffmpeg", "/usr/bin/ffmpeg").find { new File(_).exists } } ) } def getCommand(ffmpegBin: String, videoFile: String) = s"$ffmpegBin $videoFile '-vcodec libx264 -s 1024x576' /tmp/out.mp4" def callFfmpeg(command: String): IO[Option[Stream[String]]] = IO { Some(Process(command).lines_!) } def getStream(fileName: String): OptionT[IO, Stream[String]] = { val optionalCommand: OptionT[IO, String] = findFfmpeg map { getCommand(_, fileName) } optionalCommand >>= { command => OptionT[IO, Stream[String]](callFfmpeg(command)) } } def encode(fileName: String): IO[Unit] = { getStream(fileName) map { a: Stream[String] => a map { _.length } foreach (println) } getOrElse (Unit.box {println("nothing")}) } } 

The code runs at startup

 Encoder.encode("/path/to/video.mp4").unsafePerformIO 

This code works, but you will notice that the signature is type callFfmpeg IO[Option[Stream[String]]] instead of IO[Stream[String]] . I had to change it to this in order to force it to enter a check, but in fact, since all callFfmpeg is a call, execute the process that returns Stream , its type signature should be IO[Stream[String]] .

My question is that while I call callFfmpeg , I am dealing with IO[Option[String]] , how do I get to IO[Option[Stream[String]]] ?

+6
source share
1 answer

So, I was able to convert the type using liftM[OptionT] .

So my callFfmpeg function could become:

 def callFfmpeg(command: String): IO[Stream[String]] = IO { Process(command).lines_! } 

and now my getStream function will look like this:

 def getStream(fileName: String): OptionT[IO, Stream[String]] = { val optionalCommand: OptionT[IO, String] = findFfmpeg map { getCommand(_, fileName) } optionalCommand >>= { command => callFfmpeg(command).liftM[OptionT] } } 

This allows you to convert from IO[Stream[String]] to IO[Option[Stream[String]]] , which I do after.

+1
source

Source: https://habr.com/ru/post/945457/


All Articles