Icono (lenguaje de programación)

Ajustar Compartir Imprimir Citar

Icon es un lenguaje de programación de muy alto nivel basado en el concepto de "ejecución dirigida a objetivos" en cuyo código devuelve un "éxito" junto con valores válidos, o un "fallo", que indica que no hay datos válidos para devolver. El éxito y el fracaso de un bloque de código determinado se utiliza para dirigir el procesamiento posterior, mientras que los lenguajes convencionales suelen utilizar la lógica booleana escrita por el programador para lograr los mismos fines. Debido a que la lógica de las estructuras de control básicas a menudo está implícita en Icon, las tareas comunes se pueden completar con un código menos explícito.

Icon fue diseñado por Ralph Griswold después de dejar Bell Labs, donde fue uno de los principales contribuyentes al lenguaje SNOBOL. SNOBOL era un lenguaje de procesamiento de cadenas con lo que se consideraría sintaxis fechada según los estándares de principios de la década de 1970. Después de mudarse a la Universidad de Arizona, desarrolló aún más los conceptos subyacentes de SNOBOL en SL5, pero consideró que el resultado fue un fracaso. Esto condujo a Icon, significativamente actualizado, que combina el código corto pero conceptualmente denso de los lenguajes similares a SNOBOL con la sintaxis más familiar de los lenguajes inspirados en ALGOL como C o Pascal.

Al igual que los lenguajes que lo inspiraron, el área principal de uso de Icon es la gestión de cadenas y patrones textuales. Las operaciones de cadena a menudo fallan, por ejemplo, al encontrar "the" en "mundo". En la mayoría de los idiomas, esto requiere pruebas y bifurcaciones para evitar el uso de un resultado no válido. En Icon, la mayoría de este tipo de pruebas simplemente no son necesarias, lo que reduce la cantidad de código escrito por el programador. El manejo de patrones complejos se puede lograr en unas pocas líneas de código conciso, similar a lenguajes más dedicados como Perl pero conservando una sintaxis más orientada a funciones familiar para los usuarios de otros lenguajes similares a ALGOL.

Icon no está orientado a objetos, pero en 1996 se desarrolló una extensión orientada a objetos llamada Idol que finalmente se convirtió en Unicon. También inspiró a otros lenguajes, siendo sus generadores simples especialmente influyentes; Los generadores de Icon fueron una gran inspiración para el lenguaje de programación Python.

Historia

SNOBOL

El esfuerzo SNOBOL original, conocido retroactivamente como SNOBOL1, se lanzó en el otoño de 1962 en el Departamento de Estudios de Investigación de Programación de Bell Labs. El esfuerzo fue una reacción a las frustraciones de intentar usar el lenguaje SCL para la manipulación de fórmulas polinómicas, la integración simbólica y el estudio de las cadenas de Markov. SCL, escrito por el jefe de departamento Chester Lee, era lento y tenía una sintaxis de bajo nivel que generaba volúmenes de código incluso para proyectos simples. Después de considerar brevemente el lenguaje COMIT, Ivan Polonsky, Ralph Griswold y David Farber, todos miembros del departamento de seis personas, decidieron escribir su propio lenguaje para resolver estos problemas.

Las primeras versiones se ejecutaban en IBM 7090 a principios de 1963 y, para el verano, se habían desarrollado y se usaban en todo Bell. Esto condujo casi de inmediato a SNOBOL2, que agregó una serie de funciones integradas y la capacidad de vincularse a código de lenguaje ensamblador externo. Fue lanzado en abril de 1964 y se usó principalmente dentro de Bell, pero también tuvo algún uso en Project MAC. La introducción de las funciones del sistema sirvió principalmente para indicar la necesidad de funciones de usuario, que era la principal característica de SNOBOL3, lanzado en julio de 1964.

La introducción de SNOBOL3 se correspondió con cambios importantes dentro del departamento de computación de Bell Labs, incluida la adición del nuevo mainframe GE 645 que requeriría una reescritura de SNOBOL. En cambio, el equipo sugirió escribir una nueva versión que se ejecutaría en una máquina virtual, denominada SIL por SNOBOL Intermediate Language, lo que permitiría trasladarla fácilmente a cualquier plataforma suficientemente poderosa. Esta propuesta fue aceptada como SNOBOL4 en septiembre de 1965. En ese momento, surgieron planes para una versión significativamente mejorada del lenguaje en agosto de 1966. El trabajo adicional en el lenguaje continuó durante el resto de la década de 1960, en particular agregando el tipo de matriz asociativa en la versión posterior., a la que se referían como una mesa.

