# Expressions

by Jean-Rémi Desjardins

# History

See my talk at PNWScala

# Bind cannot "fail-fast"

``````trait Monad[F[_]] {
def bind[A,B](fa: F[A])(f : a => F[B]): F[B]
}``````

Expressions are an alternative to for-comprehensions that support failing fast among a few other things

# Examples

## Fails fast

``````val a: Future[A]
val b: Future[B]
val c: Future[C]``````

## Fails fast

``````for {aa <- a
bb <- b
cc <- c} yield combine(a, b, c)``````
``````val a: Future[A]
val b: Future[B]
val c: Future[C]``````

## Fails fast

``````for {aa <- a
bb <- b
cc <- c} yield combine(a, b, c)``````
``Expression { combine(a,b,c) }``
``````val a: Future[A]
val b: Future[B]
val c: Future[C]``````

## Plays well with if and match

``````val a: Future[A]
val b: Future[B]
val c: Future[C]``````

## Plays well with if and match

``````for {aa <- a
bb <- b
cc <- c} yield if (aa == something) polish(bb) else polish(cc)``````
``````val a: Future[A]
val b: Future[B]
val c: Future[C]``````

## Plays well with if and match

``````for {aa <- a
bb <- b
cc <- c} yield if (aa == something) polish(bb) else polish(cc)``````
`````` (for (aa <- a) yield
if (aa == something) for (bb <- b) yield polish(bb)
else for (cc <- c) yield polish(cc)).flatMap(identity)``````
``````val a: Future[A]
val b: Future[B]
val c: Future[C]``````

## Plays well with if and match

``````for {aa <- a
bb <- b
cc <- c} yield if (aa == something) polish(bb) else polish(cc)``````
`````` (for (aa <- a) yield
if (aa == something) for (bb <- b) yield polish(bb)
else for (cc <- c) yield polish(cc)).flatMap(identity)``````
``````val a: Future[A]
val b: Future[B]
val c: Future[C]``````
``Expression { if(extract(a) == something) polish(b) else polish(c) }``

# Not a replacement for for-comprehensions

``````def time[A](task: Task[A]): Task[(Duration, A)] = for {
} yield ((t2 - t1).milliseconds, a)``````

# When to use them

## Write Async code

``````val response: Future[HTML] = Expression {
val phone = extract(lookupPhone(phoneString))
val rep = extract(lookupReputation(phone))
}``````

# But what about a single unified notation

• That supports:

• Applicative Functor

• Functor

• conceivably others

Wouldn't that be nice Professor? One single elegant equation to explain everything?

# Not only does that reduce cognitive overload, but it is more powerful

• Monad cannot support fail-fast for Futures
• The more expressive an abstraction, the less flexible it is in it's implementation
• Our notation should use the least powerful abstraction that is required
• This allows maximum flexibility to implement behavior of combinators

# Why Monad cannot fail fast

``````trait Monad[F[_]] {
def bind[A,B](m: F[T], f: A => F[B]): F[B]
}``````

# What does it look like

``````val phoneString: String = ???
val lookupPhone: String => Future[Phone] = ???
val lookupReputation: Phone => Future[Score] = ???
val renderPage: (Phone, Address, Int) => HTML = ???

val response: Future[HTML] = Expr {
val phone = lookupPhone(phoneString)
val rep = lookupReputation(phone)
}``````

## Uses Scala implicit resolution to mirror Idris behavior but can be made explicit

``````import com.github.jedeash.Expr
import com.github.jedesah.Expr.extract

val phoneString: String = ???
val lookupPhone: String => Future[Phone] = ???
val lookupReputation: Phone => Future[Score] = ???
val renderPage: (Phone, Address, Int) => HTML = ???

val response: Future[HTML] = Expr {
val phone = extract(lookupPhone(phoneString))
val rep = lookupReputation(phone)
}``````

Explicit

Implicit

``````import com.github.jedeash.Expr
import com.github.jedesah.Expr.auto.extract

val phoneString: String = ???
val lookupPhone: String => Future[Phone] = ???
val lookupReputation: Phone => Future[Score] = ???
val renderPage: (Phone, Address, Int) => HTML = ???

val response: Future[HTML] = Expr {
val phone = lookupPhone(phoneString)
val rep = lookupReputation(phone)
}``````

# Prior Art

• Effectful*

• ​Replacement for for-comprehension

• Generalizes Async/Await

• Scala Workflow*

• Supports everything I do and more

• Uses untyped macros

• Reimplements parts of scalac including scoping which leads to minimal coverage of the language

*https://github.com/pelotom/effectful

*https://github.com/aztek/scala-workflow/

## Scala Computation Expressions

• https://github.com/jedesah/computation-expressions
• Releasing 0.1.0 today (version and date may change)

## Thought: Towards automatic code parallelization

• One of the promises of purely functional programming
• Tried by Facebook with FXL
• Computation Expressions do a lot to bring us there