Преобразователь Monad для NonEmptyList?

Мне кажется, что Scalaz 'NonEmptyList имеет экземпляр монады, поэтому для него должен быть установлен монадный трансформатор (немного похожий на ListT). Это правильно?

Если да, то там есть? (Я не смог найти его в самом Scalaz 7).

Если нет, т.е. трансформатор монады для него был бы невозможен или не имел никакого смысла, я был бы благодарен за любое дополнительное объяснение, почему бы и нет.

Ответы

Ответ 1

Конечно, возможно, так как можно показать, что любая монада, имеющая экземпляр Траверса, может быть превращена в монадный трансформатор:

import scalaz._
import Scalaz._

object MonadT {
  implicit def monadTransformerFromTraverse[M[_]: Monad, N[_]: Monad: Traverse]: Monad[({type MN[A]=M[N[A]]})#MN] = new Monad[({type MN[A]=M[N[A]]})#MN] {
    def point[A](a: => A): M[N[A]] = a.point[N].point[M]
    def bind[A,B](fa: M[N[A]])(f: A=>M[N[B]]) : M[N[B]] = {
      val M = implicitly[Monad[M]]
      val NT = implicitly[Traverse[N]]
      val N = implicitly[Monad[N]]

      M.map(M.join(M.map(M.map(fa)(N.map(_)(f)))(NT.sequence(_))))(N.join)
//                       |- => M[N[M[N[B]]]]  -|
//                 |-       => M[M[N[N[B]]]]                   -|
//         |-               => M[N[N[B]]]                       -|
//    |-                    => M[N[B]]                                  -|


    }
  }

  def main(argv: Array[String]) {
    val x: Option[NonEmptyList[Int]] = Some(NonEmptyList(1))
    val f: Int => Option[NonEmptyList[Int]] = { x: Int => Some(NonEmptyList(x+1)) }

    val MT =  monadTransformerFromTraverse[Option, NonEmptyList]
    println(MT.bind(x)(f)) // Some(NonEmptyList(2))
  }
}

Это явно не самая удобная форма для работы, но показывает, что это действительно возможно. Tom Switzer в настоящее время работает над добавлением гораздо более полезного и универсального трансформатора TraverseT monad в scalaz. Вы можете увидеть его прогресс в GitHub