mirror of
https://github.com/justinethier/cyclone.git
synced 2025-05-23 20:15:05 +02:00
Sync changes
This commit is contained in:
parent
8201399b9f
commit
dcfad7154d
4 changed files with 1137 additions and 61 deletions
1084
docs/api/srfi/1.md
1084
docs/api/srfi/1.md
File diff suppressed because it is too large
Load diff
|
@ -7,15 +7,64 @@ title: API
|
|||
|
||||
The `(srfi 2)` library provides the `and-let*` macro, an `and` with local bindings.
|
||||
|
||||
# Overview
|
||||
|
||||
Like an ordinary `and`, an `and-let*` special form evaluates its arguments -- expressions -- one after another in order, till the first one that yields `#f`. Unlike `and`, however, a non-#f result of one expression can be bound to a fresh variable and used in the subsequent expressions. `and-let*` is a cross-breed between `let*` and `and`.
|
||||
|
||||
See the [SRFI document](http://srfi.schemers.org/srfi-2/srfi-2.html) for more information.
|
||||
|
||||
- [`and-let*`](#and-let)
|
||||
|
||||
# Rationale
|
||||
|
||||
In case of an ordinary and formed of proper boolean expressions:
|
||||
|
||||
(and E1 E2 ...)
|
||||
|
||||
expression E2, if it gets to be evaluated, knows that E1 has returned non-#f. Moreover, E2 knows exactly what the result of E1 was -- #t -- which E2 can use to its advantage. If E1 however is an extended boolean expression, E2 can no longer tell which particular non-#f value E1 has returned. Chances are it took a lot of work to evaluate E1, and the produced result (a number, a vector, a string, etc) may be of value to E2. Alas, the `and` form merely checks that the result is not an #f, and throws it away. If E2 needs it, it has to compute that value anew. This proposed `and-let*` special form lets constituent expressions get hold of the results of already evaluated expressions, without re-doing their work.
|
||||
|
||||
`and-let*` can be thought of as a combination of `let*` and `and`, or a generalization of `cond`'s send operator `=>`. An `and-let*` form can also be considered a sequence of guarded expressions. In a regular program, forms may produce results, bind them to variables and let other forms use these results. `and-let*` differs in that it checks to make sure that every produced result "makes sense" (that is, not an `#f`). The first "failure" triggers the guard and aborts the rest of the sequence (which presumably would not make any sense to execute anyway). Examples:
|
||||
|
||||
(and-let* ((my-list (compute-list)) ((not (null? my-list))))
|
||||
(do-something my-list))
|
||||
|
||||
(define (look-up key alist)
|
||||
(and-let* ((x (assq key alist))) (cdr x)))
|
||||
|
||||
(or
|
||||
(and-let* ((c (read-char))
|
||||
((not (eof-object? c))))
|
||||
(string-set! some-str i c)
|
||||
(set! i (+ 1 i)))
|
||||
(begin (do-process-eof)))
|
||||
|
||||
; A more realistic example
|
||||
; Parse the 'timestamp' ::= 'token1' 'token2'
|
||||
; token1 ::= 'YY' 'MM' 'J'
|
||||
; token2 ::= 'GG' 'gg' "/"
|
||||
(define (parse-full-timestamp token1 token2)
|
||||
(and-let* (((= 5 (string-length token1)))
|
||||
((= 5 (string-length token2)))
|
||||
(timestamp
|
||||
(OS:string->time "%m/%d/%y %H:%M"
|
||||
(string
|
||||
(string-ref token1 2) (string-ref token1 3) #\/
|
||||
(string-ref token1 0) (string-ref token1 1) #\/
|
||||
(case (string-ref token1 4)
|
||||
((#\8 #\9) #\9) (else #\0))
|
||||
(string-ref token1 4) #\space
|
||||
(string-ref token2 0) (string-ref token2 1) #\:
|
||||
(string-ref token2 2) (string-ref token2 3))))
|
||||
((positive? timestamp)))
|
||||
timestamp))
|
||||
|
||||
`and-let*` is also similar to an "anaphoric AND" LISP macro [Rob Warnock, comp.lang.scheme, 26 Feb 1998 09:06:43 GMT, Message-ID: 6d3bb3$3804h@fido.asd.sgi.com]. `and-let*` allows however more than one intermediate result, each of which continues to be bound through the rest of the form.
|
||||
|
||||
# and-let*
|
||||
|
||||
(and-let* (claws) body
|
||||
*Syntax*
|
||||
|
||||
(and-let* (claws) body)
|
||||
|
||||
claws ::= '() | (cons claw claws)
|
||||
claw ::= (variable expression) | (expression) |
|
||||
|
@ -23,7 +72,7 @@ See the [SRFI document](http://srfi.schemers.org/srfi-2/srfi-2.html) for more in
|
|||
|
||||
- The `claws` are evaluated in the strict left-to-right order
|
||||
- For each `claw`, the `expression` part is evaluated first (or `bound-variable` is looked up)
|
||||
- If the result is #f, `and-let*` immediately returns #f
|
||||
- If the result is `#f`, `and-let*` immediately returns `#f`
|
||||
- Otherwise, if the `claw` is of the form `(variable expression)` the `expression`'s value is bound to a freshly made `variable`
|
||||
- The `variable` is available for the rest of the `claws` , and the `body`
|
||||
- As usual, all `variable`s must be unique (like in `let*`)
|
||||
|
|
|
@ -5,7 +5,9 @@ title: API
|
|||
|
||||
# SRFI 27 - Sources of random bits
|
||||
|
||||
The `(srfi 27)` library provides sources of random bits. See the [SRFI document](http://srfi.schemers.org/srfi-27/srfi-27.html) for more information.
|
||||
The `(srfi 27)` library provides sources of random bits.
|
||||
|
||||
See the [SRFI document](http://srfi.schemers.org/srfi-27/srfi-27.html) for more information.
|
||||
|
||||
- [`random-integer`](#random-integer)
|
||||
- [`random-real`](#random-real)
|
||||
|
|
|
@ -16,30 +16,39 @@ Hash tables are widely recognised as a fundamental data structure for a wide var
|
|||
|
||||
See the [SRFI document](http://srfi.schemers.org/srfi-69/srfi-69.html) for more information.
|
||||
|
||||
- [`make-hash-table`](#make-hash-table)
|
||||
- [`hash-table?`](#hash-table)
|
||||
- [`alist->hash-table`](#alist-hash-table)
|
||||
- [`hash-table-equivalence-function`](#hash-table-equivalence-function)
|
||||
- [`hash-table-hash-function`](#hash-table-hash-function)
|
||||
- [`hash-table-ref`](#hash-table-ref)
|
||||
- [`hash-table-ref/default`](#hash-table-refdefault)
|
||||
- [`hash-table-set!`](#hash-table-set)
|
||||
- [`hash-table-delete!`](#hash-table-delete)
|
||||
- [`hash-table-exists?`](#hash-table-exists)
|
||||
- [`hash-table-update!`](#hash-table-update)
|
||||
- [`hash-table-update!/default`](#hash-table-updatedefault)
|
||||
- [`hash-table-size`](#hash-table-size)
|
||||
- [`hash-table-keys`](#hash-table-keys)
|
||||
- [`hash-table-values`](#hash-table-values)
|
||||
- [`hash-table-walk`](#hash-table-walk)
|
||||
- [`hash-table-fold`](#hash-table-fold)
|
||||
- [`hash-table->alist`](#hash-table-alist)
|
||||
- [`hash-table-copy`](#hash-table-copy)
|
||||
- [`hash-table-merge!`](#hash-table-merge)
|
||||
- [`hash`](#hash)
|
||||
- [`string-hash`](#string-hash)
|
||||
- [`string-ci-hash`](#string-ci-hash)
|
||||
- [`hash-by-identity`](#hash-by-identity)
|
||||
## Type constructors and predicate
|
||||
[`make-hash-table`](#make-hash-table)
|
||||
[`hash-table?`](#hash-table)
|
||||
[`alist->hash-table`](#alist-hash-table)
|
||||
|
||||
## Reflective queries
|
||||
[`hash-table-equivalence-function`](#hash-table-equivalence-function)
|
||||
[`hash-table-hash-function`](#hash-table-hash-function)
|
||||
|
||||
## Dealing with single elements
|
||||
[`hash-table-ref`](#hash-table-ref)
|
||||
[`hash-table-ref/default`](#hash-table-refdefault)
|
||||
[`hash-table-set!`](#hash-table-set)
|
||||
[`hash-table-delete!`](#hash-table-delete)
|
||||
[`hash-table-exists?`](#hash-table-exists)
|
||||
[`hash-table-update!`](#hash-table-update)
|
||||
[`hash-table-update!/default`](#hash-table-updatedefault)
|
||||
|
||||
## Dealing with the whole contents
|
||||
[`hash-table-size`](#hash-table-size)
|
||||
[`hash-table-keys`](#hash-table-keys)
|
||||
[`hash-table-values`](#hash-table-values)
|
||||
[`hash-table-walk`](#hash-table-walk)
|
||||
[`hash-table-fold`](#hash-table-fold)
|
||||
[`hash-table->alist`](#hash-table-alist)
|
||||
[`hash-table-copy`](#hash-table-copy)
|
||||
[`hash-table-merge!`](#hash-table-merge)
|
||||
|
||||
## Hashing
|
||||
[`hash`](#hash)
|
||||
[`string-hash`](#string-hash)
|
||||
[`string-ci-hash`](#string-ci-hash)
|
||||
[`hash-by-identity`](#hash-by-identity)
|
||||
|
||||
# make-hash-table
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue