2016-03-03 16 views
5

Scala'da kendi anlama-anlama uyumlu monad'ları ve functor'larımı uygulamak istiyorum.Kendi anlama-anlama uyumlu scala monad'ınızı nasıl yapabilirsiniz?

Örnek olarak iki aptal monad alalım. Bir monad, harita veya düz harita oluşturabileceğiniz bir "Int" içeren bir devlet monadıdır. Başka monad alır

val maybe = IntMonad(5) 
maybe flatMap(a => 3 * (a map (() => 2 * a))) 
// returns IntMonad(30) 

val func = FunctionMonad(() => println("foo")) 
val fooBar = func map (() => println("bar")) 
fooBar() 
// foo 
// bar 
// returns Unit 

örnek bazı hatalar olabilir ... şöyle fonksiyon oluşacağının, ancak fikir.

Bu iki farklı tipte Monad'ı Scala'da bir kavrayış içinde kullanabilmek istiyorum.

val myMonad = IntMonad(5) 
for { 
    a <- myMonad 
    b <- a*2 
    c <- IntMonad(b*2) 
} yield c  
// returns IntMonad(20) 

Ben Scala usta değilim, ama sizin için-anlama, gerçekten sadece bunun için map ve flatMap yöntemlerini tanımlamak için gereken içinde kullanılmak üzere bir tür için fikir

cevap

9

olsun: Bunun gibi Aynı türdeki örnekleri döndür. Sözdizimsel olarak, kavrama, derleyici tarafından flatMap s dizisine dönüştürülür ve bunu yield için bir son map izler. Bu yöntemler uygun imza ile mevcut olduğu sürece çalışacaktır. Ben iki alt tipe (I ile ortak bir özelliği vardır

sealed trait MaybeInt { 
    def map(f: Int => Int): MaybeInt 
    def flatMap(f: Int => MaybeInt): MaybeInt 
} 

case class SomeInt(i: Int) extends MaybeInt { 
    def map(f: Int => Int): MaybeInt = SomeInt(f(i)) 
    def flatMap(f: Int => MaybeInt): MaybeInt = f(i) 
} 

case object NoInt extends MaybeInt { 
    def map(f: Int => Int): MaybeInt = NoInt 
    def flatMap(f: Int => MaybeInt): MaybeInt = NoInt 
} 

:

Burada size örnekler sayesinde tüm aradıklarınızı gerçekten emin değilim, ama önemsiz bir Option eşdeğerdir örnektir Yine de istediğim kadar olabilir. Ortak özellik MaybeInt, her alt türün map/flatMap arabirimine uymasını zorlar.

scala> val maybe = SomeInt(1) 
maybe: SomeInt = SomeInt(1) 

scala> val no = NoInt 
no: NoInt.type = NoInt 

for { 
    a <- maybe 
    b <- no 
} yield a + b 

res10: MaybeInt = NoInt 

for { 
    a <- maybe 
    b <- maybe 
} yield a + b 

res12: MaybeInt = SomeInt(2) 

Ayrıca, foreach ve filter ekleyebilir. ayrıca bu (hiçbir verim) işlemek isterseniz:

for(a <- maybe) println(a) 

Sen foreach eklersiniz. Eğer if korumaları kullanmak istiyorsanız Ve:

for(a <- maybe if a > 2) yield a 

Sen filter veya withFilter gerekir.

Tam örnek:

sealed trait MaybeInt { self => 
    def map(f: Int => Int): MaybeInt 
    def flatMap(f: Int => MaybeInt): MaybeInt 
    def filter(f: Int => Boolean): MaybeInt 
    def foreach[U](f: Int => U): Unit 
    def withFilter(p: Int => Boolean): WithFilter = new WithFilter(p) 

    // Based on Option#withFilter 
    class WithFilter(p: Int => Boolean) { 
     def map(f: Int => Int): MaybeInt = self filter p map f 
     def flatMap(f: Int => MaybeInt): MaybeInt = self filter p flatMap f 
     def foreach[U](f: Int => U): Unit = self filter p foreach f 
     def withFilter(q: Int => Boolean): WithFilter = new WithFilter(x => p(x) && q(x)) 
    } 
} 

case class SomeInt(i: Int) extends MaybeInt { 
    def map(f: Int => Int): MaybeInt = SomeInt(f(i)) 
    def flatMap(f: Int => MaybeInt): MaybeInt = f(i) 
    def filter(f: Int => Boolean): MaybeInt = if(f(i)) this else NoInt 
    def foreach[U](f: Int => U): Unit = f(i) 
} 

case object NoInt extends MaybeInt { 
    def map(f: Int => Int): MaybeInt = NoInt 
    def flatMap(f: Int => MaybeInt): MaybeInt = NoInt 
    def filter(f: Int => Boolean): MaybeInt = NoInt 
    def foreach[U](f: Int => U): Unit =() 
} 
+0

Kendi tanımlama yerine Scallaz Monad türü kullanmak daha iyi olurdu? –

+0

'filter' api ayrıca monad öğelerinin" paketlenmesini "de gerektirir. Örneğin, Belki IEC'ye benzeyen bir BelkiAB'ı kullanırsanız, fakat bir “A sınıfı (a: İnt, b: İnt)” için filtre, (AB (a, b) <- maybAB için) yapmak için gereklidir. ' –

İlgili konular