Блокноты MuPAD® будут демонтированы в будущем релизе. Используйте live скрипты MATLAB® вместо этого.
Live скрипты MATLAB поддерживают большую часть функциональности MuPAD, хотя существуют некоторые различия. Для получения дополнительной информации смотрите, Преобразуют Notebook MuPAD в Live скрипты MATLAB.
При вызове процедуры с некоторыми аргументами вы ожидаете, что процедура присвоит эти значения для своих локальных переменных и выполнит некоторые расчеты с теми переменными. Например, эта процедура делит любой номер, который вы передаете ей 10:
f := x -> (x := x/10):
В этом примере, x
локальная переменная f
. Когда вы вызываете f
с любым значением процедура присваивает то значение локальной переменной x
, использование это, чтобы вычислить результат, и затем уничтожает локальную переменную x
освобождение выделенной памяти:
x := 10: f(x), x
Несмотря на то, что значение локальной переменной x
изменения в 1
в процедуре и затем уничтожается, значение глобальной переменной x
остается то же самое. Поэтому можно прийти к заключению, что процедура не получает доступ к фактическому блоку памяти, который содержит значение x
.
Когда вы вызываете эту процедуру, MuPAD® выделяет новый блок памяти и копирует значение x
с тем блоком. В то время как процедура выполняется, система сопоставляет локальную переменную x
с этим новым блоком памяти. В конце вызова процедуры это освобождает этот блок памяти. Блок памяти, который содержит значение глобальной переменной x
не изменяется.
Стратегия копирования значений аргументов процедуры к новым блокам памяти и обращения к этим блокам во время вызовов процедуры известна как вызов значением. Большинство функций MuPAD использует эту стратегию.
Начиная с вызова значением создает дополнительные копии данных, это может быть неэффективно в терминах управления памятью. Создание дополнительных копий больших наборов данных, особенно когда ваши вызовы процедуры являются рекурсивными или вкладываются, может значительно уменьшать свободную память на вашем компьютере. На многих языках программирования, вызывающих значением всегда, означает копировать данные, даже когда процедура не изменяет те данные.
MuPAD использует ленивое копирование, чтобы не создавать ненужные копии данных. Когда вы вызываете процедуру, MuPAD не выделяет новые блоки памяти сразу же. Вместо этого это соединяет локальные переменные с блоками памяти, где аргументы процедуры хранятся. Система всегда рассчитывает, сколько объектов соединяется с тем же блоком памяти. Когда процедура изменяет значение локальной переменной, проверки MuPAD, если существуют другие объекты, соединенные с тем же блоком памяти, и создает копию только если необходимый.
Например, когда вы вызываете f(x)
, MuPAD указывает обеим глобальным переменным x
(DOM_IDENT
) и локальный (DOM_VAR
) переменная x
к тому же блоку памяти. Только, когда локальная переменная x
изменяет его значение, MuPAD выделяет новый блок памяти для него.
Как правило, когда вы вызываете процедуру MuPAD с некоторыми аргументами, система использует подход вызова значением и создает копии значений этих аргументов. Этот подход препятствует тому, чтобы процедуры изменили объекты, переданные процедуре в качестве аргументов. Для некоторых функций, таких как присвоение, MuPAD использует подход вызова ссылкой. В вызове по ссылке система не копирует значения аргументов к новым блокам памяти. Вместо этого это копирует ссылки (указатели) на эти аргументы.
Некоторые языки программирования позволяют вам задать который подход использовать в каждой конкретной функции. MuPAD не предлагает определенные построения языка для вызова ссылкой. Тем не менее, вы можете все еще вызов по ссылке в MuPAD.
Для опытных пользователей MuPAD объекты со ссылочной семантикой могут неожиданно вести себя. Будьте осторожны при представлении ссылочной семантики пользователям, потому что она может сбить с толку.
Предположим, что ваша задача требует вызова функции смочь изменить значения его аргументов. Простая стратегия состоит в том, чтобы возвратить модифицированную копию аргументов и перезаписать исходный объект при помощи присвоения. Например, матрица замены A
с его верхней формой эшелона строки:
A := linalg::hilbert(3)
A := linalg::gaussElim(A)
При работе с большими наборами данных и глубоко вложенными вызовами, эта стратегия может вызвать проблемы памяти. Проверяйте профильный отчет видеть, имеет ли ваша реализация такие проблемы. Для получения дополнительной информации смотрите Профилирование Вашего Кода.
Также можно достигнуть эффекта вызова ссылкой в использовании MuPAD:
Вместо передающих данных в качестве аргументов процедуры можно использовать локальную переменную внешней процедуры, чтобы хранить данные. Для внутренней процедуры эта переменная не локальна. Поэтому внутренняя процедура может изменить значение той переменной, и переменная не уничтожается после того, как внутренняя процедура выполняется:
f := proc(x) local n, incr; begin n := 0; incr := () -> (n := n + 1); while x > n do incr(); end_while; end_proc:
Этот подход не соответствует многим задачам программирования, но он рекомендуется везде, где можно применить его. Это является самым простым и большая часть читаемого подхода, чтобы получить эффект вызова ссылкой в MuPAD.
При работе с областями также можно использовать подход наличия фактических данных в закрытии. Например, вместо того, чтобы хранить фактические данные в объектах, можно сохранить функции, которые получают доступ к данным:
domain d local get, set; inherits Dom::BaseDomain; new := proc(x) option escape; begin new(dom, () -> x, y -> (x := y)); end; incr := x -> set(x, get(x) + 1); print := x -> get(x); begin get := x -> extop(x, 1)(); set := (x, y) -> extop(x, 2)(y); end_domain: e := d(4)
d::incr(e)
e
Дополнительную информацию см. в Закрытиях.
Можно реализовать подход вызова ссылкой в коде при помощи областей как таблицы со ссылочными эффектами. (Используя области как таблицы не связано с объектно-ориентированным программированием.) Следующий пример демонстрирует эту стратегию:
domain dd local get, set; inherits Dom::BaseDomain; new := proc(x) local d; begin d := newDomain(genident()); d::number := x; new(dom, d); end; get := (x, entry) -> slot(extop(x, 1), entry); set := (x, entry, value) -> slot(extop(x, 1), entry, value); incr := x -> (dom::set(x, "number", dom::get(x, "number") + 1); x); print := x -> dom::get(x, "number"); end_domain: e := dd(4)
dd::incr(e)
e
Примитивы plot
использование библиотеки эта стратегия. Например, когда вы выполняете следующий код, доменный plot::Function2d
перегружает slot
функция:
f := plot::Function2d(sin(x), x=-PI..PI): f::Color := RGB::Green:
context
функция и option hold
также позвольте вам реализовать вызов быть ссылочным эффектом в ваших процедурах. option hold
препятствует тому, чтобы процедура оценила свои аргументы прежде, чем выполнить код в теле процедуры. context
функция позволяет вам выполнить операции, как будто они происходят в процедуре вызова.
Например, в этом коде option hold
предотвращает incr
процедура от оценки ее аргумента. Поэтому система не копирует значение x
к новому блоку памяти:
incr := proc(x) option hold; begin context(hold(_assign)(x, x + 1)); end_proc: operator("++", incr, Prefix, 500):
При выполнении этой процедуры система выполняет операцию присвоения в контексте процедуры f
(процедура вызова для incr
). Таким образом, incr
изменяет значение аргумента, n
, которым это было вызвано:
f := proc(x) local n; begin n := 0; while x > n do ++n; end_while; end_proc:
Если вы используете ++
оператор на неизменном объекте, MuPAD выдает ошибку. Например, вы не можете присвоить значение 2 значению 1:
++1
Error: Invalid left side. [_assign]
Это сообщение об ошибке не упоминает incr
потому что ошибка происходит в присвоении, которое выполняется в различном контексте оценки. incr
процедура ведет себя по существу как динамический макрос.