Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I'm trying to make sure I understand how to write clean and robust idiomatic Scala, so I wrote a custom generic implementation sequence of type A[B[C]] => B[A[C]] (instead of TraversableOnce[Future[A]] => Future[TraversableOnce[A]] -- I know something like this exists in scalaz).

Is the following code a reasonable and idiomatic way of writing sequence? Are there existing traits in the core Scala library that would be easy to substitute for Liftable, Monoid, and Traversable that would keep this implementation of sequence relatively intact? What are the most significant improvements that can be made to this code?

import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import java.util.concurrent.Executors
import scala.util.Success
import scala.util.Failure

object TestMain {

  implicit val ec = ExecutionContext
    .fromExecutorService(Executors.newSingleThreadExecutor)

  trait Liftable[A[_], B[_]] {
    def lift[C](bc: B[C]): B[A[C]]
  }

  trait Monoid[A] {
    def mappend(a1: A, a2: A): A
    def mzero: A
  }

  trait Traversable[T[_]] {
    def head[A](t: T[A]): Option[A]
    def next[A](t: T[A]): T[A]
  }

  implicit val listOfFutureLiftable = new Liftable[List, Future] {
    def lift[C](fc: Future[C]) = fc.map(c => List(c))
  }

  implicit def listMonoid[A] = new Monoid[List[A]] {
    def mappend(a1: List[A], a2: List[A]) = a1 ++ a2
    def mzero = Nil
  }

  implicit def futureMonoid[A: Monoid] = new Monoid[Future[A]] {
    def mappend(a1: Future[A], a2: Future[A]) = {
      for {
        v1 <- a1
        v2 <- a2
      } yield implicitly[Monoid[A]].mappend(v1, v2)
    }
    def mzero = Future.successful(implicitly[Monoid[A]].mzero)
  }

  implicit val listTraversable = new Traversable[List] {
    def head[A](l: List[A]) = l match {
      case Nil => None
      case x :: _ => Some(x)
    }

    def next[A](l: List[A]) = l.tail
  }

  def sequence[A[_], B[_], C](lf: A[B[C]])(
    implicit ta: Traversable[A],
    lab: Liftable[A, B],
    mb: Monoid[B[A[C]]]): B[A[C]] = {
    val obc: Option[B[C]] = ta.head(lf)
    obc match {
      case Some(bc) => {
        val first: B[A[C]] = lab.lift(bc)
        val tail: A[B[C]] = ta.next(lf)
        val rest: B[A[C]] = sequence(tail)
        mb.mappend(first, rest)
      }
      case None => mb.mzero
    }
  }

  def main(args: Array[String]) {
    val lfi: List[Future[Int]] = List(Future(1), Future(2))
    val fli: Future[List[Int]] = sequence(lfi)
    fli andThen {
      case Success(li) => println(li)
      case Failure(e) => println("fail: " + e)
    } andThen {
      case _ => ec.shutdown
    }
  }
}
share|improve this question
    
Core Scala lacks the abstractions you are looking for (it contains only function types in this regard). –  Gábor Bakos Jan 4 at 20:24

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.