Promise is a very fundamental abstract concept - a promise to do (deliver) something (a value) later, not right now (in the future), but the procedure (a transaction) could be completed (a delegation arranged, a worker dispatched) right now.

This is the basics of a bookkeeping - one completes a transaction and receives a document which is a promise of some value to be delivered later.

This abstraction is somehow faulty, because there is no counterpart in molecular biology, which has no concept of the future (or time, or even counting - in the Universe everything happens right now), but it is useful nevertheless.

Explicit Promises

In the most generic case a promise is just unevaluated yet expression, wrapped inside a specially type-tagged lambda.

Scheme has the delay special form which wraps an unevaluated expression (copies a corresponding part of a syntax tree).

1 ]=> (define p (delay (+ 1 1)))
;Unspecified return value

1 ]=> p
;Value: #[promise 13 (unevaluated)]

There is the force special form which "forces" a Promise

1 ]=> (force p)
;Value: 2

Once evaluated, the value is memoized (cached) so it will will be always 2, no matter how many times you force it.

1 ]=> p
;Value: #[promise 13 (evaluated) 2]

1 ]=> (force p)
;Value: 2

This is the most general form of a Promise - every expression could be delayed (wrapped into a Promise), as long as it is a pure function (Same input - same output. Always.) and therefore the value it returns could be memoized (it will be semantically correct, no matter memoized or not).

There is a problem, however, with the side-effecting expressions. If it is a blocking call to a primitive procedure which does IO, force will block for the first time, but what if we force it one more time - should a memoized value be returned or a the same IO request issued again?

What if we wish to read a next chunk of data from a handle?


When we have a concept of Future, which means not now, we have an artificial problem (which Nature does not have) - what to do until that future is arrived? The natural answer is - nothing - wait, sleep, block, or do something else.

Every reasonable person would choose to continue to do something else, instead of sitting and waiting for a value to be delivered. In order to continue on has to get something instead of nothing to stop the waiting. That something is traditionally called a thunk - something "concrete to hold onto" which stands for a promise for a value.

Thunks are mere closures (All you need is Lambda!) with an unevaluated expression inside. Once called the expression is evaluated and the resulting value is returned (substituted for the thunk). The next time the same thunk is to be called a cached value is returned instead of re-evaluation of an expression.


Future is a kind of a Thunk. It is a promise to deliver a value when it would be ready (available). An attempt to evaluate a Future before the value is ready would block, because there is still nothing to deliver. A deliveryman is waiting.

Since a future is either deliver its promise or fail it is an Algebraic Data Type - an Either-Of Type - an Option Type.

Futures are composable.

Future blocks when called, because nothing could NOT be substituted for a value.


Future could be viewed as a container, a first-class type-tagged entity, which could be a member of other aggregates (ordered collections).

Implicit ordering

Since a future blocks until completion or a failure, aggregates (ordered sequences of futures) are implicitly evaluated in order (a sequence implies ordering).


Future could be viewed as a collection (of zero or one element) so it could be for-each-ed, mapped over, reduced or even filtered.


Sequences of futures (thunks) could be composed into a pipeline by folding with a combinator. Or flatMapped (map + flatten).


To enforce an order of evaluation in a lazy language a Monad ADT could be implemented (as a behavior or a trait).


Last modified 2 years ago Last modified on Nov 14, 2018, 9:20:29 AM
Note: See TracWiki for help on using the wiki.