An expression can appear delayed as `do e`

or ` 'e`

, which are both the same as `_ -> e`

and `() -> e`

. If `e`

has type `T`

, then `do e`

and ` 'e`

both have the type `forall a. a -> T`

.

If `c`

is a delayed computation, it can be forced with `!c`

, which is the same as `c ()`

. The expression `c`

must conform to a type `() -> t`

for some type `t`

, in which case `!c`

has type `t`

.

Delayed computations are important for writing expressions that require abilities. For example:

This example defines a small I/O program. The type `{IO, Exception} ()`

by itself is not allowed as the type of a top-level definition, since the `IO`

and `Exception`

abilities must be provided by a handler, see abilities and ability handlers. Instead, `program`

has the type `program : '{IO, Exception} ()`

(note the `'`

indicating a delayed computation). Inside a handler for `IO`

, this computation can be forced with `!program`

.

Inside the program, `!readLine`

has to be forced, as the type of `readLine`

is `readLine : '{IO, Exception} Text`

, a delayed computation which, when forced, reads a line from standard input.

## Syntactic precedence

The reserved symbols `'`

and `!`

bind more tightly than function application, So `'f x`

is the same as `(_ -> f) x`

and `!x + y`

is the same as `(x ()) + y`

.

These symbols bind less tightly than keywords that introduce blocks, so `do x`

and `'let x`

are both the same as `_ -> let x`

and `!if b then p else q`

is the same as `(if b then p else q) ()`

.

Additional `'`

and `!`

combine in the following way:

`do do syntacticPrecedence.x`

is the same as`(_ -> (_ -> x))`

or`(_ _ -> x)`

.`!!x`

is the same as`x () ()`

.`!'x`

and`'!x`

are both the same as`x`

.

You can use parentheses to precisely control how `'`

and `!`

get applied.