Г Р А Ф И Т — б а з и с

Концепция | Типы сущностей в информатическом моделировании

Под алгоритмикой мы понимаем область информатики, связанную с импер-знаниями; аналогично область, связанную с деклар-знаниями, будем называть датаматикой.

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

Содержание

Общие замечания

Об именах и адресах величин

О типах и операциях

О значениях и их видимости

Общие замечания

В информатике любая сущность представляется знаковой моделью, проще говоря – неким описанием. Традиционная его форма – натуральный человекочитаемый документ. При информатизации описания также существуют в предметной форме как массивы данных в памяти информашин; эти данные предъявляются человеку (для чего преобразуются в символическую форму) и частично используются самой машиной в автоматизированной части техпроцесса.

Объект реального техпроцесса уже при математической формализации представляется как величина или набор величин. В информатике любая величина есть структура вида:

<<имя-величины><тип-величины><значение-величины>>

Имя величины (называемое также идентификатором) – это уникальный набор символов, по которому величины различают.

Тип – это код, определяющий допустимые над величиной операции языка и интерпретацию значения (в общем случае – как единого объекта либо как набора элементов-полей). Типы, где значение понимается как единый объект, относят к простым, иначе говорят о составном типе.

Пример. Типичным составным типом является т.н. величина-массив (в алгоритмической нотации – табличная), представляющая набор однотипных простых значений, упорядоченных по одной и более координатам.

Другой пример. Строго говоря, и вещественное число можно понимать как составной тип, включающий два числовых поля – мантиссы и порядка – и два соответствующих знаковых поля, тип которых можно трактовать как логический (в смысле того, что они содержат ответ на вопрос, положительно числовое поле или нет).

Тип, определённый при реализации языка, называют базовым. К базовым типам обычно относят числовой, символьный и логический; возможны также специализированные подтипы (напр., целые или вещественные числа). Некоторые базовые типы (прежде всего простые) определены на уровне оборудования информашины («зашиты» в логику команд её процессора), т.е. не нужно писать программу, чтобы работать с ними; остальные определяются программно (прежде всего в трансляторе с языка программирования). Обычно в современных алгоязыках и языках приложений реализованы как базовые некоторые составные типы.

Пример. Строковый (текстовый) тип есть одномерный массив значений символьного типа, а динамическая (жарг. «электронная») таблица в динатаб-процессоре – двумерный (реже трёхмерный) массив величин, типы которых выбираются из некоторого множества.

Значение есть обьект (структура) данных, используемая в операциях в соответствии с типом (каждое поле м.б. количественной либо качественной характеристикой). Значение (каждое поле) должно находиться в пределах разрешённого типом величины набора кодов данных.

Структура хранится в памяти исполнителя алгоритма в определённом порядке (напр., так, как её элементы были перечислены выше).

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

Чаще всего производный тип в то же время и составной, однако в принципе возможно (и практикуется), что производный тип – это простой тип, которому приданы некоторые новые свойства.

Пример. Сочинитель из простого типа Символьный может создать простой же тип Русские символы, положив, что значениями величин этого типа м.б. только коды символов кириллицы по используемой кодовой таблице.

Величины различают и по динамике своего значения в ходе выполнения алгоритма.

Константа – простейший поименованный объект данных, несущий заранее заданное значение.

Переменная – поименованный объект, значение которого может меняться по ходу выполнения алгоритма. В некоторых случаях возможно и изменение типа.

Литерал – объект, представленный «как есть», т.е. только своим значением в выражении языка (число-коэффициент, строка, логический ответ).

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

Часть переменных может отражать состояние реальных объектов (прежде всего устройств ввода, программно контролируемых узлов исполнителя); значение такой переменной получается в результате считывания из заданного порта ввода – ячейки, на входы которой с объекта поступают физические сигналы данных. Аналогично возможны переменные, влияющие на состояние реальных объектов; их значения записываются в заданные порты вывода – ячейки, данные с выхода которых передаются на объекты.

