[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Destructuring lambdas in T?

   Is there any destructuring lambda in T (or a clean way to simulate one)?

   Why not hide define-destructure in a macro?

       (define-with-pattern (foo (x y) z) ...)
       => (define (foo . <generated-symbol>)
           (destructure ((((x y) z) <generated-symbol>)) ...)

    The major problem with this is that:

            (foo '(a b) 'c)
    and     (foo '(a b) 'c 'extra-argument)

    both return (a b c), whereas:

            (foo '(a b))   ; missing argument.

    returns (a b ()).  One would need to generate-symbol a symbol for each of
    foo's arguments, and destructure each of them individually.

Right.  You don't want to incur the overhead of converting every such
procedure into a lexpr, but it's trivial to adapt the code from
DESTRUCTURE so that it comes out looking like
  (define (foo g.1 z) (destructure (((x y) g.1)) ...)
So if you want the system to know that foo takes exactly two arguments,
the first of which may happen to be destructured, you got it.

However, I think it's a bad idea to make this the default.

Destructuring is quite handy for taking apart S-expressions, and it's
therefore an indispensable tool for macros.  I'd support changing the
syntax for the DEFINE-SYNTAX special form to make it completely
destructuring.  But apart from representing code, lists aren't used,
in most of the T code I've seen, to represent data structures of any
complexity.  "Flat" lists are still very useful for implementing stacks,
queues, and simple sets, but otherwise, to repeat a bad pun, T is a
fairly listless language, and I think it's because T supports vectors,
structures, closures, and other things that some old Lisps didn't have
(and were therefore forced to use lists to represent).  (This harks
back to some T-discussion mail from 1982.)  If you try to generalize
DESTRUCTURE to other data types, you might wind up trying things like
(destructure ((#(a b) c)) ...), which means that a should be bound
to (vref c 0), and b to (vref c 1).  In other words, the syntax of
the "left-hand side" actually indicates the data type of the "right-hand
side," if we make the analogy from (destructure (((a b) c)) ...).

You could do the same for LAMBDA itself: (lambda #(a b) ...) might
denote a procedure that you apply to a vector of two elements, just
as (lambda (a b) ...) is applied to a list of two elements.

Since so few data types in T have external notation like this, it begins
to feel awkward.  Moreover, if you're talking about calling a procedure
of two arguments, you normally don't care whether they're in a list,
a vector, or just sitting in some registers.  The notion that there
should be a meeting of the data structures and the semantics of the
language (e.g., EVAL) is not the heart of T.