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
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.2.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 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.
- The API Documentation
- Utilities