Переменная м.б. неопределённой; часто в этом случае значение считается отсутствующим и место в памяти под него не отводится, пока переменная не станет определённой.

Переменная м.б. предполагаемой, когда по условиям решаемой задачи на её свойства наложены некоторые ограничения, проверяемые в алгоритме (напр. для числового типа – неотрицательность значения); в некоторых реализациях алгоязыков допускается объявлять такие условия вместе с величиной и тогда в её структуре предусматриваются поля для этих условий.

Если алгоритмическое описание сложное (содержит вспомогательные алгоритмы-вставки), то переменные также могут иметь различный статус (область) видимости:

Глобальная – переменная, доступная для изменения значения во всех алгоритмах, логически связанных вызовами вставок.

Локальная – переменная, доступная для изменения значения только в одном вспомогательном алгоритме (вставке).

В простом алгоритме (без вставок) все переменные глобальны.

Обычно переменная является локальной в случае объявления её в некоторой вставке. Кроме того, локальными являются переменные, которым впервые присваивается значение во вставке, а также переменные-параметры циклов. Все остальные переменные – глобальные.

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

Реализация языка может допускать присваивания внутри вставок для ранее определённых (глобальных) переменных. Изменение значения переменных в ходе выполнения вставок есть т.н. побочный эффект, способный существенно изменить логику алгоритма. Как правило, это недопустимо, поэтому либо сочинитель алгоритма контролирует отсутствие таких изменений, либо в язык вводится принудительное объявление таких переменных локальными (то и другое можно реализовать автоматически в трансляторе языка). Возможна и реализация обратного объявления переменных глобальными во вставке; тогда сочинитель может целенаправленно получить побочный эффект.

Для эффективности реализации в языки иногда вводят дополнительные градации статуса видимости переменных.

В начало страницы

Об именах и адресах величин

Подумаем, как могут формироваться имена величин. Прежде всего, нужно содержательное основание их назначения. Исходя из категорий материального, имеем здесь три рода:

Разумеется, это касается прежде всего самой сущности, но имя вполне естественно связано с содержанием того, что именуется.

Далее, можно ввести классификацию по способу записи имени:

Символьная запись может включать как числа, так и слова (слоги).

Наконец, по структуре имена м.б.:

Обычно иерархия отражает некое подразделение предметной области, сущности которой именуются.

Т.о. получаем три измерения имени (индекса, адреса) сущности.

Пример. Для библиотечных изданий (книг, периодики) именование в указанных измерениях можно описать так.

Прежде всего издание (точнее, каждый экземпляр) получает временной индекс – учётный (инвентарный) номер в порядке поступления в библиотеку. В других отношениях этот номер является: числовым – по способу записи; линейным – по структуре.

С некоторых пор временной индекс присваивается и при выпуске – т.н. международный серийный номер издания; он символен (сочетает число и текст) и иерархичен (есть подразделение на: книги/периодику – приставка ISBN/ISSN; выпускающих – цифровой корень раздаётся блоками по издателям по мере исчерпания предыдущих блоков).

Далее, издание в момент выпуска получает библиографические индексы – функциональные по своей сути (классифицируют по содержанию).

В библиотеке бибиндексы используются при поиске по содержанию, а также часто при размещении в хранилище. По способу записи есть числовые (УДК) и символьные (ББК) индексы. Иногда встаёт задача бибиндексации внутри библиотеки.

Наконец, основной пространственный индекс издания – т.н. полочный шифр, указывающий место в хранилище; он также обычно иерархичен (напр.: место/помещение/сооружение) и символен (используются как числа, так и слова).

На время выдачи таким индексом становится номер получателя – место в пространстве читателей библиотеки, а с учётом их регистрационных данных – до некоторой степени и географическое положение издания.

