Each alternatives and similar packages
Based on the "Extensions" category.
Alternatively, view Each alternatives based on common mentions on social networks and blogs.
-
Enumeratum
A type-safe, reflection-free, powerful enumeration implementation for Scala with exhaustive pattern match warnings and helpful integrations. -
Scala Graph
Graph for Scala is intended to provide basic graph functionality seamlessly fitting into the Scala Collection Library. Like the well known members of scala.collection, Graph for Scala is an in-memory graph library aiming at editing and traversing graphs, finding cycles etc. in a user-friendly way. -
scribe
The fastest logging library in the world. Built from scratch in Scala and programmatically configurable. -
Rapture
DISCONTINUED. a collection of libraries for common, everyday programming tasks (I/O, JSON, i18n, etc.) -
Lamma
Lamma schedule generator for Scala is a professional schedule generation library for periodic schedules like fixed income coupon payment, equity deravitive fixing date generation etc. -
wvlet-log
DISCONTINUED. A library for enhancing your application logs with colors and source code locations. -
Resolvable
DISCONTINUED. A library to optimize fetching immutable data structures from several endpoints in several formats.
SaaSHub - Software Alternatives and Reviews
* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of Each or a related project?
README
ThoughtWorks Each
ThoughtWorks Each is a macro library that converts native imperative syntax to Scalaz's monadic expression. See the object cats in Dsl.scala for the similar feature for Cats.
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# 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
}
assert(plusOne(None) == None)
assert(plusOne(Some(15)) == Some(16))
import com.thoughtworks.each.Monadic._
import scalaz.std.list._
def plusOne(intSeq: List[Int]) = monadic[List] {
intSeq.each + 1
}
assert(plusOne(Nil) == Nil)
assert(plusOne(List(15)) == List(16))
assert(plusOne(List(15, -2, 9)) == List(16, -1, 10))
Usage
Step 1: Add the following line in your build.sbt
libraryDependencies += "com.thoughtworks.each" %% "each" % "latest.release"
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
or %%%
for Scala.js projects:
libraryDependencies += "com.thoughtworks.each" %%% "each" % "latest.release"
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
Note that ThoughtWorks Each requires Scalaz 7.2.x and does not compatible with Scala 7.1.x .
See https://repo1.maven.org/maven2/com/thoughtworks/each/ for a list of available versions.
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, so you just import it.
import com.thoughtworks.each.Monadic._
import scalaz.std.option._
Please import other monad instances if you need other monads.
Step 4: Use monadic[F]
to create a monadic expression
import com.thoughtworks.each.Monadic._
import scalaz.std.option._
val result: 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 result: Option[String] = monadic[Option] {
"Hello, " + name.each + "!"
}
Exception handling
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.
for
loop
Each supports .each
magic in a for
loop on 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)
@monadic[Option] val result = {
var count = 1
for (i <- List(300, 20)) {
count += i * n.each
}
count
}
Assert.assertEquals(Some(3201), result)
Note that you need to use @monadic[Option]
annotation instead of monadic[Option]
block to in order to enable the for
loop syntax.
for
comprehension
Each also supports .each
magic in a for
comprehension on any instances that support Traverse
and MonadPlus
type class.
import com.thoughtworks.each.Monadic._
import scalaz.std.list._
val n = Some(4000)
@monadic[Option] val result = {
for {
i <- List(300, 20)
(j, k) <- List(50000 -> "1111", 600000 -> "yyy")
if i > n.each - 3900
a = i + j
} yield {
a + n.each * k.length
}
}
Assert.assertEquals(Some(List(66300, 612300)), result)
Note that you need to use @monadic[Option]
annotation instead of monadic[Option]
block to in order to enable the for
comprehension syntax.
Limitation
If a call-by-name parameter of a method call is a monadic expression, Each
will transform the monadic expression before the method call. The behavior was discussed at #37.
def innerFailureFuture = Future.failed(new Exception("foo"))
val someValue = Some("value")
val result = monadic[Future] {
someValue.getOrElse(innerFailureFuture.each)
}
result
will be a future of failure because the above example equals to
def innerFailureFuture = Future.failed(new Exception("foo"))
val someValue = Some("value")
val result = innerFailureFuture.map(someValue.getOrElse)
innerFailureFuture.each
is evaluated before being passed to getOrElse
method call, even if getOrElse
accepts a call-by-name parameter.
Links
- The API Documentation
- Utilities