2013-06-12 11 views
11

Yapılandırma için Reader tekdüzenini kullanan ve IO[Option[String]] ile uğraşmak zorunda olduğum ve encode işlevindeki merdiven basamaklarını tamamladığım şu kodu kullanıyorum.Scala'daki Monad Transformers ile merdiven basamakları nasıl atılır?

benim encode işlevinde çirkin iç içe for comprehensions önlemek için Reader ve OptionT için monad trafo formüle nasıl

?

def encode(fileName: String): Reader[Config, IO[Unit]] = for { 
    ffmpegWrapper <- findFfmpegWrapper 
    ffmpegBin <- findFfmpeg 
} yield (for { 
    w <- ffmpegWrapper 
    b <- ffmpegBin 
    stream <- callFfmpeg(getCommand(w, b, fileName)).liftM[OptionT] 
} yield stream) map (_ foreach (println)) getOrElse Unit.box {} 


def getCommand(ffmpegWrapper: String, ffmpegBin: String, 
      videoFile: String) = s"$ffmpegWrapper $ffmpegBin $videoFile '-vcodec libx264 -s 1024x576' /tmp/out.mp4" 

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

def findFile(path:List[String]): OptionT[IO,String] = OptionT[IO,String](IO{path.find(new File(_).exists)}) 

def findFfmpeg:Reader[Config, OptionT[IO,String]] = Reader {c=>findFile(c.ffmpegLocations)} 

def findFfmpegWrapper:Reader[Config, OptionT[IO,String]] = Reader {c=>findFile(c.ffmpegWrapperLocations)} 

Thank-you!

cevap

13

Eğer definition of Reader in the Scalaz source bakarsanız, bunu göreceksiniz:

kullandığınız Reader monad monad sarılı olan bir monad trafonun sadece bir uzmanlık olduğunu söyler
type Reader[-E, +A] = ReaderT[Id, E, A] 

önemsiz Id monad. ReaderT'u doğrudan kullanabilirsiniz, ancak Reader ürününde yalnızca her şeyi sarmak yerine OptionT[IO, _] monad'ınızı paketleyebilirsiniz. Örneğin, aşağıdaki istediğini yapmalıdır:

Prensip olarak
type OptionIO[+A] = OptionT[IO, A] 

def findFfmpeg: ReaderT[OptionIO, Config, String] = 
    Kleisli[OptionIO, Config, String](c => findFile(c.ffmpegLocations)) 

def findFfmpegWrapper: ReaderT[OptionIO, Config, String] = 
    Kleisli[OptionIO, Config, String](c => findFile(c.ffmpegWrapperLocations)) 

def encode(fileName: String): ReaderT[OptionIO, Config, Unit] = (for { 
    w <- findFfmpegWrapper 
    b <- findFfmpeg 
    stream <- Kleisli[OptionIO, Config, Stream[String]](
    _ => callFfmpeg(getCommand(w, b, fileName)).liftM[OptionT] 
    ) 
} yield stream).map(_ foreach println) 

aşağıdaki ile stream <- sonra kısmının yerini mümkün olmalıdır:

callFfmpeg(getCommand(w, b, fileName)).liftM[OptionT].liftReaderT[Config] 

Ama nedense Unapply makine olduğunu liftReaderT güveniyor, bu durumda çalışıyor gibi görünmüyor. Kleisli bölümünün açıkça yazılması, o kadar da korkunç değil.

implicit def unapplyMFA1[TC[_[_]], F[+_], M0[F[+_], +_], A0](
    implicit TC0: TC[({ type L[x] = M0[F, x] })#L] 
): UnapplyCo[TC, M0[F, A0]] { 
    type M[+X] = M0[F, X] 
    type A = A0 
} = new UnapplyCo[TC, M0[F, A0]] { 
    type M[+X] = M0[F, X] 
    type A = A0 
    def TC = TC0 
    def leibniz = Leibniz.refl 
} 

kafamın üst kapalı emin değilim olsun bir nedeni var: Eğer böyle bir UnapplyCo örneğini tanımlarsanız bahsettiğim güzel liftReaderT sözdizimi kullanılabilir hale gelir: bir dipnot olarak


Scalaz 7 şu anda bu örneği sağlamıyor, ama muhtemelen araştırmaya değer.

+1

Seninki ortaya çıktığında hemen hemen aynı bir cevap yazma sürecindeydim. Ben senin cevabın tepesinde değiştirdim ama senin Reader değil Okuyucu = ReaderT türü takma adıyla ilgili bir şeyle değiştirilmiş, cevabınıza eklemediğini düşünüyorsanız lütfen çekinmeyin :) – stew

+0

@stew: Teşekkürler ! Az önce bahsettiğin kaynağa bir link ekledim. –

+0

Travis ve @stew bu inanılmaz derecede yararlı! Sadece şimdi deniyorum. – cwmyers

İlgili konular