Другой пример. Для различения узлов в сетях информашин используют уникальные адреса. Как известно, по стандарту интерсетей существуют два типа адресов: IP и DNS – между которыми имеется взаимно-однозначное соответствие.

Адреса IP по содержанию прежде всего временные – даются по мере появления узлов (из неиспользованных и/или ранее занятых, но освобождённых) – но также и пространственные (блоки-домены выделяются по административно-территориальному делению Земли), и функциональные – имеются негеографические домены, отражающие статус организации-владельца узла. По способу записи IP-адреса числовые, а по строению – иерархические из 4-х уровней.

Адреса DNS рассматриваются как человекочитаемая запись IP-адресов; в силу этого они по форме записи символьные, а во всём остальном – идентичны IP.

Важно понимать, что все эти измерения присущи любому конкретному имени/пространству имён; при этом, как мы видим, из 12 вариантов прямого произведения в конкретных случаях могут использоваться не все.

Некоторые варианты такой классификации трудно сразу себе представить; в частности, в европейской культуре м.б. непонятно иерархически-временное назначение. Здесь нужно вспомнить опыт иных культур; это приводит нас к циклическому представлению о времени. Так, в китайском летосчислении за единицу принят т.н. династический цикл (фактически – «жизненный цикл» общества как упорядоченная последовательность состояний вполне определённой продолжительности), что приводит к иерархии «цикл-место в цикле». У других народов, скажем, майя, имеется многоуровневая иерархия времени (вложенность циклов); по некоторым данным, она идёт от результатов наблюдения природных факторов (цикличности элементов движения Земли относительно небесной сферы).

Сказанное относится в первую очередь к символическому представлению данных (по Паронджанову – знаковой форме). А что в предметной форме? Как указывает Вирт в "Алгоритмах и структурах данных...": «в конечном итоге данные будут представлены огромным количеством двоичных цифр независимо от того, была ли написана исходная программа на языке высокого уровня, использующем понятие типа, или на ассемблере, где типов нет.»1. Это касается и имени величины, которое по сути становится одним из значащих полей, предъявляемым при отображении человеку. В машине важен только адрес памяти, с которого размещается значение величины; можно считать, что он сопоставляется имени при объявлении.

Часто значения размещаются отдельно, а записи «имя-тип-адрес» – отдельно, что упрощает организацию (в зависимости от типа значения м.б. разнообразно и сложно устроены внутри).

В начало страницы

О типах и операциях

Обсудим понятие типа подробнее. Прежде всего типизация м.б. строгой и нестрогой. Первый подход лучше всего выражается снова словами Н. Вирта:

«Сущность понятия типа, как оно используется в данном тексте..., выражается в следующих утверждениях:

1. Тип данных определяет множество значений, которому принадлежит значение константы, или в котором принимает значения переменная или выражение, или которому принадлежат значения, порождаемые операцией или функцией.

2. Тип значения, обозначенного константой, переменной или выражением, может быть выведен из их объявлений и вида выражения без выполнения вычислений.

3. Каждая операция или функция требует аргументов определенных типов и даёт результат некоторого, тоже определенного типа. Если операция допускает аргументы нескольких типов (например, + используется для сложения как целых, так и вещественных чисел), то тип результата может быть определен на основе особых правил языка программирования.

Компилятор может использовать такую информацию о типах для проверки законности различных конструкций. Например, ошибочное присваивание булевского (логического) значения арифметической переменной может быть обнаружено без выполнения программы. Подобная избыточность текста программы весьма полезна при её разработке и может рассматриваться как главное преимущество хороших языков высокого уровня по сравнению с машинным кодом (или кодом символического ассемблера).»2

При нестрогой типизации подобные ограничения не соблюдаются; в результате тип переменной определяется значением, которое ей присвоено последним, а определение типа результата операции можно провести только при её выполнении. Это создаёт трудности как при построении программ, так и при доказательстве их правильности.

Мы уже говорили, что существуют некоторые простые типы, неделимые (атомарные), из которых строятся составные (структурные). В свою очередь вид может далее делиться в первую очередь по вариантам реализации.

