2013-08-23 13 views
7

Ich habe eine Monade, die einer Sammlung Monade sehr ähnlich ist. Ich versuche gerade, einen Monade-Transformator dafür zu implementieren, aber ich versage.Wie implementiert man die "List" Monade Transformator in Scala?

Ich habe die ListT Implementierung in Scalaz 6 und 7 angeschaut, aber ich kann nicht verstehen, wie es funktioniert. Es benutzt einige zusätzliche Typen Step, deren Zweck mir unklar ist.

Kann mir bitte jemand erklären, wie man einen Listen-Monade-Transformator implementiert, entweder indem man den Scalaz Ansatz erklärt oder eine andere Implementierung benutzt?

+1

Die 7.x-Version verwendet nicht "Step", es scheint sehr einfach. https://github.com/scalaz/scalaz/blob/v7.0.3/core/src/main/scala/scalaz/ListT.scala – huynhjl

+0

@huynhjl Richtig, ich war mir sicher, dass ich eine 7-Implementierung mit 'Step' gesehen habe, obwohl . – ziggystar

Antwort

17

Ich bin mir nicht ganz sicher, was der Schritt in scalaz bedeutet, aber die Implementierung einer ListT ist ziemlich geradlinig. Je nachdem, wie viele Operationen Sie ausführen möchten, kann es ein wenig Arbeit sein, aber die grundlegenden Monad-Operationen können wie folgt implementiert werden.

Zuerst müssen wir typeclasses für Monade und Funktors (wir auch applicative hinzufügen könnte, aber das ist nicht notwendig, für dieses Beispiel):

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]] 

} 

Sobald wir die haben, können wir den Transformator schaffen, die im Grunde nur wickelt die F[List[A]] und leitet den Anruf an seine map und flatMap-Funktion an die Liste durch Aufruf map auf dem enthaltenden Funktor und dann Aufruf map oder flatMap resp. auf dem enthaltenen List/s.

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 
} 

Sobald wir mit modifizierenden fertig sind, können wir das resultierende Objekt durch den Aufruf der run Methode auf dem ListT Objekt erhalten. Wenn Sie möchten, können Sie auch andere listspezifische Operationen wie in scalaz hinzufügen. Das sollte ziemlich geradlinig sein. Zum Beispiel kann ein :: könnte wie folgt aussehen:

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

Verbrauch:

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)) 
Verwandte Themen