SL5 lleva a Ícono

Griswold dejó Bell Labs para convertirse en profesor en la Universidad de Arizona en agosto de 1971. Presentó SNOBOL4 como una herramienta de investigación en ese momento.

Como lenguaje desarrollado originalmente a principios de la década de 1960, la sintaxis de SNOBOL lleva las marcas de otros lenguajes de programación tempranos como FORTRAN y COBOL. En particular, el idioma depende de las columnas, ya que muchos de estos idiomas se ingresaron en tarjetas perforadas donde el diseño de las columnas es natural. Además, las estructuras de control se basaban casi por completo en la bifurcación del código en lugar del uso de bloques, que se estaban convirtiendo en una característica imprescindible después de la introducción de ALGOL 60. Cuando se mudó a Arizona, la sintaxis de SNOBOL4 estaba irremediablemente desactualizada.

Griswold comenzó el esfuerzo de implementar el concepto subyacente de éxito/fracaso de SNOBOL con estructuras de control de flujo tradicionales como si/entonces. Esto se convirtió en SL5, abreviatura de "SNOBOL Language 5", pero el resultado no fue satisfactorio. En 1977 volvió a la lengua para plantearse una nueva versión. Abandonó el poderoso sistema de funciones introducido en SL5 con un concepto más simple de suspender/reanudar y desarrolló un nuevo concepto para el sucesor natural de SNOBOL4 con los siguientes principios;

El nuevo lenguaje se conocía inicialmente como SNOBOL5, pero como era significativamente diferente de SNOBOL en todo menos en el concepto subyacente, finalmente se deseó un nuevo nombre. Después de considerar "s" como una especie de homenaje a "C", pero esto finalmente se abandonó debido a los problemas con la composición tipográfica de documentos con ese nombre. Se propusieron y abandonaron una serie de nuevos nombres; Irving, bardo y "TL" por "El lenguaje". Fue en ese momento que Xerox PARC comenzó a publicar sobre su trabajo en interfaces gráficas de usuario y el término "icono" comenzó a entrar en el léxico informático. Se tomó la decisión de cambiar el nombre inicialmente a "icono" antes de elegir finalmente "Icono".

Idioma

Sintaxis básica

El lenguaje Icon se deriva de la clase ALGOL de lenguajes de programación estructurados y, por lo tanto, tiene una sintaxis similar a C o Pascal. Icon es más similar a Pascal, usando la sintaxis := para tareas, la palabra clave procedure y una sintaxis similar. Por otro lado, Icon usa llaves estilo C para estructurar grupos de ejecución, y los programas comienzan ejecutando un procedimiento llamado principal.

En muchos sentidos, Icon también comparte funciones con la mayoría de los lenguajes de secuencias de comandos (así como con SNOBOL y SL5, de donde se tomaron): las variables no tienen que declararse, los tipos se convierten automáticamente y los números se pueden convertir en cadenas y volver automáticamente. Otra característica común a muchos lenguajes de secuencias de comandos, pero no a todos, es la falta de un carácter de final de línea; en Icon, las líneas que no terminan con un punto y coma terminan con un punto y coma implícito si tiene sentido.

Los procedimientos son los componentes básicos de los programas Icon. Aunque utilizan la nomenclatura de Pascal, funcionan más como funciones de C y pueden devolver valores; no hay palabra clave function en Icon.

 procedimiento algo()aString) escribir()aString) final

Ejecución dirigida a objetivos

Uno de los conceptos clave en SNOBOL era que sus funciones devolvían el "éxito" o "falla" como primitivos del lenguaje en lugar de usar números mágicos u otras técnicas. Por ejemplo, una función que devuelve la posición de una subcadena dentro de otra cadena es una rutina común que se encuentra en la mayoría de los sistemas de tiempo de ejecución de lenguaje; en JavaScript uno podría querer encontrar la posición de la palabra "Mundo" dentro de "¡Hola, mundo!", que se lograría con posición = "Hola mundo".indexOf(& #34;Mundo"), que devolvería 7. Si en cambio uno pide el posición = "Hola mundo.indexOf("Adiós) el el código "fallará", ya que el término de búsqueda no aparece en la cadena. En JavaScript, como en la mayoría de los lenguajes, esto se indicará devolviendo un número mágico, en este caso -1.

En SNOBOL, una falla de este tipo devuelve un valor especial, fallar. La sintaxis de SNOBOL opera directamente sobre el éxito o el fracaso de la operación, saltando a las secciones etiquetadas del código sin tener que escribir una prueba por separado. Por ejemplo, el siguiente código imprime "¡Hola, mundo!" cinco veces:

* Programa SNOBOL para imprimir Hello World I = 1LOOP OUTPUT = "¡Hola, mundo!" I = I + 1 LE()I, 5) : S()LOOP)FIN

