6
$\begingroup$

Consider the following:

f = 2 # &
OwnValues[f]
g = f[#]/2 &
OwnValues[g]

Since Function has the HoldAll attribute, g expresses its own value in terms of f instead of in terms of the own value of f. This obviously matters, because if I change f then g will change. Doesn't this conflict with the lambda calculus motivation of Function, making WL's "pure' functions even more impure (from a functional programming perspective)? Finally, in this case, is there a preferred way to force the definition of g to be in terms of the own values of f? I suppose g = Evaluate[f[[1]]/2] & is possible ...

$\endgroup$
  • 1
    $\begingroup$ Without it in case of simplest functions like Function[x, x ] you would have to keep track whether x doesn't have a value outside. $\endgroup$ – Kuba Sep 15 '16 at 6:31
  • 1
    $\begingroup$ I guess the first part answers itself, together with mathematica.stackexchange.com/questions/64577/… . FP-style 'pure' functions have nothing to do with 'Function' seems to be the bottom line. $\endgroup$ – masterxilo Sep 17 '16 at 3:54
5
$\begingroup$

The first question is a bit abstruse for me so I'd like to leave it to someone more knowledgeable. As to the second question,

g = f[[1]]/2 & /. OwnValues[f]
g = With[{f = f}, f[[1]]/2 &]

are 2 common ways to handle the issue.

$\endgroup$
  • $\begingroup$ Use of With seems to be exactly what I was looking for. It avoids the problems that arise trying to use Evaluate. Thanks! $\endgroup$ – Alan Sep 15 '16 at 19:59
7
$\begingroup$

Because it couldn't possibly work if it weren't HoldAll ... There's so much code which is just plain invalid unless the argument is substituted in.

What about e.g.

Plus@@Table[i, {i, #}]&

? Just try what happens if you remove the & and let the innards evaluate.

It goes wrong in multiple ways.

In[1]:= Plus @@ Table[i, {i, #}]

During evaluation of In[1]:= Table::iterb: Iterator {i,#1} does not have appropriate bounds.

Out[1]= {2 i, i + #1}

Just about any function except for ones defined as trivial formulae would break.

Plus, the effect of HoldAll can always be cancelled with a simple Evaluate.

In[2]:= f = 2 # &
Out[2]= 2 #1 &

In[3]:= g = Evaluate[f[#]/2] &
Out[3]= #1 &
$\endgroup$
  • $\begingroup$ I'm not understanding this response, because Table and Plus do not have own values. Maybe I asked the wrong way, but the core of my question is why it is desirable to "break" the substitution of own values for a symbol (thereby introducing perhaps unexpected global dependencies). I accept that your proposed use of Evaluate addresses the problem in my simple example. $\endgroup$ – Alan Sep 15 '16 at 15:52
  • 1
    $\begingroup$ @Alan There is some mismatch in our understanding of the issues involved because I also don't understand your comment. It has not relevance to evaluation whether a transformation rule is an OwnValues, DownValue, or something else. Either all transformations are applied, or none of them (with HoldAll). It's not possible to cherry pick what transformation is performed based on the type of "*Value" involved. $\endgroup$ – Szabolcs Sep 15 '16 at 15:56
  • $\begingroup$ My unfortunate specificity relates only to the example I provided (which only generates own values). But it is also the case that Table and Plus have no up values or down values. I think you are saying that there is no way to have a mechanism that would rewrite f in my example without doing something unfortunate in your example: either the argument is evaluated, or it is held. I suppose you are just saying that I seem to want a half-way measure, but there are none when it comes to evaluation. I recognize that the design decision is itself a good clue that you are correct. Thanks. $\endgroup$ – Alan Sep 15 '16 at 16:23
  • $\begingroup$ @Alan Why are you saying that those functions have no DownValues? $\endgroup$ – sebhofer Sep 15 '16 at 21:07
  • $\begingroup$ @sebhofer Because none are listed by the DownValues command. I deduce from your question that I misrepresented something here. No surprise: I'm a relative newbie. $\endgroup$ – Alan Sep 15 '16 at 21:22
1
$\begingroup$

Inspired by Szabolcs answer and the discussion in the comments, here's another solution:

EvaluateOwnValuesOnlyAndHold~SetAttributes~HoldAll
EvaluateOwnValuesOnlyAndHold[expr_] := 
 Hold[expr] /. 
  x_Symbol /; AtomQ@Unevaluated@x(*don't capture Symbol["name"]*):> 
   With[{y = x}, y /; True](*force evaluation of x -- do we call *this* 'Villegas-Gayley' too?*)

Now we get e.g.

delta = 1;
Function @@ 
 EvaluateOwnValuesOnlyAndHold[Plus @@ Table[i, {i, #, delta}]]

Plus @@ Table[i, {i, #1, 1}] &

and as desired:

f = 2 # &;
g = Function @@ EvaluateOwnValuesOnlyAndHold[
    f[#]/2
    ];
OwnValues[g]
g@42

{HoldPattern[g] :> (1/2 (2 #1 &)[#1] &)}

42

$\endgroup$
  • 1
    $\begingroup$ Note possible problems with scoping constructs e.g.: i = 5; EvaluateOwnValuesOnlyAndHold[{i, Module[{i = 6}, i]}] $\endgroup$ – jkuczm Sep 19 '16 at 13:07
  • $\begingroup$ "... do we call this 'Villegas-Gayley' too?" It's usually called Trott-Strzebonski in-place evaluation $\endgroup$ – jkuczm Sep 19 '16 at 14:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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