2013-08-23 17 views
7

Koleksiyon monadına çok benzeyen bir monadım var. Şu an için bir monad transformatörü uygulamaya çalışıyorum ama başarısız oluyorum.Scala'da `List` monad transformer nasıl uygulanır?

Scalaz 6 ve 7'de ListT uygulamasına baktım, ancak nasıl çalıştığını anlayamıyorum. Amacı bana açık olmayan bazı ek tip Step kullanır.

Birisi bana bir liste monad trafosunun nasıl uygulanacağını açıklayabilir, ya Scalaz yaklaşımını açıklayarak veya farklı bir uygulama kullanarak mı?

+1

7.x sürümü 'Step' kullanmıyor, çok basit görünüyor. https://github.com/scalaz/scalaz/blob/v7.0.3/core/src/main/scala/scalaz/ListT.scala – huynhjl

+0

@huynhjl Doğru, 'Adım' ile 7 uygulama gördüğümden eminim. . – ziggystar

cevap

17

Adımın scalazda ne anlama geldiğini, ancak bir ListT uygulanmasının oldukça basit olduğundan emin değilim. Kaç işlem yapmak istediğinize bağlı olarak, küçük bir iş olabilir, ancak temel monat işlemleri aşağıdaki gibi uygulanabilir.

Önce (biz de uygulamalı ekleyebilir, ancak bu örneğin gerekli değildir) monad ve funktor için typeclasses gerekir:

trait Functor[F[_]] { 
    def map[A,B](fa: F[A])(f: A => B): F[B] 
} 

trait Monad[F[_]] extends Functor[F] { 
    def flatMap[A,B](fa: F[A])(f: A => F[B]): F[B] 
    def pure[A](x: A): F[A] 
} 

object Monad { 

    implicit object ListMonad extends Monad[List] { 
    def map[A,B](fa: List[A])(f: A => B) = fa map f 
    def flatMap[A,B](fa: List[A])(f: A => List[B]) = fa flatMap f 
    def pure[A](x: A) = x :: Nil 
    } 

    implicit object OptionMonad extends Monad[Option] { 
    def map[A,B](fa: Option[A])(f: A => B) = fa map f 
    def flatMap[A,B](fa: Option[A])(f: A => Option[B]) = fa flatMap f 
    def pure[A](x: A) = Some(x) 
    } 

    def apply[F[_] : Monad]: Monad[F] = implicitly[Monad[F]] 

} 

biz bu edindikten sonra, biz trafo, oluşturabileceğiniz temelde sadece F[List[A]]'u sarar ve map ve flatMap işlevini, çağrıyı içeren funkendeki map numaralı telefonu arayarak ve map veya flatMap numaralarını arayarak gönderir. bulunan List/s. Biz değiştirerek bitirdikten sonra

final case class ListT[F[_] : Monad, A](fa: F[List[A]]) { 
    def map[B](f: A => B) = ListT(Monad[F].map(fa)(_ map f)) 

    def flatMap[B](f: A => ListT[F, B]) = ListT(Monad[F].flatMap(fa) { _ match { 
    case Nil => Monad[F].pure(List[B]()) 
    case list => list.map(f).reduce(_ ++ _).run 
    }}) 

    def ++(that: ListT[F,A]) = ListT(Monad[F].flatMap(fa) { list1 => 
    Monad[F].map(that.run)(list1 ++ _) 
    }) 

    def run = fa 
} 

, biz ListT nesne üzerinde run yöntemini çağırarak çıkan nesneyi elde edebilirsiniz. İsterseniz, scalaz gibi diğer listeye özel işlemleri de ekleyebilirsiniz. Bu oldukça düz ileri olmalıdır. Örneğin olarak görünebilir bir :: izler:

def ::(x: A) = ListT(Monad[F].map(fa)(x :: _)) 

Kullanımı:

scala> ListT(Option(List(1,2,3))) 
res6: ListT[Option,Int] = ListT(Some(List(1, 2, 3))) 

scala> res6.map(_+45) 
res7: ListT[Option,Int] = ListT(Some(List(46, 47, 48))) 

scala> 13 :: res7 
res8: ListT[Option,Int] = ListT(Some(List(13, 46, 47, 48))) 

scala> res8.run 
res10: Option[List[Int]] = Some(List(13, 46, 47, 48))