четверг, 10 декабря 2015 г.

#1148. О кешировании. Поговорим про устройство "слова"

О кешировании. Поговорим про устройство "слова".

Предыдущая серия была тут - http://programmingmindstream.blogspot.ru/2015/12/1147.html.

Там мы ввели понятия "слова", "переменной" и "константы", а также научились ими пользоваться.

Теперь поговорим на тему "а что же вообще говоря такое слово".

"Слово" или "элемент словаря" это вообще говоря - "словарная запись", которая представляется в словаре в виде "ключ-значение".

Т.е. слово:

: A
 ACode
; // A

В словаре будет представлено парой:

( A ACode )

Где:
 A - имя слова.
 ACode - код слова.

А точнее говоря - тройкой:

( : A ACode )

Где:
 : - стереотип слова.
 A - имя слова.
 ACode - код слова.

Что такое стереотип слова?

Это скажем так "категория" к которой это "слово" относится.

Стереотип может определять различные ограничения на работу со словом.

Из разряда того, что например:
 "константы" - умеют только вычислять значения.
 "переменные" - умеют как отдавать значения, так и хранить их.
 "слова" - умеют вычислять значения, а также могут содержать вложенные элементы.

Также стереотипы определяют наборы операций применимых к элементу словаря (об этом поговорим ещё позже).

Проиллюстрируем использование стереотипов примером:

: A
 ACode
; // A

VAR B

CONST C 1

Этот пример будет представлен в словаре так:

 ( : A ACode )
 ( VAR B {BValue} )
 ( CONST C 1 )

А пример:

: A
 ACode
; // A

VAR B

CONST C 1
CONST D C

Будет представлен в словаре так:

 ( : A ACode )
 ( VAR B {BValue} )
 ( CONST C 1 )
 ( CONST D ref C )

Обратите внимание, что элемент D не представлен значением "1", а ссылается на элемент C - "ref C".

Мы этот факт потом ещё обсудим.

А что же со вложенными словами?

Как они представляются в словаре?

Вот тут "оказывается", что слова представляются даже не тройкой, а четвёркой:
 ( Стереотип Имя_Слова Код_Слова Вложенный_Словарь ).

Проиллюстрируем примером.

Код:

: A
 VAR X
 ACode
; // A

Представляется как:

( : A ACode Dict( VAR X {XValue} ) )

Где Dict( ... ) - внутренний словарь слова A.

Ну и новый пример:

: A
 VAR X
 ACode
; // A

VAR B

CONST C 1
CONST D C

Будет представлен в словаре так:

 ( : A ACode Dict( VAR X {XValue} ) )
 ( VAR B {BValue} Dict( ) )
 ( CONST C 1 Dict( ) )
 ( CONST D ref C Dict( ) )

Тут возникает закономерный вопрос - "а раз словарь это ключ-значение, то нельзя ли получить поступ ко вложеным элементам слова?"

Ответ - "да можно, потому, что у нас присутствует полная рефлексия кода".

Как это сделать?

Для этого у нас есть три замечательных слова аксиоматики:

 @ - получает адрес слова.
 DO - выполняет слово по адресу (обратная к @).
 %% - получает по адресу слова вложенный элемент по его имени.

Вот как определено слово %%:

OBJECT operator %%
 OBJECT IN aWord
 ^ IN aName
 
 OBJECT VAR l_Member
 aName DO aWord pop:Word:FindMember >>> l_Member
 
 if ( l_Member pop:object:IsNil ) then
  ( Result := nil )
 else
  ( Result := ( l_Member pop:KeyWord:Word ) ) 
; // %%

Видим, что оно принимает два параметра - aWord и aName.

 aWord - слово для которого мы ищем вложенный элемент.
 aName - имя вложенного элемента.

И возвращает значение типа OBJECT - адрес найденного вложеного элемента, или nil, если такой элемент не найден.

Приведём пример использования:

: A
 : X
  2
 ; // X
 1
; // A

@ A // - берём адрес слова A
%% // - операция %%
'X' // - имя искомого слова X
DO // - выполняем слово, которое нашлось
Print // - печатаем значение

Что получится?

В консоль напечатается целочисленное значение "2", которое возвращает слово X.

А что делать если искомого вложенного слова нет?

Ответ - проверить возвращаемое значение на nil.

Пример:

: A
 : X
  2
 ; // X
 1
; // A

VAR l_ElementAddr // - переменная для сохранения адреса элемента

@ A %% 'X' >>> l_ElementAddr // - получаем адрес элемента X
if NOT ( l_ElementAddr IsNil ) then
// - проверяем его
begin
 l_ElementAddr DO // - напечатается 2
end

@ A %% 'Y' >>> l_ElementAddr // - получаем адрес элемента Y
if NOT ( l_ElementAddr IsNil ) then
// - проверяем его
begin
 l_ElementAddr DO // - ничего, не напечатается, 
                  //   т.к. сюда не попадём, 
                  //   т.к. у элемента A нет элемента Y
end

А можно ли обойтись без @ и DO?

Ответ - можно.

Для этого у нас есть слово - ::.

Вот как оно определено:

^@ operator ::
 ^@ IN aSelf
 ^L IN aName

 OBJECT VAR l_Self
 aSelf |^@ >>> l_Self
 
 STRING VAR l_Name
 aName |N >>> l_Name
 
 OBJECT VAR l_Res
 l_Self %% l_Name >>> l_Res
 
 ASSURE 
  NOT ( l_Res pop:object:IsNil ) 
  [ 'Не найдено поле: ' l_Self LIST %P Reverted ==> ( |N '::' ) l_Self |N '::' l_Name ]
 l_Res >>> Result
; // ::

Пример использования:

: A
 : X
  2
 ; // X
 1
; // A

A :: X Print // - напечатает значение "2", которое возвращает X
A :: Y Print // - упадёт с Run-Time ошибкой, что "поле Y не найдено"

Более того - при помощи :: можно не только читать, но и писать значения вложенных элементов (если они поддерживают запись).

На это указывает модификатор ^@ перед объявлением операции ::.

Он означает, что возвращается не значение, а ссылка.

Пример:
: A
 VAR X
; // A
A :: X := 2 // - присваиваем полю X значение "2"
A :: X Print // - печатаем это значение

Теперь возникает закономерный вопрос - "а если мы можем получать внутренние элементы слов, то можем ли мы добавлять новые элементы?"

Ответ - "да можем".

Как?

Это мы рассмотрим в следующей статье.


Комментариев нет:

Отправить комментарий