Jump to content

Значок (язык программирования)

(Перенаправлено с языка программирования Icon )
Икона
Парадигмы мультипарадигмальность : структурированная , текстово-ориентированная
Семья СНОБОЛ
Разработано Ральф Грисволд
Впервые появился 1977 год ; 47 лет назад ( 1977 )
Стабильная версия
9.5.24а / 17 января 2024 г .; 6 месяцев назад ( 17.01.2024 ) [1]
Дисциплина набора текста динамичный
Веб-сайт www .cs .Аризона .edu /икона
Основные реализации
Значок, Джейкон
Диалекты
Юникон
Под влиянием
СНОБОЛ , SL5, АЛГОЛ
Под влиянием
Юникон, Питон , Гоалди, [2] jq

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

Icon был разработан Ральфом Грисволдом после ухода из Bell Labs , где он внес основной вклад в разработку языка SNOBOL . SNOBOL был языком обработки строк с синтаксисом, который по стандартам начала 1970-х годов можно было бы считать устаревшим. Перейдя в Университет Аризоны , он продолжил разработку основных концепций SNOBOL в SL5, но посчитал результат провальным. Это привело к значительному обновлению Icon, который сочетает в себе короткий, но концептуально насыщенный код языков, подобных SNOBOL, с более знакомым синтаксисом ALGOL языков, вдохновленных , таких как C или Pascal .

Как и языки, вдохновившие его, основная область использования Icon — управление строками и текстовыми шаблонами. Строковые операции часто терпят неудачу, например, поиск «the» в «world». В большинстве языков это требует тестирования и ветвления, чтобы избежать использования недопустимого результата. В Icon большинство подобных тестов просто не нужны, что сокращает объем кода, который необходимо написать. Обработка сложных шаблонов может быть выполнена с помощью нескольких строк краткого кода, аналогично более специализированным языкам, таким как Perl , но с сохранением более функционально-ориентированного синтаксиса, знакомого пользователям других языков, подобных ALGOL.

Icon не является объектно-ориентированным , но в 1996 году было разработано объектно-ориентированное расширение под названием Idol, которое в конечном итоге стало Unicon . Он также вдохновил другие языки, особенно влиятельными были его простые генераторы; Генераторы Icon послужили главным источником вдохновения для языка Python . [3]

Первоначальная разработка SNOBOL , получившая задним числом название SNOBOL1, была запущена осенью 1962 года в Bell Labs . отделе исследований в области программирования [4] Эта попытка стала реакцией на неудачные попытки использовать язык SCL для манипулирования полиномиальными формулами, символьного интегрирования и изучения цепей Маркова . SCL, написанный главой отдела Честером Ли, был медленным и имел низкоуровневый синтаксис, что приводило к созданию объемов кода даже для простых проектов. После краткого рассмотрения языка COMIT Иван Полонский, Ральф Грисволд и Дэвид Фарбер, все члены отдела из шести человек, решили написать свой собственный язык для решения этих проблем. [5]

Первые версии работали на IBM 7090 в начале 1963 года, а к лету были готовы и использовались в Bell. Это почти сразу привело к появлению SNOBOL2, в котором был добавлен ряд встроенных функций и возможность связываться с внешним кодом на языке ассемблера . Он был выпущен в апреле 1964 года и в основном использовался в Bell, но также нашел некоторое применение в Project MAC . Введение системных функций в основном служило указанием на необходимость пользовательских функций, что было основной особенностью SNOBOL3, выпущенного в июле 1964 года. [6]

Внедрение SNOBOL3 совпало с серьезными изменениями в вычислительном отделе Bell Labs, включая добавление нового мэйнфрейма GE 645 , который потребовал бы переписывания SNOBOL. Вместо этого команда предложила написать новую версию, которая будет работать на виртуальной машине , названную SIL (от SNOBOL Intermediate Language), что позволит легко портировать ее на любую достаточно мощную платформу. Это предложение было принято как SNOBOL4 в сентябре 1965 года. К этому времени в августе 1966 года появились планы по значительно улучшенной версии языка. [7] Дальнейшая работа над языком продолжалась до конца 1960-х годов, в частности, в более поздней версии был добавлен тип ассоциативного массива , который они назвали таблицей.

SL5 ведет к Icon

[ редактировать ]