Para realizar el ciclo, el operador menor que o igual, LE, se llama en la variable de índice I, y si Stiene éxito, lo que significa que I es menor que 5, se bifurca a la etiqueta nombrada LOOP y continúa.

Icon mantuvo el concepto de control de flujo basado en el éxito o el fracaso, pero desarrolló aún más el lenguaje. Un cambio fue el reemplazo de la etiqueta GOTO-like ramificación con estructuras orientadas a bloques de acuerdo con el estilo de programación estructurada que estaba arrasando en la industria informática a fines de la década de 1960. El segundo era permitir que el "fracaso" para pasar a lo largo de la cadena de llamadas para que los bloques completos tengan éxito o fallen como un todo. Este es un concepto clave del lenguaje Icon. Mientras que en los lenguajes tradicionales uno tendría que incluir código para probar el éxito o el fracaso según la lógica booleana y luego bifurcarse según el resultado, tales pruebas y bifurcaciones son inherentes al código Icon y no tienen que escribirse explícitamente.

Por ejemplo, considere este fragmento de código escrito en el lenguaje de programación Java. Llama a la función read() para leer un carácter de un archivo (abierto previamente), asigna el resultado a la variable a , y luego escribe el valor de a a otro archivo. El resultado es copiar un archivo a otro. read eventualmente se quedará sin caracteres para leer del archivo, potencialmente en su primera llamada, lo que dejaría a en un estado indeterminado y potencialmente causar write a provocar una excepción de puntero nulo. Para evitar esto, read devuelve el valor especial EOF (fin de archivo) en esta situación, que requiere una prueba explícita para evitar escribir:

 mientras ()a = leído()) ! EOF) {} escribir()a); }

Por el contrario, en Icon, read() la función devuelve una línea de texto o &fail. &fail no es simplemente un análogo de EOF, ya que el lenguaje entiende explícitamente que significa & #34;detener procesamiento" o "haga el caso fallido" dependiendo del contexto. El código equivalente en Icon es:

 mientras a := leído() entonces escribir()a)

Esto significa, "siempre que la lectura no falle, llamar a escribir, de lo contrario detener". No es necesario especificar una prueba contra el número mágico como en el ejemplo de Java, esto es implícito y el código resultante se simplifica. Debido a que el éxito y el fracaso pasan a través de la cadena de llamadas, uno puede incrustar funciones dentro de otras y se detiene cuando falla la función anidada. Por ejemplo, el código anterior se puede reducir a:

 mientras escribir()leído())

En esta versión, si leer falla, write falla y mientras se detiene. Todas las construcciones de bifurcación y bucle de Icon se basan en el éxito o el fracaso del código que contienen, no en una prueba booleana arbitraria proporcionada por el programador. si realiza el luego bloquear si es "test" devuelve un valor, y el bloque else o se mueve a la siguiente línea si devuelve &fail. Del mismo modo, while continúa llamando a su bloque hasta que recibe un fallar. Icon se refiere a este concepto como ejecución dirigida a objetivos.

Es importante contrastar el concepto de éxito y fracaso con el concepto de excepción; las excepciones son situaciones inusuales, no resultados esperados. Las fallas en Icon son resultados esperados; llegar al final de un archivo es una situación esperada y no una excepción. Icon no tiene manejo de excepciones en el sentido tradicional, aunque fail se usa a menudo en situaciones similares a excepciones. Por ejemplo, si el archivo que se está leyendo no existe, read falla sin que se indique una situación especial. En el lenguaje tradicional, estas "otras condiciones" no tienen forma natural de ser indicados; se pueden usar números mágicos adicionales, pero más típicamente se usa el manejo de excepciones para "lanzar" un valor. Por ejemplo, para manejar un archivo faltante en el código Java, uno podría ver:

 Prueba {} mientras ()a = leído()) ! EOF) {} escribir()a); } } captura ()Excepción e) {} // algo más salió mal, utilizar esta captura para salir del bucle }

