2013-06-12 4 views
11

मेरे पास निम्न कोड है जो Reader कॉन्फ़िगरेशन के लिए मोनैड का उपयोग करता है और IO[Option[String]] से निपटने के लिए भी है और मैंने अपने encode फ़ंक्शन में सीढ़ी-चरण कोड के साथ समाप्त कर दिया है।स्कैला में मोनाड ट्रांसफॉर्मर्स के साथ सीढ़ी-कदम से कैसे बचें?

मैं Reader और OptionT के लिए एक इकाई के ट्रांसफार्मर मेरी encode समारोह में बदसूरत नेस्टेड for comprehensions से बचने के लिए कैसे तैयार कर सकते हैं?

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

धन्यवाद!

उत्तर

13

आप definition of Reader in the Scalaz source को देखो, तो आप इस देखेंगे:

type Reader[-E, +A] = ReaderT[Id, E, A] 

कौन सा हमें बताता है कि Reader इकाई प्रयोग कर रहे हैं सिर्फ एक इकाई ट्रांसफार्मर जहां इकाई लपेटा जा रहा है की एक विशेषज्ञता है तुच्छ है Id मोनड। आप सीधे ReaderT का उपयोग कर सकते हैं, लेकिन Reader में बस सबकुछ लपेटने के बजाय अपने OptionT[IO, _] मोनैड को लपेटें। उदाहरण के लिए, निम्नलिखित आप क्या चाहते हैं करना चाहिए:

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) 

सिद्धांत रूप में आप निम्नलिखित के साथ stream <- के बाद वाले हिस्से को बदलने के लिए सक्षम होना चाहिए: लेकिन किसी कारण से Unapply मशीनरी

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

कि liftReaderT इस मामले में काम नहीं कर रहा है पर निर्भर करता है। Kleisli लिखना स्पष्ट रूप से भाग्यशाली नहीं है, सौभाग्य से।


एक फुटनोट के रूप में:

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 
} 

मैं अपने सिर के ऊपर से यकीन नहीं है कि क्या वहाँ एक कारण है: यदि आप एक UnapplyCo उदाहरण इस तरह परिभाषित अच्छा liftReaderT वाक्य रचना मैंने कहा उपलब्ध हो जाता है स्कालज़ 7 वर्तमान में इस उदाहरण को प्रदान नहीं करता है, लेकिन शायद यह देखने लायक है।

+1

मैं आपका दिखाई देने पर एक समान उत्तर लिखने की प्रक्रिया में था। मैंने आपके उत्तर के शीर्ष में कुछ ऐसा किया जो मेरे अंदर था लेकिन रीडर = रीडर टी प्रकार उपनाम दिखाने के बारे में आपके अंदर नहीं है, अगर आपको लगता है कि यह आपके उत्तर में नहीं जुड़ा है तो कृपया इसे निकालने में संकोच न करें :) – stew

+0

@stew: धन्यवाद ! मैंने आपके द्वारा उल्लिखित स्रोत के लिए एक लिंक जोड़ा है। –

+0

ट्रैविस और @ स्टू यह अविश्वसनीय रूप से सहायक है! बस इसे अभी कोशिश कर रहा है। – cwmyers

संबंधित मुद्दे