Overview
The Monad trait, instances for List, Option, and Result, and do-notation.
(import (std prelude))
(import (std monad))
(: calc (-> int (Option int)))
(defun (calc n)
(do (:bind half (safe-div n 2))
(:let doubled (* half 2))
(:bind third (safe-div doubled 3))
(:return (+ doubled third))))
A monad is a type constructor that supports two core operations:
pure lifts a regular value into the monad, and bind sequences
computations by passing an inner value to a function returning the next monad.
The (do ...) macro provides convenient sequential step syntax over
chained bind calls.
Standard instances.
List:bindapplies the function to each element and concatenates the resulting lists in order.Option:bindshort-circuits onNone. The block returnsNoneif any step evaluates toNone.Result:bindshort-circuits onErr. The block returns the firstErrwithout executing subsequent steps.
The return type of the block determines which instance is used.
Reference
Types
Monad
trait ↑ Types
Trait for sequencing monadic computations via pure and bind.
Requires implementing pure and bind for a type constructor
(such as List or Option), enabling (do ...) syntax for
that type.
Functions
pure
function ↑ Functions
(: pure (-> %a (%m %a)))
Lifts a value into a monadic context.
x- The value to wrap.
- returns
- A monad wrapping x: (Cons x Nil), (Some x), or (Ok x).
bind
function ↑ Functions
(: bind (-> (%m %a) (-?-> %a (%m %b)) (%m %b)))
Sequences monadic computations by applying a function to the contained value.
m- The monadic value.
k- Continuation function taking an inner value and returning a monad. May be a fun or bjoroutine.
- returns
- The resulting monad from k. For List, concatenates all results in order. For None or Err, returns m unchanged without calling k.
(bind (Some 2) (fun (x) (Some (* x 10)))) ; (Some 20)
(bind (list 1 2) (fun (x) (list x x))) ; (1 1 2 2)
Macros
do
macro ↑ Macros
(do step ...)
Sequences monadic operations using step-based do-notation.
step ...-
A step, one of:
(:bind name expr): bindsnameto the unwrapped value of monadexpr.namemust be an identifier.(:match pattern expr): like:bind, but destructures the unwrapped value againstpattern. Mismatches raise an exception.(:let name expr): bindsnamedirectly toexprwithout monadic unwrapping.(:then expr): evaluates the monadexprfor side effects and discards its inner value.(:return expr): valid in final step position only. Returns(pure expr).Any other expression: evaluated for side effects without unwrapping. In the final position, it determines the block's return value and must evaluate to a monad.
;; All sums of pairs from two lists.
(do (:bind x (list 1 2))
(:bind y (list 10 20))
(:return (+ x y))) ; (11 21 12 22)
;; Stops at the first Err.
(do (:match (Tuple w h) (parse-pair text))
(:bind width (checked w))
(:bind height (checked h))
(:return (* width height)))
The block requires at least one step. The final step defines the block’s
result: either an explicit :return or an expression returning a
monad. Binding steps (:bind, :match, :let, or
:then) cannot appear in the final position. Unrecognized keywords in
step position produce syntax errors.
The final step can be a recursive call returning a monad, allowing tail calls in monadic loops.
Steps following :bind, :match, or :then compile into
the body of a lambda passed to bind, and therefore cannot suspend.