Глава 4 - Выражения
REBOL/Core руководство пользователя Основное содержание
Содержание:
1. Обзор
2. Блоки
3. Значения
3.1 Прямые и косвенные значения
3.2 Типы данных значений
4. Оценка выражений
4.1 Оценка входных данных с консоли
4.2 Оценка простых значений
4.3 Оценка блоков
4.4 Редукционные блоки
4.5 Оценка скриптов
4.6 Оценка строк
4.7 Ошибки оценки
5. Слова
5.1 Имена Слов
5.2 Использование слов
5.3 Установка слов
5.4 Получение слов
5.5 Буквенные слова
5.6 Неустановленные слова
5.7 Защита слов
6. Условная оценка
6.1 Условные блоки
6.2 Любые и все
6.3 Условные циклы
6.4 Распространённые ошибки
7. Повторная оценка
7.1 Loop
7.2 Repeat
7.3 For
7.4 Foreach
7.5 Forall and Forskip
7.6 Forever
7.7 Break
8. Выборочная оценка
8.1 Select
8.2 Switch
9. Остановка оценки
10. Trying Blocks
1. Обзор
Основная цель REBOL - установить стандартный метод связи, охватывающий все компьютерные системы. REBOL предоставляет простые, прямые средства выражения любого вида информации с оптимальной гибкостью и минимальным синтаксисом. Например, рассмотрите следующую строку:
Sell 100 shares of "Acme" at $47.97 per share
(Продать 100 акций "Акме" по цене 47,97 доллара за акцию.)
Строка очень похожа на английский, поэтому ее легко составить, если вы ее отправляете, и легко понять, если вы ее получаете. Однако эта строка на самом деле является допустимым выражением в REBOL, поэтому ваш компьютер также может ее понять и действовать в соответствии с ней. (Обратите внимание, что строка является «диалектом» REBOL. Ее можно напрямую оценить. Подробнее об этой концепции ниже.)
REBOL обеспечивает общий язык между вами и вашим компьютером. Кроме того, если ваш компьютер отправляет это выражение на компьютер вашего биржевого брокера, на котором также работает REBOL, компьютер вашего биржевого брокера может понять это выражение и действовать в соответствии с ним. Итак, REBOL обеспечивает общий язык между компьютерами. И эта линия может быть отправлена в миллионы других компьютерных систем, которые также могут с ней работать.
Следующая строка - еще один пример выражения REBOL:
Reschedule exam for 2-January-1999 at 10:30
(Перенести экзамен на 2 января 1999 г. в 10:30)
Выражение, показанное в приведённом выше примере (написанное на другом диалекте), могло быть получено вашим врачом, набравшим его, или, возможно, оно возникло из приложения, которое запускал ваш врач. Это неважно. Важно то, что выражение можно использовать независимо от типа компьютера, портативного устройства, киоска или телевизионной консоли, которую вы используете.
Значения данных (числа, строки, цены, даты и время) во всех выражениях, показанных в предыдущих примерах, являются стандартизованными допустимыми форматами REBOL. Однако слова зависят от конкретного контекста интерпретации, чтобы передать их значение. Такие слова, как sell (продавать) , at (в) и read (читать), имеют разное значение в разных контекстах. Слова являются относительными выражениями - их значение зависит от контекста.
Выражения могут обрабатываться одним из двух способов: напрямую интерпретатором REBOL или косвенно скриптом REBOL. Выражение, обрабатываемое косвенно, называется диалектом. Предыдущие примеры являются диалектами, поэтому они обрабатываются сценарием. Следующий пример не является диалектом и обрабатывается непосредственно интерпретатором REBOL:
send master@rebol.com read http://www.rebol.com
В этом примере слова send и read - это функции, которые обрабатываются интерпретатором REBOL.
REBOL делает различие в том, что информация интерпретируется прямо или косвенно. Различие не в том, является ли информация кодом или данными, а в том, как она обрабатывается. В REBOL код часто обрабатывается как данные, а данные часто обрабатываются как код, поэтому традиционное разделение между кодом и данными размывается. То, как обрабатывается информация, определяет, является ли это кодом или данными.
2. Блоки
Выражения REBOL основаны на этой концепции: вы объединяете значения и слова в блоки.
В скриптах блок обычно заключён в квадратные скобки []. Все, что заключено в квадратные скобки, является частью блока. Содержимое блока может занимать любое количество строк, а его формат полностью произвольный. В следующих примерах показаны различные способы форматирования содержимого блока:
[белый красный зеленый синий желтый оранжевый черный]
["Спилберг" "Назад в будущее" 1:56:20 MCA]
[
"Билл" billg@ms.dom # 315-555-1234
"Стив" jobs@apl.dom # 408-555-4321
"Тед" ted@gw2.dom # 213-555-1010
]
места: [
http://www.rebol.com [save %reb.html data]
http://www.cnn.com [print data]
ftp://www.amiga.com [send cs@org.foo data]
]
Некоторые блоки не требуют квадратных скобок, потому что они подразумеваются. Например, в сценарии REBOL весь сценарий не заключён в скобки, однако содержимое сценария представляет собой блок. Подразумеваются квадратные скобки внешнего блока скрипта. То же самое верно для выражений, вводимых в командной строке, или для сообщений REBOL, отправляемых между компьютерами - каждое из них является подразумеваемым блоком.
Ещё один важный аспект блоков - это то, что они несут дополнительную информацию. Блоки группируют набор значений в определённом порядке. То есть блок может использоваться как набор данных, а также как последовательность. Это будет описано более подробно в главе серии.
3. Значения
REBOL предоставляет встроенный набор значений, которые могут быть выражены и обменены между всеми системами. Значения являются основными элементами для составления всех выражений REBOL.
3.1 Прямые и косвенные значения
Ценности могут быть выражены прямо или косвенно.
Непосредственно выраженное значение известно, как оно написано лексически или буквально. Например, число 10 или время 10:30 являются непосредственно выраженными значениями.
Косвенно выраженное значение неизвестно до тех пор, пока оно не будет выполнено. Значения none, true и false требуют слов для их представления. Эти значения выражаются косвенно, потому что они должны быть вычислены, чтобы их значения были известны. Это также верно для других значений, таких как списки, хэши, функции, объекты.
3.2 Типы данных значений
Каждое значение REBOL относится к определённому типу данных. Тип данных значения определяет:
- Диапазон возможных значений для типа данных. Например, тип данных логики может быть только истинным или ложным.
- Операции, которые можно выполнять. Например, вы можете сложить два целых числа, но не можете сложить два логических значения.
- Способ хранения значений в памяти. Некоторые типы данных могут храниться напрямую (например, числа), а другие - косвенно (например, строки).
По соглашению после слов типа REBOL стоит восклицательный знак (!), Чтобы выделить их. Например:
integer!
char!
word!
string!
Слова типа данных - это просто слова
Слова, используемые для типов данных, такие же, как и любые другие слова в REBOL. В этом нет ничего волшебного! используется для их представления.
См. Приложение «Значения» для описания всех типов данных REBOL.
4. Оценка выражений
Чтобы оценить выражение, нужно вычислить его значение. REBOL работает, оценивая серию выражений, составляющих сценарий, и затем возвращает результат. Оценка также называется запуском, обработкой или выполнением сценария.
Оценка проводится по блокам. Блоки можно набирать на консоли или загружать из файла сценария. В любом случае процесс оценки одинаков.
4.1 Оценка ввода с консоли
Любое выражение, которое может быть вычислено в сценарии, также может быть вычислено из приглашения REBOL, предоставляя простые средства проверки отдельных выражений в сценарии.
Например, если вы введёте следующее выражение в командной строке консоли:
>> 1 + 2
выражение оценивается и возвращается следующий результат:
== 3
О примерах кода ...
В приведенном выше примере показано приглашение консоли (>>) и индикатор результата (==), чтобы дать вам представление о том, как они отображаются в консоли. Для следующих примеров строки подсказки и результата не показаны. Однако вы можете предположить, что эти примеры можно ввести в консоль, чтобы проверить их результаты.
4.2 Оценка простых значений
Поскольку значение прямо выраженных значений известно, они просто возвращают свои значения. Например, если вы наберёте следующую строку:
10:30
возвращается значение 10:30. Это поведение всех прямо выраженных значений. Оно включает:
integer 1234
decimal 12.34
string "REBOL world!"
time 13:47:02
date 30-June-1957
tuple 199.4.80.1
money $12.49
pair 100x200
char #"A"
binary #{ab82408b}
email info@rebol.com
issue #707-467-8000
tag <IMG SRC="xray.jpg">
file %xray.jpg
url http://www.rebol.com/
block [milk bread butter]
4.3 Оценка блоков
Обычно блоки не оцениваются. Например, набрав следующий блок:
[1 + 2]
возвращает тот же блок:
[1 + 2]
Блок не оценивается; это просто воспринимается как данные.
Чтобы оценить блок, используйте функцию do, как показано в следующем примере:
do [1 + 2]
3
Функция do возвращает результат оценки. В предыдущем примере возвращается число 3.
Если блок содержит несколько выражений, возвращается только результат последнего выражения:
do [
1 + 2
3 + 4
]
7
В этом примере вычисляются оба выражения, но возвращается только результат выражения 3 + 4.
Существует ряд функций, таких как if, loop,
while, и foreach, которые оценивают блок как часть своей функции. Эти функции подробно обсуждаются позже в этой главе, но вот несколько примеров:
if time > 12:30 [print "после полудня"]
после полудня
loop 4 [print "зацикливание"]
зацикливание
зацикливание
зацикливание
зацикливание
Это важно помнить: блоки обрабатываются как данные до тех пор, пока они не будут явно оценены функцией. Только функция может вызвать их оценку.
4.4 Редукционные блоки
Когда вы оцениваете блок с помощью do, в результате возвращается только значение его последнего выражения. Однако бывают случаи, когда вы хотите, чтобы возвращались значения всех выражений в блоке. Чтобы вернуть результаты всех выражений в блоке, используйте функцию reduce. В следующем примере reduce используется для возврата результатов обоих выражений в блоке:
reduce [
1 + 2
3 + 4
]
[3 7]
В приведённом выше примере блок был редуцирован до результатов оценки. Функция reduce возвращает результаты в блоке.
Функция reduce важна, поскольку она позволяет вам создавать блоки выражений, которые оцениваются и передаются другим функциям. Reduce оценивает каждое выражение в блоке и помещает результат этого выражения в новый блок. Этот новый блок возвращается в результате "редуцирования".
Некоторые функции, такие как print, используют reduce как часть своей операции, как показано в следующем примере:
print [1 + 2 3 + 4]
3 7
В rejoin , reform и remold функции также используют редуцирования как часть своей работы, как показано в следующих примерах:
print rejoin [1 + 2 3 + 4]
37
print reform [1 + 2 3 + 4]
3 7
print remold [1 + 2 3 + 4]
[3 7]
В rejoin, reform, и
remold функции основаны на join , form и mold функциях, но сперва выполняется reduce.
4.5 Оценка скриптов
Функция do может быть использована для оценки целых сценариев. Обычно do оценивает блок, как показано в следующем примере:
do [print "Привет!"]
Привет!
Но когда do оценивает имя файла вместо блока, файл будет загружен в интерпретатор как блок, а затем оценён, как показано в следующем примере:
do %script.r
Требуется заголовок REBOL
Для оценки файла сценария он должен включать допустимый заголовок REBOL, который описан в главе "Сценарии". Заголовок указывает, что файл содержит сценарий, а не просто случайный текст.
4.6 Оценка строк
функция do ожет быть использована для вычисления выражений , которые находятся в пределах текстовых строк. Например, следующее выражение:
do "1 + 2"
3
возвращает результат 3. Сначала строка преобразуется в блок, затем блок оценивается.
Оценка строк может быть удобной время от времени, но это следует делать только при необходимости. Например, чтобы создать процессор строки консоли REBOL, введите следующее выражение:
forever [probe do ask "=> "]
Приведённое выше выражение предложит вам ввести => и дождаться, пока вы наберёте строку текста. Затем текст будет оценён, и его результат будет напечатан. (Конечно, на самом деле это не так просто, потому что сценарий мог вызвать ошибку.)
Если в этом нет необходимости, оценка строк обычно не является хорошей практикой. Оценка строк менее эффективна, чем оценка блоков, а контекст слов в строке неизвестен. Например, следующее выражение:
do form ["1" "+" "2"]
намного менее эффективен, чем ввод:
do [1 + 2]
Блоки REBOL могут быть созданы так же легко, как и строки, а блоки лучше подходят для выражений, которые необходимо вычислить.
4.7 Ошибки оценки
Во время оценки ошибки могут возникать по разным причинам. Например, если вы разделите число на ноль, оценка остановится и отобразится ошибка.
100 / 0
** Математическая ошибка: попытка разделить на ноль.
** Где: 100 / 0
Распространенная ошибка - использование слова до того, как оно было определено:
size + 10
** Ошибка скрипта: size не имеет значения.
** Где: size + 10
Другая распространённая ошибка заключается в том, что функции в выражении не предоставляются правильные значения:
10 + [size]
** Ошибка скрипта: невозможно использовать добавление значения в блок! .
** Где: 10 + [size]
Иногда ошибки не так очевидны, и вам нужно будет поэкспериментировать, чтобы определить, что конкретно вызывает ошибку.
5. Слова
Выражения строятся из ценностей и слов. Слова используются для обозначения смысла. Слово может представлять идею или конкретную ценность.
В предыдущих примерах этой главы в выражениях использовалось несколько слов без объяснения причин. Например, слово do, reduce и try используются, но не объясняются.
Слова оцениваются несколько иначе, чем прямо выраженные ценности. Когда слово оценивается, его значение ищется, оценивается и возвращается в качестве результата. Например, если вы наберёте следующее слово:
zero
0
возвращается значение 0. Слово zero заранее определено как «ноль». При поиске слова обнаруживается и возвращается ноль.
Когда ищутся такие слова, как do и print, их значения оказываются функциями, а не простыми значениями. В таких случаях функция оценивается и возвращается результат функции.
5.1 Имена слов
Слова состоят из букв, цифр и любых из следующих символов:
? ! . ' + - * & | = _ ~
Слово не может начинаться с числа, а также существуют некоторые ограничения на слова, которые можно интерпретировать как числа. Например, -1 и +1 - это числа, а не слова.
Конец слова отмечается пробелом, новой строкой или одним из следующих символов:
[ ] ( ) { } " : ; /
Таким образом, квадратные скобки блока не являются частью слова. Например, следующий блок содержит слово test :
[test]
В словах нельзя использовать следующие символы, так как они могут привести к неправильной интерпретации слов или возникновению ошибки:
@ # $ % ^ ,
Слова могут быть любой длины, но слова не могут выходить за конец строки:
это-очень-длинное-слово-используется-как-пример
Следующие строки содержат примеры допустимых слов:
Copy print test
number? time? date!
image-files l'image
++ -- == +-
***** *new-line*
left&right left|right
REBOL не чувствителен к регистру. Все следующие слова относятся к одному и тому же слову:
синий
Синий
СИНИЙ
Регистр слова сохраняется при печати.
Слова можно использовать повторно. Значение слова зависит от его контекста, поэтому слова можно повторно использовать в разных контекстах. В REBOL нет ключевых слов. Вы можете повторно использовать любое слово, даже те, которые предопределены в REBOL. Например, вы можете использовать слово if в вашем коде иначе, чем интерпретатор REBOL использует это слово.
Выбирайте хорошие слова
Тщательно выбирайте слова, которые вы используете. Слова используются для обозначения смысла. Если вы правильно подберете слова, вам и другим будет легче понять ваш сценарий.
5.2 Использование слов
Слова используются двумя способами: как символы или как переменные. В следующем блоке слова используются как символы для цветов.
[red green blue]
В следующей строке:
print second [red green blue]
green
слова не имеют другого значения, кроме их использования в качестве названий цветов. Все слова, используемые в блоках, служат символами до тех пор, пока не будут оценены.
Когда слово оценивается, оно используется как переменная. В предыдущем примере слова print и second - это переменные, которые содержат собственные функции, выполняющие необходимую обработку.
Слово может быть написано четырьмя способами, чтобы указать, как с ним следует обращаться, подробней показано в форматах слова.
|
Формат
|
Что делает
|
|---|
|
слово
|
Оценивает слово. Это наиболее естественный и распространённый способ написания слов. Если слово содержит функцию, она будет оценена(выполнена). В противном случае будет возвращено значение слова.
|
|
слово:
|
Определяет или устанавливает значение слова. Слову присваивается новое значение. Значение может быть любым, включая функцию. См. Раздел "Установка слов" ниже.
|
|
:слово
|
Получает значение слова, но не оценивает его. Это полезно для обращения к функциям и другим данным без их оценки. См. Раздел "Получение слов" ниже.
|
|
'слово
|
Считает слово набором символов и не оценивает его. Само слово - это значение.
|
5.3 Установка слов
Слово, за которым следует двоеточие (:), используется для определения или установки его значения:
возраст: 42
обед: 12:32
день рождения: 20 марта 1990 г.
город: "Додж Сити"
тест: %stuff.r
Вы можете установить для слова значение любого типа. В предыдущих примерах слова определены как целые числа, время, дата, строка и значения файла. Вы также можете сделать слова более сложными типами значений. Например, для значений блоков и функций используются следующие слова:
towns: ["Ukiah" "Willits" "Mendocino"]
code: [if age > 32 [print town]]
say: func [item] [print item]
Почему слова установлены таким образом
Во многих языках слова ставятся со знаком равенства, например:
возраст = 42
В REBOL слова начинаются с двоеточия. Причина этого важна. Он превращает операцию множества над словами в одно лексическое значение. Представление операции над множествами является атомарным.
Разницу между двумя подходами можно увидеть на этом примере:
print length? [возраст: 42]
2
print length? [возраст = 42]
3
REBOL - это рефлексивный язык, он умеет манипулировать собственным кодом. Этот метод установки значений позволяет вам писать код, который легко управляет операциями с набором слов как единым целым.
Конечно, другая причина в том, что знак равенства (=) используется в качестве оператора сравнения.
За один раз можно задать несколько слов путем каскадирования определений слов. Например, каждое из следующих слов имеет значение 42:
возраст: номер: размер: 42
Слова также могут быть установлены с помощью функции set:
set 'time 10:30
В этом примере строка устанавливает слово time значению 10:30. Слово time записывается как буквальное (с использованием одинарной кавычеки (') в начале слова), поэтому оно не будет оцениваться.
Функция set также может устанавливать несколько слов:
set [number num ten] 10
print [number num ten]
10 10 10
В приведённом выше примере обратите внимание, что слова не нужно заключать в кавычки, потому что они находятся внутри блока, который не оценивается. Функция print показывает, что каждое слово имеет целое число 10.
Если функцией set задан блок значений, каждое из отдельных значений устанавливается в слова. В этом примере один, два и три установлены на 1, 2 и 3:
set [один два три] [1 2 3]
print три
3
print [один два три]
1 2 3
См. Раздел «Слова» в Приложении «Значения» для получения дополнительной информации о настройке слов.
5.4 Получение слов
Чтобы получить значение слова, которое было определено ранее, поместите двоеточие (:) перед словом. Слово с префиксом двоеточие получает значение слова, но не выполняет его дальнейшую оценку, если это функция. Например, следующая строка:
drucken: :print
определяет новое слово, drucken (что по-немецки означает печать), для обозначения той же функции, которую выполняет print. Это возможно, потому что :print возвращает функцию для печати , но не оценивает ее.
Теперь, drucken выполняет ту же функцию, что и print:
drucken "test"
test
Для print и drucken установлено одно и то же значение - функция, выполняющая печать.
Это также можно сделать с помощью функции get . Когда дано буквальное слово, get возвращает его значение, но не оценивает его:
stampa: get 'print
stampa "test"
test
Способность узнать значение слова также важна, если вы хотите определить значение слова, не оценивая его. Например, вы можете определить, является ли слово собственной функцией, используя следующую строку:
print native? :if
true
Здесь get возвращает функцию для if. Функция if не оценивается, а передаётся встроенной функции native?, которая проверяет, является ли это собственным типом данных. Без двоеточия функция if будет оценена, и, поскольку у неё нет аргументов, возникнет ошибка.
5.5 Буквальные слова
Умение воспринимать слово как буквальное полезно. И set, и get, а также другие функции, такие как value?, unset, protect,
и unprotect, ожидают буквального значения.
Буквальные слова могут быть записаны одним из двух способов: поставив перед словом одинарную кавычку, также известную как галочка, (') или поместив слово в блок.
Вы можете поставить галочку перед оцениваемым словом:
word: 'this
В приведённом выше примере для переменной word установлено буквальное слово this, а не значение this. Слово переменной word просто использует имя символически. В приведённом ниже примере показано, что если вы напечатаете значение word, вы увидите this:
print word
this
Вы также можете получить буквальные слова из неоцененного блока. В следующем примере функция first выбирает первое слово из блока. Затем это слово присваивается в виде значения переменной word.
word: first [this and that]
Любое слово может использоваться как буквальное. Это может относиться или не относиться к значению. Например, в примере ниже слово here не имеет значения. Слово print имеет значение, но его можно использовать как литерал, потому что буквальные слова не оцениваются.
word: 'here
print word
here
word: 'print
print word
print
Следующий пример иллюстрирует важность буквальных значений:
video: [
title "День Независимости"
length 2:25:24
date 4/july/1996
]
print select video 'title
День Независимости
В этом примере слово title ищется в блоке. Если галочка отсутствовала в заголовке, будет использовано её естественное значение. Если title не имеет естественного значения, отображается ошибка.
См. Раздел «Слова» в приложении «Значения» для получения дополнительной информации о словесных литералах..
5.6 Неустановленные слова
Слово, не имеющее значения, не установлено . Если оценивается неустановленное (unset) слово, возникает ошибка:
>> outlook
** Ошибка сценария: Outlook не имеет значения.
** Где: outlook
Сообщение об ошибке в предыдущем примере указывает, что для слова не задано значение. Значение слова не установлено. Не путайте это со словом, для которого установлено значение none, что является допустимым значением.
Ранее определённое слово можно сбросить в любой момент с помощью команды unset:
unset 'word
Когда слово не установлено, его значение теряется.
Чтобы определить, было ли установлено слово, используйте функцию value?, которая принимает буквальное слово в качестве аргумента:
if not value? 'word [print "слово word не заданно"]
слово word не заданно
Определение того, установлено ли слово, может быть полезно в сценариях, вызывающих другие сценарии. Например, скрипт может установить параметр по умолчанию, который ранее не был установлен:
if not value? 'test-mode [test-mode: on]
5.7 Защита слов
Вы можете предотвратить установку слова с помощью функции protect:
protect 'word
Попытка переопределить защищённое слово вызывает ошибку:
word: "here"
** Ошибка скрипта: Слово Word защищено, его нельзя изменить.
** Где: слово: "here"
Слово также можно снять с защиты с помощью unprotect:
unprotect 'word
word: "here"
Функции protect и unprotect также принимают блок слов:
protect [this that other]
Важные функции и системные слова могут быть защищены с помощью функции protect-system. Защита функциональных и системных слов особенно полезна для новичков, которые могут случайно задать важные слова. Если protect-system помещается в ваш пользовательский файл user.r, тогда все предопределённые слова будут защищены.
6. Условная оценка
Как упоминалось ранее, блоки обычно не оцениваются. Для принудительной оценки блока требуется функция do. Бывают случаи, когда вам может потребоваться условная оценка блока. В следующем разделе описано несколько способов сделать это.
6.1 Условные блоки
Функция if принимает два аргумента. Первый аргумент - это условие, а второй аргумент - это блок. Если условие истинна(true), блок оценивается (выполняется), в противном случае он не оценивается (не выполняется).
if now/time > 12:00 [print "после полудня"]
после полудня
Условие обычно является выражением, которое принимает истинное (true) или ложное (false) значение; однако можно указать и другие значения. Только значение false или none препятствует оценке блока. Все остальные значения (включая ноль(!)) обрабатываются как истинные и приводят к оценке блока. Это может быть полезно для проверки результатов find, select, next и других функций, которые не возвращают ничего (none):
string: "давайте поговорим о REBOL"
if find string "поговорим" [print "найдено"]
найдено
Функция either(либо) расширяет функцию if(если). Она включает третий аргумент, который является блоком для оценки, когда условие ложно:
either now/time > 12:00 [
print "после полудня"
][
print "до полудня"
]
после полудня
Функция either также интерпретирует значение none как false.
Обе функции if и either возвращают результат оценки своих блоков. В случае if значение блока возвращается только в том случае, если блок оценивается; в противном случае возвращается none. Функция if полезна для условной инициализации переменных::
flag: if time > 13:00 ["обед уже съеден"]
print flag
обед уже съеден
Используя результат функции either, предыдущий пример можно переписать следующим образом:
flag: either now/time > 13:00 [
"обед уже съеден"
][
"обед ещё цел"
]
print flag
обед уже съеден
Поскольку и if, и either являются функциями, их аргументы блока могут быть любым выражением, результатом которого является блок при оценке. В следующих примерах слова используются для представления аргумента блока для if и either.
notice: [print "Проснись!"]
if now/time > 7:00 notice
Wake up!
notices: [
[print "Уже восход!"]
[print "Уже полдень!"]
[print "Уже закат!"]
]
if now/time > 12:00 second notices
Уже полдень!
sleep: [print "...продолжай спать..."]
either now/time > 7:00 notice sleep
Проснись!
Условные выражения, используемые для первого аргумента как if, так и either, могут быть составлены из большого количества функций сравнения и логики. Обратитесь к главе «Математика» за дополнительной информацией.
Избегайте этой распространённой ошибки
Наиболее частая ошибка в REBOL - это забыть второй блок для either или добавить второй блок для if. Эти примеры как создатели трудно найти ошибки:
either age > 10 [print "старше"]
if age > 10 [print "старше"] [print "моложе"]
Эти типы ошибок обнаружить, поэтому имейте это в виду, если кажется, что эти функции не работают так, как вы ожидаете.
6.2 Любые и все
Функции any(любой) и all(все) позволяют быстро оценивать некоторые типы условных выражений. Эти функции можно использовать по-разному: вместе с if, either и другими условными функциями, либо отдельно.
И any, и all принимают блок выражений, которые оцениваются по одному выражению за раз. Функция any возвращает первое истинное(true) выражение, а функция all возвращает первое ложное(false) выражение. Имейте в виду, что ложное выражение также может быть none, а истинное выражение - это любое значение, кроме false или none.
Функция any возвращает первое значение, которое не является ложным, в противном случае она не возвращает none. Функция all возвращает последнее значение, если все выражения не ложны, в противном случае возвращает none.
Обе функции any и all оценивают ровно столько, сколько им нужно. Например, если какое-либо выражение обнаружило истинное выражение, ни одно из оставшихся выражений не оценивается. Вот пример использования any::
size: 50
if any [size < 10 size > 90] [
print "Размер вне допустимого диапазона."
]
Поведение any также полезно для установки значений по умолчанию. Например, в следующих строках устанавливается число 100, но только если его значение none:
number: none
print number: any [number 100]
100
Точно так же, если у вас есть различные потенциальные значения, вы можете использовать первое, у которого действительно есть значение (не none ):
num1: num2: none
num3: 80
print number: any [num1 num2 num3]
80
Вы можете использовать any с такими функциями, как find, чтобы всегда возвращать действительный результат:
data: [123 456 789]
print any [find data 432 999]
999
Точно так же all можно использовать для условий, требующих, чтобы все выражения были true(истинными):
if all [size > 10 size < 90] [print "Размер в требуемом диапазоне"]
Размер в требуемом диапазоне
Вы можете убедиться, что значения были установлены до оценки функции::
a: "REBOL/"
b: none
probe all [string? a string? b append a b]
none
b: "Core"
probe all [string? a string? b append a b]
REBOL/Core
6.3 Условные циклы
Функции until and while fповторяют оценку блока до тех пор, пока не будет выполнено условие.
Функция until повторяет блок до тех пор, пока оценка блока не вернёт true (то есть не false или none). Блок оценки всегда оценивается хотя бы один раз. Функция until возвращает значение своего блока.
В приведённом ниже примере будет напечатано каждое слово в цветовом блоке. Блок начинается с печати первого слова блока. Затем он переходит к следующему цвету для каждого цвета в блоке. Функция tail?(хвост?) проверяет конец блока и вернёт true, что приведёт к завершению работы функции until.
color: [красный зелёный синий]
until [
print first color
tail? color: next color
]
красный
зелёный
синий
Функция break(прервать) может быть использована, чтобы уйти из цикла until в любое время.
Функция while повторяет оценку двух своих аргументов блока, в то время как первый блок возвращает true. Первый блок - это блок условий, второй блок - блок оценки. Когда блок условий возвращает false или none, блок выражения больше не будет оцениваться(выполняться), и цикл завершится.
Вот пример, аналогичный показанному выше. Цикл while будет продолжать печатать цвет до тех пор пока не в цвета ещё напечатаны.
color: [красный зелёный синий]
while [not tail? color] [
print first color
color: next color
]
красный
зелёный
синий
Блок условия может содержать любое количество выражений, если последнее выражение возвращает условие. Чтобы проиллюстрировать это, в следующем примере в блок условия добавляется печать. Это напечатает значение индекса цвета. Затем он проверит наличие хвоста цветового блока, что является условием, используемым для цикла.
color: [red green blue]
while [
print index? color
not tail? color
][
print first color
color: next color
]
1
red
2
green
3
blue
4
Последнее значение блока возвращается из функции while.
Break можно использовать для выхода из цикла в любой момент времени.
6.4 Распространённые ошибки
Условные выражения являются ложными только тогда, когда они возвращают false или none, и они true, когда они возвращают любое другое значение. Все условные выражения в следующих примерах возвращают true, даже нулевые и пустые значения блоков:
if true [print "ага"]
ага
if 1 [print "ага"]
ага
if 0 [print "ага"]
ага
if [] [print "ага"]
ага
Следующие условные выражения возвращают false:
if false [print "ага"]
if none [print "ага"]
Не заключайте условные выражения в блок. Условные выражения, заключённые в блоки, всегда возвращают true результат:
if [false] [print "ага"]
ага
Не путайте either с if. Например, если вы собираетесь написать:
either some-condition [a: 1] [b: 2]
но напишите вместо этого:
if some-condition [a: 1] [b: 2]
Функция if будет игнорировать второй блок. Это не вызовет ошибки, но второй блок никогда не будет оценён.
Обратное тоже верно. Если вы напишете следующую строку, опуская второй блок:
either some-condition [a: 1]
Функция either не будет оценивать правильный код и может привести к ошибочному результату.
7. Повторная оценка
Функции while и until, указанные выше, используются для цикла до тех пор, пока не будет выполнено условие. Также есть несколько функций, которые позволяют выполнять цикл заданное количество раз.
7.1 Loop
Функция loop оценивает блок заданное количество раз. В следующем примере выводится строка из 40 тире:
loop 40 [prin "-"]
----------------------------------------
Обратите внимание, что функция prin похожа на функцию print , но выводит свой аргумент без завершения строки.
Функция loop возвращает значение окончательной оценки блока:
i: 0
print loop 40 [i: i + 10]
400
7.2 Repeat
Функция repeat расширяет loop, позволяя вам контролировать счётчик цикла. В repeat первый аргумент функции является слово, которое будет использоваться для хранения значения счётчика:
repeat count 3 [print ["count:" count]]
count: 1
count: 2
count: 3
Также возвращается окончательное значение блока:
i: 0
print repeat count 10 [i: i + count]
55
В предыдущих примерах слово count имеет своё значение только в блоке repeat. Другими словами, значение count является локальным для блока. После завершения repeat count возвращается к предыдущему установленному значению.
7.3 For
Функция for расширяет repeat, позволяя указать начальное значение, конечное значение и приращение к значению. Любое из значений может быть положительным или отрицательным.
Пример ниже начинается с нуля и отсчитывается до 50 с увеличением на 10 каждый раз в цикле.
for count 0 50 10 [print count]
0
10
20
30
40
50
Функция for проходит цикл до конечного значения включительно. Однако, если счётчик превышает конечное значение, цикл все равно завершается. В приведённом ниже примере указано конечное значение 55. Это значение никогда не будет достигнуто, потому что цикл увеличивается на 10 каждый раз. Цикл останавливается на 50.
for count 0 55 10 [prin [count " "]]
0 10 20 30 40 50
В следующем примере показано, как вести обратный отсчет. Он начинается с четырех и отсчитывается до нуля по одному.
for count 4 0 -1 [print count]
4
3
2
1
0
Функция for также работает с десятичными числами, деньгами, временем, датами, сериями и символами. Убедитесь, что начальное и конечное значения имеют один и тот же тип данных. Вот несколько примеров использования цикла for с другими типами данных.
for count 10.5 0.0 -1 [prin [count " "]]
10.5 9.5 8.5 7.5 6.5 5.5 4.5 3.5 2.5 1.5 0.5
for money $0.00 $1.00 $0.25 [prin [money " "]]
$0.00 $0.25 $0.50 $0.75 $1.00
for time 10:00 12:00 0:20 [prin [time " "]]
10:00 10:20 10:40 11:00 11:20 11:40 12:00
for date 1-jan-2000 4-jan-2000 1 [prin [date " "]]
1-Jan-2000 2-Jan-2000 3-Jan-2000 4-Jan-2000
for char #"a" #"z" 1 [prin char]
abcdefghijklmnopqrstuvwxyz
Функция for также работает с сериями. В следующем примере for используется для строкового значения. Слово end определяется как строка с текущим индексом у символа d. Функция for перемещается по серии строк по одному символу за раз и останавливается, когда достигает позиции символа, определённой как end:
str: "abcdef"
end: find str "d"
for s str end 1 [print s]
abcdef
bcdef
cdef
def
7.4 Foreach
Функция foreach предоставляет удобный способ повторить вычисление блока для каждого элемента серии. Он работает для всех типов блочных и строчных серий.
В примере ниже каждое слово в блоке будет напечатано:
цвета: [красный зелёный синий]
foreach цвет цвета [print цвет]
красный
зелёный
красный
В следующем примере каждый символ в строке будет напечатан:
строка: "REBOL"
foreach символ строка [print символ]
R E B O L
В приведённом ниже примере будет напечатано каждое имя файла, содержащее ".t" в текущем каталоге:
files: read %.
foreach file files [
if find file ".t" [print file]
]
file.txt
file2.txt
newfile.txt
output.txt
Когда блок содержит группы связанных значений, функция foreach может получить все значения группы одновременно. Например, вот блок, который содержит время, строку и цену. Предоставляя функции foreach блок слов для группы, можно выбрать и распечатать каждое из их значений.
Фильмы: [
8:30 "Контакт" $4.95
10:15 "Планета Земля" $3.25
12:45 "Матрица" $4.25
]
foreach [время название цена] фильмы [
print ["Сегодня в кино фильм " название " в " время ", цена билета " цена]
]
Сегодня в кино фильм Контакт в 8:30 цена билета $4.95
Сегодня в кино фильм Планета Земля в 10:15 цена билета $3.25
Сегодня в кино фильм Матрица в 12:45 цена билета $4.25
В приведённом выше примере блок значений foreach, [ время название цена ], указывает, что три значения должны быть извлечены из фильмы для каждой оценки блока (каждого круга).
Переменные, используемые для хранения значений foreach, являются локальными для блока. Их значение устанавливается только в внутри повторяющегося блока. После выхода из цикла переменные возвращаются к своим ранее установленным значениям.
7.5 Forall и Forskip
Подобно foreach, функция forall оценивает блок для каждого значения в серии. Однако есть несколько важных отличий. Функция forall передаёт серию, установленную в начало цикла. По мере прохождения цикла forall изменяет позицию в серии.
цвета: [красный зелёный синий]
forall цвета [print first цвета]
красный
зелёный
синий
В приведённом выше примере после каждой оценки блока серия продвигается к следующей позиции. Когда forall возвращается, индекс цвета находится в конце ряда.
Чтобы продолжить использовать серию, вам нужно будет вернуть ее в исходное положение с помощью следующей строки:
цвета: head цвета
Функция forskip оценивает блок для групп значений в серии. Второй аргумент forskip - это количество элементов, которые нужно продвинуть вперёд после каждого цикла цикла.
Как и forall, forskip передаётся серия с индексом серии, установленным в том месте, где она должна начинаться. Затем forskip изменяет позицию индекса, продолжая цикл. После каждой оценки основного блока индекс серии продвигается на величину пропуска до следующей позиции индекса. Следующий пример демонстрирует forskip:
Фильмы: [
8:30 "Контакт" $4.95
10:15 "Планета Земля" $3.25
12:45 "Матрица" $4.25
]
forskip Фильмы 3 [print second Фильмы]
Контакт
Планета Земля
Матрица
В приведённом выше примере forskip возвращается с серией фильмов в хвосте. Вам нужно будет использовать функцию head, чтобы вернуть серию в исходное положение.
7.6 Forever
Функция forever оценивает блок бесконечно или до тех пор, пока он не встретит функцию break.
В следующем примере функция forever используется для проверки существования файла каждые десять минут:
forever [
if exists? %datafile [break]
wait 0:10
]
7.7 Break
Вы можете остановить повторную оценку блока с помощью функции break. Функция break полезна, когда встречается особое условие и цикл необходимо остановить. Функция break работает со всеми типами циклов.
В следующем примере цикл прерывается (break), если число больше 5.
repeat count 10 [
if (random count) > 5 [break]
print "проверка"
]
проверка
проверка
проверка
Функция break не возвращает значение из цикла, если не используется уточнение(опция) /return:
print repeat count 10 [
if (random count) > 5 [break/return "стоп тут"]
print "проверка"
"нормальный выход"
]
проверка
проверка
проверка
стоп тут
В приведённом выше примере, если повтор завершается без возникновения условия, блок возвращает строку нормальный выход. В противном случае команда break/return вернёт строку стоп тут.
8. Выборочная оценка
Есть несколько методов выборочной оценки выражений в REBOL. Эти методы предоставляют возможность ветвления оценки множеством различных способов на основе значения ключа.
8.1 Select
Функция select часто используется для получения определённого значения или блока по заданному значению. Если вы определяете блок значений и действий, вы можете использовать select для поиска действия, соответствующего значению.
cases: [
center [print "center"]
right [print "right"]
left [print "left"]
]
action: select cases 'right
if action [do action]
right
В предыдущем примере функция select находит слово right и возвращает следующий за ним блок. (Если по какой-то причине блок не был найден, то возвращается none.) Затем блок оценивается. Значения, используемые в примере, являются словами, но они могут быть любыми значениями:
cases: [
5:00 [print "везде"]
10:30 [print "здесь"]
18:45 [print "там"]
]
action: select cases 10:30
if action [do action]
здесь
8.2 Switch
Функция select используется так часто, что существует её специальная версия, с именем switch, которая включает оценку результирующего блока. Функция switch упрощает выполнение встроенной выборочной оценки. Например, чтобы включить простой числовой регистр:
switch 22 [
11 [print "здесь"]
22 [print "там"]
]
там
Функция switch также возвращает значение блока, которое она оценивает, поэтому предыдущий пример также можно записать как:
str: copy "прямо "
print switch 22 [
11 [join str "там"]
22 [join str "тут"]
]
прямо тут
и:
автомобиль: pick [Форд Хонда Лада] random 3
print switch автомобиль [
Форд [351 * 1.4]
Хонда [454 * 5.3]
Лада [154 * 3.5]
]
2406.2
Регистры могут быть любым допустимым типом данных, включая числа, строки, слова, даты, время, URL-адреса и файлы. Вот некоторые примеры:
Строки:
персона: "ребёнок"
switch персона [
"папа" [print "тут"]
"мама" [print "там"]
"ребёнок" [print "везде"]
]
везде
Слова:
person: 'kid
switch person [
dad [print "here"]
mom [print "there"]
kid [print "everywhere"]
]
everywhere
Тип данных:
person: 123
switch type?/word [
string! [print "это строка"]
binary! [print "это двоичные"]
integer! [print "это целое число"]
decimal! [print "это десятичное число"]
]
это целое число
Файлы:
file: %rebol.r
switch file [
%user.r [print "тут"]
%rebol.r [print "везде"]
%file.r [print "там"]
]
везде
Интернет адреса (URLs):
url: ftp://ftp.rebol.org
switch url [
http://www.rebol.com [print "тут"]
http://www.cnet.com [print "там"]
ftp://ftp.rebol.org [print "везде"]
]
везде
Тэги:
tag: <LI>
print switch tag [
<PRE> ["Предварительно отформатированный текст"]
<TITLE> ["Заголовок страницы"]
<LI> ["Элемент маркированного списка"]
]
Элемент маркированного списка
Время:
time: 12:30
switch time [
8:00 [send wendy@domain.dom "Эй! Просыпайся!!!"]
12:30 [send cindy@rebol.dom "Пойдём обедать."]
16:00 [send group@every.dom "Ужин будет у кого?"]
]
8.2.1 Случай по умолчанию
Случай по умолчанию может быть указан, если ни один из других вариантов не соответствует. Используйте default, чтобы указать значение по умолчанию:
time: 7:00
switch/default time [
5:00 [print "везде"]
10:30 [print "тут"]
18:45 [print "там"]
] [print "нигде"]
нигде
8.2.2 Общие случаи
Если у вас есть общие случаи, когда результат будет одинаковым для нескольких значений, вы можете определить слово для хранения общего блока кода:
case1: [print length? url] ; общий блок кода
url: http://www.rebol.com
switch url [
http://www.rebol.com case1
http://www.cnet.com [print "тут"]
ftp://ftp.rebol.org case1
]
20
8.2.3 Другие случаи
Для кейсов можно оценивать не только блоки. В этом примере оценивается файл, соответствующий дню недели:
переключиться сейчас / будний день [
1% понедельник.р
5% пятница.р
6% суббота.р
]
Итак, если сегодня пятница, проверяется файл пятницы .r, и его результат возвращается переключателем. Этот тип оценки также работает для URL-адресов:
время переключения [
8:30 ftp://ftp.rebol.org/wakeup.r
10:30 http://www.rebol.com/break.r
18:45 ftp://ftp.rebol.org/sleep. r
]
Варианты для switch заключены в блок и поэтому могут быть определены отдельно от оператора switch:
Для кейсов можно оценивать не только блоки. В этом примере оценивается(выполняются) файл, соответствующий дню недели:
switch now/weekday [
1 %понедельник.r
5 %пятница.r
6 %суббота.r
]
Итак, если сегодня пятница, проверяется скрипт пятница.r, и его результат возвращается переключателем. Этот тип оценки также работает для URL-адресов:
switch time [
8:30 ftp://ftp.rebol.org/wakeup.r
10:30 http://www.rebol.com/break.r
18:45 ftp://ftp.rebol.org/sleep.r
]
Варианты для switch заключены в блок и поэтому могут быть определены отдельно от оператора switch:
расписание: [
8:00 [send wendy@domain.dom "Подъём"]
12:30 [send cindy@dom.dom "Пойдём обедать."]
16:00 [send group@every.dom "Угостишь ужином?"]
]
switch 8:00 расписание
9. Остановка оценки
Оценка сценария может быть остановлена в любой момент, нажав клавишу выхода (ESC) на клавиатуре или используя функции halt и quit.
Функция halt function stops evaluation and returns you to the
REBOL console prompt:
if time > 12:00 [halt]
The quit останавливает оценку и возвращает вас к приглашению консоли REBOL:
if error? try [print test] [quit]
10. Тестирование блоков
Бывают случаи, когда вы хотите оценить блок, но в случае возникновения ошибки вы не хотите останавливать оценку остальной части вашего скрипта.
Например, вы можете выполнять деление чисел, но не хотите, чтобы ваш скрипт останавливался, если происходит деление на ноль.
Функция try позволяет обнаруживать ошибки во время оценки блока. Это почти идентично функции do. Функция try обычно возвращает результат блока; однако в случае возникновения ошибки вместо этого будет возвращено значение ошибки.
В следующем примере, когда происходит деление на ноль, сценарий передаст ошибку обратно в функцию try, и оценка продолжится с этой точки.
for num 5 -5 -1 [
if error? try [print 10 / num] [print "ошибка"]
]
2
2
2.5
3.33333333333333
5
10
ошибка
-10
-5
-3.33333333333333
-2.5
-2
Подробнее об обработке ошибок можно узнать в Приложении «Ошибки»x.
|