stringtranslate.com

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

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

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

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

Icon не является объектно-ориентированным , но объектно-ориентированное расширение под названием Idol было разработано в 1996 году, которое в конечном итоге стало 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]

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

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

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

Язык

Базовый синтаксис

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

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

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

 процедура  doSomething ( aString )  write ( aString )  конец

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

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

В SNOBOL неудача такого рода возвращает особое значение, fail. Синтаксис SNOBOL работает непосредственно с успехом или неудачей операции, переходя к помеченным разделам кода без необходимости писать отдельный тест. Например, следующий код печатает "Hello, world!" пять раз: [20]

* Программа SNOBOL для печати 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. В то время как в традиционных языках пришлось бы включать код для проверки успеха или неудачи на основе булевой логики , а затем выполнять переход на основе результата, такие тесты и переходы присущи коду Icon и не должны быть явно прописаны. [21]

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

 в то время как (( a = read ()) != EOF ) { write ( a ); }        

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

 в то время как  a  :=  read ()  do  write ( a )

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

 во время  записи ( чтения ())

В этой версии, если 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 ) { // что-то еще пошло не так, используйте этот catch для выхода из цикла }                 

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

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

 написать ( а  <  б )

Другое отличие заключается в том, что <оператор возвращает свой второй аргумент, если он успешен, что в этом примере приведет к значению, которое 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процедуры. Например:

 процедура  f ( x )  если  x  >  0  тогда  {  return  1  }  конец

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

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

 процедура  ItoJ ( i ,  j )  пока  i  <=  j  сделать  {  приостановить  i  i  +:=  1  }  неудача  конец

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

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

 если  y  <  ( x  |  5 )  то  пишем ( "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. Функции не будут вызываться, если оценка их параметров не будет успешной, поэтому этот пример можно сократить до:

 запись ( "y=" ,  ( x  |  5 )  >  y )

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

 каждый  i  : =  ( 1 | 3 | 4 | 5 | 10 | 11 | 23 )  пиши  ( i )

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

 каждый  k  :=  i  до  j  делать  запись ( k )

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

 каждая  запись ( от 1  до  10 )

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

 каждый  i  :=  ( 1  | "  привет "  |  x  <  5 )  пиши  ( i )

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

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

 каждый  x  :=  ItoJ ( 0 , 10 )  &  x  %  2  ==  0  сделать  запись ( x )

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

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

 s = "Весь мир - театр. И все мужчины и женщины - просто игроки" ; i = indexOf ( "the" , s ); write ( i );       

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

 j = indexOf ( "the" , s , i + 1 ); запись ( j );     

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

 s = "Весь мир - театр. И все мужчины и женщины - просто игроки" ; i = indexOf ( "the" , s ); while i != - 1 { write ( i ); i = indexOf ( "the" , s , i + 1 ); }                  

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

 s  :=  "Весь мир - театр. И все мужчины и женщины - просто игроки"  every  write ( find ( "the" ,  s ))

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

 каждая  запись ( 5  <  find ( "the" ,  s ))

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

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

 каждый  k  :=  i  to  j  делает  запись ( someFunction ( k ))

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

 каждая  запись ( someFunction ( от i  до  j ))

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

Коллекции

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

 lines  :=  []  # создаем пустой список  while  line  :=  read ()  do  {  # цикл чтения строк из стандартного ввода  push ( lines ,  line )  # используем стекоподобный синтаксис для добавления строки в список  }  while  line  :=  pop ( lines )  do  {  # цикл while строки можно извлекать из списка  write ( line )  # записываем строку  }

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

 lines  :=  []  # создать пустой список  while  push ( lines ,  read ())  # push до тех пор, пока не опустеет  while  write ( pop ( lines ))  # write до тех пор, пока не опустеет

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

 строки  :=  []  каждый  push ( строки ,  ! &input )  каждая  запись ( ! строки )

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

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

aCat  :=  [ "маффины" ,  "полосатый" ,  2002 ,  8 ]

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

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

 символы  :=  таблица ( 0 )  символы [ "там" ]  :=  1  символы [ "здесь" ]  :=  2

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

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

Струны

В Icon строки — это списки символов. Как список, они являются генераторами и, таким образом, могут быть итерированы с использованием синтаксиса bang:

 написать ( ! "Привет, мир!" )

Каждый символ строки будет выведен на отдельную строку.

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

Например,

 "Википедия" [ 1 ]  ==>  "W"  "Википедия" [ 3 ]  ==>  "k"  "Википедия" [ 0 ]  ==>  "a"  "Википедия" [ 1 : 3 ]  ==>  "Wi"  "Википедия" [ - 2 : 0 ]  ==>  "ia"  "Википедия" [ 2 + : 3 ]  ==>  "ики"

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

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

 s  : =  "abc"  s [ 2 ]  :=  "123"  s  теперь  имеет  значение  "a123c" s : = "abcdefg" s [ 3 : 5 ] := "ABCD" s теперь имеет значение " abABCDefg" s : = " abcdefg " s [ 3 : 5 ] := "" s теперь имеет значение "abefg "                            

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

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

 s  ?  написать ( найти ( "the" ))

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

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

 s  :=  "это строка"  s  ?  write ( "subject=[" , &subject , "], pos=[" , &pos , "]" )

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

субъект=[это строка], pos=[1]

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

 s  :=  "this is a string"  s  ?  {  # Установить среду сканирования строки  while  not  pos ( 0 )  do  {  # Проверить на конец строки  tab ( many ( ' ' ))  # Пропустить все пробелы  word  :=  tab ( upto ( ' ' )  |  0 )  # следующее слово находится до следующего пробела или конца строки  write ( word )  # записать слово  }  }

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

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

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

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

 процедура  main ()  s  :=  "Пн Дек 8"  s  ?  write ( Mdate ()  |  "недопустимая дата" )  end  # Определить функцию сопоставления, которая возвращает  # строку, которая соответствует дню месяцу dayofmonth  procedure  Mdate ()  # Определить некоторые начальные значения  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 ( ! months ))  ||  # Далее следует месяц  = ​​" "  ||  # Далее следует пробел  matchdigits ( 2 )  # За которыми следует не менее 2 цифр  )  &  ( = ""  |  pos ( 0 )  )  &  # Либо пробел, либо конец строки  retval  # И, наконец, вернуть строку  end  # Функция сопоставления, которая возвращает строку из n цифр  procedure  matchdigits ( n )  suspend  ( v  :=  tab ( many ( &digits ))  &  * v  <=  n )  &  v  end

Критика

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

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

 x  :=  10  ( дополнительные  строки )  x  :=  f ( - 1 )  запись ( x )

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

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

 процедура  main ()  если  c  тогда  {  write ( "taken" )  }  конец

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

Смотрите также

Примечания

  1. ^ Согласно интервью 1985 года, Грисволд утверждает, что термин «значок» не использовался до тех пор, пока Smalltalk не был выпущен для публики некоторое время спустя. Он выразил свое раздражение тем, что этот термин теперь сбивает с толку людей, которые думали, что в языке есть графические элементы. [12]
  2. ^ В данном случае не failтребуется , так как он стоит непосредственно перед end. Он был добавлен для ясности.
  3. ^ Хотя, как указывает Тратт, в K&R C также отсутствует явный логический тип, и для ложного значения используется 0, а для истинного — любое ненулевое значение. [24]

Ссылки

Цитаты

  1. ^ Таунсенд, Грегг (26 января 2024 г.). «Обновите версию до 9.5.22e». GitHub .
  2. ^ "Goaldi". GitHub .
  3. ^ Шеменауэр, Нил; Питерс, Тим; Хетланд, Магнус Ли (18 мая 2001 г.). "PEP 255 – Простые генераторы". Предложения по улучшению Python . Python Software Foundation . Получено 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. ^ abcde Griswold & Griswold 1993, стр. 53.
  12. ^ Шапиро 1985, стр. 350.
  13. Грисволд и Грисволд 2002, стр. xv.
  14. ^ Грисволд и Грисволд 2002, стр. xvi.
  15. ^ Грисволд и Грисволд 2002, стр. 10.
  16. ^ Грисволд и Грисволд 2002, стр. 1.
  17. ^ Грисволд и Грисволд 2002, стр. 4.
  18. ^ abcdef Tratt 2010, стр. 74.
  19. ^ "Array.prototype.indexOf()". MDN Web Docs . 27 июня 2023 г.
  20. ^ ab Lane, Rupert (26 июля 2015 г.). "SNOBOL - Введение". Попробуйте MTS .
  21. ^ Тратт 2010, стр. 73.
  22. ^ abc Griswold 1996, стр. 2.1.
  23. ^ Грисволд 1996, стр. 1.
  24. ^ abcdefgh Тратт 2010, стр. 75.
  25. ^ abcd Tratt 2010, стр. 76.
  26. ^ Грисволд и Грисволд 2002, стр. 128.

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

Внешние ссылки