mirror of
https://github.com/justinethier/cyclone.git
synced 2025-05-23 20:15:05 +02:00
New files
This commit is contained in:
parent
3688ae91df
commit
105797c108
3 changed files with 701 additions and 0 deletions
339
docs/api/cyclone/concurrent.md
Normal file
339
docs/api/cyclone/concurrent.md
Normal file
|
@ -0,0 +1,339 @@
|
|||
---
|
||||
layout: main
|
||||
title: API
|
||||
---
|
||||
|
||||
# Concurrency Library
|
||||
|
||||
The `(cyclone concurrent)` library makes it easier to write concurrent programs using Cyclone.
|
||||
|
||||
This library complements the multithreading support provided by [SRFI 18](../srfi/18).
|
||||
|
||||
## Index
|
||||
|
||||
[Shared Objects](#shared-objects)
|
||||
- [`make-shared`](#make-shared)
|
||||
- [`share-all!`](#share-all)
|
||||
|
||||
[Immutability](#immutability)
|
||||
- [`immutable?`](#immutable)
|
||||
|
||||
[General](#general)
|
||||
- [`deref`](#deref)
|
||||
|
||||
[Atoms](#atoms)
|
||||
- [`make-atom`](#make-atom)
|
||||
- [`atom`](#atom)
|
||||
- [`atom?`](#atom-1)
|
||||
- [`swap!`](#swap)
|
||||
- [`compare-and-set!`](#compare-and-set)
|
||||
|
||||
[Futures](#futures)
|
||||
- [`future?`](#future)
|
||||
- [`future`](#future-1)
|
||||
- [`future-call`](#future-call)
|
||||
- [`future-deref`](#future-deref)
|
||||
- [`future-done?`](#future-done)
|
||||
|
||||
[Shared Queues](#shared-queues)
|
||||
- [`shared-queue?`](#shared-queue)
|
||||
- [`make-shared-queue`](#make-shared-queue)
|
||||
- [`shared-queue`](#shared-queue)
|
||||
- [`shared-queue-add!`](#shared-queue-add)
|
||||
- [`shared-queue-remove!`](#shared-queue-remove)
|
||||
- [`shared-queue-clear!`](#shared-queue-clear)
|
||||
- [`shared-queue-size`](#shared-queue-size)
|
||||
- [`shared-queue-capacity`](#shared-queue-capacity)
|
||||
- [`shared-queue-wait-count`](#shared-queue-wait-count)
|
||||
- [`shared-queue-empty?`](#shared-queue-empty)
|
||||
|
||||
[Thread Pool](#thread-pool)
|
||||
- [`thread-pool?`](#thread-pool-1)
|
||||
- [`make-thread-pool`](#make-thread-pool)
|
||||
- [`thread-pool-size`](#thread-pool-size)
|
||||
- [`thread-pool-idling-count`](#thread-pool-idling-count)
|
||||
- [`thread-pool-idling?`](#thread-pool-idling)
|
||||
- [`thread-pool-push-task!`](#thread-pool-push-task)
|
||||
- [`thread-pool-release!`](#thread-pool-release)
|
||||
|
||||
|
||||
## Shared Objects
|
||||
|
||||
Cyclone allocates new objects using the current thread's local stack. This is efficient for single-threaded code but makes it difficult to use an object from another thread. An object on a local stack could be overwritten or moved at any time, leading to undefined behavior. The solution is to guarantee an object is located in a section of memory available for use by any thread. We call these shared objects.
|
||||
|
||||
Note that concurrency primitives must still be used to safely coordinate access to shared objects!
|
||||
|
||||
The following types of objects are always shared:
|
||||
|
||||
- Concurrency primitives (mutex, conditional variable, atom). These object are allocated directly on the heap since by definition multiple threads need to use them for synchronization.
|
||||
|
||||
- Fixnum integers and characters. These are immediates (IE, value types) so there is no object in memory to reference.
|
||||
|
||||
- Booleans, bignums, symbols, and the EOF object.
|
||||
|
||||
All other objects must be explicitly shared before they can be safely used by multiple threads.
|
||||
|
||||
### make-shared
|
||||
|
||||
(make-shared obj)
|
||||
|
||||
Return an object that can be safely shared by many threads.
|
||||
|
||||
If the given object is already shared it it simply returned. Otherwise it is necessary to create a copy of the object.
|
||||
|
||||
Note this function may trigger a minor GC if a thread-local pair or vector is passed.
|
||||
|
||||
### share-all!
|
||||
|
||||
(share-all!)
|
||||
|
||||
Allow all objects currently on the calling thread's local stack to be shared with other threads.
|
||||
|
||||
Note this function will trigger a minor garbage collection on the calling thread.
|
||||
|
||||
## Immutability
|
||||
|
||||
Many types of objects are mutable by default: pairs, strings, vectors, and bytevectors. However, if an object is declared as a literal constant then it will be designated immutable.
|
||||
|
||||
The easiest way to do this is to use a single-quote, EG:
|
||||
|
||||
cyclone> (import (cyclone concurrent))
|
||||
ok
|
||||
Error: Expected immutable object : (1 2)
|
||||
cyclone> (define my-lis '(1 2))
|
||||
ok
|
||||
cyclone> (immutable? my-lis)
|
||||
#t
|
||||
|
||||
It is an error to call a mutation procedure (such as `set-car!` or `string-set!`) on an immutable object.
|
||||
|
||||
### immutable?
|
||||
|
||||
(immutable? obj)
|
||||
|
||||
Predicate that returns `#t` if `obj` is immutable and `#f` otherwise.
|
||||
|
||||
## General
|
||||
|
||||
### deref
|
||||
|
||||
(deref object)
|
||||
|
||||
Dereference; returns the current value of the given concurrency object.
|
||||
|
||||
## Atoms
|
||||
|
||||
This section provides atomic operations modelled after Clojure's [Atoms](https://clojure.org/reference/atoms).
|
||||
|
||||
Per the Clojure docs:
|
||||
|
||||
> Atoms are an efficient way to represent some state that will never need to be coordinated with any other, and for which you wish to make synchronous changes.
|
||||
|
||||
Note an atom may only reference a shared object that is immutable. This guarantees that the value the atom is referencing is not modified unexpectedly by another thread.
|
||||
|
||||
For example:
|
||||
|
||||
cyclone> (import (cyclone concurrent))
|
||||
ok
|
||||
cyclone> (make-atom (list 1 2))
|
||||
Error: Expected immutable object : (1 2)
|
||||
cyclone> (make-atom (make-shared '(1 2)))
|
||||
<atom 0x7f742b99bb00>
|
||||
|
||||
Example programs:
|
||||
|
||||
- Summing numbers using atomic operations: [`sum-atomic.scm`](../../../examples/threading/sum-atomic.scm)
|
||||
- For comparison, summing numbers using locks: [`sum-mutex.scm`](../../../examples/threading/sum-mutex.scm)
|
||||
|
||||
### make-atom
|
||||
|
||||
(make-atom obj)
|
||||
|
||||
Create a new atom referencing `obj`.
|
||||
|
||||
`obj` must be an immutable, shared object.
|
||||
|
||||
### atom
|
||||
|
||||
(atom)
|
||||
(atom obj)
|
||||
|
||||
Create a new atom in the same manner as `make-atom`. If `obj` is not provided it will default to `#f`.
|
||||
|
||||
### atom?
|
||||
|
||||
(atom? obj)
|
||||
|
||||
Type predicate, returns `#t` if `obj` is an atom and `#f` otherwise.
|
||||
|
||||
### swap!
|
||||
|
||||
(swap! atom f . args)
|
||||
|
||||
Atomically swaps the value of `atom` to be:
|
||||
|
||||
(apply f current-value-of-atom args)
|
||||
|
||||
Note that `f` may be called multiple times and thus should be free of side effects. Returns the value that was swapped in.
|
||||
|
||||
Based on the procedure of the same name from Clojure.
|
||||
|
||||
### compare-and-set!
|
||||
|
||||
(compare-and-set! atom oldval newval)
|
||||
|
||||
Atomically changes the value of `atom` to `newval` but only if the value of `atom` is currently equal to `oldval`. This is also commonly known as the compare-and-swap (CAS) atomic instruction.
|
||||
|
||||
Based on the procedure of the same name from Clojure.
|
||||
|
||||
## Futures
|
||||
|
||||
Futures are used to perform computations on another thread. The results are cached and may be retrieved later using `deref`. Note that `deref` will block on a future until a result is generated by the other thread.
|
||||
|
||||
### future?
|
||||
|
||||
(future? obj)
|
||||
|
||||
Type predicate, returns `#t` if `obj` is a future and `#f` otherwise.
|
||||
|
||||
### future
|
||||
|
||||
*Syntax*
|
||||
|
||||
(future expr ...)
|
||||
|
||||
Executes the given expressions on another thread and returns a future object that can be dereferenced later to retrieve the cached result. Note the result will be the value obtained from executing the last expression.
|
||||
|
||||
### future-call
|
||||
|
||||
(future-call thunk)
|
||||
|
||||
Invokes `thunk` on another thread and returns a future object that can be dereferenced later to retrieve the cached result.
|
||||
|
||||
`thunk` is a function that takes no arguments.
|
||||
|
||||
### future-done?
|
||||
|
||||
(future-done? obj)
|
||||
|
||||
Returns `#t` if the future has finished executing on another thread, and `#f` otherwise.
|
||||
|
||||
## Shared Queues
|
||||
|
||||
A shared queue contains a circular buffer of objects intended to be shared among many threads. All operations are locked and thread-safe, and the queue will ensure any objects added are made into shared objects for use by other threads.
|
||||
|
||||
Removal from a queue is a blocking operation, so threads can easily wait for new data to arrive.
|
||||
|
||||
### shared-queue?
|
||||
|
||||
(shared-queue? obj)
|
||||
|
||||
Predicate to determine if `obj` is a shared queue. Returns `#t` if so, `#f` otherwise.
|
||||
|
||||
### make-shared-queue
|
||||
|
||||
(make-shared-queue)
|
||||
|
||||
Create a new shared queue.
|
||||
|
||||
### shared-queue
|
||||
|
||||
(shared-queue . elements)
|
||||
|
||||
Create a new shared queue containing the given elements.
|
||||
|
||||
### shared-queue-add!
|
||||
|
||||
(shared-queue-add! q obj)
|
||||
|
||||
Add `obj` to the given shared queue `q`.
|
||||
|
||||
### shared-queue-remove!
|
||||
|
||||
(shared-queue-remove! q)
|
||||
|
||||
Removes an element from the front of shared queue `q` and returns it to the caller. If `q` is empty the calling thread will be blocked until an element is available.
|
||||
|
||||
This function is meant to be called on a different thread than the thread(s) adding data to `q`.
|
||||
|
||||
### shared-queue-clear!
|
||||
|
||||
(shared-queue-clear! q)
|
||||
|
||||
Remove all elements from the given shared queue `q`.
|
||||
|
||||
### shared-queue-size
|
||||
|
||||
(shared-queue-size q)
|
||||
|
||||
Return the number of elements in the given shared queue.
|
||||
|
||||
### shared-queue-capacity
|
||||
|
||||
(shared-queue-capacity q)
|
||||
|
||||
Return the maximum capacity of `q`. Note that when this capacity is exceeded the queue will automatically be resized.
|
||||
|
||||
### shared-queue-wait-count
|
||||
|
||||
(shared-queue-wait-count q)
|
||||
|
||||
Return the number of threads currently blocked waiting for data from `q`.
|
||||
|
||||
### shared-queue-empty?
|
||||
|
||||
(shared-queue-empty? q)
|
||||
|
||||
Returns `#t` if the given queue is empty, and `#f` otherwise.
|
||||
|
||||
## Thread Pool
|
||||
|
||||
A thread pool is used to start several OS-level threads that will be used to execute jobs queued to the pool via `thread-pool-push-task!`. This allows an application to run asynchronous tasks on other threads while avoiding the overhead of starting a new thread for each task.
|
||||
|
||||
### thread-pool?
|
||||
|
||||
(thread-pool? obj)
|
||||
|
||||
Predicate to determine if `obj` is a thread pool. Returns `#t` if so, `#f` otherwise.
|
||||
|
||||
### make-thread-pool
|
||||
|
||||
(make-thread-pool thread-count [handler])
|
||||
|
||||
Create a new thread pool consisting of `thread-count` threads.
|
||||
|
||||
If `handler` is specified then it will be used as each thread's default exception handler.
|
||||
|
||||
### thread-pool-size
|
||||
|
||||
(thread-pool-size tp)
|
||||
|
||||
Return the number of threads in thread pool `tp`.
|
||||
|
||||
### thread-pool-idling-count
|
||||
|
||||
(thread-pool-idling-count tp)
|
||||
|
||||
Return number of idle threads in thread pool `tp`.
|
||||
|
||||
### thread-pool-idling?
|
||||
|
||||
(thread-pool-idling? tp)
|
||||
|
||||
Return `#t` if any of the given thread pool's threads are idle, `#f` otherwise.
|
||||
|
||||
### thread-pool-push-task!
|
||||
|
||||
(thread-pool-push-task! tp thunk)
|
||||
|
||||
Add a new task to the given thread pool `tp`.
|
||||
|
||||
`thunk` is a function accepting no arguments and will be queued to run on the next available thread.
|
||||
|
||||
### thread-pool-release!
|
||||
|
||||
(thread-pool-release! tp)
|
||||
|
||||
Call this if the thread pool `tp` will no longer be used. Stops and cleans up all thread pool threads.
|
||||
|
||||
|
274
docs/api/cyclone/match.md
Normal file
274
docs/api/cyclone/match.md
Normal file
|
@ -0,0 +1,274 @@
|
|||
---
|
||||
layout: main
|
||||
title: API
|
||||
---
|
||||
|
||||
# Match Library
|
||||
|
||||
The `(cyclone match)` library provides a hygienic pattern matcher, based on Alex Shinn's portable `match.scm`.
|
||||
|
||||
This is a full superset of the popular [match](http://www.cs.indiana.edu/scheme-repository/code.match.html) package by Andrew Wright, written in fully portable `syntax-rules` and thus preserving hygiene.
|
||||
|
||||
The most notable extensions are the ability to use *non-linear* patterns - patterns in which the same identifier occurs multiple times, tail patterns after ellipsis, and the experimental tree patterns.
|
||||
|
||||
## Index
|
||||
|
||||
- [`match`](#match)
|
||||
- [`match-lambda`](#match-lambda)
|
||||
- [`match-lambda*`](#match-lambda-1)
|
||||
- [`match-let`](#match-let)
|
||||
- [`match-letrec`](#match-letrec)
|
||||
- [`match-let*`](#match-let-1)
|
||||
|
||||
## Patterns
|
||||
|
||||
Patterns are written to look like the printed representation of the objects they match. The basic usage is
|
||||
|
||||
(match expr (pat body ...) ...)
|
||||
|
||||
where the result of `expr` is matched against each pattern in
|
||||
turn, and the corresponding body is evaluated for the first to
|
||||
succeed. Thus, a list of three elements matches a list of three
|
||||
elements.
|
||||
|
||||
(let ((ls (list 1 2 3))) (match ls ((1 2 3) #t)))
|
||||
|
||||
If no patterns match an error is signalled.
|
||||
|
||||
Identifiers will match anything, and make the corresponding
|
||||
binding available in the body.
|
||||
|
||||
(match (list 1 2 3) ((a b c) b))
|
||||
|
||||
If the same identifier occurs multiple times, the first instance
|
||||
will match anything, but subsequent instances must match a value
|
||||
which is `equal?` to the first.
|
||||
|
||||
(match (list 1 2 1) ((a a b) 1) ((a b a) 2))
|
||||
|
||||
The special identifier `_` matches anything, no matter how
|
||||
many times it is used, and does not bind the result in the body.
|
||||
|
||||
(match (list 1 2 1) ((_ _ b) 1) ((a b a) 2))
|
||||
|
||||
To match a literal identifier (or list or any other literal), use `quote`.
|
||||
|
||||
(match 'a ('b 1) ('a 2))
|
||||
|
||||
Analogous to its normal usage in scheme, `quasiquote` can
|
||||
be used to quote a mostly literally matching object with selected
|
||||
parts unquoted.
|
||||
|
||||
(match (list 1 2 3) (`(1 ,b ,c) (list b c)))
|
||||
|
||||
Often you want to match any number of a repeated pattern. Inside
|
||||
a list pattern you can append `...` after an element to
|
||||
match zero or more of that pattern (like a regexp Kleene star).
|
||||
|
||||
(match (list 1 2) ((1 2 3 ...) #t))
|
||||
(match (list 1 2 3) ((1 2 3 ...) #t))
|
||||
(match (list 1 2 3 3 3) ((1 2 3 ...) #t))
|
||||
|
||||
Pattern variables matched inside the repeated pattern are bound to
|
||||
a list of each matching instance in the body.
|
||||
|
||||
(match (list 1 2) ((a b c ...) c))
|
||||
(match (list 1 2 3) ((a b c ...) c))
|
||||
(match (list 1 2 3 4 5) ((a b c ...) c))
|
||||
|
||||
More than one `...` may not be used in the same list, since
|
||||
this would require exponential backtracking in the general case.
|
||||
However, `...` need not be the final element in the list,
|
||||
and may be succeeded by a fixed number of patterns.
|
||||
|
||||
(match (list 1 2 3 4) ((a b c ... d e) c))
|
||||
(match (list 1 2 3 4 5) ((a b c ... d e) c))
|
||||
(match (list 1 2 3 4 5 6 7) ((a b c ... d e) c))
|
||||
|
||||
`___` is provided as an alias for `...` when it is
|
||||
inconvenient to use the ellipsis (as in a syntax-rules template).
|
||||
|
||||
The `..1` syntax is exactly like the `...` except
|
||||
that it matches one or more repetitions (like a regexp "+").
|
||||
|
||||
(match (list 1 2) ((a b c ..1) c))
|
||||
(match (list 1 2 3) ((a b c ..1) c))
|
||||
|
||||
The boolean operators `and`, `or`, and `not`
|
||||
can be used to group and negate patterns analogously to their
|
||||
Scheme counterparts.
|
||||
|
||||
The `and` operator ensures that all subpatterns match.
|
||||
This operator is often used with the idiom `(and x pat)` to
|
||||
bind `x` to the entire value that matches `pat`
|
||||
(c.f. "as-patterns" in ML or Haskell). Another common use is in
|
||||
conjunction with `not` patterns to match a general case
|
||||
with certain exceptions.
|
||||
|
||||
(match 1 ((and) #t))
|
||||
(match 1 ((and x) x))
|
||||
(match 1 ((and x 1) x))
|
||||
|
||||
The `or` operator ensures that at least one subpattern
|
||||
matches. If the same identifier occurs in different subpatterns,
|
||||
it is matched independently. All identifiers from all subpatterns
|
||||
are bound if the `or` operator matches, but the binding is
|
||||
only defined for identifiers from the subpattern which matched.
|
||||
|
||||
(match 1 ((or) #t) (else #f))
|
||||
(match 1 ((or x) x))
|
||||
(match 1 ((or x 2) x))
|
||||
|
||||
The `not` operator succeeds if the given pattern doesn't
|
||||
match. None of the identifiers used are available in the body.
|
||||
|
||||
(match 1 ((not 2) #t))
|
||||
|
||||
The more general operator `?` can be used to provide a
|
||||
predicate. The usage is `(? predicate pat ...)` where
|
||||
`predicate` is a Scheme expression evaluating to a predicate
|
||||
called on the value to match, and any optional patterns after the
|
||||
predicate are then matched as in an `and` pattern.
|
||||
|
||||
(match 1 ((? odd? x) x))
|
||||
|
||||
The field operator `=` is used to extract an arbitrary
|
||||
field and match against it. It is useful for more complex or
|
||||
conditional destructuring that can't be more directly expressed in
|
||||
the pattern syntax. The usage is `(= field pat)`, where
|
||||
`field` can be any expression, and should result in a
|
||||
procedure of one argument, which is applied to the value to match
|
||||
to generate a new value to match against `pat`.
|
||||
|
||||
Thus the pattern `(and (= car x) (= cdr y))` is equivalent
|
||||
to `(x . y)`, except it will result in an immediate error
|
||||
if the value isn't a pair.
|
||||
|
||||
(match '(1 . 2) ((= car x) x))
|
||||
(match 4 ((= square x) x))
|
||||
|
||||
The record operator `$` is used as a concise way to match
|
||||
records defined by SRFI-9 (or SRFI-99). The usage is
|
||||
`($ rtd field ...)`, where `rtd` should be the record
|
||||
type descriptor specified as the first argument to
|
||||
`define-record-type`, and each `field` is a subpattern
|
||||
matched against the fields of the record in order. Not all fields
|
||||
must be present.
|
||||
|
||||
(let ()
|
||||
(define-record-type employee
|
||||
(make-employee name title)
|
||||
employee?
|
||||
(name get-name)
|
||||
(title get-title))
|
||||
(match (make-employee "Bob" "Doctor")
|
||||
(($ employee n t) (list t n))))
|
||||
|
||||
For records with more fields it can be helpful to match them by
|
||||
name rather than position. For this you can use the `@`
|
||||
operator, originally a Gauche extension:
|
||||
|
||||
(let ()
|
||||
(define-record-type employee
|
||||
(make-employee name title)
|
||||
employee?
|
||||
(name get-name)
|
||||
(title get-title))
|
||||
(match (make-employee "Bob" "Doctor")
|
||||
((@ employee (title t) (name n)) (list t n))))
|
||||
|
||||
The `set!` and `get!` operators are used to bind an
|
||||
identifier to the setter and getter of a field, respectively. The
|
||||
setter is a procedure of one argument, which mutates the field to
|
||||
that argument. The getter is a procedure of no arguments which
|
||||
returns the current value of the field.
|
||||
|
||||
(let ((x (cons 1 2))) (match x ((1 . (set! s)) (s 3) x)))
|
||||
(match '(1 . 2) ((1 . (get! g)) (g)))
|
||||
|
||||
The new operator `***` can be used to search a tree for
|
||||
subpatterns. A pattern of the form `(x *** y)` represents
|
||||
the subpattern `y` located somewhere in a tree where the path
|
||||
from the current object to `y` can be seen as a list of the
|
||||
form `(x ...)`. `y` can immediately match the current
|
||||
object in which case the path is the empty list. In a sense it's
|
||||
a 2-dimensional version of the `...` pattern.
|
||||
|
||||
As a common case the pattern `(_ *** y)` can be used to
|
||||
search for `y` anywhere in a tree, regardless of the path
|
||||
used.
|
||||
|
||||
(match '(a (a (a b))) ((x *** 'b) x))
|
||||
(match '(a (b) (c (d e) (f g))) ((x *** 'g) x))
|
||||
|
||||
## Notes
|
||||
|
||||
The implementation is a simple generative pattern matcher - each
|
||||
pattern is expanded into the required tests, calling a failure
|
||||
continuation if the tests fail. This makes the logic easy to
|
||||
follow and extend, but produces sub-optimal code in cases where you
|
||||
have many similar clauses due to repeating the same tests.
|
||||
Nonetheless a smart compiler should be able to remove the redundant
|
||||
tests. For MATCH-LET and DESTRUCTURING-BIND type uses there is no
|
||||
performance hit.
|
||||
|
||||
The original version was written on 2006/11/29 and described in the
|
||||
following Usenet post: http://groups.google.com/group/comp.lang.scheme/msg/0941234de7112ffd
|
||||
|
||||
and is still available at: http://synthcode.com/scheme/match-simple.scm
|
||||
|
||||
It's just 80 lines for the core MATCH, and an extra 40 lines for
|
||||
MATCH-LET, MATCH-LAMBDA and other syntactic sugar.
|
||||
|
||||
# match
|
||||
|
||||
*Syntax*
|
||||
|
||||
(match {expression} {clauses})
|
||||
|
||||
where `{clauses}` has the form:
|
||||
|
||||
(pattern body ...)
|
||||
|
||||
This is the primary pattern match macro. See the [Patterns](#patterns) section above for complete details.
|
||||
|
||||
# match-lambda
|
||||
|
||||
*Syntax*
|
||||
|
||||
(match-lambda (pattern body ...))
|
||||
|
||||
Shortcut for `lambda` + `match`. Creates a procedure of one argument, and matches that argument against each clause.
|
||||
|
||||
# match-lambda*
|
||||
|
||||
*Syntax*
|
||||
|
||||
(match-lambda* (pattern body ...))
|
||||
|
||||
Similar to `match-lambda`. Creates a procedure of any number of arguments, and matches the argument list against each clause.
|
||||
|
||||
# match-let
|
||||
|
||||
*Syntax*
|
||||
|
||||
(match-let ((var value) ...) body ...)
|
||||
(match-let loop ((var value) ...) body ...)
|
||||
|
||||
Matches each var to the corresponding expression, and evaluates the body with all match variables in scope. Raises an error if any of the expressions fail to match. Syntax analogous to named let can also be used for recursive functions which match on their arguments as in `match-lambda*`.
|
||||
|
||||
# match-letrec
|
||||
|
||||
*Syntax*
|
||||
|
||||
(match-letrec ((var value) ...) body ...)
|
||||
|
||||
Similar to `match-let`, but analogously to `letrec` matches and binds the variables with all match variables in scope.
|
||||
|
||||
# match-let*
|
||||
|
||||
*Syntax*
|
||||
|
||||
(match-let* ((var value) ...) body ...)
|
||||
|
||||
Similar to `match-let`, but analogously to `let*` matches and binds the variables in sequence, with preceding match variables in scope.
|
88
docs/api/cyclone/test.md
Normal file
88
docs/api/cyclone/test.md
Normal file
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
layout: main
|
||||
title: API
|
||||
---
|
||||
|
||||
# Test Library
|
||||
|
||||
The `(cyclone test)` library contains a testing framework ported from `(chibi test)` which in turn was ported from CHICKEN.
|
||||
|
||||
- [`warning`](#warning)
|
||||
- [`test-group-inc!`](#test-group-inc)
|
||||
- [`print-exception`](#print-exception)
|
||||
- [`test`](#test)
|
||||
- [`test-equal`](#test-equal)
|
||||
- [`test-error`](#test-error)
|
||||
- [`test-assert`](#test-assert)
|
||||
- [`test-not`](#test-not)
|
||||
- [`test-values`](#test-values)
|
||||
- [`test-group`](#test-group)
|
||||
- [`current-test-group`](#current-test-group)
|
||||
- [`test-begin`](#test-begin)
|
||||
- [`test-end`](#test-end)
|
||||
- [`test-syntax-error`](#test-syntax-error)
|
||||
- [`test-propagate-info`](#test-propagate-info)
|
||||
- [`test-vars`](#test-vars)
|
||||
- [`test-run`](#test-run)
|
||||
- [`test-exit`](#test-exit)
|
||||
- [`current-test-verbosity`](#current-test-verbosity)
|
||||
- [`current-test-applier`](#current-test-applier)
|
||||
- [`current-test-handler`](#current-test-handler)
|
||||
- [`current-test-skipper`](#current-test-skipper)
|
||||
- [`current-test-group-reporter`](#current-test-group-reporter)
|
||||
- [`test-failure-count`](#test-failure-count)
|
||||
- [`current-test-epsilon`](#current-test-epsilon)
|
||||
- [`current-test-comparator`](#current-test-comparator)
|
||||
|
||||
# warning
|
||||
|
||||
# test-group-inc!
|
||||
|
||||
# print-exception
|
||||
|
||||
# test
|
||||
|
||||
# test-equal
|
||||
|
||||
# test-error
|
||||
|
||||
# test-assert
|
||||
|
||||
# test-not
|
||||
|
||||
# test-values
|
||||
|
||||
# test-group
|
||||
|
||||
# current-test-group
|
||||
|
||||
# test-begin
|
||||
|
||||
# test-end
|
||||
|
||||
# test-syntax-error
|
||||
|
||||
# test-propagate-info
|
||||
|
||||
# test-vars
|
||||
|
||||
# test-run
|
||||
|
||||
# test-exit
|
||||
|
||||
# current-test-verbosity
|
||||
|
||||
# current-test-applier
|
||||
|
||||
# current-test-handler
|
||||
|
||||
# current-test-skipper
|
||||
|
||||
# current-test-group-reporter
|
||||
|
||||
# test-failure-count
|
||||
|
||||
# current-test-epsilon
|
||||
|
||||
# current-test-comparator
|
||||
|
Loading…
Add table
Reference in a new issue