Грисволд покинул Bell Labs и стал профессором Университета Аризоны в августе 1971 года. [8] В то время он представил SNOBOL4 как исследовательский инструмент. [9] Он получил гранты от Национального научного фонда для продолжения поддержки и развития SNOBOL. [10]

Синтаксис SNOBOL, первоначально разработанного в начале 1960-х годов, несет в себе черты других ранних языков программирования, таких как FORTRAN и COBOL . В частности, язык зависит от столбцов, поскольку многие из этих языков были введены на перфокартах , где расположение столбцов является естественным. Кроме того, структуры управления почти полностью основывались на разветвлении кода, а не на использовании блоков , которые стали обязательной функцией после появления ALGOL 60 . К тому времени, когда он переехал в Аризону, синтаксис SNOBOL4 безнадежно устарел. [11]

Грисволд начал работу по реализации базовой концепции успеха/неудачи SNOBOL с помощью традиционных структур управления потоками, таких как «если/то». Это стало SL5, сокращением от «SNOBOL Language 5», но результат оказался неудовлетворительным. [11] В 1977 году он вернулся к языку, чтобы рассмотреть новую версию. Он отказался от очень мощной системы функций, представленной в SL5, с более простой концепцией приостановки/возобновления и разработал новую концепцию естественного преемника SNOBOL4 со следующими принципами: [11]

  • Философско-смысловая основа СНОБОЛ4
  • Синтаксическая основа SL5
  • Возможности SL5, за исключением механизма обобщенных процедур

Первоначально новый язык был известен как SNOBOL5, но, поскольку он значительно отличался от SNOBOL во всем, кроме базовой концепции, в конечном итоге потребовалось новое имя. После рассмотрения «s» как своего рода дань уважения «C», но в конечном итоге от него отказались из-за проблем с набором документов с использованием этого имени. Был предложен ряд новых названий, от которых отказались; Ирвинг, бард, и «TL» для «Языка». Именно в это время Xerox PARC начала публиковать информацию о своей работе над графическими пользовательскими интерфейсами , и термин «значок» начал входить в компьютерный лексикон. Было принято решение сначала изменить имя на «Значок», а затем окончательно выбрать «Значок». [11] [а]

Основной синтаксис

[ редактировать ]

Язык Icon произошел от ALGOL класса структурированных языков программирования и, таким образом, имеет синтаксис, аналогичный C или Pascal . Icon больше всего похож на Pascal, используя := синтаксис присваиваний, procedure ключевое слово и аналогичный синтаксис. С другой стороны, Icon использует фигурные скобки в стиле C для структурирования групп выполнения, и программы начинаются с запуска процедуры, называемой main. [13]

Во многих отношениях Icon также имеет общие функции с большинством языков сценариев (а также с SNOBOL и SL5, из которых они были взяты): переменные не нужно объявлять, типы приводятся автоматически, а числа могут автоматически преобразовываться в строки и обратно. [14] Еще одна особенность, общая для многих языков сценариев, но не для всех, — это отсутствие символа окончания строки; в Icon строки, которые не заканчиваются точкой с запятой, заканчиваются подразумеваемой точкой с запятой, если это имеет смысл. [15]

Процедуры являются основными строительными блоками программ Icon. Хотя они используют имена Pascal, они больше похожи на функции C и могут возвращать значения; нет function ключевое слово в Icon. [16]

 procedure doSomething(aString)
   write(aString)
 end

Целенаправленное исполнение

[ редактировать ]

Одной из ключевых концепций SNOBOL было то, что его функции возвращали «успех» или «неуспех» в виде примитивов языка, а не с использованием магических чисел или других методов. [17] [18] Например, функция, возвращающая позицию подстроки внутри другой строки, является обычной процедурой, встречающейся в большинстве языковых систем выполнения ; в JavaScript может потребоваться найти позицию слова «Мир» внутри слова «Привет, мир!» программа , которая будет выполнена с помощью position = "Hello, World".indexOf("World"), который вернет 7. Если вместо этого запросить position = "Hello, World".indexOf("Goodbye") код потерпит неудачу, поскольку поисковый запрос не отображается в строке. В JavaScript, как и в большинстве языков, это будет обозначаться возвратом магического числа, в данном случае -1. [19]

