Function Repository Resource:

LetScope

Source Notebook

Scoped let expression with pattern variables

Contributed by: Nik Murzin

ResourceFunction["LetScope"][set,expr]

binds pattern variables in set to substitute in expr.

ResourceFunction["LetScope"][set1,set2,,expr]

uses multiple nested set patterns.

Details

ResourceFunction["LetScope"] emulates classic let construction in programming languages by providing locally scoped variable bindings. It allows destructuring and substitutions using pattern variables within expressions, ensuring encapsulation.
Examples featuring let-like syntax:
ResourceFunction["LetScope"] bindings can use only Set or LeftArrow (←) heads for pattern matching.
Unmatched pattern variables are bound to Sequence[].
ResourceFunction["LetScope"] has the HoldAllComplete attribute.

Examples

Basic Examples (3) 

Pattern match and use the pattern variable:

In[1]:=
ResourceFunction["LetScope"][x_ = 1, x + 1]
Out[1]=

Use any pattern:

In[2]:=
ResourceFunction["LetScope"][f[x_, g[y_, z_ : 4]] = f[2, g[3]], x y z]
Out[2]=

Nest multiple patterns:

In[3]:=
ResourceFunction["LetScope"][f[x_] = f[10], g[a_, b_] = g[2 x, x + 1], {x, a, b}]
Out[3]=

Scope (7) 

Use LeftArrow (←) as an alternative symbol for let bindings:

In[4]:=
ResourceFunction["LetScope"][x_ \[LeftArrow] 1, x + 1]
Out[4]=

Unmatched variables bind to Sequence[]:

In[5]:=
ResourceFunction["LetScope"][f[x_] = 1, x]
Out[5]=

Pattern variables inside Verbatim are ignored:

In[6]:=
ResourceFunction["LetScope"][f[Verbatim[x_], y_] = f[x_, 2], {x, y}]
Out[6]=

Unevaluated can be used to delay evaluation:

In[7]:=
ResourceFunction["LetScope"][z : x_ + y_ = Unevaluated[10 + 20], Hold[x, y, z]]
Out[7]=

Variable names can be reused:

In[8]:=
ResourceFunction["LetScope"][f[x_] = f[10], g[x_] = g[x + 20], x]
Out[8]=

Use intermediate non-binding expressions to evaluate in between:

In[9]:=
ResourceFunction["LetScope"][f[x_] = f[10], Echo[x], g[x_] = g[x + 20],
  x]
Out[9]=

Because LetScope is HoldAllComplete, Sequence can be returned:

In[10]:=
ResourceFunction["LetScope"][x_ = 1, y_ = x + 1, Sequence[x, y]]
Out[10]=

Applications (3) 

Use LetScope as a scope with support for binding to multiple variables:

In[11]:=
ResourceFunction["LetScope"][{x_, y_} = RandomInteger[10, 2], {x, y}]
Out[11]=

Use LetScope for destructuring any expression with pattern matching:

In[12]:=
ResourceFunction["LetScope"][Tree[root_, _] = \!\(\*
GraphicsBox[
NamespaceBox["Trees",
DynamicModuleBox[{Typeset`tree = HoldComplete[
Tree[1, {
Tree[3, {
Tree[4, None]}], 
Tree[2, None], 
Tree[5, None]}]]}, {
{Hue[0.6, 0.7, 0.7], Opacity[0.7], CapForm["Round"], Arrowheads[{{Medium, 0.8}}], 
StyleBox[{
{LightDarkSwitched[
RGBColor[
             0.32313725490196077`, 0.6964705882352942, 0.5741176470588235]], AbsoluteThickness[1], LineBox[{{0.8164965809277261, 1.6303803727964836`}, {0., 0.8151901863982418}}]}, 
{LightDarkSwitched[
RGBColor[
             0.32313725490196077`, 0.6964705882352942, 0.5741176470588235]], AbsoluteThickness[1], LineBox[{{0.8164965809277261, 1.6303803727964836`}, {
             0.8164965809277261, 0.8151901863982418}}]}, 
{LightDarkSwitched[
RGBColor[
             0.32313725490196077`, 0.6964705882352942, 0.5741176470588235]], AbsoluteThickness[1], LineBox[{{0.8164965809277261, 1.6303803727964836`}, {
             1.6329931618554523`, 0.8151901863982418}}]}, 
{LightDarkSwitched[
RGBColor[
             0.32313725490196077`, 0.6964705882352942, 0.5741176470588235]], AbsoluteThickness[1], LineBox[{{0., 0.8151901863982418}, {0., 0.}}]}},
FontFamily->"Arial"]}, 
{Hue[0.6, 0.5, 1.], EdgeForm[{GrayLevel[0], Opacity[0.7]}], 
StyleBox[{InsetBox[
FrameBox["1",
Background->Directive[
LightDarkSwitched[
RGBColor[0.9403921568627451, 0.9870588235294118, 0.971764705882353]], Opacity[1]],
BaseStyle->Directive[
LightDarkSwitched[
GrayLevel[0]], FontFamily -> "Arial"],
FrameMargins->{{2, 2}, {1, 1}},
FrameStyle->Directive[
LightDarkSwitched[
RGBColor[
                0.32313725490196077`, 0.6964705882352942, 0.5741176470588235]], 
AbsoluteThickness[1], 
Opacity[1]],
ImageSize->Automatic,
RoundingRadius->4,
StripOnInput->False], {0.8164965809277261, 1.6303803727964836}], InsetBox[
FrameBox["3",
Background->Directive[
LightDarkSwitched[
RGBColor[0.9403921568627451, 0.9870588235294118, 0.971764705882353]], Opacity[1]],
BaseStyle->Directive[
LightDarkSwitched[
GrayLevel[0]], FontFamily -> "Arial"],
FrameMargins->{{2, 2}, {1, 1}},
FrameStyle->Directive[
LightDarkSwitched[
RGBColor[
                0.32313725490196077`, 0.6964705882352942, 0.5741176470588235]], 
AbsoluteThickness[1], 
Opacity[1]],
ImageSize->Automatic,
RoundingRadius->4,
StripOnInput->False], {0., 0.8151901863982418}], InsetBox[
FrameBox["4",
Background->Directive[
LightDarkSwitched[
RGBColor[0.9403921568627451, 0.9870588235294118, 0.971764705882353]], Opacity[1]],
BaseStyle->Directive[
LightDarkSwitched[
GrayLevel[0]], FontFamily -> "Arial"],
FrameMargins->{{2, 2}, {1, 1}},
FrameStyle->Directive[
LightDarkSwitched[
RGBColor[
                0.32313725490196077`, 0.6964705882352942, 0.5741176470588235]], 
AbsoluteThickness[1], 
Opacity[1]],
ImageSize->Automatic,
RoundingRadius->0,
StripOnInput->False], {0., 0.}], InsetBox[
FrameBox["2",
Background->Directive[
LightDarkSwitched[
RGBColor[0.9403921568627451, 0.9870588235294118, 0.971764705882353]], Opacity[1]],
BaseStyle->Directive[
LightDarkSwitched[
GrayLevel[0]], FontFamily -> "Arial"],
FrameMargins->{{2, 2}, {1, 1}},
FrameStyle->Directive[
LightDarkSwitched[
RGBColor[
                0.32313725490196077`, 0.6964705882352942, 0.5741176470588235]], 
AbsoluteThickness[1], 
Opacity[1]],
ImageSize->Automatic,
RoundingRadius->0,
StripOnInput->False], {0.8164965809277261, 0.8151901863982418}], InsetBox[
FrameBox["5",
Background->Directive[
LightDarkSwitched[
RGBColor[0.9403921568627451, 0.9870588235294118, 0.971764705882353]], Opacity[1]],
BaseStyle->Directive[
LightDarkSwitched[
GrayLevel[0]], FontFamily -> "Arial"],
FrameMargins->{{2, 2}, {1, 1}},
FrameStyle->Directive[
LightDarkSwitched[
RGBColor[
                0.32313725490196077`, 0.6964705882352942, 0.5741176470588235]], 
AbsoluteThickness[1], 
Opacity[1]],
ImageSize->Automatic,
RoundingRadius->0,
StripOnInput->False], {1.6329931618554523, 0.8151901863982418}]},
FontFamily->"Arial"]}}]],
AlignmentPoint->Center,
Axes->False,
AxesLabel->None,
AxesOrigin->Automatic,
AxesStyle->{},
Background->None,
BaseStyle->{FontFamily -> "Arial"},
BaselinePosition->Automatic,
ContentSelectable->Automatic,
DefaultBaseStyle->"TreeGraphics",
DisplayFunction->Identity,
Epilog->{},
FormatType->StandardForm,
Frame->False,
FrameLabel->None,
FrameStyle->{},
FrameTicks->None,
FrameTicksStyle->{},
GridLines->None,
GridLinesStyle->{},
ImageMargins->0.,
ImagePadding->All,
LabelStyle->{},
PlotLabel->None,
PlotRange->All,
PlotRangeClipping->False,
PlotRangePadding->Automatic,
PlotRegion->Automatic,
Prolog->{},
RotateLabel->True,
Ticks->Automatic,
TicksStyle->{}]\), root]
Out[12]=
In[13]:=
ResourceFunction["LetScope"][
 KeyValuePattern[b -> value_] = <|a -> 10, b -> 20|>, value]
Out[13]=

Compound nested scope with dependencies:

In[14]:=
ResourceFunction["LetScope"][
 x_ = 10,
 y_ = x + 1,
 {a_, b_} = x + y RandomReal[1, 2],
 a/b
 ]
Out[14]=

Properties and Relations (3) 

For a single binding LetScope is equivalent to a substitution with Replace:

In[15]:=
ResourceFunction["LetScope"][f[x_] = f[10], x + 20]
Out[15]=
In[16]:=
Replace[f[10], f[x_] :> x + 20]
Out[16]=

For a single variable left-hand-side LetScope is similar to ResourceFunction["CompoundScope"]:

In[17]:=
ResourceFunction["LetScope"][x_ = 10, y_ = x + 1, z_ = 2 y, z]
Out[17]=
In[18]:=
ResourceFunction["CompoundScope"][{x = 10, y = x + 1, z = 2 y}, z]
Out[18]=

LetScope effectively applies binding rules (similar to ResourceFunction["PatternBindings"]) to consequent expressions:

In[19]:=
rules = ResourceFunction["PatternBindings"][f[10, 20], f[x_, y_]]
Out[19]=
In[20]:=
ResourceFunction["LetScope"][f[x_, y_] = f[10, 20], x + y]
Out[20]=
In[21]:=
x + y /. rules
Out[21]=

Requirements

Wolfram Language 14.0 (January 2024) or above

Version History

  • 1.0.0 – 21 May 2025

Related Resources

License Information