Function Repository Resource:

AssociationTemplate

Source Notebook

Define a data structure that can refer to its own values to compute new ones

Contributed by: Sjoerd Smit

ResourceFunction["AssociationTemplate"][assoc]

creates an Association-like object in which RuleDelayed (⧴) values can be combined with TemplateSlots and Functions to create values that depend on other keys.

Details

Self-referential values have to be specified using RuleDelayed. Optionally, TemplateObject, TemplateExpression or StringTemplate (which evaluates to a TemplateObject) can be wrapped around the expressions.
Self-referential values defined with Function should use Slot to refer to other keys in the ResourceFunction["AssociationTemplate"], e.g. keyFunction[#a+#b].
Strings such as those used by StringTemplate (e.g. keyfirst`a`then`b`) are also supported and will be automatically converted.
Only String keys are supported by ResourceFunction["AssociationTemplate"].
The dependencies between keys cannot be cyclical since that would result in an infinite loop. If a cyclical dependency is found among the keys, a Failure object will be returned.
When a ResourceFunction["AssociationTemplate"] is queried, the dependent keys necessary for resolving queried keys will each be evaluated at most once and the result will be cached. This is also true if multiple keys are queried simultaneously with Part or Values.
The following built-in functions can be used with ResourceFunction["AssociationTemplate"]: Normal, Keys, Values, Length, Part, Join, Append and Prepend.

Examples

Basic Examples (5) 

Define an AssociationTemplate in which the first key acts as a parameter for a computation:

In[1]:=
tAssoc = ResourceFunction["AssociationTemplate"][
  <|
   "a" -> 3,
   "int" :> Function[NIntegrate[Abs@Sin[#a x], {x, 0, 10}]],
   "title" :> "The integral of |Sin[`a` x]| on 0 <= x <= 10 is `int`",
   "plot" :> Plot[Abs@Sin[TemplateSlot["a"] x], {x, 0, 10}, PlotLabel -> Style[TemplateSlot["title"], Small], Filling -> Axis]
   |>
  ]
Out[1]=

Query a value:

In[2]:=
tAssoc["plot"]
Out[2]=

Use a two-argument query to temporarily override keys with new (non-templated) values. The second argument has to be an Association:

In[3]:=
tAssoc["plot", <|"a" -> 2|>]
Out[3]=

Query all keys and return the result as an Association:

In[4]:=
tAssoc[[All]]
Out[4]=

Use Append or Prepend to create a new AssociationTemplate with a different key value:

In[5]:=
newtAssoc = Append[tAssoc, "a" -> 1]
Out[5]=
In[6]:=
newtAssoc["plot"]
Out[6]=

Scope (3) 

AssociationTemplate can be used with the functions Length, Keys, Values and Normal:

In[7]:=
tAssoc = ResourceFunction["AssociationTemplate"][
   <|
    "a" -> 3,
    "int" :> Function[NIntegrate[Abs@Sin[#a x], {x, 0, 10}] ],
    "title" :> "The integral of |Sin[`a` x]| on 0 <= x <= 10 is `int`",
    "plot" :> Plot[Abs@Sin[TemplateSlot["a"] x], {x, 0, 10}, PlotLabel -> Style[TemplateSlot["title"], Small], Filling -> Axis]
    |>
   ];
In[8]:=
Length[tAssoc]
Out[8]=
In[9]:=
Keys[tAssoc]
Out[9]=
In[10]:=
Values[tAssoc]
Out[10]=

Normal will turn all templated values into a TemplateExpression or TemplateObject or leave them as a Function:

In[11]:=
Normal[tAssoc]
Out[11]=

Join two templates together:

In[12]:=
newtAssoc = Join[tAssoc, ResourceFunction[
   "AssociationTemplate"][<|"intSquared" :> TemplateSlot["int"]^2|>]]
Out[12]=
In[13]:=
newtAssoc[[{"int", "intSquared"}]]
Out[13]=

Properties and Relations (2) 

It is possible that some keys can return different values with each query:

In[14]:=
tAssoc = ResourceFunction["AssociationTemplate"][
   <|
    "a" :> RandomInteger[{1, 10}],
    "b" :> 2*TemplateSlot["a"] + Pi*RandomInteger[{1, 10}] ,
    "c" :> {TemplateSlot["a"], TemplateSlot["b"]}
    |>
   ];
In[15]:=
{tAssoc["a"], tAssoc["a"]}
Out[15]=

Within a single query, the values will be consistent and each key will be evaluated no more than once:

In[16]:=
tAssoc[[All]]
Out[16]=
In[17]:=
tAssoc[[{"a", "b", "c"}]]
Out[17]=
In[18]:=
Values[tAssoc]
Out[18]=

Possible Issues (1) 

AssociationTemplate will return a Failure object if cyclical dependencies are detected:

In[19]:=
ResourceFunction["AssociationTemplate"][<|"a" :> TemplateSlot["a"] |>]
Out[19]=
In[20]:=
ResourceFunction["AssociationTemplate"][<|"a" :> Function[#a] |>]
Out[20]=
In[21]:=
ResourceFunction["AssociationTemplate"][
 <|
  "a" :> TemplateSlot["b"],
  "b" :> TemplateSlot["a"] |>
 ]
Out[21]=

Publisher

Sjoerd Smit

Version History

  • 1.0.2 – 15 September 2023
  • 1.0.1 – 07 June 2021

Related Resources

License Information