Este caso necesita dos comparaciones: una para EOF y otra para todos los demás errores. Dado que Java no permite que las excepciones se comparen como elementos lógicos, como en Icon, el largo try/catch. Los bloques de prueba también imponen una penalización de rendimiento incluso si no se lanza una excepción, un costo distribuido que Icon normalmente evita.

Icon usa este mismo mecanismo dirigido a objetivos para realizar pruebas booleanas tradicionales, aunque con diferencias sutiles. Una comparación simple como if a < b luego escribir("a es menor que b") no significa que "si la evaluación de la expresión condicional da como resultado o devuelve un valor verdadero" como lo harían en la mayoría de los idiomas; en cambio, significa algo más como, "si la expresión condicional, aquí <, tiene éxito y no falla". En este caso, el operador < tiene éxito si el la comparación es cierta. El if llama a su then cláusula si la expresión tiene éxito, o else o la siguiente línea si falla. El resultado es similar al tradicional si/entonces visto en otros idiomas, el si realiza entonces si a es menor que b. La sutileza es que la misma expresión de comparación se puede colocar en cualquier lugar, por ejemplo:

 escribir()a . b)

Otra diferencia es que el operador < devuelve su segundo argumento si tiene éxito, lo que en este ejemplo dará como resultado el valor de b se escribe si es más grande que a, de lo contrario no se escribe nada. Como no se trata de una prueba per se, sino de un operador que devuelve un valor, se pueden unir permitiendo cosas como si un < b < c, un tipo común de comparación que en la mayoría de los idiomas debe escribirse como una conjunción de dos desigualdades como si (a < b) && (b < c).

Un aspecto clave de la ejecución dirigida a objetivos es que el programa puede tener que retroceder a un estado anterior si falla un procedimiento, una tarea conocida como retroceso. Por ejemplo, considere el código que establece una variable en una ubicación de inicio y luego realiza operaciones que pueden cambiar el valor; esto es común en las operaciones de escaneo de cadenas, por ejemplo, que hará avanzar un cursor a través de la cadena mientras escanea. Si el procedimiento falla, es importante que cualquier lectura posterior de esa variable devuelva el estado original, no el estado en el que se estaba manipulando internamente. Para esta tarea, Icon tiene el operador asignación reversible, <-, y el intercambio reversible, <->. Por ejemplo, considere un código que intenta encontrar una cadena de patrón dentro de una cadena más grande:

 {} ()i := 10) " ()j := ()i . encontrar()patrón, inString)) }

Este código comienza moviendo i a 10, la ubicación inicial de la búsqueda. Sin embargo, si find falla, el bloque fallará como un todo, lo que resulta en el valor de i quedando en 10 como efecto secundario indeseable. Reemplazando i:= 10 con i <- 10 indica que i debe restablecerse a su valor anterior si el bloque falla. Esto proporciona un análogo de atomicidad en la ejecución.

Generadores

Las expresiones en Icon pueden devolver un único valor, por ejemplo, 5 > x evaluará y devolverá x si el valor de x es menor que 5, o fallará. Sin embargo, Icon también incluye el concepto de procedimientos que no inmediatamente devuelven el éxito o el fracaso, sino que devuelven nuevos valores cada vez que se les llama. Estos se conocen como generadores y son una parte clave del lenguaje Icon. Dentro del lenguaje de Icon, la evaluación de una expresión o función produce una secuencia de resultados. Una secuencia de resultados contiene todos los valores posibles que puede generar la expresión o función. Cuando se agota la secuencia de resultados, la expresión o función falla.

Icon permite que cualquier procedimiento devuelva un solo valor o múltiples valores, controlados usando el falla, return y suspender palabras clave. Un procedimiento que carece de alguna de estas palabras clave devuelve &fail, que ocurre cada vez que la ejecución se ejecuta hasta el end de un procedimiento. Por ejemplo:

 procedimiento f()x) si x  0 entonces {} retorno 1 } final

Llamar a f(5) devolverá 1, pero llamar a f(-1) devolverá &fail. Esto puede llevar a un comportamiento no obvio, por ejemplo, write(f (-1)) no generará nada porque f falla y suspende la operación de write.