В СНОБОЛЕ ошибка такого рода возвращает специальное значение: fail. Синтаксис SNOBOL напрямую зависит от успеха или неудачи операции, переходя к помеченным участкам кода без необходимости писать отдельный тест. Например, следующий код печатает «Привет, мир!» пять раз: [20]

* SNOBOL program to print Hello World
      I = 1
LOOP  OUTPUT = "Hello, world!"
      I = I + 1
      LE(I, 5) : S(LOOP)
END

Чтобы выполнить цикл, используйте оператор «меньше или равно», LE, вызывается для индексной переменной I, и если она Sуспешно, то есть I меньше 5, он переходит к указанной метке LOOP и продолжается. [20]

Icon сохранил концепцию управления потоком данных, основанную на успехе или неудаче, но развил язык дальше. Одним из изменений была замена маркированного GOTO-подобное ветвлению с использованием блочно-ориентированных структур в соответствии со стилем структурированного программирования , который захлестнул компьютерную индустрию в конце 1960-х годов. [11] Второе заключалось в том, чтобы разрешить передачу «сбоя» по цепочке вызовов, чтобы целые блоки выполнялись успешно или терпели неудачу как единое целое. Это ключевая концепция языка иконок. В то время как в традиционных языках нужно было бы включать код для проверки успеха или неудачи на основе логической логики , а затем разветвлять его на основе результата, такие тесты и ветвления присущи коду Icon и не требуют явного написания. [21]

Например, рассмотрим этот фрагмент кода, написанный на языке программирования Java . Он вызывает функцию read() чтобы прочитать символ из (ранее открытого) файла, присваивает результат переменной a, а потом writeэто ценность a в другой файл. Результатом является копирование одного файла в другой. read в конечном итоге закончатся символы для чтения из файла, возможно, при самом первом вызове, что приведет к a в неопределенном состоянии и потенциально может стать причиной write чтобы вызвать исключение нулевого указателя . Чтобы избежать этого, read возвращает специальное значение EOF (конец файла) в этой ситуации, что требует явного теста, чтобы избежать writeделаю это:

 while ((a = read()) != EOF) {
   write(a);
 }

Напротив, в Icon read() функция возвращает строку текста или &fail. &fail это не просто аналог EOF, поскольку в языке это явно означает «остановить обработку» или «выполнить случай сбоя» в зависимости от контекста. Эквивалентный код в Icon: [18]

 while a := read() do write(a)

Это означает: «пока чтение не завершается сбоем, вызовите запись, в противном случае остановитесь». [18] Нет необходимости указывать проверку магического числа, как в примере с Java, это неявно, и полученный код упрощается. Поскольку успех и неудача передаются по цепочке вызовов, можно встраивать вызовы функций в другие, и они прекращаются, когда вызов вложенной функции завершается неудачно. Например, приведенный выше код можно сократить до: [22]

 while write(read())

В этой версии, если read вызов не удался, write вызов не удался, и while останавливается. [22] Все конструкции ветвления и цикла Icon основаны на успехе или неудаче кода внутри них, а не на произвольной логической проверке, предоставленной программистом. if выполняет then блокируется, если его «тест» возвращает значение и выполняет else блокируется или переходит на следующую строку, если она возвращается &fail. Так же, while продолжает вызывать свой блок, пока не получит ошибку. Icon называет эту концепцию целенаправленным исполнением . [23]

Важно противопоставить концепцию успеха и неудачи концепции исключения ; исключениями являются необычные ситуации, а не ожидаемые результаты. Неудачи в Icon являются ожидаемыми результатами; достижение конца файла является ожидаемой ситуацией, а не исключением. Icon не имеет обработки исключений в традиционном смысле, хотя Fail часто используется в ситуациях, подобных исключениям. Например, если читаемый файл не существует, read не удается без указания особой ситуации. [18] В традиционном языке эти «другие условия» не имеют естественного способа обозначения; могут использоваться дополнительные магические числа, но чаще всего обработка исключений используется для «выдачи» значения. Например, чтобы обработать отсутствующий файл в коде Java, можно увидеть:

 try {
   while ((a = read()) != EOF) {
     write(a);
   }
 } catch (Exception e) {
   // something else went wrong, use this catch to exit the loop
 }