Важно, что часто по правилам языка один из подтипов можно выбрать по умолчанию (просто не указав подтип вообще).

В то же время среди составных типов определяются фундаментальные (своего рода «молекулярные»). Их множество различно в разных информатических методологиях;

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

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

Наконец, остальные типы относятся к произвольным; их отличие состоит в том, что в ходе исполнения алгоритма (человеком ли, информашиной – неважно) переменные этих типов могут менять и своё строение, и множество своих допустимых значений.

Здесь мы видим обычную классификацию систем по масштабу: простые, сложные и большие. При этом непроизвольные типы можно считать регулярными (закон построения которых задан полностью при сочинении), в отличие от произвольных.

Иерархию «простой-сложный-произвольный» мы применим и при описании структур управления (алгоритмических) ДРАКОНа.

Будем пользоваться определением типов для текстового прогязыка Оберон-2, разработанного Н. Виртом на основе теории структур данных К. Хоора, основной в датаматике.

Для деклар-текста визуалов нам нужны обозначения типов и подтипов. Предлагается в основном заимствовать их из алгонотации (русского псевдокода), для зрительного различения кодируя составной тип 4-мя буквами, простой – 3-мя, а подтип простого – 2-мя.

Предлагаются простые типы следующих видов: числовой; логический; литерный. Здесь мы уточняем обычные в программировании классификации, где часто нет точного смыслового разграничения по уровням (многое «валится в одну кучу»).

Числовой тип Оберон-2 включает подтипы целый (ЦЕЛ) и вещественный (ВЕЩ); первый подразумевает арифметически точное представление числа, второй – приближённое.

При реализации числовых типов обычно вводятся по крайней мере два субподтипа в зависимости от длины кода: короткий (КР) и длинный (ДЛ); возможны и сверхдлинные для вычислений с повышенной точностью (в этом случае часто сверхдлинный тип называют длинным, а длинный – обычным, нормальным или никак не называют).

Логический тип определяется единственным образом как булевый (БУЛ, в алгонотации – ЛОГ), в т.ч. в связи с бистабильностью элементов оборудования современных информашин.

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

Для Оберона-2 предлагаются как фундаментальные сложные типы: массив (фиксированной длины по каждому из заданного числа измерений; обозначим как ТАБЛ), запись (ЗАПС) и множество (МНОЖ)3. Ни один из них не допускает изменение строения и/или множества допустимых значений. При этом тип запись и тип массив состоят из компонентов любых типов; отличие в том, что все компоненты массива д.б. одного типа и организуются по измерениям, а для записи это не обязательно. Тип множество же имеет фиксированный тип для линейно упорядоченных компонент; в Обероне-2 это целые числа.

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

Очевидно, в целях сохраняемости строения типа запись в Обероне исключена возможность вариантов в его определении, имевшаяся, скажем в его предке – языке Паскаль.

Среди произвольных типов в Обероне-2 прежде всего вводится новая структура данных – последовательность (массив переменной длины, обозначим как ПОСЛ).

У переменной последовательного типа структура массива (одномерного), а вот размер заранее не известен; он определяется при исполнении алгоритма. Поэтому вводится последовательный метод доступа к элементам: для очередной операции можно выбрать только соседний элемент, а добавить новый элемент можно только в конец.

Последовательность Вирт определяет как гибридный тип; точнее будет сказать, что он пограничный между базовым и произвольным видами типов.

При таком ограничении доступа реализация последовательности (управление адресуемой памятью для её размещения) оказывается сложным, но не произвольным; в этом её отличие от произвольных (но тем не менее конечных, как и положено в информатике) структур данных у которых заранее не определено не только число составных элементов, но и сам состав). Для реализации работы с последовательностью используется сочиняемая служебная структура данных, т.н. бегунок (указатель на текущий её элемент); в Обероне он имеет тип запись.

