• Stars
    star
    253
  • Rank 160,776 (Top 4 %)
  • Language
    Scala
  • License
    Apache License 2.0
  • Created over 9 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

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

ThoughtWorks Each

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

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

More Repositories

1

Binding.scala

Reactive data-binding for Scala
Scala
1,579
star
2

DeepLearning.scala

A simple library for creating complex neural networks
Scala
766
star
3

DeepDarkFantasy

A Programming Language for Deep Learning
Haskell
465
star
4

cd4ml-workshop

Repository with sample code and instructions for "Continuous Intelligence" and "Continuous Delivery for Machine Learning: CD4ML" workshops
Jupyter Notebook
316
star
5

Dsl.scala

A framework to create embedded Domain-Specific Languages in Scala
Scala
255
star
6

guia-de-desenvolvimento-tecnico

JavaScript
206
star
7

Compute.scala

Scientific computing with N-dimensional arrays
Scala
199
star
8

CD4ML-Scenarios

Repository with sample code and instructions for "Continuous Intelligence" and "Continuous Delivery for Machine Learning: CD4ML" workshops
Python
138
star
9

microbuilder

A toolset that helps you build system across multiple micro-services and multiple languages.
HTML
93
star
10

sbt-api-mappings

An Sbt plugin that fills apiMappings for common Scala libraries.
Scala
88
star
11

enableIf.scala

A library that toggles Scala code at compile-time, like #if in C/C++
Scala
65
star
12

todo

Binding.scala β€’ TodoMVC
Scala
60
star
13

sinais

πŸ”£ Desenvolvimento passo a passo do exemplo `sinais` em Go.
Go
59
star
14

sbt-best-practice

Configure common build settings for a Scala project
Scala
56
star
15

TWU101-TDDIntro

Java
46
star
16

template.scala

C++ Flavored Template Metaprogramming in Scala
Scala
40
star
17

future.scala

Stack-safe asynchronous programming
Scala
39
star
18

ml-app-template

An ML project template with sensible defaults
Python
37
star
19

sbt-scala-js-map

A Sbt plugin that configures source mapping for Scala.js projects hosted on Github
Scala
36
star
20

aws_role_credentials

Generates AWS credentials for roles using STS
Python
34
star
21

transervicos

Ruby
33
star
22

RAII.scala

Resource Acquisition Is Initialization
Scala
32
star
23

sbt-example

Run Scaladoc as unit tests
Scala
31
star
24

feature.scala

Access Scala language features on the type-level
Scala
31
star
25

sbt-ammonite-classpath

Export the classpath for Ammonite and Almond
Scala
27
star
26

Import.scala

A Scala compiler plugin for magic imports
Scala
26
star
27

JS-Monthly-Chengdu

CSS
23
star
28

infra-problem

resources for the infrastructure as code practical assessment
Clojure
23
star
29

bindable.scala

User-friendly Binding.scala components
Scala
23
star
30

implicit-dependent-type

Scala
22
star
31

Extractor.scala

Make PartialFunction and extractors composable
Scala
22
star
32

ml-cd-starter-kit

Set up cross-cutting services (e.g. CI server, monitoring) for ML projects using kubernetes and helm
Smarty
22
star
33

objective8

For the most up to date version of this project, see https://github.com/d-cent/objective8
Clojure
21
star
34

oktaauth

Module and CLI client to handle Okta authentication
Python
20
star
35

js-test-project

JavaScript
18
star
36

tryt.scala

Monad transformers for exception handling
Scala
18
star
37

lein-s3-static-deploy

Lein task to deploy static website to s3 bucket.
Clojure
17
star
38

DesignPattern.scala

Functional Programming Design Patterns
Scala
17
star
39

daffy

Function decorators for Pandas Dataframe column name and data type validation
Python
15
star
40

TWTraining

Open source ThoughtWorks training materials
HTML
15
star
41

dsl-domains-cats

Scala
12
star
42

Q.scala

Convert any value to code
Scala
12
star
43

ZeroCost.scala

Zero-cost Abstractions in Scala
Scala
10
star
44

Constructor.scala

Mixin classes and traits dynamically
Scala
10
star
45

dataclouds