В этом случае необходимы два сравнения: одно для EOF, а другое для всех остальных ошибок. Поскольку Java не позволяет сравнивать исключения как логические элементы, как в случае с Icon, try/catch вместо этого необходимо использовать синтаксис. Блоки Try также налагают штраф на производительность, даже если исключение не генерируется, — распределенные затраты , которых Icon обычно избегает.

Icon использует тот же целевой механизм для выполнения традиционных логических тестов, хотя и с небольшими отличиями. Простое сравнение типа if a < b then write("a is smaller than b") не означает, «если оценка условного выражения приводит или возвращает истинное значение», как это происходит в большинстве языков; вместо этого это означает что-то вроде: «если условное выражение здесь < операция завершается успешно и не завершается неудачей». В этом случае < оператор завершается успешно, если сравнение истинно. if называет его then предложение, если выражение завершается успешно, или else или следующую строку, если это не удалось. Результат аналогичен традиционному оператору if/then, наблюдаемому в других языках: if выполняет then если a меньше, чем b. Тонкость в том, что одно и то же выражение сравнения можно разместить где угодно, например:

 write(a < b)

Еще одно отличие состоит в том, что < В случае успеха оператор возвращает свой второй аргумент, что в этом примере приведет к значению b записывается, если оно больше, чем a, иначе ничего не пишется. Поскольку это не тест как таковой , а оператор, возвращающий значение, их можно объединить, позволяя использовать такие вещи, как if a < b < c, [22] распространенный тип сравнения, который в большинстве языков должен быть записан как соединение двух неравенств, таких как if (a < b) && (b < c).

Ключевым аспектом целенаправленного выполнения является то, что программе, возможно, придется вернуться в более раннее состояние в случае сбоя процедуры — задача, известная как возврат назад . Например, рассмотрим код, который устанавливает переменную в начальное положение, а затем выполняет операции, которые могут изменить значение - это часто встречается, например, в операциях сканирования строк, которые перемещают курсор по строке по мере ее сканирования. Если процедура завершается неудачно, важно, чтобы любые последующие чтения этой переменной возвращали исходное состояние, а не состояние, в котором она подвергалась внутренним манипуляциям. Для этой задачи в Icon есть обратимый оператор присваивания : <-и обратимый обмен , <->. Например, рассмотрим код, который пытается найти строку шаблона внутри более крупной строки:

 {
   (i := 10) &
   (j := (i < find(pattern, inString)))
 }

Этот код начинается с перемещения i до 10, начальной точки поиска. Однако, если find терпит неудачу, то блок выйдет из строя в целом, что приводит к значению i оставление на уровне 10 как нежелательный побочный эффект . Замена i := 10 с i <- 10 указывает на то, что i должен быть сброшен к предыдущему значению в случае сбоя блока. Это обеспечивает аналог атомарности при выполнении.

Генераторы

[ редактировать ]

Выражения в Icon могут возвращать одно значение, например: 5 > x оценит и вернет x, если значение x меньше 5, иначе произойдет сбой. Однако Icon также включает в себя концепцию процедур, которые не возвращают немедленно успех или неудачу, а вместо этого возвращают новые значения каждый раз, когда они вызываются. Они известны как генераторы и являются ключевой частью языка Icon. На языке Icon вычисление выражения или функции дает последовательность результатов . Результирующая последовательность содержит все возможные значения, которые могут быть сгенерированы выражением или функцией. Когда результирующая последовательность исчерпана, выражение или функция завершается с ошибкой.

Значок позволяет любой процедуре возвращать одно или несколько значений, управляемых с помощью fail, return и suspend ключевые слова. Процедура, в которой отсутствует какое-либо из этих ключевых слов, возвращает &fail, который происходит всякий раз, когда выполнение доходит до end процедуры. Например:

 procedure f(x)
   if x > 0 then {
     return 1
   }
 end

Вызов f(5) вернет 1, но вызов f(-1) вернется &fail. Это может привести к неочевидному поведению, например, write(f(-1)) ничего не выведет, потому что f выходит из строя и приостанавливает работу write. [24]

Преобразование процедуры в генератор использует suspend Ключевое слово, которое означает «вернуть это значение и при повторном вызове начать выполнение с этой точки». В этом отношении это что-то вроде сочетания static концепция на C и return. Например: [18]

 procedure ItoJ(i, j)
   while i <= j do {
     suspend i
     i +:= 1
   }
   fail
 end

