我正在努力用 Scalaz7
来理解monad堆栈和monad变换器 . 我觉得我能绕过一个特定的步骤 .
以下代码在磁盘上查找 ffmpeg
二进制文件,然后创建要运行的可执行命令,然后执行该命令,然后对输出执行一些微不足道的操作 .
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")})
}
}
代码通过运行启动
Encoder.encode("/path/to/video.mp4").unsafePerformIO
此代码有效,但您会注意到 callFfmpeg
的类型签名是 IO[Option[Stream[String]]]
而不是 IO[Stream[String]]
. 我不得不改变它以使其进行类型检查,但实际上因为所有 callFfmpeg
都是调用执行一个返回 Stream
的进程,它的类型签名应该是 IO[Stream[String]]
.
我的问题是,鉴于当时我打电话 callFfmpeg
我正在处理 IO[Option[String]]
我怎么去 IO[Option[Stream[String]]]
?
1 回答
所以我设法通过使用
liftM[OptionT]
来转换类型 .所以我的
callFfmpeg
函数可以变成:我的
getStream
函数现在变为:这允许从
IO[Stream[String]]
到IO[Option[Stream[String]]]
的转换,这就是我所追求的 .