Фактически последовательность организует элементы данных в историческом (линейно-временном) порядке; поэтому естественно определить такой тип для переменных, хранящих данные как результат обмена между основной памятью и внешними по отношению к ней носителями данных (т.е. поступающие в ОП/выдаваемые из ОП). При этом другим участником обмена м.б. как внешняя память (файлы), так и окружающая среда исполнителя (устройства ввода/вывода). Именно поэтому мы не обозначаем этот тип как «файл» (в отличие от нотации большинства прогязыков).

К чисто произвольным относятся: рекурсивные типы (линейные списки, двоичные и иные деревья); другие конечные графы (в т.ч. «прошитые» деревья, циклические структуры, вроде кольцевых списков). Такие структуры Вирт предлагает определять не как статические типы (в реализации языка), а как динамические (формируя в использующем их алгоритме).

Для реализации чисто произвольных типов в язык вводится служебный тип ссылка (указатель на положение элемента в основной памяти; в Обероне-2 тип так и называется указатель). Переменная этого типа имеет значением либо адрес элемента в ОП (обычно начальный), либо значение «пусто» (англ. NIL).

Служебность ссылочного типа означает, что в принципе он м.б. и неявным для сочинителя. Однако Вирт указывает, что «...если явно разрешается использование указателей, то можно построить и более общие структуры данных, чем ...с помощью рекурсивных определений. ...можно определять потенциально бесконечные или циклические структуры (графы) и указывать, что некоторые структуры используются совместно»4. Отсюда потребность в общем случае работать как с целевыми данными некоторого типа, так и с указателями на эти данные (адресами их в ОП).

Однако в «безопасных» прогязыках5 работать с указателями – не значит вычислять их значения арифметико-логически – можно только использовать неизменными значения, предоставляемые системой реализации языка (транслятор+ОС для заданной аппаратной архитектуры) и тем самым манипулировать значениями переменных, на которые указывает ссылка (динамически размещать/удалять их элементы); говорят, что тем самым достигается герметичность системы типов языка.

«Безопасный» подход принят и в Обероне-2, где определена операция получения значения для указателя, связанного с целевой переменной (м.б. с её компонентой для неатомарного типа), при размещении этой переменной (компоненты) в ОП; далее возможно только присваивание значения указателя и использование его для обращения к значению целевой переменной (компоненты); разумеется, можно использовать значение указателя и как аргумент отношения (т.е. выносить в алгоритме некое суждение о свойствах значения прежде, чем его использовать).

Логическим следствием из структурности типов является определение в Обероне любого составного (неатомарного) типа как шаблона, имеющего имя собственное (идентификатор типа). При этом даже одинаково определённые типы, отличающиеся только именами, считаются различными.

В объявлениях величин, принадлежащих неатомарному типу, используется объявленное имя типа, а не его определение.

Пример. Так, по правилам Оберона нельзя, как в алгонотации, неоднократно определить величины типа «какой-то массив целых [коротких|длинных] чисел заданной размерности» как ТАБЛ ЦЕЛ [КР|ДЛ] '['N1{,Ni}']' : <имя-вел>{,<имя-вел>}; нужно вначале определить именованный составной тип «конкретный массив целых чисел заданной размерности» объявлением вида6:

<имя-типа> = ТАБЛ N1{, Ni} из ЦЕЛ [КР|ДЛ].

После этого можно объявлять конкретные величины (переменные, константы) данного типа конструкциями вида:

<имя-вел>{,<имя-вел>} : <имя-типа>

Наконец, в структурных алгоязыках, в т.ч. в Обероне-2, имеется тип процедура7. Он также относится к неатомарным и потому объявляется под именем собственным. Переменные этого типа имеют значением процедуру (после трансляции – её программный код) либо «пусто». Процедуру (уже существующее именованное описание алгоритма) можно присвоить другой переменной процедурного типа при определённых условиях.

