MathGroup Archive 1995

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Using Hold, ReleaseHold, and Unevaluated

In article <DGvxIx.BL4 at>,
Claudio Fahey <claudio at> wrote:
>I'm trying to write a function that constructs a pure function.  I would
>like to do the following (for example):
>In[1] :=	f = Func[{{x1,y1},{x2,y2}}, (x1-x2)^2 + (y1-y2)^2];
>In[2] :=	f[{{a,b}, {c,d}}]
>Out[2] =	(a-c)^2 + (b-d)^2
>The function I want to write, Func, is similar to Function but it
>accepts nested lists of variables as well as a flat list.
>Func[varpattern_, f_] := Module[ Evaluate[Flatten[varpattern]],
>                                 (varpattern = #; f) & ];
>This function works fine but I would like it to have the HoldAll
>attribute.  Without this attribute, the following problem occurs:
>In[1] :=	x1 = 1.0;
>In[2] :=	f = Func[{{x1,y1},{x2,y2}}, (x1-x2)^2 + (y1-y2)^2]
>Out[2] =
>   Local variable specification {2, y1, x2, y2} contains 2
>     which is not a symbol or an assignment to a symbol.
>Module[{2, y1, x2, y2}, 
>                                    2            2
> ({{2, y1}, {x2, y2}} = #1; (2 - x2)  + (y1 - y2) ) & ]
>The x1 in the parameter list was replaced with 1.0.  The HoldAll
>attribute would prevent the x1 in the parameter list from being
>However, even with the HoldAll attribute, x1 is still being evaluated
>because Evaluate is being called to flatten the nested list of
>variables.  I've tried various combinations of mapping Hold,
>Unevaluated, and ReleaseHold but I've been unable to make Func work
>properly (like Function but with nested variable lists).

My first reaction was that this is a bizarre thing to want to do.
I would write the example this way:

    f = Function[{p1,p2}, Apply[Plus, (p1-p2)^2]]

but I presume you have a more complicated example for which it really
does make your life easier.  Anyway, this seems like something that
one ought to be able to do, so I took it as a challenge.  Here's my

	x1 := 1.

First of all, this function flattens a nested list without allowing the
stuff inside of it to evaluate.  It relies on the fact that Flatten
takes an optional argument that tells it what head to flatten.  You can
simply replace all List heads with a head that holds its arguments,
then Flatten w.r.t. that head.  I defined my own "hold" head hh so that
there'd be no confusion in case the expression being flattened
contained, e.g., literal calls to Hold.

	SetAttributes[hh, HoldAll]
	SetAttributes[flat, HoldFirst]
	flat[stuff_] :=
		Flatten[Hold[stuff] /. List->Hold, Infinity, Hold] /.
			Hold[x__] :> Hold[{x}]
	flat[{{x1, x2}, {{x3}, x4}}]
	Hold[{x1, x2, x3, x4}]

Now we have the variable list that you want to use as the first
argument to Module, with Hold wrapped around it.  A general strategy
for getting something like this inside of a function that holds its
arguments is to Apply that function to the held expression.  The Apply
operation replaces the Hold head with the function that you are really
interested in calling.  This is complicated slightly by the fact that
you want to apply a function (Module) that takes more than one
argument.  You do this, of course, by constructing a pure function that
has just "plugs in" the argument in question.  However, note that the
pure function has to have a hold attribute as well; this is specified
using the syntax "Function[arg, body, attribute]".  The whole thing looks
like this:

	SetAttributes[Func, HoldAll];
	Func[varpattern_, f_] :=
			Module[ varlist, (varpattern = #; f) & ],
		] @@ flat[varpattern]

	f = Func[{{x1,y1},{x2,y2}}, (x1-x2)^2 + (y1-y2)^2];

	       2          2
	(a - c)  + (b - d)

		Dave Wagner
		Principia Consulting
		(303) 786-8371
		dbwagner at

  • Prev by Date: Re: Help with factoring out an exponential
  • Next by Date: Re: Log Plots
  • Previous by thread: Using Hold, ReleaseHold, and Unevaluated
  • Next by thread: Re: Using Hold, ReleaseHold, and Unevaluated