1

I want to construct an association that some of the Values are constructed from other parts of the Values, for the simplest example

assoc=<|
    "a"->1,
    "b"->assoc["a"]
|>;

The output I desired is

<|a->1,b->1|>

but to get this result we need to evaluate the Set twice

assoc=<|
    "a"->1,
    "b"->assoc["a"]
|>;

and the first evaluation returns

<|a->1,b->assoc[a]|>

I believe this is related to the inner construction of association, see https://mathematica.stackexchange.com/a/128456/86893.

Notice that this feature is different from the sequential CompoundExpression[a=1,b=a];

Is there some trick to bypass this problem?


The real example is much complicated than this example. What I want is a method similar to the "in-place evaluation trick". I have tried RuleCondition but failed for this example.

The method I currently use is like

assoc=<|
    "a"->1
|>
assoc=<|
    assoc,
    "b"->assoc["a"]
|>

As you can see, for more complicated situations this get harder to read and organize.

Lacia
  • 2,253
  • 3
  • 19

2 Answers2

5

There is a function on the FunctionRepository that does what you want: AssociationTemplate

The basic use is:

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]
   |>
  ]
JuanG970
  • 456
  • 2
  • 5
5

@Juanito970's answer has reminded me of the injection pattern. To my understanding, the injection pattern is just like providing a template of more complicated code.

For the toy example, we can try

assoc=1/.x_:><| 
    "a"->x,
    "b"->x
|>
(*<|"a" -> 1, "b" -> 1|>*)
Lacia
  • 2,253
  • 3
  • 19