ТОП 10:

В Лиспе используется передача параметров по значению



Статические переменные локальны

Свободные переменные меняют свое значение

Динамическая и статическая область действия

Одно имя может обозначать разные переменные

 

 

Введение

В языках программирования в основном используются два способа передачи параметров – это передача параметров по значению (call by value) и по ссылке (call by reference). При передаче параметров по значению формальный параметр связывается с тем же значением, что и значение фактического параметра. Изменения значения формального параметра во время вычисления функции никак не отражаются на значении фактического параметра. С помощью параметров, передаваемых по значению, информацию можно передавать только внутрь процедур, но не обратно из них. При передаче параметров по ссылке изменения значений формальных параметров видны извне, и можно возвращать данные из процедур с помощью присваивания значений формальным параметрам.

 

В Лиспе используется передача параметров по значению

Передача параметров в Лиспе осуществляется в основном по значению. Параметры в Лиспе используются преимущественно лишь для передачи данных в функцию, а результаты возвращаются как значение функции, а не как значения параметров, передаваемых по ссылке. В Лиспе все-таки можно с помощи псевдофункций, меняющих структуры, использовать формальные параметры таким же образом, как это происходит при передаче параметров по ссылке. Побочные эффекты их использования отражаются на значениях всех переменных, ссылающихся на некоторый элемент данных. Мы вернемся к этим псевдофункциям чуть позже. Кроме того, механизм возврата значений из многозначных функций также напоминает передачу параметров по ссылке.

 

 

Статические переменные локальны

Формальные параметры функции в Лиспе (Коммон Лиспе) называют лексическими или статическими переменными (lexical/static variable). Связи статической переменной действительны только в пределах той формы, в которой они определены. Они перестают действовать в функциях, вызываемых во время вычисления, но текстуально описанных вне данной формы. Изменение значений переменных не влияет на одноименные переменные вызовов более внешнего уровня. Статические переменные представляют собой лишь формальные имена других лисповских объектов. После вычисления функции, созданные на это время связи формальных параметров ликвидируются и происходит возврат к тому состоянию, которое было до вызова функции.

Например:

 

_(defun не-меняет (х) ; Х статическая

(setq x ’новое))

НЕ-МЕНЯЕТ

_(setq x ’старое)

СТАРОЕ

_(не-меняет ’новое) ; статическое

НОВОЕ ; значение Х изменяется

_х ; первоначальная связь

СТАРОЕ ; не меняется

 

Свободные переменные меняют свое значение

Возникающие в результате побочного эффекта изменения значений свободных переменных (free variable), т.е. используемых в функции, но не входящих в число ее формальных параметров, остаются в силе после окончания выполнения функции. Определим далее функцию ИЗМЕНИТЬ, в которой переменная Х свободна. Ее значение будет меняться:

 

_(defun изменить ()

(setq x ’новое)) ; Х свободная

ИЗМЕНИТЬ

_(изменить)

НОВОЕ

_х ; значение свободной

НОВОЕ ; переменной изменилось

 

 

Динамическая и статическая область действия

Под вычислительным окружением или контекстом (evaluation environment) будем понимать совокупность действующих связей переменных с их значениями. Связи формальных параметров вызова со значениями аргументов действительны (по умолчанию) только в пределах текста определения функции. Будем говорить, что область действия (scope) или видимость переменных статическая.

В Лиспе (Коммон Лиспе) существует однако возможность использования динамических, или специальных (dynamic/special variable), переменных. Это обычно достигается при помощи директивы

 

(DEFVAR переменная &OPTIONAL начальное значение)

Значение переменной, объявленной специальной, определяется динамически во время вычисления, а не в зависимости от контекста места ее определения, как для статических переменных. Будем говорить, что временем действия (extent) связи динамического формального параметра является все время вычисления вызова, в котором возникла эта связь.

Если переменная свободна и является формальным параметром какого-нибудь охватывающего вызова, то значения статической и динамической переменных вычисляются по-разному. Если переменная является статической (как, например, по умолчанию в Коммон Лиспе), то ее использование в качестве формального параметра в более внешней, предшествующей, форме не влияет на значение свободной переменной. У переменной либо не будет значения, что приведет к ошибке, либо ее значение определяется в соответствии с ее глобальным значением, присвоенным на самом внешнем уровне функцией SETQ.

Если переменная при помощи DEFVAR объявлена динамической, то связь, установленная в более внешнем вызове, остается в силе для всех вложенных контекстов, возникающих во время вычисления (при условии, что эта переменная снова не связывается).

Например:

 

_(setq x 100) ; глобальное значение Х

_(defun первая (х) (вторая 2)) ; статическая Х

ПЕРВАЯ

_(defun вторая (y) (list x y)) ; Х свободна

ВТОРАЯ

