Tôi không hoàn toàn chắc chắn, ý nghĩa của Bước trong scalaz, nhưng việc triển khai ListT
là khá đơn giản. Tùy thuộc vào số lượng hoạt động bạn muốn đặt vào nó, nó có thể là một công việc nhỏ, nhưng các hoạt động đơn lẻ cơ bản có thể được thực hiện như sau.
Đầu tiên chúng ta cần typeclasses cho đơn nguyên và functor (chúng tôi cũng có thể thêm applicative, nhưng điều đó là không cần thiết ví dụ này):
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]]
}
Một khi chúng ta có những người, chúng ta có thể tạo ra các biến, mà về cơ bản chỉ kết thúc cuộc gọi F[List[A]]
và chuyển tiếp cuộc gọi tới chức năng map
và flatMap
vào danh sách bằng cách gọi map
trên functor chứa và sau đó gọi map
hoặc flatMap
resp. trên có chứa 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
}
Một khi chúng ta đang thực hiện với sửa đổi, chúng ta có thể có được đối tượng kết quả bằng cách gọi phương pháp run
trên đối tượng ListT
. Nếu bạn muốn, bạn cũng có thể thêm các hoạt động danh sách khác cụ thể như trong scalaz. Điều này nên được khá thẳng về phía trước. Ví dụ một ::
có thể nhìn như sau:
def ::(x: A) = ListT(Monad[F].map(fa)(x :: _))
Cách sử dụng:
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))
Phiên bản 7.x không sử dụng 'Bước', có vẻ như rất đơn giản. https://github.com/scalaz/scalaz/blob/v7.0.3/core/src/main/scala/scalaz/ListT.scala – huynhjl
@huynhjl Phải, tôi chắc chắn rằng tôi đã thấy một triển khai 7 với 'Step', mặc dù . – ziggystar