kzccm1d4if10m2xaz1wqy3xar821pp1r-my-site-anaphoric-git.test.suzanne.soy-0.0.1

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

anaphoric.scrbl (7130B)


      1 #lang scribble/manual
      2 @require[@for-label[anaphoric
      3                     racket/base]]
      4 
      5 @title{Anaphoric macros}
      6 @author[@author+email["Suzanne Soy" "racket@suzanne.soy"]]
      7 
      8 @defmodule[anaphoric]
      9 
     10 @section{Overview}
     11 
     12 This package provides anaphoric versions of @racket[if], 
     13 @racket[when], @racket[cond], @racket[map], and @racket[filter]. These bind the syntax
     14 parameter @racket[it] to the value produced by the
     15 condition expression. 
     16 
     17 @racketblock[(aif (member 'a lst)
     18                (displayln it)
     19                (displayln "not found"))]
     20 
     21 @racketblock[(awhen (member 'a lst)
     22                (displayln it))]
     23 
     24 @racketblock[(acond
     25                [(member 'a lst) (displayln it)]
     26                [(member 'b lst) (displayln it)]
     27                [else (displayln "not found")])]
     28 
     29 In the @racket[else] clause of @racket[acond] and in the
     30 else branch of @racket[aif], the @racket[it] syntax
     31 parameter keeps its value. This means it keeps the value
     32 bound by the surrounding conditional, if any. Otherwise it
     33 acts exactly as when it is used at the top-level, and raises
     34 a syntax error.
     35 
     36 @racketblock[(aif 'first
     37                (aif (eq? 'second 'no)
     38                  'not-executed
     39                  (displayln it))
     40                'not-executed)]
     41 
     42 In the example above, @racket[(displayln it)] prints 
     43 @racket['first]. In the example below, 
     44 @racket[(displayln it)] raises a syntax error, as it appears
     45 in a sequence of else branches:
     46 
     47 @racketblock[(aif (eq? 'first 'no)
     48                'not-executed
     49                (aif (eq? 'second 'no)
     50                  'not-executed
     51                  (displayln it)))]
     52 
     53 This package also provides the hygienic versions 
     54 @racket[if-let], @racket[when-let] and @racket[cond-let],
     55 for which the user needs to specify an identifier instead of
     56 using @racket[it].
     57 
     58 @section{The anaphoric conditionals @racket[aif], 
     59  @racket[awhen] and @racket[acond]}
     60 
     61 @defidform[it]{
     62  Syntax parameter which acts as a rename transformer for
     63  the result of the condition expression, when bound by 
     64  @racket[aif], @racket[awhen] or @racket[acond].
     65 
     66  Raises a syntax error when used outside of the 
     67  @racket[_true-branch] of an @racket[aif] or the body of an
     68  @racket[awhen] or the body of a non-@racket[else] case in 
     69  @racket[acond].}
     70 
     71 @defform[(aif condition true-branch false-branch)]{
     72  Variant of @racket[if] which binds @racket[it] to the
     73  value of @racket[condition] in @racket[true-branch]. 
     74  @racket[condition] is only evaluated once. In the 
     75  @racket[false-branch], @racket[it] is left unchanged.}
     76 
     77 @defform[(awhen condition body ...+)]{
     78  Variant of @racket[when] which binds @racket[it] to the
     79  value of @racket[condition] in @racket[body ...+]. 
     80  @racket[condition] is only evaluated once.}
     81 
     82 @defform*[#:literals (else)
     83           [(acond [conditionᵢ bodyᵢ ...+] ...)
     84            (acond [conditionᵢ bodyᵢ ...+] ... [else body ...+])]]{
     85  Variant of @racket[cond] which binds @racket[it] to the
     86  corresponding @racket[conditionᵢ] in the non-@racket[else]
     87  cases. More precisely, in each @racket[bodyᵢ ...+], 
     88  @racket[it] is bound to the value of the corresponding 
     89  @racket[conditionᵢ]. Each @racket[conditionᵢ] is evaluated
     90  at most once (evaluation stops at the first successful 
     91  @racket[conditionᵢ]).}
     92 
     93 @defform*[[(aand)
     94            (aand conditionᵢ ... body)]]{
     95  Variant of @racket[and] which binds @racket[it]
     96  to the value of each @racket[conditionᵢ], in scope within the
     97  next @racket[conditionᵢ] or @racket[body]. More precisely, the value
     98  of each @racket[conditionᵢ] can be referred to as @racket[it] in
     99  the following @racketvarfont{conditionᵢ₊₁}, and the value of the last
    100  @racket[conditionᵢ] can be referred to as @racket[it] in the
    101  @racket[body]. If there are no @racket[conditionᵢ], i.e. when
    102  writing, @racket[(aand body)], then @racket[it] retains its original
    103  binding (which means that @racket[it] could be unbound, e.g. if no
    104  other @racketmodname[anaphoric] form wraps this one).
    105 
    106  Each @racket[condition] is evaluated at most once, and
    107  evaluation stops at the first false condition. The
    108  @racket[body] is only evaluated when every
    109  @racket[conditionᵢ] is successful.
    110 }
    111 
    112 @section{The hygienic versions @racket[if-let], 
    113  @racket[when-let] and @racket[cond-let]}
    114 
    115 @defform[(if-let [identifier condition] true-branch false-branch)]{
    116  Variant of @racket[if] which binds @racket[identifier] to
    117  the value of @racket[condition] in @racket[true-branch]. 
    118  @racket[condition] is only evaluated once. In the 
    119  @racket[false-branch], @racket[identifier] is left unchanged.}
    120 
    121 @defform[(when-let [identifier condition] body ...+)]{
    122  Variant of @racket[when] which binds @racket[identifier] to
    123  the value of @racket[condition] in @racket[body ...+]. 
    124  @racket[condition] is only evaluated once.}
    125 
    126 @defform*[#:literals (else)
    127           [(cond-let [[identifierᵢ conditionᵢ] bodyᵢ ...+] ...)
    128            (cond-let [[identifierᵢ conditionᵢ] bodyᵢ ...+] ... [else body ...+])
    129            (cond-let identifier [conditionᵢ bodyᵢ ...+] ...)
    130            (cond-let identifier [conditionᵢ bodyᵢ ...+] ... [else body ...+])]]{
    131  Variant of @racket[cond] which binds each 
    132  @racket[identifierᵢ] to the corresponding 
    133  @racket[conditionᵢ] in the non-@racket[else] cases. More
    134  precisely, in each @racket[bodyᵢ ...+], the corresponding 
    135  @racket[identifierᵢ] is bound to the value of the
    136  corresponding @racket[conditionᵢ].
    137 
    138  The last two variants are shorthands for using the same 
    139  @racket[identifier] in all cases (except the @racket[else]
    140  case).
    141 
    142  Each @racket[conditionᵢ] is evaluated at most once
    143  (evaluation stops at the first successful 
    144  @racket[conditionᵢ]).}
    145 
    146 @defform*[[(and-let)
    147            (and-let [identifier conditionᵢ] ... body)]]{
    148  Variant of @racket[and] which binds each @racket[identifier]
    149  to the value of its @racket[conditionᵢ], in scope within every
    150  @racket[conditionᵢ] afterwards as well as in @racket[body].
    151 
    152  Each @racket[conditionᵢ] is evaluated at most once, and
    153  evaluation stops at the first false condition. The
    154  @racket[body] is only evaluated when every
    155  @racket[conditionᵢ] is successful.
    156 }
    157 
    158 @section{Anaphoric map and filter}
    159 
    160 @defform[(amap body lst)]{
    161  Anaphoric @racket[map]. Binds the syntax parameter @racket[it]
    162  in the @racketid[body], and maps it over the list @racketid[lst]. Effectively the same
    163  as wrapping the @racketid[body] in a @racket[lambda] with an @racket[it] parameter. Unlike @racket[map], @racket[amap]
    164  only works on a single list.
    165 
    166  @racket[amap] works with nested function calls:
    167 
    168   @racketblock[(amap (string-append (string-upcase it) "!")
    169                      '("apple" "banana"))]
    170 
    171  The syntax parameter @racket[it] may be used multiple times in the procedure:
    172 
    173   @racketblock[(amap (* it it) '(1 2 3))]
    174 }
    175 
    176 @defform[(afilter body lst)]{
    177  Anaphoric @racket[filter]. Binds the syntax parameter @racket[it]
    178  in the @racketid[body], and filters the list @racketid[lst] using it. Effectively the same
    179  as wrapping the body in a @racket[lambda] with an @racket[it] parameter.
    180 
    181  @racket[afilter] works with nested function calls:
    182 
    183   @racketblock[(afilter ((* it it) . > . 50) lst)]
    184 }