8000 GitHub - CJavaScala/each at cb7b13c01ce10eff8d9e91b98879070d0ca89a69
[go: up one dir, main page]

Skip to content

CJavaScala/each

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Each

Build Status

Each is a macro library that converts native imperative syntax to scalaz's monadic expression.

Motivation

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# 4.5, 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 with 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 other monads 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)))
8000

Usage

Step 1: And add the following line in your build.sbt

libraryDependencies += "com.thoughtworks.each" %% "each" % "0.2.0"

Step 2: In your source file, import monadic and each method

import com.thoughtworks.each.Monadic._

Step 3: Import implicit Monad instances

Scalaz has provided Option monad, you just import it.

import com.thoughtworks.each.Monadic._
import scalaz.std.option._

Please import other monad instances if you need other monad.

Step 4: Use monadic[F] to create a monadic expression

import com.thoughtworks.each.Monadic._
import scalaz.std.option._
val Option[String] = monadic[Option] {
  "Hello, Each!"
}

Step 5: In the monadic block, use .each postfix to extract each element in a F

import com.thoughtworks.each.Monadic._
import scalaz.std.option._
val name = Option("Each")
val Option[String] = monadic[Option] {
  "Hello, " + name.each + "!"
}

Limitation

monadic blocks do not support try, catch and finally. If you want these expressions, use catchIoMonaic instead, for example:

var count = 0
val io = catchIoMonadic[IO] {
  val _ = IO(()).each
  try {
    count += 1
    (null: Array[Int])(0) // Will throw a NullPointerException
  } catch {
    case e: NullPointerException => {
      count += 1
      100
    }
  } finally {
    count += 1
  }
}
assertEquals(0, count)
assertEquals(100, io.unsafePerformIO())
assertEquals(3, count)

Note that catchIoMonaic requires an implicit parameter scalaz.effect.MonadCatchIO[F], which is only provided for scalaz.effect.IO by default.

Links

About

A macro library that converts native imperative syntax to scalaz's monadic expressions

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Scala 100.0%
0