As of 10.4
Where
appears to no longer reside in "GeneralUtilities'"
however I quite like its form so here is the <= 10.3 Definition
(v. similar to M.R.'s answer) that can be placed in an init.m
file.
SetAttributes[Where, HoldAll];
Where[s : Verbatim[Set][x_List, y_], rest___, expr_] :=
With[{x2 = Quiet[Replace[Hold[x], z_Symbol :> z_, {2}]]},
Replace[y, {HoldPattern @@ x2 :> Where[rest, expr], _ -> $Failed}]]
Where[expr_] := expr
Where[x_List, expr_] := With[x, expr]
Where[x_, expr_] := With[{x}, expr]
Where[x_, rest__, expr_] := Where[x, Where[rest, expr]]
Note that this slightly improves the previous "GeneralUtilities'"
definition by giving effect to a "multiple set" presumably originally intended by the first Where[s:Verbatim[Set] ...
definition:
Where[
{x, y} = {1, 3 + x},
z = 2,
{x, y, z}]
(* {1, 3 + x, 2} *)
whereas
In 10.3.1
Needs["GeneralUtilities`"];
Where[
{x, y} = {1, 3 + x},
z = 2,
{x, y, z}]
(*
With::lvset: Local variable specification {{x,y}={1,3+x}} contains {x,y}={1,3+x}, which is an assignment to {x,y}; only assignments to symbols are allowed. >>
With[{{x, y} = {1, 3 + x}}, Where[z = 2, {x, y, z}]]
*)
Update - turns out Where
can (if rarely) let a few bullets through; To collate:
First, some compression helping:
SetAttributes[CompressCode,HoldAll];
CompressCode[code_] := Compress@Hold@code;
UncompressCode[compressed_] := ReleaseHold@Uncompress@compressed;
UncompressCode[compressed_List] := Scan[UncompressCode, compressed];
i.e. with the compressed strings coming from CompressCode[(* defs *)]
with defs
being substituted by the code that defines Where
, LetL
and Let
(the latter two due to Leonid)
WhereDef = "1:eJytVNtOhDAQZUFdo9kH/QMTv8A/wFt8MEZ3E/e5SMk2Foq0TcCvt9NSunRhZY0vE2jPnDlnOu1VwpbZLAgCfqTCE6NpNoe/SxXuWF4yWaQPdVlhzgkrshD2FiqssIiFqEgihdo6VivrDVaoecsSU2rAZwZ8jylqcJpFsNbBDQRyXpEQuCq4lqKXjapTFd5xlSBBch4ZruGs2iQA9y1Fxac29Ez4CLzJgh58FwX5ypEwwAsLfJGUrvCXxMXHgH5Iwqpfg+ywuSZi4xru9LXeOPzUN87LmyTKcWTrLHFJkSrcO7LWv+Y5B5Ck2DZ80Py336sTqN7kCaNjCZ6fngOizyv0NLZtDne9DmoE7rgsaaO3wZYV0LakQ5lJs8fjWt5VAm5PsBZ2/YgItfW8wZwF+wdz5GC96h5p+AvpgXM7abgM6X/omnJBDpz1KeKmPBHTxLnbu7DAP95cN3ZbV23PLOoPeCl+APfNJQs=";
LetLDef = "1:eJzNk9tOAkEMhhfxFBGjvoGPgkiiCTGGNXpdoAsTygzOzBJ4ezs7e3APuMErbybtTvu3/ab7MFWTqBMEgTnl41nRPLp03j0fQ7XeqFjOR7uNRmOEkj7SBQwJQQ+IkrQx2nF04q76fIRoB9ZqMY0tZ2X35iLV5yQf2/WxXvPOOXtpYfciI6XXYLlcRTzxhLGFN4kJw1s2BnoRr1Fa8wbWopaVhMB5Z3w8EshV1S3L3bgkNQP6AC1gSmjKYqFLDBVtsfxd5Gx4AiGF3UfdDMk7LHjSJyTY47w8lRdxcNLWzTnbwLgX6RTXbj5yVwxly0ivPLhMrpd2nvp1QdcGLU3j2NU4zXHJIL30uepAXeedoIa3nwmH+BWjnGFjPe+q2aoskRifwi591IHtq6+NQ1FZtkSlLF5bvQJxDid/vdEWKAZWy3CcZIUK5hUaQX07f3J1N8hTVIAU39srdNorLBHmrU98oJWiWgO9TPyYfhv+1z/3a0HQoRU7bsD/sXwtmOub+Nsu5ITyyRPjNSb6BgoRTRw=";
LetDef = "1:eJzVVslu2zAQlZduaXto/6Cf4qQJ2iIpUjtNzrQ5ioXQlCpRQfz35XA1aUqyAaNAL4REcRa+92ZGX5blPB9lWdZM5fKtZDR/j2+f5XJRbqqy5fTypaqhaYqS52P89lEuCxAzIepi2Qr56UzuVKQWd+saCG3eGFczxrTFmbb4Coxsgfo9b6P30PCWCAE1bzAplme4/Uku54zwp58tYwv40wJfwb7FRD7X60bbvLI2+hy+zqqKbdU9f5QFzyfWfg4VI9YhpnVDqu+cwotMVUHzVi5XLV8JB8Fr7Q449eAtWCkKfNNbGPGqqBsRnRi7E+jE3D5kwL1dF40wQKiwSM28ZRAA6cySEKbhiE8V8anRvueJJtF4daFvJYcWeuMryF9DMrY4XjAgtRSGMrkGbcpAdEjLx1FYREaB0ibWwR159GKzJrnHHdO4h3pJRLFJSjMWFesQVUp8I8sTpmU+evwwkczmqTw5OXep9pyVq6dIEvjwUIi1PtVXq4Y0bY933ala5yV0PlC9DhGH5eUzYS0ROwVkKsrSjLgk9dsNlsst280tLd5lhJ3Z7Ow8u4oInGEYUj82R3UdNFqWdBsTOLWhGIgEfRgnsnW3TNw5ukfgfACirgQTMSP5pUnwDgczG+9nFgiyn9fjeOjr/jEcskTESUhOZkFhdVAWzXaTThcHw01JZaEkhCNgU6UqLTVVNYyRWbII+4cI7QMrYHzSybjLIhgW1PHhMLYYeow6K/ldhp2P00JN5kOllyRNBjq4x/9TiQ0UytSA1RfrABdeiz3pql+aGuCXb9y/OZjuT8MR+EEuM4b+5Zh9NtNGRRlojIEWovHvLhsIy9AXjprARsVNDRtH/WArOwDDk42Ooyj/n/4kOs65C+3/UpxqiqoHZOMvo9XPxg==";
and now some defining:
UncompressCode@{WhereDef, LetLDef, LetDef}
we get the following syntactic variants (ordered by rough chronology) that all do the same thing:
With[{x = 1}, With[{y = x}, {x, y}]]
LetL[{x = 1, y = x}, {x, y}]
Where[x = 1, y = x, {x, y}]
Let[x = 1, y = x, {x, y}]
With[{x = 1}, {y = x}, {x, y}]
(* {1,1} *)
(* For all of the above*)
Where
and Let
also permit threaded List Assignments
Where[{x, y} = {1, 1}, {x, y}]
Let[{x, y} = {1, 1}, {x, y}]
(* {1,1} *)
(* For both*)
while noting users' potential scoping oversights
Where[{x, y} = {1, x}, {x, y}]
Let[{x, y} = {1, x}, {x, y}]
(* {1,x} *)
(* For both*)
(but which I suspect differ in more involved scenarios that suggest Let
is more robust)
I think it is important to have a succinct, natural, robust and efficient version of this scoping construct given its ubiquity. My vote would be for Let
based on how it satisfies the first two qualities while seeming to do likewise for the latter two.
With
that binds variables sequentially" and "Iterative constants and variables definitions." $\endgroup$