[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: cond*
From: |
Richard Stallman |
Subject: |
Re: cond* |
Date: |
Thu, 28 Dec 2023 22:52:58 -0500 |
[[[ To any NSA and FBI agents reading my email: please consider ]]]
[[[ whether defending the US Constitution against all enemies, ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]
I include below the latest version.
Compare the total complexity of specification of cond* with the total
complexity of specification of pcase. Then likewise compare the
generality and flexibility of cond* with pcase.
Each clause in cond* that has just one element -- no "clause body" --
is a "non-exit" clause. After that clause completes, control always
proceeds to the following clause.
All other clauses are like cond clauses, in that when the condition is
true, the executes its clause body and then exits the cond*.
(cond*
;; Same as a clause in `cond',
(CONDITION
DO-THIS-IF-TRUE-THEN-EXIT...)
;; Execute FORM and ignore its value.
(FORM)
;; Variables to bind, as in let*, around the rest
;; of the cond*.
((bind* (x foobar) y z (foo 5) a))
;; Bindings continue in effect for the whole cond* construct.
;; Bind variables for the clause, as in let*.
((bind* (foo 5) (condition (hack-it foo)))
;; condition is that the last variable bound be non-nil.
BODY...)
;; Bindings no longer in effect.
;; Extracts substructure and binds variables for the clause.
((match* `(expt ,foo ,bar) x)
DO-THIS-IF-IT-MATCHED-THEN-EXIT...)
;; Bindings no longer in effect.
;; Extracts substructure and binds variables
;; for the rest of the cond*.
;; Like above but always falls thru to next clause.
;; All the variables mentioned in the pattern
;; are bound whether match succeeds or not.
;; If a value can be determined from an incomplete match,
;; the variable gets that value.
((match* `(expt ,foo ,bar) x))
;; Bindings continue in effect.
;; Another example of fall-through match* clause.
;; All the variables mentioned in the pattern
;; are bound in all cases.
((match* (or `() `(,macroexp-const-p const)) body)
;; The `match-set*' is a tentative proposal. It may not be worth including.
;; Extracts substructure and sets variables if match succeeds
((match-set* `(expt ,foo ,bar) x)
DO-THIS-IF-IT-MATCHED-THEN-EXIT...)
;; Extracts substructure and sets variables without binding them.
;; Always falls thru to next clause.
((match-set* `(expt ,foo ,bar) x))
)
To execute several expressions and not exit, use this:
((progn DO-THIS-UNCONDITIONALLY-AND-DONT-STOP...)
To test CONDITION and return its value if non-nil, use this:
(CONDITION CONDITION)
That is the best way when CONDITION is simple. When it is complex,
this may be clearer and shorter than repeating CONDITION:
((bind* (value CONDITION))
value)
**Possible types of patterns for match*.
CONSTANT: nil, t, a keyword, a quoted constant other than a cons cell,
fixed parts of a backquote.
This matches any value equal to CONSTANT.
_
_ means to match any value and not store it anywhere.
VARIABLE: a symbol
A symbol means to match any value and set VARIABLE to it.
A backquoted cons cell
The car and the cdr are subpattenrs. The cons cell pattern
matches any cons cell whose car and cdr match those two subpatterns.
How nil as a cdr matches is controlled by the match-nil flag.
When the nil-match-all flag is false, nil as a cdr matches
only nil itself.
When the nil-match-all flag is true, nil as a cdr matches
any object and ignores that object.
The nil-match-all flag is false by default. The `cdr' pattern maks
it false within its its subpattern, and the `cdr-safe' pattern makes
it true forwithin its its subpattern.
(cdr-safe QUOTED-CONS-CELL)
This pattern is equivalent to QUOTED-CONS-CELL by itself
except that it makes the nil-match-all flag true within it.
(cdr-safe `(a b)) matches (a b), (a b c), (a b . d), etc.
(cdr QUOTED-CONS-CELL)
This pattern is equivalent to QUOTED-CONS-CELL by itself
except that it makes the nil-match-all flag false within it.
(cdr `(a b)) matches only (a b).
A backquoted vector
Each element is a subpattern. This
matches a vector of data if each element of that vector is
matched by the corresponding subpattern.
A backquoted structure constructor
Each field is a subpattern. This matches a structure as data if
each field element of that structure is matched by the corresponding
subpattern.
Constrained variable: (PRED VARIABLE) or, more generally,
(PRED VARIABLE OTHER-ARGS...)
This matches any value VALUE that satisfies the specified
constraint. PRED is a function to test the constraint. It receives
VALUE as its first argument. If PRED returns true, that means VALUE
satisfies the constraint, so this pattern binds (or sets) VARIABLE
to that value. For instance,
(symbolp sym) ; Match any symbol, bind `sym' to it.
xxxxxxxxxxxxxx not decided yet
This would give some added power, but does that power really enable
the user to do more with cond*? I am not sure.
PATTERN can also be a list, which is a pattern to destructure,
For instance,
(plistp `(,a ,b . ,rest))
checks that VA<UE is a valid plist, then binds a and b to the first
and second element and binds rest to its cddr.
xxxxxxxxxxxxxx not decided yet
If you wish, you can specify additional arguments to pass to PRED.
The OTHER-ARGS are not patterns to match, they are Lisp expressions
whose values specify the additional arguments to pass to PRED,
following the first argument which is VALUE. In effect, the call
to PRED looks like this:
(apply PRED VALUE (mapcar 'eval OTHER-ARGS))
Here are two examples of passing an additional argument.
(> num-foos 1) ; Match any number greater than 1, bind `num-foos' to it.
(> num-foos min-foos) ; Match any number greater than MIN-FOOS,
; bind `num-foos' to it.
When matching to bind variables, the presence of a constrained
variable pattern, as a subpattern of the overall pattern to be
matched, unconditionally binds VARIABLE whether the subpattern
matches or not.
Errors in constrained variable constructs:
If an error occurs in testing the constraint, or calculating
the other arguments to pass to the predicate, that pattern fails
to match but does not terminate the cond* form.
Constrained variable constructs can be nested:
For example,
(integerp (> num-foos 1)) ; Match any integer > 1,
; bind `num-foos' to it.
nests the constrained pattern (integerp num-foos) inside the
constrained pattern (< ... 1). This nested constrained pattern
first tests that the value is greater than 1, then tests it is an
integer. If both of those constraints are true, it setse `num-foos'.
(> (integerp num-foos) 1) ; Match any integer > 1,
; bind `num-foos' to it.
does the two tests in the opposite order; it is equivalent, because
an error in the call to `>' only makes this pattern fail to match.
Advanced hack for experts: the OTHER-ARGS can refer to variables
bound earlier in this pattern-matching operation. For example,
`(,(integerp smaller) ,(> (integerp bigger) smaller))
; Matches a list of two integers in which the second integer
; is larger than the first.
(or `(,(integerp smaller) ,(> (integerp bigger) smaller))
`(,(integerp bigger) ,(< (integerp smaller) bigger)))
; matches a ist of two integers and binds `bigger' to the bigger one
; and `smaller' to the smaller one.
However, it might be cleaner to match the two integers regardless of
their numberical ordering, then in Lisp code see which one is larger.
General constrained variable: (constrain VAR EXPRESSION)
This general constrained variable pattern binds VAR to the
value being matched against, tentatively, then evaluates EXPRESSION.
If the result is true, the match succeeds and leaves VAR
bound to that value.
For instance,
(constrain x (and (> x 0) (< x 100)))
succeeds if the value being matched aainst is in the open interval (0, 100),
and in that case it binds x to that value.
Alternatives: (or SUBPATTERNS...)
This tries to match each of the SUBPATTERNS in order until one matches.
If the pattern is being used to bind variables, it binds all the variables
specified in any of SUBPATTERNS
These three ways of using `cond*' are worth noting.
(cond* ((match* PATTERN VALUE) TEST))
PATTERN is a pattern as described above. For instance
(match `(+ (expt ,_ ,_)) (get-complex-list))
would decompose the result of (get-complex-list) and check
for `+' and `expt' in it.
PATTERN will not be evaluated, just used as guidance when the
`match' form is macroexpanded.
If PATTERN includes substitutions, it will virtually perform
those substitutions and compare parts of VALUE against them.
(match `(foo ,foo) x) compares (car x) with `foo'.
TEST is a Lisp expression to be evaluated if VALUE seems
to fit PATTERN. If TEST evaluates non-nil, the match succeeds.
`match' returns t if it succeeds in matching, otherwise nil.
`match' can also handle vectors and maybe some other kinds of
structures.
(cond* ((match-set* PATTERN VALUE)))
PATTERN is a pattern as described above. For instance
(match-set `(+ ,y ,z) (get-complex-list))
would decompose the result of (get-complex-list), verify the car,
and set y and z. It is equivalent to this:
(if (eq (car value) '+)
(progn
(setq y (car (cadr value)) z (cadr (cadr value)))
TEST))
PATTERN will not be evaluated, just used as guidance when the
`match-set' form is macroexpanded, producing code like this:
TEST is a Lisp expression to be evaluated if VALUE seems
to fit PATTERN. If TEST evaluates non-nil, the match succeeds.
`match-set' returns t if it succeeds in matching, otherwise nil.
`match-set' can also handle vectors and maybe some other kinds of
structures.
(cond* ((match* PATTERN VALUE) BODY...))
Like the previous, except that instead of setting the
variables found in PATTERN, it let-binds them and runs BODY
with those bindings.
--
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)
- Re: cond*, (continued)
- Re: cond*, Richard Stallman, 2023/12/23
- Re: cond*, Ihor Radchenko, 2023/12/25
- Re: cond*, Richard Stallman, 2023/12/18
- Re: cond*, João Távora, 2023/12/19
- Re: cond*, Richard Stallman, 2023/12/21
- Re: cond*, Philip Kaludercic, 2023/12/22
- Re: cond*, Richard Stallman, 2023/12/24
- Re: cond*, Philip Kaludercic, 2023/12/25
- Re: cond*, Richard Stallman, 2023/12/26
- Re: cond*, Philip Kaludercic, 2023/12/27
- Re: cond*,
Richard Stallman <=
- RE: [External] : Re: cond*, Drew Adams, 2023/12/19
- Re: [External] : Re: cond*, Richard Stallman, 2023/12/20
- Re: [External] : Re: cond*, Richard Stallman, 2023/12/20
- cond*, Richard Stallman, 2023/12/17
- Re: cond*, Adam Porter, 2023/12/18
- Re: cond*, Richard Stallman, 2023/12/20
- Re: Instead of pcase, Richard Stallman, 2023/12/15
- Re: Instead of pcase, Adam Porter, 2023/12/16
- Re: Instead of pcase, Richard Stallman, 2023/12/19
- Re: Instead of pcase, Adam Porter, 2023/12/20