2013-08-23 3 views
7

나는 모나드와 매우 흡사 한 모나드를 가지고있다. 나는 현재 그것을 위해 모나드 변환기를 구현하려고하는데, 실패하고있다.Scala에서`List` 모나드 변환기를 구현하는 방법은 무엇입니까?

ListT 구현을 Scalaz 6 및 7로 보았습니다.하지만 어떻게 작동하는지 이해할 수 없습니다. 일부 추가 유형 Step을 사용합니다. 그 목적은 나에게 불명확합니다.

따라서 누군가가 Scalaz 접근 방식을 설명하거나 다른 구현을 사용하여 목록 모나드 변환기를 구현하는 방법을 설명해 줄 수 있습니까?

+1

7.x 버전은'Step'을 사용하지 않습니다. 매우 간단합니다. https://github.com/scalaz/scalaz/blob/v7.0.3/core/src/main/scala/scalaz/ListT.scala – huynhjl

+0

@huynhjl 오른쪽으로, 나는 'Step'을 사용하여 7 가지 구현을 보았습니다. . – ziggystar

답변

17

저는 스카지가 의미하는 바는 무엇인지 모르지만, ListT을 구현하는 것은 꽤나 간단합니다. 얼마나 많은 연산을 넣고 싶은가에 따라 약간의 작업이 될 수 있지만 기본 모나드 연산은 다음과 같이 구현 될 수 있습니다.

먼저 우리는 (우리는 또한 실용적를 추가 할 수 있지만,이 예제 필요하지 않습니다) 모나드와 펑에 대한 typeclasses 필요합니다

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

} 

우리가 그이 있으면, 우리는 변압기를 만들 수있는 기본적으로 그냥 F[List[A]]을 래핑하고 mapflatMap 함수의 호출을 포함하는 함수기에서 map을 호출 한 다음 map 또는 flatMap resp를 호출하여 호출을 목록에 전달합니다. 포함 된 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 
} 

, 우리는 ListT 개체에 run 메소드를 호출하여 결과 객체를 얻을 수 있습니다. 원하는 경우 scalaz와 같은 다른 목록 관련 작업을 추가 할 수도 있습니다. 이것은 꽤 솔직해야합니다. 예를 들어으로 볼 수있는 ::은 다음과 같습니다

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

사용법 :

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