Delayed computations

An expression can appeardelayedasdo eor 'e,which are both the same as_ -> eand() -> e.Ifehas typeT,thendo eand 'eboth have the typeforall a. a -> T.

Ifcis a delayed computation, it can beforcedwith!c,which is the same asc ().The expressioncmust conform to a type() -> tfor some typet,in which case!chas typet.

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

program : '{IO, Exception} ()
program = do
  use Text ++
  printLine "What is your name?"
  name = !readLine
  printLine ("Hello, " ++ name)

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 theIOandExceptionabilities must be provided by a handler, seeabilities and ability handlers.Instead,programhas the typeprogram : '{IO, Exception} ()(note the'indicating a delayed computation). Inside a handler forIO,this computation can be forced with!program.

Inside the program,!readLinehas to be forced, as the type ofreadLineisreadLine : '{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 xis the same as(_ -> f) xand!x + yis the same as(x ()) + y.

These symbols bind less tightly than keywords that introduce blocks, sodo xand'let xare both the same as_ -> let xand!if b then p else qis the same as(if b then p else q) ().

Additional'and!combine in the following way:

  • do 'syntacticPrecedence.xis the same as(_ -> (_ -> x))or(_ _ -> x).
  • !!xis the same asx () ().
  • !'xand'!xare both the same asx.

You can use parentheses to precisely control how'and!get applied.