Non sono del tutto sicuro, cosa significa Step in scalaz, ma l'implementazione di ListT
è piuttosto semplice. A seconda del numero di operazioni che vuoi mettere su di esso, può essere un po 'di lavoro, ma le operazioni di base di Monad possono essere implementate come segue.
Prima dobbiamo typeclasses per monade e funtore (potremmo anche aggiungere applicativa, ma che non è necessario per questo esempio):
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]]
}
volta abbiamo quelli, possiamo creare il trasformatore, che fondamentalmente solo avvolge lo F[List[A]]
e inoltra la chiamata alla sua funzione e flatMap
all'elenco chiamando map
sul functor contenente e quindi chiamando map
risp. flatMap
risp. sul contenuto 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
}
Una volta che abbiamo finito con la modifica, si può ottenere l'oggetto risultante chiamando il metodo run
sull'oggetto ListT
. Se lo desideri, puoi anche aggiungere altre operazioni specifiche come in scalaz. Questo dovrebbe essere abbastanza semplice. Ad esempio, un ::
potrebbe apparire come segue:
def ::(x: A) = ListT(Monad[F].map(fa)(x :: _))
Usage:
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))
La versione 7.x non usa 'Passo', sembra molto semplice. https://github.com/scalaz/scalaz/blob/v7.0.3/core/src/main/scala/scalaz/ListT.scala – huynhjl
@huynhjl Giusto, ero sicuro di aver visto un'implementazione 7 con 'Step', sebbene . – ziggystar