создает генератор, который возвращает серию чисел, начиная с i и окончание j, а затем возвращает &fail после этого. [б] suspend i останавливает выполнение и возвращает значение i без сброса какого-либо состояния. Когда выполняется другой вызов той же функции, выполнение возобновляется с этого момента с предыдущими значениями. В данном случае это заставляет его выполнять i +:= 1, вернитесь к началу блока while, а затем верните следующее значение и снова приостановите выполнение. Это продолжается до тех пор, пока i <= j терпит неудачу, после чего он выходит из блока и вызывает fail. Это позволяет итераторы . легко создавать [18]

Другой тип генератора-генератора — генератор переменного тока , который выглядит и работает как логическое значение. or оператор. Например:

 if y < (x | 5) then write("y=", y)

Кажется, это говорит «если y меньше x или 5, то...», но на самом деле это сокращенная форма генератора, который возвращает значения до тех пор, пока они не выпадут из конца списка. Значения списка «вводятся» в операции, в данном случае <. Итак, в этом примере система сначала проверяет y < x, если x действительно больше, чем y, она возвращает значение x, тест проходит, и значение y записывается в then пункт. Однако, если x не больше, чем y, он терпит неудачу, и генератор продолжает работать, выполняя y < 5. Если этот тест пройден, записывается y. Если y меньше ни x, ни 5, генератор не выдерживает испытаний и выходит из строя. if терпит неудачу, и write не выполняется. Таким образом, значение y появится на консоли, если оно меньше x или 5, тем самым выполняя функцию логического значения. or. Функции не будут вызываться, если оценка их параметров не будет успешной, поэтому этот пример можно сократить до:

 write("y=", (x | 5) > y)

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

 every i := (1|3|4|5|10|11|23) do write(i)

Поскольку списки целых чисел часто встречаются во многих контекстах программирования, Icon также включает в себя to ключевое слово для создания специальных целочисленных генераторов:

 every k := i to j do write(k)

который можно сократить:

 every write(1 to 10)

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

 every i := (1 | "hello" | x < 5)  do write(i)

Это записывает 1, «привет» и, возможно, 5 в зависимости от значения x.

Аналогично конъюнкции оператор &, используется аналогично логическому значению and оператор: [25]

 every x := ItoJ(0,10) & x % 2 == 0 do write(x)

Этот код вызывает ItoJ и возвращает начальное значение 0, присвоенное x. Затем он выполняет правую часть союза, и поскольку x % 2 равно 0, он записывает значение. Затем он вызывает ItoJ снова генератор, который присваивает 1 значению x, что приводит к сбою в правой части и ничего не печатает. Результатом является список всех четных целых чисел от 0 до 10. [25]

Концепция генераторов особенно полезна и эффективна при использовании со строковыми операциями и является основной основой для общего дизайна Icon. Рассмотрим indexOf операция встречается на многих языках; эта функция ищет одну строку внутри другой и возвращает индекс ее местоположения или магическое число, если она не найдена. Например:

 s = "All the world's a stage. And all the men and women merely players";
 i = indexOf("the", s);
 write(i);

Это сканирует строку s, найдите первое вхождение «the» и верните этот индекс, в данном случае 4. Однако строка содержит два экземпляра строки «the», поэтому для возврата второго примера используется альтернативный синтаксис:

 j = indexOf("the", s, i+1);
 write(j);

Это предписывает ему сканировать, начиная с позиции 5, поэтому он не будет соответствовать первому экземпляру, который мы нашли ранее. Однако второго экземпляра "the" может не быть, как и первого, поэтому возвращаемое значение из indexOf необходимо сверить с магическим числом -1, которое используется для обозначения отсутствия совпадений. Полная процедура, которая распечатывает местоположение каждого экземпляра:

 s = "All the world's a stage. And all the men and women merely players";
 i = indexOf("the", s);
 while i != -1 {
   write(i);
   i =  indexOf("the", s, i+1);
 }

В Icon эквивалент find является генератором, поэтому те же результаты можно получить с помощью одной строки:

 s := "All the world's a stage. And all the men and women merely players"
 every write(find("the", s))

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

 every write(5 < find("the", s))

Позиция будет возвращена только в том случае, если после позиции 5 появится «the»; в противном случае сравнение завершится неудачей, передайте ошибку для записи, и запись не произойдет.