Процедуру также можно связать с типом запись; при этом обозначение8 переменной-компоненты записи, с которой связана переменная-процедура, указывается в качестве т.н. приёмника в этой процедуре. В результате, если с типом приёмника связана статически (по исходному тексту) некая процедура, а тип приёмника динамически (при исполнении кода этого текста) может меняться, то может заменяться и процедура – статическая на ту, которая связана с переменной данного типа запись. При этом мы никаких сущностей не конструируем при выполнении – всё было определено в исходном тексте, просто при проверке типа переменной-приёмника мы можем передать её как фактический параметр (предмет труда) вместо одной процедуры в другую.

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

По умолчанию (для правильного хода исполнения) токарная обработка обеспечивает нужный класс; поэтому статическим типом детали будет «чисто точёная» и с ним связывается процедура, алгоритмизующая следующую целевую техоперацию (допустим, установку детали в сборочную единицу). Однако сочинитель (технолог) знает, что возможно отклонение класса чистоты, допускающее исправление (скажем, машинную или электролитическую шлифовку поверхности); поэтому при алгоритмизации он предусматривает тип детали «грубо точёная» и связывает с ним дополнительную процедуру шлифовки (разумеется, с заключительным контролем, как и для любой техоперации).

Понятно, что деталь может вообще не поддаваться исправлению (скажем, неточно сделанная); на этот случай предусматривается тип «брак» и с ним связывается процедура утилизации. Поэтому измерение, конечно, не сводится к проверке класса чистоты.

По существу процедурный тип представляет алгоритм как структуру данных. При этом он качественно иной, чем другие, что выражается в множественности точек зрения на него: он и атомарный (т.к. используется целиком – процедуру нужно выполнить, как она описана, а не «по кусочкам» – если нужно противное, объявляем части как отдельные процедуры), и сложный – значение является агрегатом, в т.ч. и объявлений типов данных, и в какой-то мере произвольный – имени процедуры, связанной с динамическим типом, может соответствовать (динамически) не единственное содержание.

Мы можем соотнести структуры данных со структурами управления, что в основном сделал Вирт, выявив глубокое внутреннее родство этих категорий10.

Позицию Вирта можно развить. При этом будем исходить из того, что чисто произвольные типы алгоструктур меняются также как за счёт рекурсивного порождения/исключения однородных элементов (вызова/завершения вставок, т.е. БП с возвратом), так и путём свободного порождения/модификации/исключения разнородных элементов (создания/изменения хода параллельных процессов, по существу – БП «без возврата», а точнее – «безусловного ветвления» маршрутов, или расщепления рабочей точки, т.е. пуска/завершения из данного процесса нового процесса либо внешней модификации состояния последнего); сюда же, видимо, относится и динамическое связывание процедуры с типом приёмника (по сути – условный переход к подпрограмме). Последовательность же определяется не только циклическими операторами, но и естественным переходом (по ходу следования).

Можно ли аналогично и независимо от типов объектов задать базовый набор операций над ними? Да, и здесь также возможны варианты. Мы полагаем, что элементарными (простыми) типами операций можно считать передачу данных (так реализуется и присваивание), их обработку (арифметико-логическое преобразование) и анализ (проверку логических отношений). Сложные образуются комбинированием простых в выражения, произвольные – комбинированием простых и/или сложных в вычислительные процедуры. Простые типы имеют соответствие на низшем уровне рассмотрения информоделей – в системе команд процессора информашины (и микроопераций, из которых м.б. составлены эти команды).

Отчасти определение операций зависит от масштабного уровня рассмотрения; так, Вирт на уровне алгоязыка формулирует:

«Для вычислений нужно иметь набор операций. Поэтому для каждого стандартного типа данных язык программирования предлагает некий набор примитивных, стандартных операций, а для каждого метода структурирования – специальные операции для доступа к компонентам вместе с соответствующей нотацией...

