8

I've always thought

(2#+1)&

and

Function[x,2x+1]

are interchangeable in common sense. But,

Clear[F]; F[x_] := (2 # + 1) &[x^2]; F[3]
(* 19 *)

Clear[F]; F[a_] := Function[x, 2 x + 1][a^2]; F[3] (* 19 *)

Clear[F]; F[x_] := Function[x, 2 x + 1][x^2]; F[3] (* Function::flpar: Parameter specification 3 in Function[3,2 3+1] should be a symbol or a list of symbols. ) ( Function::flpar: Parameter specification 3 in Function[3,2 3+1] should be a symbol or a list of symbols. ) ( Function[3, 2 3 + 1][9] *)

As you see, it seems mathematica provokes an error if you use same variable used in Function[ ], to define a new function.

Looks mathematica wants to prevent a kind of collision of variable names. But I think such thoughtfulness is unnecessary for this case. Function[x, 2 x + 1] just represents a function that maps a thing to its double plus one. After completing interpretation of the function, we can completely forget the fact : 'the variable used in Function[ ] was x'. What do you think ?

Lukas Lang
  • 33,963
  • 1
  • 51
  • 97
imida k
  • 4,285
  • 9
  • 17

1 Answers1

15

The issue is that to SetDelayed1 (:=), Function is just a normal head. For your third example, this means the following: You are defining a downvalue for F that says "every time you see F[something] replace it with the expression Function[x, 2 x + 1][x^2], where all x are to be replaced by something". Notice that at no point in that process is the head Function treated separately. This means that the x inside Function is simply replaced by 3 in your example before Function has any change to do anything.

Now, there are some functions that do treat Function differently, e.g. With:

With[{x = 1}, Function[x, x]]
(* Function[x, x] *)

That being said, I do think that your initial statement is pretty much correct: Function[x,2x+1] and 2#+1& are mostly identical, the only issue is that SetDelayed1 knows about neither of them, and will blindly replace parts inside them. You could equally well break the second version:

Clear[F]; F[Slot_] := (2 # + 1) &[Slot^2]; F[3]
(* 1 + 2 3[1] *)

The only difference here is that there is no error message, and since # is Slot[1] (and not Slot), the failure mode is slightly different, but the point still stands I think.

1 As noted by Leonid Shifrin in the comments, it is not really accurate to say that the behavior described here is due to SetDelayed. SetDelayed effectively defines replacement rules (with head RuleDelayed), that are then applied using a mechanism similar to Replace. This means that it would be more accurate to say that the rule application mechanism of Mathematica does not know or care about Function.

Lukas Lang
  • 33,963
  • 1
  • 51
  • 97
  • The first sentence is so impressive "The issue is that to SetDelayed (:=), Function is just a normal head. " Thank you. – imida k Jun 28 '21 at 02:26
  • 1
    I would mostly agree with this answer, except I think that the significance of SetDelayed here is overemphasized: rather, the main culprit is RuleDelayed and rule application in general, while SetDelayed simply creates a rule. This is just another manifestation of the well-known fact that rule application does not generally respect inner scoping constructs, not even other delayed rules. Similar problems were discussed in 1 (see at the end of that post) and 2. – Leonid Shifrin Jun 28 '21 at 05:52
  • 1
    @LeonidShifrin Thanks, that's a very good point! I have added a note to the answer to hopefully clear things up a bit – Lukas Lang Jun 28 '21 at 08:22