I'm struggling with understanding monad stacks and monad transformers with Scalaz7
. I feel I'm pretty close to the answer but just can't get my head around a particular step.
The following code looks on disk for an ffmpeg
binary, then creates an executable command to be run, then executes that 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 is kicked off by running
Encoder.encode("/path/to/video.mp4").unsafePerformIO
This code works, but you will notice that callFfmpeg
's type signature is IO[Option[Stream[String]]]
instead of IO[Stream[String]]
. I had to change it to that to get it to type check, but really since all callFfmpeg
does is call execute a process which returns a Stream
it's type signature should be IO[Stream[String]]
.
My question is, given that at the time I call callFfmpeg
I'm dealing with IO[Option[String]]
how do I get to IO[Option[Stream[String]]]
?
findFfmpeg
return a plain oldIO[Option[String]]
action and then map into that? – Antonetteantoni