Важнейшие основные операции – сравнение и присваивание, то есть проверка равенства (или порядка в случае упорядоченных типов) и команда, так сказать, обеспечивающая равенство. Принципиальное различие между ними подчёркивается обозначениями, которые используются на протяжении всей книги:

Проверка равенства: х = у (выражение, дающее значение TRUE или FALSE).

Присваивание переменной х: х := у (оператор, делающий х равным у).

Эти основополагающие действия определены для большинства типов данных, но следует заметить, что их выполнение может требовать серьезных вычислений, если данные велики по объёму и имеют сложную структуру.

Для стандартных примитивных типов данных мы постулируем не только возможность присваивания и сравнения, но ещё и набор операций для создания (вычисления) новых значений. А именно: для числовых типов мы вводим стандартные арифметические операции, а для логических значений – элементарные операции логики высказываний.»11

Здесь мы видим по сути тот же базис: анализ как сравнение, передача как присваивание, обработка как вычисление (правой части присваивания).

В начало страницы

О значениях и их видимости

Значения величины образуют некоторое множество. Оно характеризуется в первую очередь мощностью – числом различных значений; от этого зависит объём памяти, необходимый для представления значения величины. Далее, значения м.б. упорядочены, т.е. можно ответить на вопрос, какое из них больше/меньше.

Мощность составного типа определяется как прямое произведение значений составляющих типов. В информатике мощность любого типа конечна.

В целом значения типов хорошо описаны, напр. у Вирта; мы лишь предложим некоторые дополнительные точки зрения на них.

Для числовых значений определен порядок (линейный) т.н. поглощения одними подтипами других при присваивании. Общие правила: целое значение можно присвоить вещественному, а короткое – длинному, но не наоборот.

Булевы значения типа логический в Обероне по традиционной языковой практике программирования обозначены символически как «истина» и «ложь» (по-английски). Критику неэргономичности этого представления можно найти у Паронджанова в /1, Гл.10/; соглашаясь с ней, мы будем трактовать эти значения как ответы на вопрос вида: «Имеется ли некая вещь (предмет, свойство)/Выполняется ли некое отношение?»; естественным образом это будут ответы «да» и «нет» (по-русски, а в общем случае – на любом родном языке сочинителя).

Для типа литерный в самой таблице каждому предметному коду сопоставлен символ одной из двух категорий: отображаемый – имеющий символическое представление как знака, читаемого человеком; неотображаемый – не имеющий своего знака, что обычно связано с его использованием как управляющего (для алгоритмов работы с литерными величинами).

Размерность машинных кодов символа и префикса определяется соглашениями по реализации; сегодня общепринята длина каждого из них в 1 Байт.

Существует кодовая таблица по умолчанию (выбираемая при отсутствии префикса, т.е. при общей разрядности значения литерного типа 1 Байт). Обычно ею считается алфавит ASCII (представляющий десятичные цифры, буквы латиницы и принятые в европейских естественных языках знаки препинания); но на самом деле ASCII – это лишь подтаблица, составляющая первую половину байтового алфавита. Вторую половину составляют гл. обр. буквы нелатинского алфавита и знаки псевдографики. Её определяют по-разному (прежде всего – заменяя буквы одних языков другими). В этом одна из основных причин появления разных кодовых таблиц; другая связана с тем, что кроме алфавита естественного языка, надо представить и специальные алфавиты (математический, научный и пр.).

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

Естественными значениями типа множество являются числа (целые), принадлежащих некоторому отрезку целочисленной оси. Из этого исходит определение Виртом множества в предметной форме; число представлено неявно, как номер позиции в характеристической функции (иначе говоря, битовой маски присутствия элемента в подмножестве целых, начиная с 0 и заканчивая N-1, где N-разрядность кода значения типа множество).

Итак, речь идёт о заданном наборе значений, выбранных из более широкого; и здесь можно увидеть родство типа множество и типа перечислимый (последний существовал, напр. в Паскале).