The every оператор аналогичен while, перебирая каждый элемент, возвращаемый генератором, и завершая работу в случае сбоя: [24]

  every k := i to j do
    write(someFunction(k))

Существует ключевое различие между every и while; while переоценивает первый результат до тех пор, пока он не завершится неудачно, тогда как every извлекает следующее значение из генератора. every фактически вводит значения в функцию аналогично блокам в Smalltalk . Например, приведенный выше цикл можно переписать следующим образом: [24]

 every write(someFunction(i to j))

В этом случае значения от i до j будут введены в someFunction и (потенциально) записать несколько строк вывода. [24]

Коллекции

[ редактировать ]

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

 lines := []                    # create an empty list
 while line := read() do {      # loop reading lines from standard input
   push(lines, line)            # use stack-like syntax to push the line on the list
 }
 while line := pop(lines) do {  # loop while lines can be popped off the list
   write(line)                  # write the line out
 }

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

 lines := []                    # create an empty list
 while push(lines, read())      # push until empty
 while write(pop(lines))        # write until empty

Поскольку коллекция списков является генератором, ее можно еще упростить с помощью синтаксиса bang:

 lines := []
 every push(lines, !&input)
 every write(!lines)

В этом случае взрыв в write заставляет Icon возвращать строки текста одну за другой из массива и, наконец, завершать работу с ошибкой. &input представляет собой генераторный аналог read который читает строку со стандартного ввода , поэтому !&input продолжает читать строки до тех пор, пока файл не закончится.

Поскольку Icon не имеет типа, списки могут содержать любые типы значений:

aCat := ["muffins", "tabby", 2002, 8]

Элементы могут включать в себя другие структуры. Для создания более крупных списков Icon включает в себя list генератор; i := list(10, "word") генерирует список, содержащий 10 копий «слова». Как и массивы в других языках, Icon позволяет искать элементы по положению, например: weight := aCat[4]. Включено нарезка массива , что позволяет создавать новые списки из элементов других списков, например aCat := Cats[2:4] создает новый список под названием aCat, содержащий слова «табби» и 2002.

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

 symbols := table(0)
 symbols["there"] := 1
 symbols["here"] := 2

Этот код создает таблицу, которая будет использовать ноль в качестве значения по умолчанию для любого неизвестного ключа. Затем он добавляет в таблицу два элемента с ключами «там» и «здесь» и значениями 1 и 2.

Наборы также похожи на списки, но содержат только один элемент любого заданного значения. Значок включает в себя ++ произвести объединение двух множеств, ** перекрёсток, и -- разница. Значок включает в себя ряд предопределенных «Cset», наборов, содержащих различные символы. В Icon есть четыре стандартных набора Cset: &ucase, &lcase, &letters, и &digits. Новые Csets можно создать, заключив строку в одинарные кавычки, например: vowel := 'aeiou'.

В Icon строки представляют собой списки символов. В виде списка они являются генераторами, поэтому их можно перебирать, используя синтаксис bang:

 write(!"Hello, world!")

Распечатает каждый символ строки в отдельной строке.

Подстроки можно извлечь из строки, используя спецификацию диапазона в квадратных скобках. Спецификация диапазона может возвращать точку для одного символа или фрагмента строки. Строки могут индексироваться как справа, так и слева. Позиции внутри строки определяются как находящиеся между символами 1 A 2 B 3 C 4 и могут быть указаны справа −3 A −2 B −1 C 0

Например,

 "Wikipedia"[1]     ==> "W"
 "Wikipedia"[3]     ==> "k"
 "Wikipedia"[0]     ==> "a"
 "Wikipedia"[1:3]   ==> "Wi"
 "Wikipedia"[-2:0]  ==> "ia"
 "Wikipedia"[2+:3]  ==> "iki"

Где в последнем примере показано использование длины вместо конечной позиции.

Спецификация индексации может использоваться как lvalue в выражении. Это можно использовать для вставки строк в другую строку или удаления частей строки. Например:

    s := "abc"
    s[2] := "123"
    s now has a value of "a123c"
    s := "abcdefg"
    s[3:5] := "ABCD"
    s now has a value of "abABCDefg"
    s := "abcdefg"
    s[3:5] := ""
    s now has a value of "abefg"

Сканирование строк

[ редактировать ]

