Вспомним
команду map . Как вы уже знаете, эта команда
применяет функцию к списку.
Если, например, задан список
> restart;lst:=[2,4,5,6];
и мы хотим все его элементы возвести в
степень, равную первому элементу списка (2), то
можно записать процедуру
> map(x->x^lst[1],lst);
Как записать эту процедуру внутри
другой процедуры, которая будет внешней для
процедуры map (назовем ее out), чтобы она правильно
выполнялась? Попробуем вначале записать так
> v:='v';out:=proc(x::list)
local v;
v:=x[1];
map(y->y^v,x);
### WARNING: `v` is a lexically scoped local
end;
> out(lst);
Такая запись процедуры не привела к
нужному результату, так как будучи локальной для
процедуры out переменная v не перенесла
присвоенное ей значение x[1] во внутреннюю
процедуру y -> y^v .
Теперь попробуем в процедуре out1 переменную
v продекларировать, как глобальную
> out1:=proc(x::list)
global v;
v:=x[1];
map(y->y^v,x);
### WARNING: `v` is a lexically scoped global
end;
> out1(lst);
Теперь все в порядке, однако
продекларируем v , как локальную в процедуре out2
и как глобальную во вложенной процедуре
> v:='v';out2:=proc(x::list)
local v;
v:=x[1];
map(proc(y) global v; y^v; end,x);
end;
> out2(lst);
Такая запись также не приводит к нужному
результату. Это можно объяснить тем, что во
внутренней процедуре переменная v является
глобальной и поэтому отличается от локальной
переменной v процедуры out2 .
Попробуем передать переменную v во
внутреннюю процедуру через параметр внутренней
процедуры
> out3:=proc(x::list)
map(proc(y,z) y^z; end,x,x[1]);
end;
> out3(lst);
Теперь получился правильный результат.
Однако есть и другие приемы. Можно использовать
команду unapply вместо оператора
стрелки или proc() для создания вложенной
процедуры.
> unapply(y^v,y);
Эта команда создает процедуру из
математических выражения с аргументом y. Причем,
внутри созданной таким образом процедуры
переменные, не являющиеся аргументами процедуры
такие же какими они являлись вне процедуры, то
есть глобальные для процедуры out . Запишем еще
один вариант вложенной процедуры.
> out4:=proc(x::list)
unapply(y^x[1],y);
map(%,x)
end;
> out4(lst);
Еще один прием - использование команды
подстановки sub s для замены глобальной
переменной вложенной процедуры значением
локальной переменной процедуры out .
> out5:=proc(x::list)
local v;
global w;
print(`это w`,w);
v:=x[1];
map(subs('w'=v,y->y^w),x);
### WARNING: `w` is a lexically scoped global
end;
> out5(lst);
Здесь w берется в кавычки, чтобы
исключить ошибки в случаях, когда глобальному
имени w присвоено некоторое значение. Когда w в
кавычках, то используется только имя w. Этот метод
передачи значений локальных переменных во
вложенную процедуру работает всегда, но
программы получаются менее ясными для понимания
и более сложными для прочтения.
Итак, подведем итоги. Для передачи
значения некоторой переменной a в процедуру
int(), вложенную в процедуру out() можно применить
следующие приемы:
1. в процедуре out() определить переменную a
как глобальную;
2. передать переменную a во вложенную
процедуру int() через параметр вложенной
процедуры: int(..,a);
3. определить (если это возможно)
вложенную процедуру при помощи
оператора-функции, созданного командой unapply;
4. передать значение локальной
переменной a процедуры out() во вложенную
процедуру int() при помощи вспомогательной
глобальной переменной w процедуры out() и функции
подстановки subs(w=a,inproc()).
|