Anaphoric macros
1 Overview
2 The anaphoric conditionals aif, awhen and acond
it
aif
awhen
acond
aand
3 The hygienic versions if-let, when-let and cond-let
if-let
when-let
cond-let
and-let
4 Anaphoric map and filter
amap
afilter
8.12

Anaphoric macros🔗ℹ

Suzanne Soy <racket@suzanne.soy>

 (require anaphoric) package: anaphoric

1 Overview🔗ℹ

This package provides anaphoric versions of if, when, cond, map, and filter. These bind the syntax parameter it to the value produced by the condition expression.

(aif (member 'a lst)
  (displayln it)
  (displayln "not found"))
(awhen (member 'a lst)
  (displayln it))
(acond
  [(member 'a lst) (displayln it)]
  [(member 'b lst) (displayln it)]
  [else (displayln "not found")])

In the else clause of acond and in the else branch of aif, the it syntax parameter keeps its value. This means it keeps the value bound by the surrounding conditional, if any. Otherwise it acts exactly as when it is used at the top-level, and raises a syntax error.

(aif 'first
  (aif (eq? 'second 'no)
    'not-executed
    (displayln it))
  'not-executed)

In the example above, (displayln it) prints 'first. In the example below, (displayln it) raises a syntax error, as it appears in a sequence of else branches:

(aif (eq? 'first 'no)
  'not-executed
  (aif (eq? 'second 'no)
    'not-executed
    (displayln it)))

This package also provides the hygienic versions if-let, when-let and cond-let, for which the user needs to specify an identifier instead of using it.

2 The anaphoric conditionals aif, awhen and acond🔗ℹ

syntax

it

Syntax parameter which acts as a rename transformer for the result of the condition expression, when bound by aif, awhen or acond.

Raises a syntax error when used outside of the true-branch of an aif or the body of an awhen or the body of a non-else case in acond.

syntax

(aif condition true-branch false-branch)

Variant of if which binds it to the value of condition in true-branch. condition is only evaluated once. In the false-branch, it is left unchanged.

syntax

(awhen condition body ...+)

Variant of when which binds it to the value of condition in body ...+. condition is only evaluated once.

syntax

(acond [conditionᵢ bodyᵢ ...+] ...)

(acond [conditionᵢ bodyᵢ ...+] ... [else body ...+])
Variant of cond which binds it to the corresponding conditionᵢ in the non-else cases. More precisely, in each bodyᵢ ...+, it is bound to the value of the corresponding conditionᵢ. Each conditionᵢ is evaluated at most once (evaluation stops at the first successful conditionᵢ).

syntax

(aand)

(aand conditionᵢ ... body)
Variant of and which binds it to the value of each conditionᵢ, in scope within the next conditionᵢ or body. More precisely, the value of each conditionᵢ can be referred to as it in the following conditionᵢ₊₁, and the value of the last conditionᵢ can be referred to as it in the body. If there are no conditionᵢ, i.e. when writing, (aand body), then it retains its original binding (which means that it could be unbound, e.g. if no other anaphoric form wraps this one).

Each condition is evaluated at most once, and evaluation stops at the first false condition. The body is only evaluated when every conditionᵢ is successful.

3 The hygienic versions if-let, when-let and cond-let🔗ℹ

syntax

(if-let [identifier condition] true-branch false-branch)

Variant of if which binds identifier to the value of condition in true-branch. condition is only evaluated once. In the false-branch, identifier is left unchanged.

syntax

(when-let [identifier condition] body ...+)

Variant of when which binds identifier to the value of condition in body ...+. condition is only evaluated once.

syntax

(cond-let [[identifierᵢ conditionᵢ] bodyᵢ ...+] ...)

(cond-let [[identifierᵢ conditionᵢ] bodyᵢ ...+] ... [else body ...+])
(cond-let identifier [conditionᵢ bodyᵢ ...+] ...)
(cond-let identifier [conditionᵢ bodyᵢ ...+] ... [else body ...+])
Variant of cond which binds each identifierᵢ to the corresponding conditionᵢ in the non-else cases. More precisely, in each bodyᵢ ...+, the corresponding identifierᵢ is bound to the value of the corresponding conditionᵢ.

The last two variants are shorthands for using the same identifier in all cases (except the else case).

Each conditionᵢ is evaluated at most once (evaluation stops at the first successful conditionᵢ).

syntax

(and-let)

(and-let [identifier conditionᵢ] ... body)
Variant of and which binds each identifier to the value of its conditionᵢ, in scope within every conditionᵢ afterwards as well as in body.

Each conditionᵢ is evaluated at most once, and evaluation stops at the first false condition. The body is only evaluated when every conditionᵢ is successful.

4 Anaphoric map and filter🔗ℹ

syntax

(amap body lst)

Anaphoric map. Binds the syntax parameter it in the body, and maps it over the list lst. Effectively the same as wrapping the body in a lambda with an it parameter. Unlike map, amap only works on a single list.

amap works with nested function calls:

(amap (string-append (string-upcase it) "!")
      '("apple" "banana"))

The syntax parameter it may be used multiple times in the procedure:

(amap (* it it) '(1 2 3))

syntax

(afilter body lst)

Anaphoric filter. Binds the syntax parameter it in the body, and filters the list lst using it. Effectively the same as wrapping the body in a lambda with an it parameter.

afilter works with nested function calls:

(afilter ((* it it) . > . 50) lst)