Convertir un procedimiento en un generador utiliza la suspend palabra clave, que significa "devolver este valor y, cuando se le llame de nuevo, iniciar la ejecución en este punto". En este sentido, es algo así como una combinación del concepto estático en C y regresar. Por ejemplo:

 procedimiento ItoJ()i, j) mientras i . j do {} suspensión i i +:= 1 } falla final

crea un generador que devuelve una serie de números a partir de i y finalizando con j, y luego devuelve &fail después de eso. suspend i detiene la ejecución y devuelve el valor de i sin restablecer ninguno de los estados. Cuando se realiza otra llamada a la misma función, la ejecución continúa en ese punto con los valores anteriores. En este caso, eso hace que realice i +:= 1, regresa al inicio del bloque while y luego devuelve el siguiente valor y suspende nuevamente. Esto continúa hasta que i <= j falla, en en qué punto sale del bloque y llama a fail. Esto permite construir iteradores con facilidad.

Otro tipo de generador-constructor es el alternador, que se ve y funciona como el booleano o. Por ejemplo:

 si Sí. . ()x Silencio 5) entonces escribir()"y=", Sí.)

Esto parece decir "si y es menor que x o 5, entonces...", pero en realidad es una forma abreviada de un generador que devuelve valores hasta que cae al final de la lista.. Los valores de la lista son "inyectados" en las operaciones, en este caso, <. Entonces, en este ejemplo, el sistema primero prueba y < x, si x es realmente mayor que y, devuelve el valor de x, la prueba pasa y el valor de y se escribe en el then. Sin embargo, si x no es mayor que y, falla y el alternador continúa, realizando y < 5. Si pasa la prueba, se escribe y. Si y es menor que x o 5, el alternador se queda sin pruebas y falla, el directorio si falla y escribe no se ejecuta. Por lo tanto, el valor de y aparecerá en la consola si es menor que x o 5, cumpliendo así el propósito de un booleano o. Las funciones no se llamarán a menos que la evaluación de sus parámetros tenga éxito, por lo que este ejemplo se puede acortar a:

 escribir()"y=", ()x Silencio 5)  Sí.)

Internamente, el alternador no es simplemente un o y uno también puede usarlo para construir listas arbitrarias de valores. Esto se puede usar para iterar sobre valores arbitrarios, como:

 cada uno i := ()1Silencio3Silencio4Silencio5Silencio10Silencio11Silencio23) do escribir()i)

Como las listas de enteros se encuentran comúnmente en muchos contextos de programación, Icon también incluye el to para construir generadores de enteros ad hoc:

 cada uno k := i a j do escribir()k)

que se puede acortar:

 cada uno escribir()1 a 10)

El icono no está fuertemente tipado, por lo que las listas de alternadores pueden contener diferentes tipos de elementos:

 cada uno i := ()1 Silencio "hola" Silencio x . 5) do escribir()i)

Esto escribe 1, "hola" y tal vez 5 dependiendo del valor de x.

Del mismo modo, el operador de conjunción, &, se usa de forma similar a un booleano y:

 cada uno x := ItoJ()0,10) " x % 2 == 0 do escribir()x)

Este código llama a ItoJ y devuelve una inicial valor de 0 que se asigna a x. Luego realiza el lado derecho de la conjunción, y desde x % 2 es igual a 0, escribe el valor. Luego llama de nuevo al generador ItoJ que asigna 1 a x, que falla en el lado derecho y no imprime nada. El resultado es una lista de todos los enteros pares del 0 al 10.

El concepto de generadores es particularmente útil y poderoso cuando se usa con operaciones de cadena, y es una base subyacente importante para el diseño general de Icon. Considere la operación indexOf que se encuentra en muchos idiomas; esta función busca una cadena dentro de otra y devuelve un índice de su ubicación, o un número mágico si no se encuentra. Por ejemplo:

 s = "Todo el mundo es un escenario. Y todos los hombres y mujeres simplemente jugadores"; i = índice()"el", s); escribir()i);

Esto escaneará la cadena s, encuentra la primera aparición de "the", y devolver ese índice, en este caso 4. La cadena, sin embargo, contiene dos instancias de la cadena "the", por lo que para devolver el segundo ejemplo un se utiliza una sintaxis alternativa:

 j = índice()"el", s, i+1); escribir()j);