Можем ли мы трактовать множество как перечислимый тип для других «атомарных» типов? Если говорить о множестве типа логический, то «лобовое» его понимание – как результатов проверки некоего набора суждений (вычисления их логвыров). Однако естественней будет другая трактовка – каждая позиция множества отражает присутствие сопоставленного ей суждения из числа использованных в условных операторах данного алгоритма (процедуры).

Говоря проще, мы по ходу исполнения алгоритма «маскируем» или «размаскируем» логвыры, т.е. принимаем или нет результаты их вычисления во внимание в условных операторах. Это даёт возможность грубой адаптации алгоритма к обстановке (прежде всего для целей интеллектного программирования); тонкая адаптация, конечно, возможна при использовании нечёткой логики и нестрогой математики. Ясно, что для этой цели длина кода множества д.б. не меньше мощности набора логвыров.

Для литерного типа множество может трактоваться как маска употребления тех или иных литер из заданного набора (кодовой таблицы/подтаблицы); для этого длина кода множества д.б. не меньше мощности этого набора.

Не следует забывать, что различные трактовки множества существуют в представлении сочинителя; в языке Оберон невозможно переопределить тип компонент множества (а их подразумеваемый тип, как мы помним – целые числа). Поэтому сочинитель должен сам определять структуры данных и операции над ними, вытекающие из иной трактовки.

Уже говорилось, что возможно более детальное определение видимости значений, чем просто глобальное/локальное; здесь встаёт задача разумного усложнения. И снова компонентная парадигма предлагает прозрачный подход: вводится свойство импортируемости/экспортируемости величины между модулями (программными реализациями алгоритмов). Оно реализовано в прогязыках Оберон-семейства.

Экспортируемость означает, что величина, определённая в данном алгоритме, будет видна за его пределами без каких-то дополнительных ограничений (глобальна); иначе величина будет видна только в данном алгоритме (локальна). В то же время импортируемость означает, что величина, экспортируемая другим алгоритмом, будет видна в данном; иначе она видна в нём не будет, хоть и экспортирована.

Как следствие, возможно, что некая экспортированная величина фактически не видна (её значение не м.б. использовано) ни в одном алгоритме, кроме «родного» для неё (где она объявлена). Это проверяется просто по объявлениям величин, т.е. до исполнения программы; в общем случае, видимо, такую ситуацию не нужно считать ошибочной.

В начало страницы | Оглавление | Версия для печати

Copyright © Жаринов В.Н.

1 Вирт Н. Алгоритмы и структуры данных. Новая версия для Оберона. – М:ДМК–Пресс, 2010. – с.21.

2 Вирт Н., 2010. – с.21.

3 Вирт Н., 2010. – с.12.

4 Вирт Н., 2010. – с.171.

5 Т.е. дающих потенциально наиболее гарантоспособный машинный код, при исполнении которого на подходящей и работоспособной аппаратуре, в окружении также правильно построенных и закодированных программ и с корректными значениями данных исключены ситуации типа: «программа выполнила недопустимую операцию и будет закрыта».

6 Здесь мы воспроизводим синтаксис Оберона для составных записей в переводе, причём «из» заменяет «OF».

7 Более подробное определение типа процедура см. в: Свердлов С.З. Языки программирования и методы трансляции. – СПб.: Питер, 2007. – Приложение 1.

8 В Обероне-2 – полное имя величины или процедуры с учётом вхождения как компонента в некую структуру.

9 Визуальная формализация описанного процесса (и программная реализация средствами того же Оберона-2) может оказаться весьма сложной и нетривиальной; автор на момент написания данной сноски не уверен даже, что он в примере верно употребляет процедурный тип, но исходит из того, что сама возможность реализации появляется как результат приложения теории к практическим задачам, и с чего-то надо начинать.

10 Вирт Н., 2010. – п/р 4.2; Табл. 4.1.

11 Вирт Н., 2010. – с.22.

Hosted by uCoz