All Projects → ThoughtWorksInc → Each

ThoughtWorksInc / Each

Licence: apache-2.0
A macro library that converts native imperative syntax to scalaz's monadic expressions

Programming Languages

scala
5932 projects
scalaz
18 projects

Projects that are alternatives of or similar to Each

Placeholderview
This library provides advance views for lists and stacks. Some of the views are build on top of RecyclerView and others are written in their own. Annotations are compiled by annotation processor to generate bind classes. DOCS -->
Stars: ✭ 2,104 (+758.78%)
Mutual labels:  annotations
Bastet
A ReasonML/Ocaml library for category theory and abstract algebra
Stars: ✭ 200 (-18.37%)
Mutual labels:  monad
Dsl.scala
A framework to create embedded Domain-Specific Languages in Scala
Stars: ✭ 220 (-10.2%)
Mutual labels:  monad
Fluture
🦋 Fantasy Land compliant (monadic) alternative to Promises
Stars: ✭ 2,249 (+817.96%)
Mutual labels:  monad
Qmbform
Create simple Android forms
Stars: ✭ 184 (-24.9%)
Mutual labels:  annotations
React Image Annotation
An infinitely customizable image annotation library built on React
Stars: ✭ 203 (-17.14%)
Mutual labels:  annotations
Sequelize Typescript
Decorators and some other features for sequelize
Stars: ✭ 2,200 (+797.96%)
Mutual labels:  annotations
Cats Mtl
cats transformer type classes.
Stars: ✭ 238 (-2.86%)
Mutual labels:  monad
Simple Spring Memcached
A drop-in library to enable memcached caching in Spring beans via annotations
Stars: ✭ 185 (-24.49%)
Mutual labels:  annotations
Koro1fileheader
VSCode插件:自动生成,自动更新VSCode文件头部注释, 自动生成函数注释并支持提取函数参数,支持所有主流语言,文档齐全,使用简单,配置灵活方便,持续维护多年。
Stars: ✭ 3,137 (+1180.41%)
Mutual labels:  annotations
Drf Typed Views
Use type annotations to validate/deserialize request parameters in Dango REST Framework.
Stars: ✭ 181 (-26.12%)
Mutual labels:  annotations
Funcadelic.js
Functional programming and category theory for everyday JavaScript development
Stars: ✭ 183 (-25.31%)
Mutual labels:  monad
Labelimg
🖍️ LabelImg is a graphical image annotation tool and label object bounding boxes in images
Stars: ✭ 16,088 (+6466.53%)
Mutual labels:  annotations
Functional Examples
Examples with Functional JavaScript, following Professor Frisby's course
Stars: ✭ 179 (-26.94%)
Mutual labels:  monad
Monadless
Syntactic sugar for monad composition in Scala
Stars: ✭ 231 (-5.71%)
Mutual labels:  monad
Ray.di
Guice style dependency injection framework for PHP
Stars: ✭ 175 (-28.57%)
Mutual labels:  annotations
Convalida
A simple, lightweight and powerful field validation library for Android.
Stars: ✭ 201 (-17.96%)
Mutual labels:  annotations
Jsoup Annotations
Jsoup Annotations POJO
Stars: ✭ 242 (-1.22%)
Mutual labels:  annotations
React Tater
A React component to add annotations to any element on a page 🥔
Stars: ✭ 235 (-4.08%)
Mutual labels:  annotations
Awesome Data Annotation
A list of tools for annotating data, managing annotations, etc.
Stars: ✭ 204 (-16.73%)
Mutual labels:  annotations

ThoughtWorks Each

Join the chat at https://gitter.im/ThoughtWorksInc/each Build Status Latest version Codacy Badge

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

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].