Esto le dice que escanee comenzando en la ubicación 5, por lo que no coincidirá con la primera instancia que encontramos anteriormente. Sin embargo, es posible que no haya una segunda instancia de "the" -puede que tampoco haya uno primero- por lo que el valor de retorno de indexOf debe compararse con el número mágico -1 que se utiliza para indicar que no hay coincidencias. Una rutina completa que imprime la ubicación de cada instancia es:

 s = "Todo el mundo es un escenario. Y todos los hombres y mujeres simplemente jugadores"; i = índice()"el", s); mientras i ! -1 {} escribir()i); i = índice()"el", s, i+1); }

En Icon, el equivalente find es un generador, por lo que se pueden crear los mismos resultados con una sola línea:

 s := "Todo el mundo es un escenario. Y todos los hombres y mujeres simplemente jugadores" cada uno escribir()encontrar()"el", s)

Por supuesto, hay momentos en los que uno quiere encontrar una cadena después de algún punto en la entrada, por ejemplo, si escanea un archivo de texto que contiene un número de línea en las primeras cuatro columnas, un espacio y luego una línea de texto.. La ejecución dirigida a objetivos se puede utilizar para saltarse los números de línea:

 cada uno escribir()5 . encontrar()"el", s)

La posición solo se devolverá si "the" aparece después de la posición 5; de lo contrario, la comparación fallará, pase el error de escritura y no se producirá la escritura.

El operador cada es similar a while, recorrer cada elemento devuelto por un generador y salir en falla:

 cada uno k := i a j do escribir()algunosFunción()k)

Existe una diferencia clave entre every y while; while vuelve a evaluar el primer resultado hasta que falla, mientras que every obtiene el siguiente valor de un generador. every en realidad inyecta valores en la función de manera similar a bloques bajo Smalltalk. Por ejemplo, el ciclo anterior se puede reescribir de esta manera:

 cada uno escribir()algunosFunción()i a j)

En este caso, los valores de i a j se inyectarán en someFunction y (potencialmente) escribir varias líneas de salida.

Colecciones

Icon incluye varios tipos de colecciones, incluidas listas que también se pueden usar como pilas y colas, tablas (también conocidas como mapas o diccionarios en otros idiomas), conjuntos y otros. Icon se refiere a estos como estructuras. Las colecciones son generadores inherentes y se pueden llamar fácilmente usando la sintaxis bang. Por ejemplo:

 líneas := [] # Crear una lista vacía mientras línea := leído() do {} # líneas de lectura de bucle de entrada estándar empujar()líneas, línea) # Usar sintaxis tipo pila para empujar la línea en la lista } mientras línea := pop()líneas) do {} # bucle mientras las líneas pueden ser arrancadas de la lista escribir()línea) # Escribir la línea hacia fuera }

Usando la propagación de fallas como se vio en ejemplos anteriores, podemos combinar las pruebas y los bucles:

 líneas := [] # Crear una lista vacía mientras empujar()líneas, leído()) # empujar hasta vacío mientras escribir()pop()líneas) # Escribir hasta vacío

Debido a que la colección de listas es un generador, esto se puede simplificar aún más con la sintaxis bang:

 líneas := [] cada uno empujar()líneas, !Input) cada uno escribir()!líneas)

En este caso, la explosión en write hace que Icon devuelva una línea de texto una por una de la matriz y finalmente falle al final. &input es un análogo basado en generador de read que lee una línea de entrada estándar, por lo que !&input continúa leyendo líneas hasta que finaliza el archivo.

Como Icon no tiene tipo, las listas pueden contener diferentes tipos de valores:

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

Los elementos pueden incluir otras estructuras. Para crear listas más grandes, Icon incluye el generador list; i:= lista(10, "palabra") genera una lista que contiene 10 copias de "palabra". Al igual que las matrices en otros idiomas, Icon permite buscar elementos por posición, por ejemplo, peso:= aCat[4]. Se incluye el corte de matrices, lo que permite crear nuevas listas a partir de los elementos de otras listas, por ejemplo, aCat:= Cats[2:4] produce una nueva lista llamada aCat que contiene "tabby" y 2002.

Las tablas son esencialmente listas con claves de índice arbitrarias en lugar de números enteros:

 símbolos := cuadro()0) símbolos["Allí"] := 1 símbolos["Aquí"] := 2

Este código crea una tabla que utilizará cero como valor predeterminado de cualquier clave desconocida. Luego agrega dos elementos a la tabla, con las teclas "allí" y "aquí", y valores 1 y 2.