Blog for dataclouds@thoughtworks.
CSS
10
star
46

tf-image-interpreter

Object detection and text spotting from images of any size. Based on TensorFlow.
Python
10
star
47

WorkingEffectivelyWithLegacyCode

Java
10
star
48

Binding.scala-website

Scala
9
star
49

voter-service

The Voter Spring Boot RESTful Web Service, backed by MongoDB, is used for DevOps-related training and testing.
Java
9
star
50

OpenStack-EC2-Driver

OpenStack-EC2-Driver
9
star
51

stonecutter

[Main repo found at https://github.com/d-cent/stonecutter] A D-CENT project: an easily deployable oauth server for small organisations.
Clojure
9
star
52

streaming-data-pipeline

Streaming pipeline repo for data engineering training program
Scala
9
star
53

JavaBootcamp

Java
8
star
54

java-test-project

Java
7
star
55

infra-code-workshop

TechRadar Academy em PoA - Cloud
7
star
56

twseleniumworkshop

Workshop Selenium Belo Horizonte - Setembro 2014
Java
7
star
57

DeepLearning.scala-website

The website of DeepLearning.scala
CSS
7
star
58

AS101-4-workshop

Python
7
star
59

skadoosh

Here we have the building blocks of a virtual entity in the making (in crude words, a chat bot - but don't call it that. It gets offended).
Python
7
star
60

json-stream-core

Universal Serialization Framework for JSON
Haxe
6
star
61

ScaleWorks_YUMChina

Ruby
6
star
62

microbuilder-core

Haxe
6
star
63

clj-http-s3

Middleware to allow cli-http to authenticate with s3
Clojure
6
star
64

lein-filegen

A leiningen plugin to generate files
Clojure
6
star
65

expend-rs

Internal application to submit certain expenses to ThoughtWorks' system
Rust
6
star
66

LatestEvent.scala

bidirectional data-binding and routing for Scala.js
Scala
6
star
67

sbt-jdeps

an sbt plugin to run JDeps
Scala
5
star
68

modularizer

Scala
5
star
69

twu-toolkit

Calendar generator for TWU
Ruby
5
star
70

twcss

CSS Coding Guidelines
5
star
71

loans-lah-tdd-workshop

JavaScript
5
star
72

Binding.scala-play-template

Scala
5
star
73

TypeOf.scala

Create types from expressions
Scala
4
star
74

SG-ObjectBootcamp

Java
4
star
75

sbt-delombok

an sbt plug-in to delombok Java sources files that contain Lombok annotations
Scala
4
star
76

zeratul

a wrapper for JPA
Java
4
star
77

CSharpTestProject

C#
4
star
78

HashRoute.scala

Scala
4
star
79

Tensor.scala

A totally functional DSL for general purpose GPU programming
4
star
80

akka-http-rpc

Turn akka-http to a RPC server
Scala
4
star
81

monadic-deep-learning

TeX
4
star
82

wxapp-workshop

3
star
83

sde

Scala
3
star
84

clojuregoat

A goat, in Clojure
Clojure
3
star
85

go-maven-poller

Go plugin that polls Maven (Nexus) repositories
3
star
86

sonic

React UI Components
JavaScript
3
star
87

mooncake

A D-CENT project: Secure notifications combined with w3 activity streams
Clojure
3
star
88

Binding.scala-activator-template

Scala
3
star
89

offnet

The Unified Neural Network
Jupyter Notebook
3
star
90

akka-http-webjars

Serve static assets from WebJars
Scala
3
star
91

scala-project-template

3
star
92

aem-training-2016

Code repo for AEM training in August 2016.
Java
3
star
93

helsinki

[Main repo found at https://github.com/d-cent/decisionsproto] Spike for indexing data from the Open Ahjo API in elasticsearch
Python
3
star
94

hackerbrasileiro

Java
3
star
95

FallbackLookupStrategy.java

Java
2
star
96

cep-conference

Core Engineering Practices "Conference" exercise
Java
2
star
97

Cifar10.scala

Scala
2
star
98

infra-code-devopslabs01

TechRadar Academy - Cloud Workshop - IaC
Python
2
star
99

Kaleidoscopez

JavaScript
2
star
100

android-test-project

Kotlin
2
star