6
$\begingroup$

This is a demo code

r = {1, 2, 3};

fs1 = Table[
    Function[t, 
        Evaluate@{"arg" -> t, "diff" -> f[r[[i]], t]}],    
      {i, 3}]; 

fs2 = Table[
    Function[t, 
        Evaluate@<|"arg" -> t, "diff" -> f[r[[i]], t]|>],    
      {i, 3}]; 

fs1[[2]]["hi"] outputs {"arg" -> "hi", "diff" -> f[2, "hi"]}, however fs2[[2]]["hi"] outputs <|"arg" -> t, "diff" -> f[2, t]|>

$\endgroup$
7
  • $\begingroup$ Probably related to the fact that an evaluated association is 'constructed' and atomic. See asso = <|"arg" -> t, "diff" -> 2 t|>; asso /. t -> 1 for example. That is not enough to explain why Function[t, Evaluate@<|1 -> t|>]@2 does not work though. $\endgroup$
    – Kuba
    Aug 13, 2021 at 8:51
  • $\begingroup$ Attributes[Association] contains HoldAllComplete. $\endgroup$
    – tueda
    Aug 13, 2021 at 8:52
  • $\begingroup$ @tueda yes but Function[t, Evaluate@HoldComplete[t]]@2 still injects the argument. $\endgroup$
    – Kuba
    Aug 13, 2021 at 8:53
  • 2
    $\begingroup$ Related: Evaluated vs. unevaluated Assocation, Pattern matching Association in rules $\endgroup$
    – WReach
    Aug 14, 2021 at 20:56
  • 1
    $\begingroup$ Not a direct answer, but you can use Table[With[{ri = r[[i]]}, Function[t, <|"arg" -> t, "diff" -> f[ri, t]|>]], {i, 3}] to fix this. $\endgroup$ Aug 16, 2021 at 17:05

2 Answers 2

3
$\begingroup$

The issue is that Association is atomic. Since Association is also HoldAllComplete, let's examine an atomic object that is not HoldAllComplete.

Clear[x]
g = Graph[{x->1}];
g //AtomQ
g //InputForm

True

Graph[{x, 1}, {DirectedEdge[x, 1]}]

Now, give x a value:

x = 2;
g //InputForm

Graph[{x, 1}, {DirectedEdge[x, 1]}]

Notice that x has not changed inside of the Graph object. This is exactly what is happening in your example.

$\endgroup$
2
  • 1
    $\begingroup$ I agree with the diagnosis but SparseArray is atomic as well yet: Function[t, Evaluate@SparseArray[{i_, i_} -> t, 3]][2] // InputForm. $\endgroup$
    – Kuba
    Aug 17, 2021 at 6:09
  • 1
    $\begingroup$ To me it is a confusing design to have atomic "objects" which do not look like there are atomic (in the sense that they have no subparts). $\endgroup$ Aug 17, 2021 at 7:55
0
$\begingroup$

It must be clearly a bug, because (ToExpression@ToString@fs2[[2]])[hi] works correctly. Moreover,

On[Assert];
Assert[fs2[[2]] == Function[t, <|"arg" -> t, "diff" -> f[2, t]|>]]

gives:

Assert::asrttf: Assertion test fs2[[2]]==Function[t,Association[arg->t,diff->f[2,t]]] evaluated to Function[t,<|arg->t,diff->f[2,t]|>]==Function[t,Association[arg->t,diff->f[2,t]]] 
that is neither True nor False.

while Assert[fs1[[2]] == Function[t, {"arg" -> t, "diff" -> f[2, t]}]] succeedes.

Also it is definitely Not an issue with atomicity:

fs1 = Table[Function[t, {"arg" -> t, "diff" -> f[r[[i]], t]}], {i, 1, 3}]
fs2 = Table[Function[t, <|"arg" -> t, "diff" -> f[r[[i]], t]|>], {i, 1, 3}]

fs1[[2]][hi]
Part::pkspec1: The expression i cannot be used as a part specification.
{"arg" -> hi, "diff" -> f[{1, 2, 3}[[i]], hi]}

fs2[[2]][hi]
Part::pkspec1: The expression i cannot be used as a part specification.
<|"arg" -> hi, "diff" -> f[{1, 2, 3}[[i]], hi]|>

fs1[[2]] // AtomQ
False
fs2[[2]] // AtomQ
False

w/o Evaluate or if you replace r[[i]] with r[[2]] both fs1 and fs2 succeede to replace t with hi.

$\endgroup$
3
  • 1
    $\begingroup$ With ToString/ToExpression the association is destroyed and constructed again and with the latter stage it can have values injected inside. $\endgroup$
    – Kuba
    Aug 17, 2021 at 6:07
  • $\begingroup$ @Kuba no, it is not injected, because if you just type the output of Evaluate by hand: fs3 ={Function[t,<|"arg"->t,"diff"->f[1,t]|>],Function[t,<|"arg"->t,"diff"->f[2,t]|>],Function[t,<|"arg"->t,"diff"->f[3,t]|>]} and then call it fs3[[2]][hi] you will get the correct return value <|arg->hi,diff->f[2,hi]|> . So it's obviously someting wrong is going on inside the VM of WL or whatever they call it. $\endgroup$
    – wolfRAMM
    Aug 17, 2021 at 6:44
  • 1
    $\begingroup$ Your 'by hand' example, without Evaluate has associations before construction, and they are not constructed before function injects t because Fuction is HoldAll. Then they are constructed and atomic but t is already replaced. This is confusing because constructed and not associations look the same as explained in a topic linked in comments. What I meant earlier is that associations constructed (forced by Evaluate) will be destroyed with ToString and ToExpression will create a function again, but without Evaluate so it will indeed 'work' $\endgroup$
    – Kuba
    Aug 17, 2021 at 7:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.