Mathematica Destructuring

Leonid provides a nice method for doing this within "pure functions" but I think it should be pointed out that the common method for doing this is pattern matching.

I argue that destructuring is the foundational use of pattern matching in Mathematica.

Every replacement pattern, be it an explicit rule (:>, ->) or part of a definition (:=, =), that uses a named pattern on the left-hand side that does not match the entire expression or argument is doing destructuring.

Applied to your specific example:

f[a_, {i_, j_}] := a == 0 || Abs[i - j] <= 1

triDiagonalQ[mat_] := And @@ Flatten @ MapIndexed[f, mat, {2}]

Or:

triDiagonalQ[mat_] := And @@ Flatten @
   MapIndexed[#2 /. {i_, j_} :> # == 0 || Abs[i - j] <= 1 &, mat, {2}]

The second example is almost exactly what you asked for: "with a {i, j} <- #2 somewhere"
It's just turned around: #2 /. {i_, j_}.

This destructuring is common in Mathematica programming for experienced users.

Among many examples:

Here I use it to separate a + b + c:

(a + b + c) /. head_[body___] :> {head, body}  (* Out= {Plus, a, b, c} *)

Here Leonid uses it in a recursive function. ({x_, y_List})

Szabolcs uses it in iter, also recursive.

Heike uses it with /. in PerforatePolygons and with := in torn.

Here I used it simply in formula but also in MakeBoxes[defer[args__], fmt_] := where the parameter pattern defer[args__] serves to match the literal head defer while also destructuring.

In withOptions it is used both in the function definition and in the replacement rule.

The "injector pattern" is a form of destructing.

I also used it in inside, withTaggedMsg, pwSplit, dPcore etc.


Another, simpler form of destructuring exists in the form of Set and List ({}). A matching List structure on the left and right sides of = will assign values part-wise.

{{a, b}, c, {d}} = {{1, 2}, 3, {4}};

{a, b, c, d}
 {1, 2, 3, 4}

This is used e.g. in the first LUDecomposition example, and R.M uses it here.


You can use macros / code generation to be able to use the syntax you like. Here is one possibility:

ClearAll[withLiteralIndices];
SetAttributes[withLiteralIndices, HoldAll];
withLiteralIndices[code_, inds : {__Symbol}] :=
  Block[inds,
     Unevaluated[code] /.
       MapIndexed[
          Function[{i, pos}, pos /. {p_} :> (i :> #2[[p]])], 
          inds
       ]
  ]

Now, you can pretty much literally use the code you would like to use:

withLiteralIndices[
  triDiagonalQ[mat_] := 
     MapIndexed[#1 == 0 || Abs[i - j] <= 1 &, mat, {2}] // Flatten // And @@ # &,
  {i, j}
]

When you look at the resulting definition, you can see that this is entirely equivalent to hand-written code using slots:

?triDiagonalQ

(*
  Global`triDiagonalQ

  triDiagonalQ[mat_]:=
    (And@@#1&)[Flatten[MapIndexed[#1==0||Abs[#2[[1]]-#2[[2]]]<=1&,mat,{2}]]]
*)

EDIT

Here is a simpler and perhaps more elegant version of the macro, which uses the injector pattern more explicitly:

ClearAll[withLiteralIndices];
SetAttributes[withLiteralIndices, HoldAll];
withLiteralIndices[code_, inds : {__Symbol}] :=
  Block[inds,
     Unevaluated[code] /.
        Replace[
          Range[Length[inds]],
          p_ :> (inds[[p]] :> #2[[p]]),
          {1}
        ]
  ]

I think Mr. Wizard provided a very thorough answer to the question. I would however like to add a slight example of wrapping this up nicely in a format similar to Function[] but using destructuring:

SetAttributes[dFunction, HoldAll]
dFunction[pattern_, body_][arg___] /;MatchQ[{arg}, pattern] := {arg} /. pattern :> body

This then allows you to have nice syntax for an anonymous destructuring function using pattern matching:

triDiagonalQ3[mat_] := And @@ Flatten@ MapIndexed[
   dFunction[{v_, {i_, j_}}, v == 0 || Abs[i - j] <= 1], mat, {2}]

Syntax

As to the "clumsiness" of this syntax, I have to agree with Mr. Wizard that it's not as nicely looking as replacement rules, but then again I don't particularly like Function[x,x^2] either, and much prefer the aesthetics of the built-in shorthand which looks like x ↦ x^2(entered via EscfnEsc). The above code can be made to use a similar shorthand rather simply by setting RightArrowBar = dFunction; which allows the definition to look like :

{v_, {i_, j_}}  ⇥  (v == 0 || Abs[i - j] <= 1)

And if one is afraid of using the build-in undefined infix operators, you could of course define a custom symbol for it which doesn't lay claim on RightArrowBar. Personally I find this appearance of an anonymous replacement rule based function to be quite nice.

The value of pattern matching

As was discussed in comments, one of the interesting behaviors of this construct is that it closely mirrors the behavior of a function defined through pattern matching. if f[x_Integer]:=... is defined and called with arguments not matching the pattern the function remains unevaluated. For instance f[2.3] will return itself. The same behavior can be observed with dFunction where for instance dFunction[{x_Integer}, x][3.2] will return itself unevaluated.

Sadly due to the nature of SubValues, it's not possible to fully simulate pattern matching functions in an anonymous form using this method, since attributes such as HoldAll cannot be implemented. I do belive that this could be implimented using devious hacks similar to the method employed here https://mathematica.stackexchange.com/a/5458/1194 by Leonid Shifrin. However I fear that even if I did mange to implement it I would never use the result for fear of unexpected behavior, while I quite like the simplicity of my current dFunction.