Problems with lexical scoping

116 views
Skip to first unread message

Leonid Shifrin

unread,
Mar 8, 2010, 6:15:59 AM3/8/10
to
Hi everyone,

I have encountered a behavior which seems to me like a bug in the
implementation of the lexical scoping of either Function or RuleDelayed or
both.

Here is a toy problem: given a list where I may have some number (possibly
zero) of consecutive integers at the beginning end at the end, and some
(nonzero) number of consecutive reals in the middle, I want to

1. Deconstruct the list into these 3 groups and be able to apply some
function of my choice, taking 3 arguments, to the result.

2. Use the above to apply some arbitrary function to the reals in the
middle.

Here is my implementation:

ClearAll[deconstruct, applyToReals, applyToRealsAlt];
With[{valuePattern = {(_Integer | _Real) ..}},

deconstruct[decF_, values : valuePattern] :=
values /. {leftInts : _Integer ..., reals : _Real ..,
rightInts : _Integer ...} :>
decF[{leftInts}, {reals}, {rightInts}];

applyToReals[f_, values : {_Integer ..}] := values;
applyToReals[f_, values : valuePattern] :=
deconstruct[
Function[{leftInts, reals, rightInts},
{leftInts, f[{reals}], rightInts}], values];

applyToRealsAlt[f_, values : {_Integer ..}] := values;
applyToRealsAlt[f_, values : valuePattern] :=
deconstruct[
Function[{leftIntsLoc, realsLoc, rightIntsLoc},
{leftIntsLoc, f[{realsLoc}], rightIntsLoc}], values];
]; (* End external With *)

Note that the functions <applyToReals> and <applyToRealsAlt> only differ in
the names of variables of internal Function, so I'd expect identical
behavior for them, regardless of where they are used, if the lexical scoping
is working properly. Now please observe:

In[136]:=
test = {1, 2, 3, 3.5, 4.0, 4.5, 5, 6, 7}

Out[136]= {1, 2, 3, 3.5, 4., 4.5, 5, 6, 7}

In[139]:= applyToReals[f, test]

During evaluation of In[139]:= Function::flpar: Parameter specification
{1,2,3,3.5,4.,4.5,5,6,7} in
Function[{1,2,3,3.5,4.,4.5,5,6,7},{1,2,3,f[{3.5,4.,4.5}],5,6,7}] should be a
symbol or a list of symbols. >>

During evaluation of In[139]:= Function::flpar: Parameter specification
{1,2,3,3.5,4.,4.5,5,6,7} in
Function[{1,2,3,3.5,4.,4.5,5,6,7},{1,2,3,f[{3.5,4.,4.5}],5,6,7}] should be a
symbol or a list of symbols. >>

Out[139]=
Function[{1, 2, 3, 3.5, 4., 4.5, 5, 6, 7}, {1, 2, 3,
f[{3.5, 4., 4.5}], 5, 6, 7}][{1, 2, 3}, {3.5, 4., 4.5}, {5, 6, 7}]

In[142]:= applyToRealsAlt[f, test]

Out[142]= {{1, 2, 3}, f[{{3.5, 4., 4.5}}], {5, 6, 7}}

To me this looks like a clear case of inappropriate variable capture: the
names of variables in internal Function in <applyToReals> happen to be the
same as those used in <deconstruct> to deconstruct the list, and are
captured by Function before it binds those symbols.

In the alternative version, the names are different and everything is as
expected. But I'd expect things to work also in the first case - the fact
that they don't is an indication to me that a lexical scope is broken for
this particular use case. Tracing shows that both RuleDelayed and Function
do rename their variables, but in the same way, so the name collision still
happens - perhaps this (plus the fact that RuleDelayed does not respect the
inner scoping constructs in terms of name collisions) is the origin of the
problem?

Just to make myself clear, I am not looking for a solution to this toy
problem that would work, I just want to understand the reason for this
behavior, particularly to know whether I am missing something (perhaps using
things inappropriately) or this is indeed a bug.

Thanks in advance.

Regards,
Leonid


DrMajorBob

unread,
Mar 9, 2010, 6:21:54 AM3/9/10
to
Test sequence:

test = Flatten@{RandomInteger[{0, 1}, RandomInteger[{0, 2}]],
RandomReal[{0, 1}, RandomInteger[{1, 3}]],
RandomInteger[{0, 1}, RandomInteger[{0, 2}]]}

{1, 0.260818, 0.767116, 0}

Split into sublists:

SplitBy[test, IntegerQ]

{{1}, {0.260818, 0.767116}, {0}}

Apply a function:

f @@ SplitBy[test, IntegerQ]

f[{1}, {0.260818, 0.767116}, {0}]

Apply another function to the reals:

SplitBy[test, IntegerQ] /. x_Real :> g@x

{{1}, {g[0.260818], g[0.767116]}, {0}}

Do both, in either order:

f @@ (SplitBy[test, IntegerQ] /. x_Real :> g@x)

f[{1}, {g[0.260818], g[0.767116]}, {0}]

(f @@ SplitBy[test, IntegerQ]) /. x_Real :> g@x

f[{1}, {g[0.260818], g[0.767116]}, {0}]

Bobby

On Mon, 08 Mar 2010 05:15:39 -0600, Leonid Shifrin <lsh...@gmail.com>
wrote:


--
DrMaj...@yahoo.com

Reply all
Reply to author
Forward
0 new messages