_(первая 1) ; свободная нединамическая переменная

(100 2) ; значением Х является глобальное значение

; Х

_(defvar x 100) ; начиная с этого момента Х динамическая

Х ; переменная

_(первая 1) ; Х определяется динамически

(1 2) ; по последней связи

Если в функции не используется ни одной свободной переменной, то вычисления в обоих случаях производятся совершенно одинаково. Именно таким функциям надо отдавать предпочтение во время обучения языку Лисп.

Одно имя может обозначать разные переменные

Интересные различия возникают в использовании статических и глобальных (динамических) переменных, когда один и тот же символ является и фактическим, и формальным параметром:

 

_(setq x . . .) ; глобальная Х

. . .

_(defun fn (x) . . .) ; статическая Х

. . .

_(fn ’x) ; статическая Х связывается с глобальной Х

. . .

В случае, подобном приведенному, Х в функции FN может быть именем как статической, так и глобальной (или динамической) переменной. В этом случае нужно различать, какая переменная что означает.

Ранее мы описали функцию НЕ-МЕНЯЕТ, которая изменяла значение статической переменной Х, и поэтому глобальное значение Х сохранялось. В функции SET-DYN будет меняться динамическое значение Х, так как значением первого аргумента вызова SET, т.е. статического Х, будет динамическое Х из вызова функции. Предположим, что Х не объявлена динамической через DEFVAR:

 

_(setq x ’старое)

СТАРОЕ

_(defun set-dyn (x) (set x ’новое)) ; меняет динамическую Х

SET-DYN

_(set-dyn ’x)

НОВОЕ

НОВОЕ

Все участвующие в вычислениях переменные, как и первый фактический параметр вызова SET в предыдущем примере, являются динамическими. Сослаться на статическую переменную можно лишь в форме, не вычисляющей своих аргументов, такой как SETQ. Статические переменные не могут выступать как лисповские объекты сами по себе или в составе более сложных структур, поскольку они используются лишь как формальные имена, при помощи которых записываются вычисления. Следующая функция SET_DYN работает точно так же, как и предыдущая, так как значение первого аргумента вызова функции SET ссылается не на статическую переменную Х, а на динамическую:

 

_(defun set-dyn (x) (set (car ’(x y)) ’новое))

Функция QUOTE также возвращает в качестве значения лишь динамическую переменную, что видно из следующего примера:

 

_(defun проба-eval (x) (eval ’x))

ПРОБА-EVAL

_(setq x ’старое) ; динамическая связь Х

СТАРОЕ

_(проба-eval ’новое) ; аргументом EVAL является не статическая,

СТАРОЕ ; а динамическая Х

В некоторых Лисп-системах переменные по умолчанию являются не статическими, а динамическими. В таких системах в приведенных ранее примерах результаты будут другие. Если, например, переменная Х была бы определена как динамическая специальная переменная, то функция SET-DYN не присвоила бы ей нового глобального значения. Значение можно было бы изменить лишь в динамическом контексте вызова SET-DYN, уничтожаемом после завершения вызова.

Современная тенденция развития языка ведет к статическим Лисп-системам. Фактически разница между динамическими и статическими переменными позволяет использовать во вложенных функциях динамическое значение переменной внешнего уровня, несмотря на то, что встречались статические переменные с тем же именем. К ошибкам, возникающим из подобных конфликтов имен, мы вернемся подробнее в связи с функциональными вычислениями, работой в вычислительном контексте момента определения и в связи с макросами.

Статические вычисления позволяют сделать более хорошие трансляторы. С другой стороны, динамический интерпретатор Лиспа реализовать легче, чем статический. В некоторых системах интерпретируемые функции вычисляются динамически, а оттранслированные функции вычисляются по статическим правилам. В результате одна и та же программа может работать по-разному в режиме интерпретации и в оттранслированном виде.

 

 

ЛАБОРАТОРНАЯ РАБОТА №6

 

 

1. В чем различия следующих типов переменных:

a) статические переменные;

b) динамические переменные;

c) специальные переменные;

d) глобальные переменные;

e) свободные переменные.

 

 

2. Чем отличается статическое вычисление от динамического, если в функции нет свободных переменных?

 

3. Определите функции F и G следующим образом:

_(defun f (y) (g y))

F

_(defun g (x) (list x y))

G

 

Какое значение или сообщение об ошибке будет результатом следующих вызовов функций F и G:

 

a) (f ’y)

b) (f (setq y ’y))

c) (g ’y)

d) (g (setq y ’y))

e) последовательное вычисление: (setq y ’x); (g y); (f y).

 

ВЫЧИСЛЕНИЕ В ЛИСПЕ







Последнее изменение этой страницы: 2016-09-05; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 34.200.236.68 (0.016 с.)