2013-08-23 51 views
7

Tôi có một đơn vị rất giống với một bộ sưu tập. Tôi hiện đang cố gắng để thực hiện một biến áp monad cho nó, nhưng tôi thất bại.Làm cách nào để triển khai biến áp đơn lẻ `List` trong Scala?

Tôi đã xem triển khai ListTScalaz 6 và 7, nhưng tôi không thể hiểu cách hoạt động. Nó sử dụng một số loại bổ sung Step, có mục đích không rõ ràng với tôi.

Vì vậy, ai đó có thể vui lòng giải thích cho tôi cách thực hiện biến danh sách đơn lẻ, bằng cách giải thích cách tiếp cận Scalaz hoặc sử dụng triển khai khác?

+1

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

+0

@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

Trả lời

17

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 mapflatMap 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))