Previous page Table of Contents Next page
Destructuring occurs when an invocation of a constructor appears in a left-hand-side position. The object on the right-hand-side must be the type of object that the constructor would construct. The object is disassembled into its component parts and each argument of the constructor is placed on the left-hand side with the corresponding part as its right-hand side. Destructuring is allowed when and only when a destructuring macro corresponding to the constructor has been defined. The name of the destructuring macro is the name of the constructor suffixed by ":=". For example, corresponding to the list constructor is the list:= destructuring macro which expands into assignments of parts of the list to its arguments.
Destructuring is allowed in assignment, as explained in the Assignment section above. It is also allowed in the def statement and in parameter-lists. This is implemented by expanding the destructuring macro as if the containing expression was an assignment, then rewriting the resulting P-expressions as definitions rather than assignments.
In a def statement, the last argument to the destructuring macro is the right-hand side. In a parameter-list, the last argument to the destructuring macro is a place-holder variable that will receive the corresponding argument to the function. The type restriction of the place-holder defaults to the type-specifier of the first definition in the expansion of the destructuring macro whose right-hand side is the place-holder, rather than defaulting to $anything.
The expansion of the destructuring macro must be an assignment, a collation, or a scopation. The sub-expressions of a collation or scopation can be assignments, additional levels of collation or scopation, and other expressions. Each assignment within the expansion whose left-hand side is not defined in a scope inside the expansion is rewritten as a definition of that variable. This definition appears in the outer scope, not in any scopation that is part of the expansion; there is no built-in way to do that special scoping in source code but it is easily done in P-expressions.
Examples of destructuring in the def statement:
def list(a, b, c) = dThis first translates into a macro call
list:=(a, b, c, d)which expands into
block def temp is list = d a := temp[0] b := temp[1] c := temp[2]which the def macro rewrites as the final expansion
block def temp is list = d def a = temp[0] def b = temp[1] def c = temp[2]except the definitions of a, b, and c are not scoped in their immediately containing block but instead in the scope where the def appeared.
Destructuring can be nested:
def list(a, list(b, c)) = f(y)turns into
block def temp1 is list = f(y) def a = temp1[0] block def temp2 is list = temp1[1] def b = temp2[0] def c = temp2[1]
Example of destructuring in a parameter list:
defun f(list(a, b), c) a + b + cexpands the macro call
list:=(a, b, arg1)into
block def temp is list = arg1 a := temp[0] b := temp[1]which the parameter-list parser and the defun statement rewrite as
defun f(arg1 is list, c) def temp is list = arg1 def a = temp[0] def b = temp[1] a + b + c
The same example can be written more concisely using the prefix [ operator:
defun f([a, b], c) a + b + c
Here is how to define the list destructor macro:
defmacro list:= ( ?arg & , ^^ ) => def rhs = last(arg) def assignments = for i from 0 below arg.length - 1, a in arg collect `?a := temp[?i]` `block def temp is list = ?rhs { ?assignments & ^ }*`
Previous page Table of Contents Next page