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))
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
@huynhjl Richtig, ich war mir sicher, dass ich eine 7-Implementierung mit 'Step' gesehen habe, obwohl . – ziggystar