2013-10-30 22 views
22

Yakın bir zamanda IO monad'la nasıl gelebileceğine dair bir video izledim, konuşma scaladaydı. Aslında, işleve sahip olmanın ne anlama geldiğini merak ediyorum. IO nesnesine sarılmış lambda ifadeleri, mutasyonların ne olduğu ve bir noktada gözlemlenmeleri gereken değişimin üstünde olduğu anlamına gelir, yani bir şey gerçekleşir. Sorunu sadece ağacın tepesinde başka bir yere itmiyor musunuz? GörebildiğimScala IO monad: ne anlamı var?

tek yararı da unsafePerformIO operasyonu aramazsam hiçbir yan etkiler görülebilir anlamında, tembel değerlendirme için izin vermesidir. Ayrıca sanırım programın diğer bölümleri/paylaşım kodu kullanabilir ve yan etkilerin gerçekleşmesini istediğinde deciede olabilir. Bu hepsi ise

merak ediyorum? Test edilebilirlikte herhangi bir avantaj var mı? Bu gibi olumsuzlukları gözlemlemeniz gerektiği gibi değil. Eğer özellikler/arayüzler kullandıysanız, bağımlılıkları kontrol edebilirsiniz, ancak etkiler bu bağımlılıklar üzerinde gerçekleştiğinde değil.

kodda Aşağıdaki örnek, bir araya getirdi.

case class IO[+A](val ra:() => A){ 
    def unsafePerformIO() : A = ra(); 
    def map[B](f: A => B) : IO[B] = IO[B](() => f(unsafePerformIO())) 
    def flatMap[B](f: A => IO[B]) : IO[B] = { 
    IO(() => f(ra()).unsafePerformIO()) 
    } 
} 



case class Person(age: Int, name: String) 

object Runner { 

    def getOlderPerson(p1: Person,p2:Person) : Person = 
    if(p1.age > p2.age) 
     p1 
     else 
     p2 

    def printOlder(p1: Person, p2: Person): IO[Unit] = { 
    IO(() => println(getOlderPerson(p1,p2))).map(x => println("Next")) 
    } 

    def printPerson(p:Person) = IO(() => { 
    println(p) 
    p 
    }) 

    def main(args: Array[String]): Unit = { 

    val result = printPerson(Person(31,"Blair")).flatMap(a => printPerson(Person(23,"Tom")) 
            .flatMap(b => printOlder(a,b))) 

    result.unsafePerformIO() 
    } 

} 

Etkilerin ne kadar iyi olduğunu tahmin ettiğim ana kadar, nasıl ertelendiğini görebilirsiniz. Bunu videodan hissettirdikten sonra ortaya çıktım.

doğru benim uygulanması mı ve benim anlayış doğru mu.

Ayrıca, ValidationMonad [IO [Kişi]] 'de olduğu gibi ValidationMonad ile birleştirilmesinin milaj yapılıp yapılmayacağını merak ediyorum, bu yüzden istisnalar oluştuğunda kısa devre yapabiliriz? Düşünceler lütfen.

Blair

cevap

27

O yan etkileri olup olmadığını kaydetmek için bir fonksiyonun tipi imzasına değerlidir. IO'nun uygulamanızın değeri vardır, çünkü bu çok şey başarır. Kodunuzu daha iyi belgelendirir; ve kodunuzu IO'yu içermeyen mantığı mümkün olduğu kadar ayırmak için kodunuzu yeniden düzenlerseniz, IO'yu içermeyen işlevleri daha karmaşık ve daha test edilebilir hale getirdiniz. Açık bir IO türü olmadan aynı refactoring'i yapabilirdiniz; ama açık bir tip kullanmak, derleyicinin ayrımı yapmanıza yardımcı olabileceği anlamına gelir.

Ancak bu sadece başlangıç. Sorunuzdaki kodda, IO eylemleri lambdas olarak kodlanır ve bu nedenle opaktır; Çalıştırmak dışında bir IO eylemiyle yapabileceğiniz hiçbir şey yoktur ve çalışma kodu kodlandığında etkilenir. GÇ monad uygulamak için yalnızca olası yol değildir