Еще одним упрощением обработки строк является система сканирования , вызываемая с помощью ?, который вызывает функции для строки:

 s ? write(find("the"))

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

The ? это не просто форма синтаксического сахара, он также устанавливает «среду сканирования строк» ​​для любых последующих строковых операций. Это основано на двух внутренних переменных: &subject и &pos; &subject это просто указатель на исходную строку, а &pos это текущая позиция внутри него или курсор. Различные процедуры манипуляции со строками в Icon используют эти две переменные, поэтому программисту не требуется явно указывать их. Например:

  s := "this is a string"
  s ? write("subject=[",&subject,"], pos=[",&pos,"]")

будет производить:

subject=[this is a string], pos=[1]

Для перемещения по сканируемой строке можно использовать встроенные и определяемые пользователем функции. Все встроенные функции по умолчанию будут &subject и &pos чтобы разрешить использование синтаксиса сканирования. Следующий код запишет все слова, разделенные пробелами, в строку:

  s := "this is a string"
  s ? {                               # Establish string scanning environment
      while not pos(0) do  {          # Test for end of string
          tab(many(' '))              # Skip past any blanks
          word := tab(upto(' ') | 0)  # the next word is up to the next blank -or- the end of the line
          write(word)                 # write the word
      }
  }

В этом примере представлен ряд новых функций. pos возвращает текущее значение &pos. Возможно, не сразу очевидно, зачем нужна эта функция, а не просто использовать значение &pos напрямую; причина в том, что &pos является переменной и поэтому не может принимать значение &fail, какая процедура pos может. Таким образом pos обеспечивает легкую оболочку &pos что позволяет легко использовать целенаправленное управление потоком данных Icon без необходимости предоставления рукописных логических тестов против &pos. В данном случае проверкой является «is &pos ноль», что в нечетной нумерации строковых позиций Icon является концом строки. Если оно не равно нулю, pos возвращает &fail, который инвертируется с помощью not и цикл продолжается.

many находит один или несколько примеров предоставленного параметра Cset, начиная с текущего &pos. В данном случае она ищет пробельные символы, поэтому результатом этой функции является местоположение первого символа, не являющегося пробелом, после &pos. tab движется &pos в это место, опять же с потенциальным &fail в случае, например, many падает с конца веревки. upto по сути является противоположностью many; он возвращает местоположение непосредственно перед предоставленным ему Cset, которому затем в примере присваивается значение &pos с другим tab. Чередование также используется для остановки в конце строки.

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

Более сложный пример демонстрирует интеграцию генераторов и сканирования строк в языке.

 procedure main()
     s := "Mon Dec 8"
     s ? write(Mdate() | "not a valid date")
 end
 # Define a matching function that returns
 # a string that matches a day month dayofmonth
 procedure Mdate()
 # Define some initial values
 static dates
 static days
 initial {
        days := ["Mon","Tue","Wed","Thr","Fri","Sat","Sun"]
        months := ["Jan","Feb","Mar","Apr","May","Jun",
                  "Jul","Aug","Sep","Oct","Nov","Dec"]
 }
 every suspend   (retval <-  tab(match(!days)) ||     # Match a day
                             =" " ||                  # Followed by a blank
                             tab(match(!months)) ||   # Followed by the month
                             =" " ||                  # Followed by a blank
                             matchdigits(2)           # Followed by at least 2 digits
                 ) &
                 (=" " | pos(0) ) &                   # Either a blank or the end of the string
                 retval                               # And finally return the string
 end
 # Matching function that returns a string of n digits
 procedure matchdigits(n)
     suspend (v := tab(many(&digits)) & *v <= n) & v
 end

Лоуренс Трэтт написал статью об Icon, в которой исследовал ее реальное применение и указал на ряд проблемных областей. Среди них был ряд практических решений, которые возникли в области обработки строк, но не имеют большого смысла в других областях. [24] Среди них:

Решение о сбое по умолчанию в конце процедур имеет смысл в контексте генераторов, но в меньшей степени в случае общих процедур. Возвращаясь к примеру, отмеченному выше, write(f(-1)) не будет выведено, чего можно было ожидать. Однако: [24]

 x := 10
 (additional lines)
 x := f(-1)
 write(x)

