Each is a macro library that converts native imperative syntax to scalaz's monadic expression.
There is a macro library Stateless Future that provides await for asynchronous programming.
await is a mechanism that transform synchronous-like code into asynchronous expressions. C# 5.0, ECMAScript 7 and Python 3.5 also support the mechanism.
The await mechanism in Stateless Future is implemented by an algorithm called CPS transform. When learning scalaz, we found that the same algorithm could be applied for any monadic expression, including Option monad, IO monad, and Future monad. So we started this project, Each.
Each is a superset of await syntax. Each supports multiple types of monads, while await only works with Future. When we perform a CPS transform for monadic expression with the Future monad, the use case looks almost the same as the await syntax in Stateless Future. Each is like F#'s Computation Expressions, except Each reuses the normal Scala syntax instead of reinventing new syntax.
For example:
import com.thoughtworks.each.Monadic._
import scalaz.std.scalaFuture._
// Returns a Future of the sum of the length of each string in each parameter Future,
// without blocking any thread.
def concat(future1: Future[String], future2: Future[String]): Future[Int] = monadic[Future] {
future1.each.length + future2.each.length
}The similar code works for monads other than Future:
import com.thoughtworks.each.Monadic._
import scalaz.std.option._
def plusOne(intOption: Option[Int]) = monadic[Option] {
intOption.each + 1
}
assertEquals(None, plusOne(None))
assertEquals(Some(16), plusOne(Some(15)))import com.thoughtworks.each.Monadic._
import scalaz.std.list._
def plusOne(intSeq: List[Int]) = monadic[List] {
intSeq.each + 1
}
assertEquals(Nil, plusOne(Nil))
assertEquals(List(16), plusOne(List(15)))
assertEquals(List(16, -1, 10), plusOne(List(15, -2, 9)))libraryDependencies += "com.thoughtworks.each" %% "each" % "0.4.0"import com.thoughtworks.each.Monadic._Scalaz has provided Option monad, so you just import it.
import com.thoughtworks.each.Monadic._
import scalaz.std.option._Please import other monad instances if you need other monads.
import com.thoughtworks.each.Monadic._
import scalaz.std.option._
val result: Option[String] = monadic[Option] {
"Hello, Each!"
}import com.thoughtworks.each.Monadic._
import scalaz.std.option._
val name = Option("Each")
val result: Option[String] = monadic[Option] {
"Hello, " + name.each + "!"
}monadic blocks do not support try, catch and finally. If you want these expressions, use throwableMonadic or catchIoMonadic instead, for example:
var count = 0
val io = catchIoMonadic[IO] {
count += 1 // Evaluates immediately
val _ = IO(()).each // Pauses until io.unsafePerformIO()
try {
count += 1
(null: Array[Int])(0) // Throws a NullPointerException
} catch {
case e: NullPointerException => {
count += 1
100
}
} finally {
count += 1
}
}
assertEquals(1, count)
assertEquals(100, io.unsafePerformIO())
assertEquals(4, count)Note that catchIoMonadic requires an implicit parameter scalaz.effect.MonadCatchIO[F] instead of Monad[F]. scalaz.effect.MonadCatchIO[F] is only provided for scalaz.effect.IO by default.
Each supports .each magic in a for loop on MonadicLoop. You can create a MonadicLoop instance via .monadicLoop method from any instances that support Foldable type class. For example, you could import scalaz.std.list._ to enable the Foldable type class for List.
import com.thoughtworks.each.Monadic._
import scalaz.std.list._
import scalaz.std.option._
val n = Some(10)
val result = monadic[Option] {
var count = 1
for (i <- List(300, 20).monadicLoop) {
count += i * n.each
}
count
}
Assert.assertEquals(Some(3201), result)Each also supports .each magic in a for comprehension on MonadicLoop. You can create a MonadicLoop instance via .monadicLoop method from any instances that support Traverse and MonadPlus type class.
import com.thoughtworks.each.Monadic._
import scalaz.std.list._
val n = Some(4000)
val result = monadic[Option] {
(for {
i <- List(300, 20).monadicLoop
(j, k) <- List(50000 -> "1111", 600000 -> "yyy").monadicLoop
if i > n.each - 3900
a = i + j
} yield {
a + n.each * k.length
}).underlying
}
Assert.assertEquals(Some(List(66300, 612300)), result)- The API Documentation
- Utilities