ZX-Ревю 1993 №5-6 1992 г.

Sinclair logo - продолжение. Начало см. на стр. 69 - 74. "Черепашка" в ЛОГО имеет небольшую систему собственных команд. Рассмотрим эти команды.


Темы статьи: Пресса  

SINCLAIR LOGO

(Продолжение. Начало см. на стр. 69 - 74)

Команды "Черепашки".

"Черепашка" в ЛОГО имеет небольшую систему собственных команд. Рассмотрим эти команды.

FENCE.

Обычно, когда "черепашка" доходит до границы экрана, она может продолжать свою работу, выходя за него. При этом если она покинула экран справа, то появляется на экране слева. Если покинула экран сверху, то появляется, соответственно, снизу. Действует эффект автоматического возврата. Это во многих случаях бывает удобным, но не всегда. Если Вы хотите, чтобы Ваша "черепашка" останавливалась дойдя до границ экрана и не возвращалась, то можете дать команду FENCE.

WINDOW.

Команда FENCE отключит возврат "черепашки" с противоположной стороны, но не позволит ей покинуть пределы экрана. Может быть, Вам нужен вариант, когда она может покидать экран в любом направлении без возврата. В этом случае используется команда WINDOW. Представьте себе, что Ваша "черепашка" ходит по огромному столу, а Вы смотрите сверху на этот стол через небольшое "окно" своего экрана размером 255*176. Покинув экран, "черепашка" продолжает движение в любом направлении. Она может удалиться от центра экрана на расстояние до 32767 шагов.

WRAP.

Этой командой отбивают действие включенных команд FENCE и WINDOW и возвращают "черепашку" к нормальной работе "с возвратом".

PENUP.

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

PENDOWN.

Команда на опускание пера. "Черепашка" опять готова к рисованию.

Если Вы вспомните, что "черепашка" - это как бы маленький робот-манипулятор, установленный на колесной тележке и подключенный к компьютеру, то Вам все станет ясно. С помощью электромагнита по командам от компьютера ее пишущий узел (карандаш, фломастер, шариковый стержень и т.п.) может подниматься или опускаться.

PENERASE.

"Черепашка" на нашем экране - воображаемая и потому она может делать немного больше разных вещей, чем настоящий робот. Так, например, с помощью команды PENERASE можно дать задание на стирание всех линий, которые встретятся на ее пути.

PENREVERSE - еще более хитрая команда. Для "черепашки" это указание стирать все нарисованные линии на своем пути там, где они есть, а там, где их нет - наоборот рисовать.

SETPC - эта команда расшифровывается как SET PEN COLOR - установка цвета пера. "Спектрум" работает с восемью цветами:

0 - черный

1 - синий

2 - красный

3 - пурпурный

4 - зеленый

5 - голубой

6 - желтый

7 - белый

Вы можете задать любой из восьми цветов в качестве цвета пера. Например, команда SETPC 6 установит в качестве текущего цвета желтый. Все новые линии будут изображаться желтым цветом. Более того, все то, что нарисовано в пределах одного знакоместа рядом с нарисованной линией, тоже будет окрашено в желтый цвет.

Для работы с цветом, ЛОГО имеет еще одну удобную процедуру. Это процедура PENCOLOR. С ее помощью можно получить число, которое соответствует номеру включенного в данный момент цвета. Таким образом, манипулируя с цветами, Вы можете запомнить текущий цвет в какой-либо переменной и потом, когда надо, к нему вернуться: MAKE "MYCOLOR PENCOLOR

SETPC :MYCOLOR

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

SETBG - эта команда расшифровывается как SET BackGround. Она устанавливает цвет фона экрана. Таким образом, она так же эквивалентна команде PAPER БЕЙСИКА, как команда SETPC эквивалентна команде INK.

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

MAKE "OLDCOLOR BACKGROUND

SETBG :OLDCOLOR

SETBORDER

Эта команда служит для переключения цвета рамки экрана и эквивалентна команде БЕЙСИКа BORDER.

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

Спирали.

Без этого примера не обходится ни одна книга по ЛОГО. Не знаем, что уж в нем так понравилось авторам книг, наверное дело в том, что здесь используется рекурсия.

