2013-05-20 11 views
6

Ich habe Probleme mit dem Verständnis von Monad Stacks und Monade-Transformatoren mit Scalaz7. Ich fühle, dass ich der Antwort ziemlich nahe bin, aber ich komme einfach nicht um einen bestimmten Schritt herum.Wie ich zwischen Monad-Stacks mit Transformatoren in scalaz konvertieren 7

Der folgende Code sieht auf der Festplatte für eine ffmpeg Binärdatei, dann erstellt einen ausführbaren Befehl ausgeführt werden, führt dann diesen Befehl und dann etwas Triviales mit der Ausgabe.

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")}) 
    } 
} 

Der Code wird durch das Ausführen

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

Dieser Code funktioniert, aber Sie werden feststellen, dass callFfmpeg ‚s Art Signatur ist IO[Option[Stream[String]]] statt IO[Stream[String]] gestartet. Ich musste es ändern, um es zur Überprüfung zu bekommen, aber wirklich, da alle callFfmpeg heißt, führen Sie einen Prozess, der eine Stream zurückgibt es Typ-Signatur sollte IO[Stream[String]] sein.

Meine Frage ist, angesichts der Tatsache, dass ich callFfmpegIO[Option[String]] anrufen, wie komme ich zu IO[Option[Stream[String]]]?

+0

Warum nicht 'findFfmpeg' eine einfache, alte 'IO [Option [String]]' Aktion zurückgeben und dann in diese umwandeln? –

Antwort

1

So habe ich es geschafft, den Typ mit liftM[OptionT] zu transformieren.

So kann meine callFfmpeg Funktion werden:

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

und meine getStream Funktion wird jetzt:

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

Dadurch wird die Umwandlung von IO[Stream[String]] zu IO[Option[Stream[String]]] erlaubt das ist, was ich bin nach.