I wrote earlier about problems with Mathematica's pure functions. The problems make the abstraction somewhat leaky. Here
are some more problems with that abstraction:

Contrast the return values of the following expressions:

Function[expr, With[{x = 1}, expr]][x]
(* x *)
Function[Null, With[{x = 1}, #]][x]
(* 1 *)
With[{x = 1}, #]&[x]
(* 1 *)

Tracing reveals that `Function`

is sometimes renaming variables:

Trace @ Function[expr,With[{x=1},expr]][x]
(* {Function[expr,With[{x=1},expr]][x], With[{x$=1},x], x} *)
Trace @ Function[Null,With[{x=1},#]][x]
(* {Function[Null,With[{x=1},#1]][x], With[{x=1},x], 1} *)

This renaming of variables within enclosed scoping constructs is somewhat
erratic. It happens if the function arguments are named but not if the arguments are anonymous.
The differences in behaviour can be exploited to good effect, to be sure, but they are certainly not intuitive.
It is not clear to me which of these behaviours is "correct". But it is even *more* unclear why the behavioural difference is triggered by the naming of function arguments. This is another example of subtle
Mathematica behaviour for beginners to trip over -- and experienced users too.

`Function`

with named arguments will rename variables in inner `With`

and `Module`

constructs, but not `Block`

constructs. The exception for
`Block`

makes sense given that it does not actually introduce any new variables, it just
overrides the definitions of existing ones. However, `Function`

with anonymous arguments
does not rename variables in *any* of these constructs.

It is possible to "trick" `Function`

so that it does not rename variables of enclosed scoping
constructs. The trick is to disguise those constructs. For example:

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

In this case, `Function`

does not spot the inner `With`

since it is not generated
until a later evaluation.

Note that `Function`

does not rename (non-pattern) symbols in replacement expressions, irrespective of whether
the function arguments are named or not. For example, both of the following expressions return the same
result:

Function[expr, expr /. x -> 1][x]
(* 1 *)
Function[Null, # /. x -> 1][x]
(* 1 *)

Maybe all of this behaviour can be divined from Variables in Pure Functions in the Mathematica
help. But it didn't occur to me.