в результате будет напечатано 10. Проблема такого рода не совсем очевидна, поскольку даже в интерактивном отладчике весь код вызывается. x никогда не достигает ожидаемого значения. Это можно было бы отбросить как одну из тех «подводных камней», о которых программисты должны знать на любом языке, но Трэтт исследовал множество программ Icon и обнаружил, что подавляющее большинство процедур не являются генераторами. Это означает, что поведение Icon по умолчанию используется лишь крошечным меньшинством его конструкций, но представляет собой основной источник потенциальных ошибок во всех остальных. [24]

Другая проблема — отсутствие логического типа данных. [с] и обычная булева логика. Хотя система успеха/неудачи работает в большинстве случаев, когда конечной целью является проверка значения, это все равно может привести к странному поведению в, казалось бы, простом коде: [25]

 procedure main()
    if c then {
      write("taken")
    } 
 end

Эта программа напечатает «взято». Причина в том, что тест, c, возвращает значение; это значение &null, значение по умолчанию для всех неинициализированных переменных. [26] &null является допустимым значением, поэтому if c удается. Чтобы проверить это, нужно сделать тест явным, c === &null. Трэтт предположил, что это отвлекает от самодокументируемого кода, ошибочно предположив, что он проверяет «является ли c нулевым» или «существует ли c». [25]

См. также

[ редактировать ]

Примечания

[ редактировать ]
  1. Согласно интервью 1985 года, Грисволд заявляет, что термин «значок» не использовался до тех пор, пока некоторое время спустя Smalltalk не был выпущен для публики. Он выразил раздражение тем, что этот термин теперь сбивает с толку людей, которые думают, что в языке есть графические элементы. [12]
  2. ^ fail в данном случае не требуется , так как это происходит непосредственно перед end. Это добавлено для ясности.
  3. ^ Хотя, как указывает Трэтт, K&R C также не имеет явного логического типа и использует 0 для false и любое ненулевое значение для true. [24]
  1. ^ Таунсенд, Грегг (26 января 2024 г.). «Обновить версию до 9.5.22e» . Гитхаб .
  2. ^ «Гоальди» . Гитхаб .
  3. ^ Шеменауэр, Нил; Питерс, Тим; Хетланд, Магнус Ли (18 мая 2001 г.). «PEP 255 – Простые генераторы» . Предложения по улучшению Python . Фонд программного обеспечения Python . Проверено 9 февраля 2012 года .
  4. ^ Грисволд 1981 , стр. 601, 602.
  5. ^ Грисволд 1981 , стр. 602.
  6. ^ Грисволд 1981 , стр. 606.
  7. ^ Грисволд 1981 , стр. 608.
  8. ^ Грисволд 1981 , стр. 609.
  9. ^ Грисволд 1981 , стр. 629.
  10. ^ Шапиро 1985 , стр. 346.
  11. ^ Jump up to: а б с д и Грисволд и Грисволд 1993 , с. 53.
  12. ^ Шапиро 1985 , с. 350.
  13. ^ Грисволд и Грисволд 2002 , с. хв.
  14. ^ Грисволд и Грисволд 2002 , с. xvi.
  15. ^ Грисволд и Грисволд 2002 , с. 10.
  16. ^ Грисволд и Грисволд 2002 , с. 1.
  17. ^ Грисволд и Грисволд 2002 , с. 4.
  18. ^ Jump up to: а б с д и ж Тратт 2010 , с. 74.
  19. ^ "Array.prototype.indexOf()" . Веб-документы MDN . 27 июня 2023 г.
  20. ^ Jump up to: а б Лейн, Руперт (26 июля 2015 г.). «СНОБОЛ - Введение» . Попробуйте МТС .
  21. ^ Трактат 2010 , с. 73.
  22. ^ Jump up to: а б с Грисволд 1996 , с. 2.1.
  23. ^ Грисволд 1996 , с. 1.
  24. ^ Jump up to: а б с д и ж г час Тратт 2010 , с. 75.
  25. ^ Jump up to: а б с д Тратт 2010 , с. 76.
  26. ^ Грисволд и Грисволд 2002 , с. 128.

Библиография

[ редактировать ]
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 4d5113895a120a094bb0bb75efc3d9d5__1715093520
URL1:https://arc.ask3.ru/arc/aa/4d/d5/4d5113895a120a094bb0bb75efc3d9d5.html
Заголовок, (Title) документа по адресу, URL1:
Icon (programming language) - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)