Starting with the last line, when you define
ScaleFunc = (# -
Min[data]) (Last[range] - First[range])/(Max[data] - Min[data]) &;
the HoldAll
attribute of the &
(see Function
) prevents data
and range
to receive any values. As soon as you then apply ScaleFunc
to an argument, say ScaleFunc[Range[10]]
, the functions Min
etc. in the function body do evaluate their arguments because they themselves as usual.
This HoldAll
effect doesn't occur when you use the definition
Clear[ScaleFunc,x];
ScaleFunc[x_] = (x - Min[data]) (Last[range] - First[range])/(Max[data] - Min[data]);
as you do in the Module
. There, it would actually have been safer to use SetDelayed
instead of Set
because x
is a global variable as written (I added the Clear
just because I pulled things apart from your Module
for the sake of discussion).
Since you want to use a pure function somehow, we should try to modify the ingredients of your Module
accordingly. Here are two suggestions that get by without Module
but use functions in rather different ways:
ScaleTo[range_] :=
With[{del = Last[range] - First[range]}, (# - Min[#]) del/(Max[#] - Min[#]) &]
ScaleTo[range_] := Function[d, (d - Min[d]) #/(Max[d] - Min[d])] &[
Last[range] - First[range]]
Both approaches separate the range
from the second argument because range
contains parameters that we don't want to be fed into a re-evaluation every time the second argument (data
) is supplied.
The first version uses With
as suggested by @march. It substitutes the calculated value of del
when you call ScaleFunc
with a range
argument. The result is a function that can be applied to data
.
The same result is also achieved in the second version, but there I use Function
to define it. In addition, the range
information is injected into the definition of that function by another (pure) function (that's what With
did in the previous version).
The explanation why we need With
or a sequence of two functions is again the HoldAll
attribute of Function
. With
gets around this attribute because it makes literal substitutions inside its scope, and the #
inside Function
together with &
allow evaluation of Last[range]-First[range]
before defining the Function
, because that intermediate step is calculated outside the function body.
Evaluate
somewhere you want it to be evaluated so that temporary variable is unnecessary $\endgroup$With
. $\endgroup$Rescale
):ScaleTo[data_, range_] := (data - Min[data]) (Last[range] - First[range])/(Max[data] - Min[data])
. So you don't need a pure function at all. $\endgroup$MinMax
and save one evaluation. $\endgroup$