Los conjuntos también son similares a las listas, pero contienen solo un miembro de cualquier valor dado. El ícono incluye el ++ para producir la unión de dos conjuntos, ** la intersección y -- la diferencia. El icono incluye una serie de "Cset"s predefinidos, un conjunto que contiene varios caracteres. Hay cuatro Csets estándar en Icon, &ucase, &lcase, &letters, y &digits. Se pueden crear nuevos Csets encerrando una cadena entre comillas simples, por ejemplo, vocal:= 'aeiou'.

Cuerdas

En Icon, las cadenas son listas de caracteres. Como lista, son generadores y, por lo tanto, se pueden iterar utilizando la sintaxis bang:

 escribir()!"¡Hola, mundo!")

Imprimirá cada carácter de la cadena en una línea separada.

Las subcadenas se pueden extraer de una cadena usando una especificación de rango entre paréntesis. Una especificación de rango puede devolver un punto a un solo carácter o una porción de la cadena. Las cadenas se pueden indexar desde la derecha o la izquierda. Las posiciones dentro de una cadena se definen para estar entre los caracteres 1A2B3C4 y se puede especificar desde la derecha −3A−2B−1C0

Por ejemplo,

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

Donde el último ejemplo muestra el uso de una longitud en lugar de una posición final

La especificación de subíndice se puede usar como un valor l dentro de una expresión. Esto se puede usar para insertar cadenas en otra cadena o eliminar partes de una cadena. Por ejemplo:

 s := "abc" s[2] := "123" s Ahora tiene a valor de "a123c" s := "abcdefg" s[3:5] := "ABCD" s Ahora tiene a valor de "abABCDefg" s := "abcdefg" s[3:5] := " s Ahora tiene a valor de "abefg"

Escaneo de cadenas

Otra simplificación para el manejo de cadenas es el sistema escaneado, invocado con ?, que llama a funciones en una cadena:

 s ? escribir()encontrar()"el")

El icono se refiere al lado izquierdo del ? como el asunto, y lo pasa a funciones de cadena. Recuerde que find toma dos parámetros, el texto de búsqueda como parámetro uno y la cadena para buscar dentro del parámetro dos. Usando ? el segundo parámetro es implícito y no tiene a especificar por el programador. En los casos comunes en los que se llama a varias funciones en una sola cadena en secuencia, este estilo puede reducir significativamente la longitud del código resultante y mejorar la claridad. Las firmas de función de icono identifican el parámetro sujeto en sus definiciones para que el parámetro se pueda izar de esta manera.

El ? no es simplemente una forma de azúcar sintáctico, también configura un "entorno de escaneo de cadenas" para cualquier operación de cadena siguiente. Esto se basa en dos variables internas, &subject y &pos; &subject es simplemente un puntero a la cadena original, mientras que &pos es la posición actual dentro de él, o cursor. Los diversos procedimientos de manipulación de cadenas de Icon utilizan estas dos variables para que el programador no tenga que proporcionarlas explícitamente. Por ejemplo:

 s := "Esto es una cuerda" s ? escribir()"sujeto",Sujeto,", pos= [,",")

produciría:

subject=[esto es una cuerda], pos=[1]

Las funciones integradas y definidas por el usuario se pueden usar para moverse dentro de la cadena que se está escaneando. Todas las funciones integradas tendrán por defecto &subject y &pos para permitir la sintaxis de escaneo para ser utilizado. El siguiente código escribirá todas las "palabras" delimitadas por espacios en blanco. en una cadena:

 s := "Esto es una cuerda" s ? {} # Establecer entorno de escaneo de cadenas mientras no pos()0) do {} # Prueba para el final de la cadena pestaña()muchos()') # Pasar más allá de cualquier blanco palabra := pestaña()arriba()') Silencio 0) # la siguiente palabra es hasta el siguiente blanco -o- el final de la línea escribir()palabra) # Escribir la palabra } }