.Örneğin, IO eylemlerimi ortak bir özelliği genişleten vaka sınıfları haline getirebilirim. Sonra, örneğin, bir işlevi çalıştıran bir sınama yazabilirim ve IO eyleminin doğru tür döndürüp döndürmediğini görür.

Farklı türdeki IO eylemlerini temsil eden sınıflar söz konusu olduğunda, çalıştırdığımda işlemlerin ne yaptığına ilişkin kodlanmış uygulamalara yer vermeyebilir. Bunun yerine, typeclass desenini kullanarak bunu çözebilirim. Bu, IO eylemlerinin yaptığı farklı uygulamalarda takas yapılmasına izin verir. Örneğin, bir üretim veritabanında konuşan bir uygulama kümesine ve deneme amacıyla sahte bir bellek içi veritabanına konuşan başka bir kümeye sahip olabilirim.

Bölüm 13 Scala yılında Bjarnason & Chiusano kitabı Fonksiyonel Programlama ("I/O Harici Effects ve") bu konuların iyi bir tedavi yoktur. Özellikle bkz. 13.2.2, “Basit IO tipinin faydaları ve dezavantajları”.

GÜNCELLEME (Aralık 2015): “IO eylemlerinin yaptığı farklı uygulamalarda yeniden takas”, bu günlerde daha çok insan bu tür bir şey için “serbest monad” kullanıyor; bakınız örn. John De Goes'ün blog yazısı “A Modern Architecture for FP”.

+0

Teşekkürler. Büyük cevap bu fikirlere bir göz atacağım. –

+0

Alt sınıflara ve tür sınıflarına göre bir kod snippet'iniz var mı? –

+2

Drexin'in özellikle ConsoleIO gibi şeylere bağladığı Runar'ın slaytlarına bakın. Bu eylemleri (Eğer örtülü nesne ConsoleEffect .. çalıştırırsanız ne olabilir tanımından IO eylemleri ("vaka nesne GetLine ...", "dava sınıfı PutLine ...") beyanı ayrılığı gösterir. .'). Ama orada başka şeyler de var; Ben söylediğimi _only_ gösteren minimal kod değil. –

18

GÇ monad kullanmanın avantajı saf programları yaşıyor. Yan etkileri, zincirden yukarı doğru itmeyin, ancak bunları ortadan kaldırın.

def greet { 
    println("What is your name?") 
    val name = readLine 
    println(s"Hello, $name!") 
} 

Sen bunu yeniden yazarak yan etkisi kaldırabilirsiniz:: Aşağıdaki gibi bir saf olmayan işlevi varsa

def greet: IO[Unit] = for { 
    _ <- putStrLn("What is your name?") 
    name <- readLn 
    _ <- putStrLn(s"Hello, $name!") 
} yield() 

ikinci fonksiyon referentially şeffaftır.

IO monad'larının niçin kullanıldığına dair çok iyi bir açıklama, scala.io sitesinden in Rúnar Bjarnason's slides saf video bulunabilmektedir (video here bulunabilir).

+0

FP olmayan programcılar burada. İkincisi neden şeffaftır? Baskı, selamlama işlevinin içerdiği kullanıcı girişine bağlı olacaktır, değil mi? – nawfal

+0

@nawfal Bu, dış dünya üzerinde hiçbir etkisi olmadığı ve dış devlete bağlı olmadığı için doğrudan şeffaftır. Her çalıştırdığınızda aynı şeyi alırsınız: Çalıştırıldığında bazı metinleri yazdıracak ve giriş isteyecek bir eylem. Bunu iki kez yapmak isterseniz, iki kez aynı eylemi almak için iki kez işlevini çağırabilir veya bir kez işlevi çağırabilir ve döndürdüğü eylemi yeniden kullanabilir ve programınız semantik olarak aynı olur. Ayrıca bunu çağırabilir ve hiç bir zaman işlevi çağırmak için semantik olarak özdeş olan sonucu kullanamazsınız. – puhlen

+0

@ puhlen Anlıyorum, ama sonra bu geri dönüş eylemini çağırdığınızda, yan etkilerin var, değil mi? Temel olarak, yan etki bölümünü başka bir yere mi taşıyorsunuz? – nawfal

İlgili konular