Начнем так же, как мы начинали при рисовании квадрата:

FORWARD :SIZE RIGHT 90

Но теперь, чтобы получить эффект спирали, нам надо увеличить размер стороны (SIZE) "квадрата" после одного витка и повторить все тоже самое несколько раз.

ТО SQUARESPI :SIZE FORWARD :SIZE RIGHT 90

MAKE "SIZE :SIZE+5 SQUARESPI :SIZE

END

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

50UHRE5PI 10

Рис. 1 Рис. 2

Спирали не обязательно должны быть прямоугольными. Вы можете изменить приведенную выше процедуру, задав поворот после каждого шага не на 90 градусов, а на столько, на сколько Вам нужно. Может быть, Вам нужно управлять и величиной приращения, на которую увеличивается размер спирали после каждого витка. Это могло бы быть полезным в тех случаях, когда "черепашка" слишком быстро выходит за пределы экрана. Так в итоге мы получим процедуру для рисования спиралей с тремя параметрами:

SIZE - размер начальной стороны;

ANGLE - угол поворота;

INC - приращение стороны на каждом новом витке.

ТО SPIRAL :SIZE: ANGLE: INC FORWARD :SIZE RIGHT :ANGLE MAKE "SIZE :SIZE + :INC SPIRAL :SIZE :ANGLE :INC

END

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

SPIRAL 10, 121, 5

SPIRAL 10, 119, 5

SPIRAL 10, 135, 5

Вы можете менять не только линейный размер витков :SIZE, но и угол поворота спирали :ANGLE.

ТО ASPI :SIZE: ANGLE: INC FORWARD :SIZE RIGHT :ANGLE

MAKE "ANGLE :ANGLE + :INC SPIRAL :SIZE :ANGLE :INC

END

Посмотрите, что получится для следующих вариантов:

ASPI 10 0 5

ASPI 10 40 30

ASPI 10 2 20

Один из примеров приведен на рис. 2.

Не менее интересным будет изображение части спирали, а затем повторение ее вновь из другой точки, в которой в данный момент времени находится "черепашка". В этом случае вместо изменения значения SIZE (которое должно быть постоянным) мы делаем шаг FORWARD на переменную величину, которая рассчитывается как произведение SIZE на некоторое число COUNT, изменяющееся от единицы до максимального значения МАХ.

ТО RESPI :SIZE :ANGLE :MAX MAKE "COUNT 1