Hay varias funciones nuevas introducidas en este ejemplo. pos devuelve el valor actual de &pos. Puede que no sea inmediatamente obvio por qué uno necesitaría esta función y no simplemente usar el valor de &pos directamente; la razón es que &pos es una variable y por lo tanto, no puede tomar el valor &fail, que el procedimiento pos puede. Por lo tanto, pos proporciona un contenedor ligero en &pos que permite el control de flujo dirigido por objetivos de Icon para ser usado fácilmente sin tener que proporcionar pruebas booleanas escritas a mano contra &pos. En este caso, la prueba es "es &pos cero", que, en la numeración impar de las ubicaciones de las cadenas de iconos, es el final de la línea. Si no es cero, pos devuelve &fail, que está invertido con not y el ciclo continúa.

many encuentra uno o más ejemplos de proporcionó el parámetro Cset que comienza en el &pos actual. En este caso, está buscando caracteres de espacio, por lo que el resultado de esta función es la ubicación del primer carácter que no es un espacio después de &pos. tab mueve &pos a esa ubicación, nuevamente con un potencial &fail en caso de que, por ejemplo, many cae al final de la cadena. hasta es esencialmente lo contrario de muchos; devuelve la ubicación inmediatamente anterior a su Cset proporcionado, que luego el ejemplo establece el &pos con otra pestaña. La alternancia también se utiliza para detenerse al final de una línea.

Este ejemplo se puede hacer más sólido mediante el uso de una "separación de palabras" Cset que puede incluir puntos, comas y otros signos de puntuación, así como otros caracteres de espacios en blanco como tabulaciones y espacios de no separación. Ese Cset se puede usar en muchos y hasta.

Un ejemplo más complejo demuestra la integración de generadores y escaneo de cadenas dentro del lenguaje.

 procedimiento principal() s := "Mon Dic 8" s ? escribir()Mdate() Silencio "no una fecha válida") final # Define una función que coincida que devuelve # una cuerda que coincide un día de mes procedimiento Mdate() # Define algunos valores iniciales estática fechas estática días inicial {} días := ["Mon","Tue","Wed","Thr","Fri","Sat","Sun"] meses := ["Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"] } cada uno suspensión ()Retval . pestaña()partido()!días) Silencio # Coincide un día =" Silencio # Seguido por un blanco pestaña()partido()!meses) Silencio # Seguido por el mes =" Silencio # Seguido por un blanco matchdigits()2) # Seguido por al menos 2 dígitos ) " ()=" Silencio pos()0) ) " # O un blanco o el final de la cadena Retval # Y finalmente devolver la cuerda final # Función de emparejamiento que devuelve una cadena de n dígitos procedimiento matchdigits()n) suspensión ()v := pestaña()muchos()" dígitos ") " *v . n) " v final

Críticas

Laurence Tratt escribió un artículo sobre Icon examinando sus aplicaciones en el mundo real y señalando una serie de áreas de preocupación. Entre estas había una serie de decisiones prácticas que se derivan de sus orígenes en el procesamiento de cadenas pero que no tienen tanto sentido en otras áreas. Entre ellos:

La decisión de fallar por defecto al final de los procedimientos tiene sentido en el contexto de los generadores, pero menos en el caso de los procedimientos generales. Volviendo al ejemplo mencionado anteriormente, write(f(-1)) no generará lo que se puede esperar. Sin embargo:

 x := 10 ()adicionales líneas) x := f()-1) escribir()x)

dará como resultado que se impriman 10. Este tipo de problema no es del todo obvio, ya que incluso en un depurador interactivo se invoca todo el código todavía x nunca toma el valor esperado. Esto podría descartarse como uno de esos "trampas" que los programadores deben tener en cuenta en cualquier idioma, pero Tratt examinó una variedad de programas Icon y descubrió que la gran mayoría de los procedimientos no son generadores. Esto significa que el comportamiento predeterminado de Icon solo lo usa una pequeña minoría de sus construcciones, pero representa una fuente importante de errores potenciales en todos los demás.

Otro problema es la falta de un tipo de datos booleano y una lógica booleana convencional. Si bien el sistema de éxito/fracaso funciona en la mayoría de los casos en los que el objetivo final es verificar un valor, esto aún puede conducir a un comportamiento extraño en un código aparentemente simple:

 procedimiento principal() si c entonces {} escribir()"tomada") } final

Este programa imprimirá "tomado". La razón es que la prueba, c, devuelve un valor; ese valor es cero, el valor predeterminado para todas las variables no iniciadas. Cero es un valor válido, por lo que si c tiene éxito. Para resolver esto, se necesita hacer la prueba explícita, c == 0, lo que resta valor al código de autodocumentación: es ambiguo si esto está probando "es c cero" o "existe c".