[alexandria-devel] Re: Review cycle 2: SWITCH, ESCWITCH, and CSWITCH

Nikodemus Siivola nikodemus at random-state.net
Sun Jun 8 22:13:11 UTC 2008


Ok. Here's my take in addressing the issues. I am not 100% happy with
the docstrings, but can't seem to do better right now. If someone else
feels up to it, input much appreciated.

Notable differences aside from the docstrings:

1. :TEST and :KEY syntax:

   (switch (foo :test test)
    (bar :bar))

   means to test with (FUNCALL TEST #:VALUE BAR), not (TEST #:VALUE BAR).

2. NIL as :KEY is the same as identity, as usual.

I additionally considered getting rid of T as a special clause marker,
but I suppose paralleling CASE &co makes sense. I adjusted the tests
to the new syntax, but more tests still need to be added.

As for the fallthrough/multiple keys issue: something like this can be done:

 (switch (foo :test (lambda (x y) (member x y :test #'equal)))
   ('("foo" "bar") ...)
   (...))

but it is ugly as hell. Not sure about what to do. Re. expanding into
COND: I think the API is the important bit. If we are able to figure
out that something else is more efficient, then we can expand into
something else -- COND is an implementation detail.

Here are the new (proposed) docstrings:

macro switch (&whole whole (keyform &key (test #'eql) key) &body clauses)
  "Conditionally executes one of the clauses, and returns its values. KEYFORM
is first evaluated, and if KEY is given and non-null, it is used to extract a
comparison value from the result of evaluating KEYFORM.

Clauses are of the form:

  (CLAUSE-KEY &BODY CLAUSE-FORMS)

Each clause is tested in turn. The first clause for which

  (FUNCALL TEST COMPARISON-VALUE CLAUSE-KEY)

evaluates to true has its CLAUSE-FORMS executed as an implicit PROGN, and the
values returned. No further clauses are executed.

If no clause matches, and the final clause has the symbol OTHERWISE or T as
its CLAUSE-KEY, it is executed. If no OTHERWISE clause exists, NIL is
returned.

To use T as a regular CLAUSE-KEY, quote it:

  (switch (foo)
    ('t 1)
    (t  0))    ; evaluates to 1 if FOO evaluates to T, and 0 otherwise."

macro eswitch (&whole whole (keyform &key (test #'eql) key) &body clauses)
  "Conditionally executes one of the clauses, and returns its values. KEYFORM
is first evaluated, and if KEY is given and non-null, it is used to extract a
comparison value from the result of evaluating KEYFORM.

Clauses are of the form:

  (CLAUSE-KEY &BODY CLAUSE-FORMS)

Each clause is tested in turn. The first clause for which

  (FUNCALL TEST COMPARISON-VALUE CLAUSE-KEY)

evaluates to true has its CLAUSE-FORMS executed as an implicit PROGN, and the
values returned. No further clauses are executed.

If no clause matches, an error is signalled."

macro cswitch (&whole whole (keyform &key (test #'eql) key) &body clauses)
  "Conditionally executes one of the clauses, and returns its values. KEYFORM
is first evaluated, and if KEY is given and non-null, it is used to extract a
comparison value from the result of evaluating KEYFORM.

Clauses are of the form:

  (CLAUSE-KEY &BODY CLAUSE-FORMS)

Each clause is tested in turn. The first clause for which

  (FUNCALL TEST COMPARISON-VALUE CLAUSE-KEY)

evaluates to true has its CLAUSE-FORMS executed as an implicit PROGN, and the
values returned. No further clauses are executed.

If no clause matches, a continuable error is signalled."

Complete diff attached.

Cheers,

 -- Nikodemus
-------------- next part --------------
A non-text attachment was scrubbed...
Name: switch.patch
Type: application/octet-stream
Size: 8140 bytes
Desc: not available
URL: <https://mailman.common-lisp.net/pipermail/alexandria-devel/attachments/20080609/6629d84a/attachment.obj>


More information about the alexandria-devel mailing list