REPEAT :MAX [FORWARD :SIZE* :COUNT RIGHT :ANGLE MAKE "COUNT :COUNT + 1] RESPI :SIZE :ANGLE :MAX

END

Один из возможных примеров приведен на рис. 3:

>

>

<

RE5PI

30 130 5

Рис. 3

ПРИМЕЧАНИЕ "ИНФОРКОМА".

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

Конечно, такие процедуры пишут не на ЛОГО, а на АССЕМБЛЕРе, но для "обкатки" алгоритма, прежде чем переносить его на "АССЕМБЛЕР", ЛОГО очень удобен, ведь надо подобрать и исследовать все параметры.

Технология создания подобных объектов квазирегулярной структуры хоть и не сложна, но почему-то малоисследована - то ли у многих до нее не дошли руки, то ли мало кто об этом знает, то ли информацию об этой технологии закрывают как ценное "ноу-хау"

Вы имеете уникальную возможность провести подобные исследования, используя ЛОГО в качестве удобного подручного инструмента. В исследованиях стоит стремиться к тому, чтобы Ваш объект (например дым) выглядел как можно более натурально. Он может быть динамичным, т.е. постоянно меняться и переливаться на экране. Возможно задействование команд управления цветом. Стоит также стремиться к тому, чтобы алгоритм, положенный в основу генератора, был легко переносим на АССЕМБЛЕР.

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

Объекты ЛОГО.

Если Вы еще не запутались со всеми двоеточиями и кавычками, с которыми пришлось иметь дело в предыдущих разделах, то это очень хорошо. Дело не в том, что трудно разобраться, где что нужно ставить, просто это такой вопрос, который лучше не объяснять, а демонстрировать на примере. Если же сейчас что-то покажется не очень понятным, не пугайтесь, у Вас всегда будет возможность вернуться к этому разделу, когда Вы будете сами писать свои процедуры.

Итак, ЛОГО имеет дело с четырьмя различными видами объектов:

• Слова

• Числа

• Процедуры

• Списки

О списках мы поговорим в следующей главе.

Что касается чисел, так официально их тоже квалифицируют как "слова", но поскольку они подчиняются несколько иным правилам, мы их выделили в отдельный объект. Числа состоят из десятеричных цифр от 0 до 9. Возможно использование знака "минус" в начале

числа, а также использование десятичной точки. Числа, превышающие 10 миллионов в ЛОГО печатаются в экспоненциальной форме. Так, например, 2.3E+9 означает:

2 300 000 000

Запись E+9 обозначает, что десятичную точку следует перенести на девять позиций вправо от того места, в котором она показана в числе 2.3.

Точно так же для очень малых чисел величина экспоненты может быть отрицательной. Запись 1.4Е-6 обозначает перенос десятичной точки влево на шесть позиций. Получим:

0.0000014

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

Number too big Число слишком велико.

Если же Ваше число окажется меньше, чем 1Е-38, то оно воспринимается компьютером как ноль.

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

"FRED

Будьте внимательны и следите за тем, чтобы между кавычками и словом не образовалось случайного пробела. Дело в том, что ЛОГО признает существование "пустого слова", в котором нет ни одного символа. В программе такое "пустое слово" изображается кавычками, за которыми следует пробел. Этот странный объект на самом деле не столь бесполезен, как многим может показаться. Когда мы манипулируем со словами, обрабатывая по очереди букву за буквой, "пустое слово" является отличным индикатором того места, где следует остановиться.

Слово может быть именем какого-либо другого объекта. Мы с Вами уже рассматривали примеры, когда слово являлось именем процедуры или именем числовой переменной. Как Вы помните, последнее достигалось с помощью команды МАКЕ.

MAKE "NDS 15*40/100

По этой команде будет рассчитано значение NDS, равное 6. Мы можем сказать так, что "6" - это содержание того, что именуется словом NDS. Для того, чтобы по имени найти его содержание служит команда THING. Например:

PRINT THING "NDS

В результате получите число 6.

Поскольку поиск содержания переменной по ее имени очень и очень часто встречающаяся задача, решено было упростить форму записи и вместо THING ставить двоеточие:

PRINT :NDS

Впрочем, команда THING и двоеточие - это не вполне эквивалентные вещи и не всегда могут быть использованы одно вместо другого. Об этом мы еще поговорим чуть ниже.

Команда MAKE всегда имеет следующую конструкцию:

MAKE <имя> <содержание>

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

MAKE "PRICE 27

PRINT PRICE

27

Число 27 является значением переменной с именем PRICE.

Другой пример:

MAKE "MARY "CONTRARY

PRINT "MARY

MARY

Поскольку в команде PRINT стояли кавычки, то мы точно указали, что мы хотим напечатать именно слово MARY, что и было сделано. А вот если сделать так:

PRINT :MARY

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

CONTRARY

А вот еще более сложный пример:

MAKE "JEAN :MARY

PRINT JEAN CONTRARY

Команда MAKE присвоила имени JEAN содержимое имени MARY. Оно, как мы помним равно CONTRARY, что мы и получили по команде PRINT, дав указание распечатать содержимое JEAN.

На первый раз может показаться нелепым использовать одно слово вместо другого, но при создании программ это может быть полезным. Так, например, Вы хотите, чтобы Ваша программа сначала спросила как зовут того, кто с ней работает, а потом в диалогах с ним всегда пользовалась этим именем. Тогда Вы, не зная заранее имени пользователя, всюду в диалогах используете вместо него например имя ANSWER. А когда узнаете его имя, присвоите переменной ANSWER необходимое содержание.

ТО GREET

PRINT [WHAT IS YOUR NAME] MAKE "ANSWER READLIST PRINT "HELLO PRINT :ANSWER

END

Когда Вы работаете в БЕЙСИКе, то для ввода имени пользователя Вы использовали бы команду INPUT. Здесь же мы воспользовались для этой цели вызовом процедуры READLIST. О том, что это за процедура мы поговорим, когда придет время. Пока же Вам достаточно знать, что она возьмет слово, набранное пользователем с клавиатуры (или список слов) и присвоит его в качестве параметра в команде МАКЕ.

Теперь Вы можете видеть, что если, скажем JOHN является именем человека, работающего на компьютере, то ANSWER является именем переменной, содержанием которой является слово JOHN.

Рассмотрим еще более сложный пример:

MAKE "GIRL "MARY

PRINT "GIRL GIRL

Пока все идет тривиально просто.

PRINT :GIRL MARY

Это мы тоже уже проходили.

PRINT THING :GIRL CONTRARY

А вот это уже что-то новенькое. Фактически мы дали команду напечатать содержание имени, которое является содержанием переменной по имени GIRL. В принципе конструкция

THING :GIRL

эквивалентна конструкции

:: GIRL ,

которая не разрешена, или конструкции

THING THING GIRL

Последнюю конструкцию Вы можете проверить сами. Фактически мы имеем два уровня вложения имени: GIRL ---> MARY ---> CONTRARY

Вот перед Вами как раз тот случай, когда команда THING и знак "двоеточие" не вполне взаимозаменяемы, о чем мы и упомянули выше.

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

Рассмотрим пример. У Вас на складе лежат разные товары: кассеты, дискеты, джинсы и пр. Каждый из этих товаров обладает разной ценой (PRICE). Предположим, что Вы хотите написать процедуру, которая быстро сообщит вам данные по запрашиваемому товару.

Чтобы не делать по каждому виду товара свою процедуру, Вы сделаете подстановку имени:

TO NAMEPRINT :OBJECT PRINT :OBJECT PRINT THING :OBJECT

END

Предположим, что джинсы стоят 15 долларов, кассеты - 2, а дискеты - 1.

MAKE "JEANS 15 MAKE "CASSETTES 2 MAKE "DISKETTES 1

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

NAMEPRINT "JEANS

По такой команде получим сообщение:

JEANS

15

Если воспользоваться еще и оператором SENTENCE (с ним мы будем разбираться позже), то можно программировать целые отчеты от компьютера, например:

ТО NAMEPRINT :OBJECT

PRINT (SENTENCE "THE_PRICE_OF

:OBJECT "IS THING :OBJECT)

END

Если теперь дать команду NAMEPRINT "JEANS, то получите сообщение:

THE PRICE OF JEANS IS 15

(Цена джинсов - 15)

Еще более интересно использовать такую технику в команде МАКЕ, что дает возможность косвенного присвоения и переприсвоения переменных. Пример:

MAKE "QUANTITY "PRICE MAKE :QUANTITY 27 PRINT :PRICE

27

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

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

Как Вы знаете, в ЛОГО все слова, которые не являются числами и не начинаются с кавычек или двоеточия, интерпретируются, как имена процедур. Таким образом, встретив например слово JUMP, ЛОГО либо перейдет к поиску и исполнению процедуры JUMP, либо (если она не задана), выдаст сообщение об ошибке. Но ведь бывают случаи, когда Вам надо сделать с процедурой что-либо иное, например вызвать ее для редактирования. В этом случае перед именем процедуры должны стоять кавычки: ED "JUMP

То же самое относится и к системным операторам РО, ER и SAVE.

MAKE

"P

LIST

FIRST THING

A SENTENCE "PR WORD

CHAR 3 4 :A

Рис. 4а

MAKE

"P

LIST

FIRST THING

A SENTENCE "PR WORD

CHAR 34 :

2

2

1

1

2 2

1

Рис. 4б

"P

/

/

MAKE

/

FIRST ---

-- THING----: A

/

LIST

/ "PR

/

SENTENCE

/ CHAR --

--- 34

/

WORD

:A

Рис. 4в.

Виды процедур.

В ЛОГО имеет смысл различать два вида процедур.

Первый вид - команды, которые дают компьютеру указание выполнить какие-то действия, например:

FORWARD 50 PRINT "HELLO PENUP

SAVE "MYPROC

и т.п.

Второй вид - операторы. Их задача - рассчитать результат и выдать его для исполнения командой. Например:

SUM DIV

и т.п.

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

Единственным исключением этого общего принципа "Вход справа - выход налево" являются знаки арифметических операций +, -, /, >, <, =. Эти знаки ставятся между своими операндами - это исключение является как бы данью традиции.

Те процедуры, которые встроены в ЛОГО без Вашего участия и являются системными, называют ПРИМИТИВАМИ.

Иногда строки в ЛОГО могут выглядеть очень сложными. Посмотрите, например, на строку, приведенную на рис. 4а.

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

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

являются встроенными примитивами.

Теперь на листе бумаги напишите первое слово строки. Это обязательно команда. К нему проведите столько стрелок, сколько параметров требует эта команда, см. рис 4в. В конце первой стрелки запишите следующее слово. Если это не имя процедуры, то следующее слово запишите в конце следующей стрелки. Если же это процедура, то к ней тоже проведите столько стрелок, сколько параметров она требует.

Продолжайте таким образом, пока не дойдете до конца ЛОГО-строки. Результат для данной строки показан на рис. 4в. Здесь ясно видно как и от кого каждая процедура ожидает входные данные и куда направляет результат своей работы.

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

ГЛАВА 4. СЛОВА И СПИСКИ

Что такое список, знают конечно все и объяснять этого не надо. Даже совсем не рассеянные люди, готовясь к поездке, составляют список того, что надо захватить в дорогу.

Список как объект языка ЛОГО ничем не отличается от тех списков, к которым Вы привыкли в обыденной жизни. Правда, ЛОГО любит, чтобы списки для него заключали в квадратные скобки, а отдельные элементы списков отделяли друг от друга с помощью пробелов. Порядок элементов в списке играет важную роль. Так, два нижеследующих списка являются различными: [JANUARY FEBRUARY MARCH] [JANUARY MARCH FEBRUARY]

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

Обычно нет необходимости слова в списках начинать с кавычек. ЛОГО полагает, что два нижеследующих списка идентичны:

[JANUARY FEBRUARY MARCH] ["JANUARY "FEBRUARY "MARCH)

Для чисел мы вводили имена переменных, точно так же можно дать имя списку. Это тоже делается командой MAKE.

MAKE "SHOPPING [BREAD BUTTER MILK STAMPS]

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

Преимущество работы с именованным списком состоит в том, что мы можем ссылаться на него по имени. Например, команда PRINT :SHOPPING

BREAD BUTTER MILK STAMPS

Обратите внимание на то, что при печати списка ЛОГО опускает квадратные скобки. Мы можем присвоить списку другое имя или, наоборот, списку с заданным именем присвоить иное содержание, например:

MAKE "BOUGHT :SHOPPING PRINT :BOUGHT

BREAD BUTTER MILK STAMPS

Так у нас появился новый список BOUGHT.

Выбор элементов списка.

В списках было бы очень мало пользы, если бы с ними можно было работать только как с одной цельной вещью (хранить, переименовывать и распечатывать). Нам нужны приемы, с помощью которых мы могли бы иметь доступ к отдельным элементам списка. ЛОГО предоставляет несколько таких приемов. Самый простой и наиболее широко применяющийся - оператор FIRST. Он выдает первый элемент списка. Например: PRINT FIRST [JANUARY FEBRUARY MARCH] JANUARY

Оператор FIRST может работать и с именованными списками тоже:

PRINT FIRST :SHOPPING BREAD

Разобравшись с первым элементом списка, мы хотели бы разобраться и с остальными. Для этого наиболее стандартным является оператор BUTFIRST. Он создает второй список, состоящий из всех элементов исходного списка, кроме первого. Т.е. как бы отбрасывается первый элемент, а оставшиеся элементы становятся новым списком.

PRINT BUTFIRST [JANUARY FEBRUARY MARCH] FEBRUARY MARCH

совершенно аналогично для именованных списков:

PRINT BUTFIRST :SHOPPING BUTTER MILK STAMPS

Кроме естественного различия между FIRST и BUTFIRST есть еще одно очень важное различие:

FIRST - дает слово; BUTFIRST - дает список.

Специально для удобства пользователей со списками можно работать не только с начала, но и с конца. Оператор LAST дает последний элемент списка:

PRINT LAST :SHOPPING STAMPS

Есть и оператор BUTLAST, который, как Вы уже очевидно догадались, создает новый список, равный исходному без последнего элемента.

PRINT BUTLAST [MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY] MONDAY TUESDAY WEDNESDAY THURSDAY

Можно выбирать не только первый или последний элемент из списка. Для того, чтобы получить любой произвольный элемент, служит оператор ITEM, который требует после себя указания двух параметров - номера нужного элемента списка и самого списка.

PRINT ITEM 2 [APRIL MAY JUNE] MAY

Список может быть задан своим именем:

PRINT ITEM 3 :SHOPPING MILK

Часто бывает важным знать, сколько же элементов содержится в Вашем списке. Для этого служит оператор COUNT.

PRINT COUNT [JANUARY FEBRUARY MARCH]

3

PRINT COUNT :SHOPPING

4

Многие стандартные процедуры ЛОГО воспринимают списки в качестве входных параметров. С некоторыми мы уже сталкивались. Такова, например, команда REPEAT, после которой должны быть два параметра. Первый параметр - число повторов. Второй параметр -список повторяющихся команд. Это один из тех случаев, когда кавычки могут быть внутри списка, причем опустить их нельзя:

REPEAT 4[MAKE "NUMBER :NUMBER+1]

Хоть команда REPEAT и принимает список как список, тем не менее команда МАКЕ, стоящая в списке, требует, чтобы ее первым параметром было имя. Если Вы захотите испытать этот пример, то предварительно не забудьте задать первоначальное значение переменной NUMBER.

Некоторые из встроенных примитивов могут работать как со словами, так и со списками. Примером может служить команда PRINT, которая распечатает и слово и список. Фактически именно для таких случаев в ЛОГО и ввели правило, по которому списки должны быть заключены в квадратные скобки.

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

Процедура работает в цикле REPEAT, переходя от одного элемента к другому и выхватывая его с помощью оператора ITEM.

TO LBL :ALIST

MAKE "COUNTER 1 REPEAT COUNT :ALIST

[PRINT ITEM :COUNTER :ALIST MAKE "COUNTER :COUNTER+1]

END

Тогда команда:

LBL [LBL STANDS FOR LINE BY LINE] даст результат

LBL

STANDS FOR LINE BY

LINE

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

Используя уже изученные инструменты и приемы, мы можем применять списки для того, чтобы хранить и обрабатывать информацию. Например, Вам надо сохранить в базе данных свои ежемесячные расходы в течение года, а потом найти их среднюю величину и сумму. Тогда Вы составите список, в котором первым элементом будет расход за январь, вторым - за февраль и т.д. Нижеприведенная процедура пройдет по списку таким же образом, как это делала процедура LBL. Только она не будет распечатывать найденные элементы, а будет накапливать их текущую сумму в переменной TOTAL, которая конечно в начале процедуры должна быть занулена. Средняя величина расходов определится делением суммы на двенадцать.

TO AVERAGE :ALIST MAKE "TOTAL 0 MAKE "COUNTER 1

REPEAT 12 [MAKE "TOTAL, :TOTAL + ITEM: COUNTER :ALIST

MAKE "COUNTER :COUNTER + 1] MAKE "AVERAGE :TOTAL/12 PRINT "TOTAL PRINT :TOTAL PRINT "AVERAGE PRINT :AVERAGE

END

Испытайте эту процедуру с любым удобным Вам списком из двенадцати чисел.

Ввод слов и списков.

Обычно ввод списков с клавиатуры выполняют с помощью оператора READLIST. Результат его работы должен быть тут же передан какой-либо переменной или процедуре. Обычно это делают с помощью команды MAKE. Например:

MAKE "ANSWER READLIST

По этой команде компьютер переходит в состояние ожидания до тех пор, пока Вы не наберете то, что Вам нужно на клавиатуре. Обозначается это состояние вопросительным знаком на экране. Список ввода состоит из тех слов, разделенных пробелами, которые Вы наберете до нажатия клавиши ENTER, после чего ввод будет закончен. Попробуйте и посмотрите, что Вы набрали:

MAKE "ANSWER READLIST

PRINT :ANSWER

LOGO не имеет соответствующего оператора для ввода только одного слова, но в нем и нет необходимости. Обычно, когда в этом возникает необходимость, пользуются конструкцией:

FIRST READLIST

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

MAKE "START FIRST READLIST

MAKE "REST BUTFIRST READLIST

Просто встретив READLIST второй раз, компьютер снова войдет в состояние ожидания и примет окончание списка, НО ЭТО БУДЕТ УЖЕ НЕ ТОТ СПИСОК.

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

MAKE "ANSWER READLIST

MAKE "START FIRST :ANSWER

MAKE "REST BUTFIRST :ANSWER

Пустой список.

Список, в котором не содержится ни один элемент, является необычным, но очень полезным объектом. Обозначается он - [] и называется пустым списком. Он нужен, например, при создании списков в качестве исходного элемента. Он же используется для сигнализации о конце работы, когда какой-то заполненный список сканируется и элемент за элементом извлекаются из него и отправляются на обработку процедурами.

Создание и слияние списков.

Для этих целей широко используется процедура SENTENCE. Мы уже встречались с ней в команде PRINT. Она принимает в качестве входных параметров два или более слова или списка и объединяет их в один список. Например:

MAKE "PROVERB SENTENCE "MANY "HANDS

PRINT :PROVERB MANY HANDS

Мы слили два слова: MANY и HANDS в один список MANY HANDS. Но SENTENCE может сливать и списки:

MAKE "PROVERB SENTENCE [MANY HANDS] [MAKE LIGHT WORK]

PRINT :PROVERB

MANY HANDS MAKE LIGHT WORK Или:

MAKE "NEWSAYING SENTENCE :PROVERB [OR SPOIL BROTH]

PRINT :NEWSAYING

MANY HANDS MAKE LIGHT WORK OR SPOIL BROTH

Оператор SENTENCE может иметь более двух входных параметров. В этом случае и SENTENCE и параметры должны быть заключены в круглые скобки.

PRINT (SENTENCE [A ROLLING][STONE GATHERS][NO MOSS]) или:

MAKE "OLDSAYING (SENTENCE [THE SAYING) :PROVERB [IS TRUE]) PRINT :OLDSAYING THE SAYING MANY HANDS MAKE LIGHT WORKS IS TRUE

Команда PRINT всегда требует при себе только одного входного параметра - слова или списка, поэтому Вы не можете напечатать:

PRINT "MANY "HANDS

Вам на помощь приходит список:

PRINT [MANY HANDS]

Но если текст еще более сложен и требует слияния списков и слов в одно целое, то мы пользуемся оператором SENTENCE:

PRINT SENTENCE [THE SHOPPING LIST IS] :SHOPPING В результате Вы получите:

THE SHOPPING LIST IS BREAD BUTTER MILK STAKES

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

Мы начнем с того, что создадим список месяцев - YEAR, а список расходов EXPEND сделаем пока пустым списком. Затем повторим двенадцать раз процедуру ввода данных с клавиатуры - INMONTH.

ТО BUILDLIST

MAKE "YEAR [JANUARY FEBRUARY MARCH APRIL MAY

JUNE JULY AUGUST SEPTEMBER OCTOBER NOVEMBER DECEMBER] MAKE "EXPEND [] MAKE "COUNTER 1 REPEAT 12[INMOUNTH]

END

Процедура INMONTH должна печатать название очередного месяца и принимать с клавиатуры данные по расходам за этот месяц. Для этого используется техника FIRST READLIST, рассмотренная выше.

ТО INMONTH

MAKE "MOUTH ITEM :COUNTER :YEAR PRINT :MONTH

MAKE "EXPEND SENTENCE :EXPEND

FIRST READLIST

MAKE COUNTER :COUNTER + 1

END

Есть еще один изощренный метод исполнения того, что делает оператор SENTENCE. Обычно изощрения в программировании вовсе не являются необходимыми улучшениями, но в данном случае у нас появляется одно преимущество. В этой технологии используется идея, описанная в конце предыдущей главы. Давайте рассмотрим слова в списке YEAR как имена переменных, содержанием которых является ежемесячный расход. Тогда, например, "JANUARY - это имя месячного расхода за январь. Тогда процедура INMONTH может выглядеть так:

ТО INMONTH

MAKE "MONTH ITEM :COUNTER :YEAR PRINT :MONTH

MAKE :MONTH FIRST READLIST MAKE "COUNTER :COUNTER+1

END

Вторая команда MAKE использует содержание MONTH в качестве своего первого параметра, в результате JANUARY станет именем тех данных, которые будут считаны с клавиатуры по FIRST READLIST.

Такой подход дает нам то преимущество, что каждый элемент данных может быть легко индивидуально изменен. При написании программ всегда следует думать о том, что должен сделать пользователь, если случайно допустит ошибку. Если мы будем работать таким приемом, то нам не нужен список расходов EXPEND.

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

Если Вам захочется сохранить результаты этих экспериментов на кассете в виде сборника процедур для ведения личной бухгалтерии, ЛОГО обеспечивает для этого только одну возможность. Вы можете воспользоваться командой SAVEALL, после которой надо указать имя файла:

SAVEALL "MONEY

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

Работа со словами.

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

PRINT FIRST "ABC A

Точно так же:

PRINT COUNT "Friday

даст в результате:

6

Из рассмотренных в этой главе процедур только две неприменимы для работы с отдельными словами. Это процедуры ITEM и SENTENCE.

Аналог процедуре ITEM мы сделаем несколько позже, воспользовавшись для этого FIRST, LAST, BUTFIRST, BUTLAST и рекурсией.

А вот в качестве аналога процедуры SENTENCE для создания слов есть специальная процедура WORD. Она и работает как SENTENCE, принимая два или более слов, но сливает их не в список, а в одно слово, т.е. не оставляет между составляющими словами пробелов.

PRINT WORD "BLACK "POOL

BLACKPOOL

Так же, как и SENTENCE, процедура WORD требует наличия круглых кавычек, если входных данных более, чем два.

PRINT (WORD "BIRM "ING "HAM)

BIRMINGHAM

В качестве примера мы рассмотрели несложную процедуру, которая принимает с клавиатуры от пользователя слово и печатает его задом наперед. Для приема слова мы опять используем технику FIRST READLIST. Затем, начиная с конца, это слово сканируется и символ за символом собираются в новое слово с помощью оператора WORD. Исходно новое слово задается пустым словом.

ТО REVERSE

PRINT (GIVE ME A WORD) MAKE "INWORD FIRST READLIST MAKE "NEWWORD " REPEAT COUNT :INWORD [MAKE "NEWWORD WORD :NEWWORD LAST :INWORD MAKE - INWORD BUTLAST : INWORD] PRINT :NEWWORD

END

Те, кто программируют на БЕЙСИКе, должны быть знакомы с процедурами, отрезающими левую или правую часть слова. В ЛОГО нет соответствующих встроенных примитивов, вместо этого мы напишем свою процедуру, которая принимает в качестве входных параметров слово и число символов, которые должны быть "отрезаны" от слова, считая слева, то есть от начала слова. Эта процедура создаст два новых слова, назовем их LEFT и RIGHT.

Работа этой процедуры похожа на работу ранее рассмотренной процедуры REVERSE. В качестве исходного значения правой (RIGHT) части задается все исходное слово, а в качестве исходного значения левой (LEFT) его части задается пустое слово. Затем необходимое количество символов переносится из RIGHT в LEFT.

ТО SPLIT :AWORD :NUM MAKE "RIGHT :AWARD MAKE "LEFT " REPEAT :NUM

[MAKE "LEFT WORD :LEFT FIRST :RIGHT

MAKE "RIGHT BUTFIRST :RIGHT]

END

для эксперимента попробуйте:

SPLIT "DEFINED 4

PRINT :RIGHT

PRINT :LEFT

В результате должно получиться

NED DEFI

А сейчас мы прощаемся с Вами до следующего выпуска, в котором рассмотрим работу с циклами и еще немного углубим свои взгляды на "черепашью графику".

(Продолжение следует)




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Трибуна - Рассуждения на тему.
Размышления - Проект "Суперспектрум".
Программирование - курс изучения ассемблера от Wlodek Black, продолжение. Методы сжатия данных.
Вступление - Сегодня публикуется самая, что ни есть, свежая версия Каталога SOSG.
Prologue - Вместо эпиграфа...

В этот день...   23 ноября