stringtranslate.com

Icono (lenguaje de programación)

Icon es un lenguaje de programación de muy alto nivel basado en el concepto de "ejecución dirigida a objetivos" en el que el código devuelve un "éxito" junto con valores válidos, o un "error", lo que indica que no hay datos válidos que devolver. El éxito y el fracaso de un bloque de código determinado se utilizan para dirigir el procesamiento posterior, mientras que los lenguajes convencionales normalmente utilizarían 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 suele estar 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 una sintaxis anticuada 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 la actualización significativa de Icon, 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 con cadenas a menudo fallan, por ejemplo, al encontrar "the" en "world". En la mayoría de los lenguajes, esto requiere pruebas y ramificaciones para evitar usar un resultado no válido. En Icon, la mayoría de este tipo de pruebas son simplemente innecesarias, lo que reduce la cantidad de código que debe escribirse. El manejo de patrones complejos se puede realizar 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 que resulta 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 especialmente influyentes sus generadores simples; los generadores de Icon fueron una gran inspiración para el lenguaje Python . [3]

Historia

SNOBOL

El proyecto original de SNOBOL , 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 . [4] El proyecto 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 cadenas de Markov . SCL, escrito por el jefe del departamento Chester Lee, era lento y tenía una sintaxis de bajo nivel que daba como resultado 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. [5]

Las primeras versiones se ejecutaban en el IBM 7090 a principios de 1963, y para el verano ya se habían desarrollado y se usaban en toda Bell. Esto condujo casi inmediatamente a SNOBOL2, que agregó una serie de funciones integradas y la capacidad de vincularse a código de lenguaje ensamblador externo . Se lanzó en abril de 1964 y se usó principalmente dentro de Bell, pero también se usó en el Proyecto MAC . La introducción de funciones del sistema sirvió principalmente para indicar la necesidad de funciones de usuario, que fue la característica principal de SNOBOL3, lanzado en julio de 1964. [6]

La introducción de SNOBOL3 coincidió con importantes cambios dentro del departamento de computación de Bell Labs, incluida la incorporación del nuevo mainframe GE 645 que requeriría una reescritura de SNOBOL. En su lugar, el equipo sugirió escribir una nueva versión que se ejecutaría en una máquina virtual , llamada SIL (lenguaje intermedio de SNOBOL), lo que permitiría que se pudiera trasladar fácilmente a cualquier plataforma lo suficientemente potente. 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. [7] El trabajo adicional sobre el lenguaje continuó durante el resto de la década de 1960, en particular agregando el tipo de matriz asociativa en una versión posterior, a la que se refirieron como tabla.

SL5 conduce a Icon

Griswold dejó Bell Labs para convertirse en profesor en la Universidad de Arizona en agosto de 1971. [8] Introdujo SNOBOL4 como una herramienta de investigación en ese momento. [9] Recibió subvenciones de la Fundación Nacional de Ciencias para continuar apoyando y desarrollando SNOBOL. [10]

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 lenguaje depende de columnas, ya que muchos de estos lenguajes se ingresaban en tarjetas perforadas donde la disposición de columnas es natural. Además, las estructuras de control se basaban casi por completo en ramificaciones alrededor 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. Para cuando se mudó a Arizona, la sintaxis de SNOBOL4 estaba irremediablemente obsoleta. [11]

Griswold comenzó el esfuerzo de implementar el concepto subyacente de éxito/fracaso de SNOBOL con estructuras de control de flujo tradicionales como if/then. Esto se convirtió en SL5, abreviatura de "SNOBOL Language 5", pero el resultado no fue satisfactorio. [11] En 1977, volvió al lenguaje para considerar una nueva versión. Abandonó el sistema de funciones muy potente 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: [11]

El nuevo lenguaje se conoció inicialmente como SNOBOL5, pero como era significativamente diferente de SNOBOL en todo, salvo en el concepto subyacente, finalmente se buscó 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 que usaran ese nombre. Se propusieron una serie de nombres nuevos que se abandonaron; Irving, bard y "TL" para "The Language" (El lenguaje). Fue en ese momento cuando Xerox PARC comenzó a publicar sobre su trabajo en interfaces gráficas de usuario y el término "icon" comenzó a ingresar al léxico informático. Se tomó la decisión de cambiar el nombre inicialmente a "icon" antes de elegir finalmente "Icon". [11] [a]

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, ya que utiliza :=sintaxis para asignaciones, la procedurepalabra clave y una sintaxis similar. Por otro lado, Icon usa llaves de estilo C para estructurar grupos de ejecución y los programas comienzan ejecutando un procedimiento llamado main. [13]

En muchos sentidos, Icon también comparte características con la mayoría de los lenguajes de script (así como con SNOBOL y SL5, de donde se tomaron): no es necesario declarar las variables, los tipos se convierten automáticamente y los números se pueden convertir en cadenas y viceversa automáticamente. [14] Otra característica común a muchos lenguajes de script, 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 se terminan con un punto y coma implícito si tiene sentido. [15]

Los procedimientos son los componentes básicos de los programas Icon. Aunque utilizan nombres Pascal, funcionan más como funciones C y pueden devolver valores; no hay ninguna functionpalabra clave en Icon. [16]

 procedimiento  doSomething ( aString )  escribir ( aString )  fin

Ejecución dirigida a objetivos

Uno de los conceptos clave en SNOBOL era que sus funciones devolvían el "éxito" o el "fracaso" como primitivas del lenguaje en lugar de usar números mágicos u otras técnicas. [17] [18] 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 ejecución de lenguajes ; en JavaScript, uno podría querer encontrar la posición de la palabra "Mundo" dentro de un programa "¡Hola, Mundo!" , lo que se haría con , que devolvería 7. Si en cambio uno pide 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. [19]position = "Hello, World".indexOf("World")position = "Hello, World".indexOf("Goodbye")

En SNOBOL, un fallo de este tipo devuelve un valor especial, fail. La sintaxis de SNOBOL actúa directamente sobre el éxito o el fracaso de la operación, saltando a secciones etiquetadas del código sin tener que escribir una prueba aparte. Por ejemplo, el siguiente código imprime "Hola, mundo!" cinco veces: [20]

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

Para realizar el bucle, se llama al operador menor o igual, LE, en la variable de índice I, y si tiene Séxito, es decir, si I es menor que 5, se ramifica a la etiqueta nombrada LOOPy continúa. [20]

Icon mantuvo el concepto de control de flujo basado en el éxito o el fracaso, pero desarrolló el lenguaje aún más. Uno de los cambios fue la sustitución de la GOTOramificación de tipo etiquetada por estructuras orientadas a bloques, en consonancia con el estilo de programación estructurada que estaba arrasando en la industria informática a finales de los años 1960. [11] El segundo fue permitir que el "error" se transmitiera a lo largo de la cadena de llamadas, de modo que los bloques enteros tuvieran éxito o fallaran 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 basándose en la lógica booleana y luego ramificar en función del resultado, dichas pruebas y ramificaciones son inherentes al código Icon y no tienen que estar escritas explícitamente. [21]

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 (previamente abierto), asigna el resultado a la variable ay luego writecopia el valor de aa otro archivo. El resultado es copiar un archivo a otro. readeventualmente se quedará sin caracteres para leer del archivo, potencialmente en su primera llamada, lo que lo dejaría aen un estado indeterminado y potencialmente causaría writeuna excepción de puntero nulo . Para evitar esto, readdevuelve el valor especial EOF(fin de archivo) en esta situación, lo que requiere una prueba explícita para evitarlo write:

 mientras (( a = leer ()) != EOF ) { escribir ( a ); }        

En cambio, en Icon la read()función devuelve una línea de texto o &fail. &failno es simplemente un análogo de EOF, ya que el lenguaje entiende explícitamente que significa "detener el procesamiento" o "ejecutar el caso de error" según el contexto. El código equivalente en Icon es: [18]

 mientras  a  :=  leer ()  hacer  escribir ( a )

Esto significa, "mientras la lectura no falle, llamar a la escritura, de lo contrario detener". [18] No hay necesidad de 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 se transmiten a través de la cadena de llamadas, uno puede incrustar llamadas de función dentro de otras y detenerse cuando la llamada de función anidada falla. Por ejemplo, el código anterior se puede reducir a: [22]

 mientras  escribe ( lee ())

En esta versión, si la readllamada falla, la writellamada falla y se whiledetiene. [22] Las construcciones de ramificación y bucle de Icon se basan en el éxito o el fracaso del código dentro de ellas, no en una prueba booleana arbitraria proporcionada por el programador. ifejecuta el thenbloque si su "prueba" devuelve un valor, y ejecuta el elsebloque o pasa a la siguiente línea si devuelve &fail. Del mismo modo, whilecontinúa llamando a su bloque hasta que recibe un error. Icon se refiere a este concepto como ejecución dirigida a objetivos . [23]

Es importante contrastar el concepto de éxito y fracaso con el concepto de excepción ; las excepciones son situaciones inusuales, no resultados esperados. Los fallos 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, readfalla sin que se indique una situación especial. [18] En el lenguaje tradicional, estas "otras condiciones" no tienen una forma natural de indicarse; se pueden usar números mágicos adicionales, pero lo más típico es que el manejo de excepciones se use para "lanzar" un valor. Por ejemplo, para manejar un archivo faltante en el código Java, se podría ver:

 try { while (( a = read ()) != EOF ) { write ( a ); } } catch ( Exception e ) { // algo más salió mal, usa este catch para salir del bucle }                 

Este caso necesita dos comparaciones: una para el EOF y otra para todos los demás errores. Dado que Java no permite comparar excepciones como elementos lógicos, como en Icon, try/catchse debe utilizar en su lugar la sintaxis extensa. Los bloques Try también imponen una penalización de rendimiento incluso si no se lanza ninguna excepción, un costo distribuido que Icon normalmente evita.

Icon utiliza este mismo mecanismo orientado a objetivos para realizar pruebas booleanas tradicionales, aunque con diferencias sutiles. Una comparación simple como no significa "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 lenguajes; en cambio, significa algo más como "si la expresión condicional, aquí operación, tiene éxito y no falla". En este caso, el operador tiene éxito si la comparación es verdadera. El llama a su cláusula si la expresión tiene éxito, o al o a la siguiente línea si falla. El resultado es similar al if/then tradicional que se ve en otros lenguajes, el realiza if es menor que . La sutileza es que la misma expresión de comparación se puede colocar en cualquier lugar, por ejemplo:if a < b then write("a is smaller than b")<<ifthenelseifthenab

 escribe ( a  <  b )

Otra diferencia es que el <operador devuelve su segundo argumento si tiene éxito, lo que en este ejemplo dará como resultado que bse escriba el valor de si es mayor que a, de lo contrario no se escribe nada. Como esto no es una prueba per se , sino un operador que devuelve un valor, se pueden encadenar permitiendo cosas como if a < b < c, [22] un tipo común de comparación que en la mayoría de los lenguajes debe escribirse como una conjunción de dos desigualdades como if (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 un procedimiento falla, una tarea conocida como retroceso . Por ejemplo, considere un código que establece una variable en una posición inicial y luego realiza operaciones que pueden cambiar el valor; esto es común en las operaciones de escaneo de cadenas, por ejemplo, que harán avanzar un cursor a través de la cadena a medida que la 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 de asignación reversible<- , , y el operador de 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  <  find ( patrón ,  inString )))  }

Este código comienza moviéndose ia 10, la ubicación de inicio de la búsqueda. Sin embargo, si findfalla, el bloque fallará en su totalidad, lo que da como resultado que el valor de iquede en 10 como un efecto secundario no deseado . Reemplazar i := 10por i <- 10indica que idebe 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 > xevaluarán y devolverán x si el valor de x es menor que 5, o de lo contrario fallarán. Sin embargo, Icon también incluye el concepto de procedimientos que no devuelven inmediatamente éxito o fracaso, y en su lugar devuelven nuevos valores cada vez que se los 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 pueden generarse por la expresión o función. Cuando la secuencia de resultados se agota, la expresión o función falla.

Icon permite que cualquier procedimiento devuelva un único valor o varios valores, controlados mediante las palabras clave fail, returny suspend. Un procedimiento que no tenga ninguna de estas palabras clave devuelve &fail, lo que ocurre siempre que la ejecución se ejecuta en el endde un procedimiento. Por ejemplo:

 procedimiento  f ( x )  si  x  >  0  entonces  {  devuelve  1  }  fin

La llamada f(5)devolverá 1, pero la llamada f(-1)devolverá &fail. Esto puede provocar un comportamiento no obvio, por ejemplo, write(f(-1))no generará nada porque ffalla y suspende la operación de write. [24]

Para convertir un procedimiento en generador se utiliza la suspendpalabra clave, que significa "devolver este valor y, cuando se lo vuelva a llamar, iniciar la ejecución en este punto". En este sentido, es algo así como una combinación del staticconcepto en C y return. Por ejemplo: [18]

 procedimiento  ItoJ ( i ,  j )  mientras  i  <=  j  hacer  {  suspender  i  i  +:=  1  }  falla  fin

crea un generador que devuelve una serie de números que comienzan iy terminan en a j, y luego regresa &faildespués de eso. [b] El suspend idetiene la ejecución y devuelve el valor de isin restablecer ninguno de los estados. Cuando se realiza otra llamada a la misma función, la ejecución retoma en ese punto con los valores anteriores. En este caso, eso hace que ejecute i +:= 1, vuelva al inicio del bloque while y luego devuelva el siguiente valor y se suspenda nuevamente. Esto continúa hasta que i <= jfalla, momento en el que sale del bloque y llama a fail. Esto permite que los iteradores se construyan con facilidad. [18]

Otro tipo de generador es el alternadoror , que tiene el mismo aspecto y funciona como el operador booleano . Por ejemplo:

 si  y  <  ( x  |  5 )  entonces  escribe ( "y=" ,  y )

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 se cae del final de la lista. Los valores de la lista se "inyectan" en las operaciones, en este caso, <. Por lo tanto, en este ejemplo, el sistema primero prueba y < x, si x es de hecho mayor que y devuelve el valor de x, la prueba pasa y el valor de y se escribe en la thencláusula. Sin embargo, si x no es mayor que y falla y el alternador continúa, realizando y < 5. Si esa prueba pasa, se escribe y. Si y no es menor que x o 5, el alternador se queda sin pruebas y falla, la iffalla y la writeno se realiza. 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 or. No se llamarán funciones a menos que la evaluación de sus parámetros tenga éxito, por lo que este ejemplo se puede acortar a:

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

Internamente, el alternador no es simplemente un ory también se puede utilizar para construir listas arbitrarias de valores. Esto se puede utilizar para iterar sobre valores arbitrarios, como:

 cada  i  : =  ( 1 | 3 | 4 | 5 | 10 | 11 | 23 )  escribe  ( i )

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

 cada  k  :  = i  a  j  escribe  ( k )

que se puede abreviar:

 cada  escritura ( 1  a  10 )

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

 cada  i  :=  ( 1  |  "hola  " |  x  <  5 )  escribe  ( i )

Esto escribe 1, "hola" y quizás 5 dependiendo del valor de x.

Del mismo modo, el operador de conjunción , &, se utiliza de manera similar a un andoperador booleano: [25]

 cada  x  :  = ItoJ ( 0 , 10 )  y  x  %  2  ==  0  escribe  ( x )

Este código llama ItoJy devuelve un valor inicial de 0 que se asigna a x. Luego realiza el lado derecho de la conjunción y, dado que x % 2es igual a 0, escribe el valor. Luego llama ItoJnuevamente al generador que asigna 1 a x, lo que falla en el lado derecho y no imprime nada. El resultado es una lista de todos los números enteros pares de 0 a 10. [25]

El concepto de generadores es particularmente útil y poderoso cuando se utiliza con operaciones de cadenas, y es una base fundamental para el diseño general de Icon. Considere la indexOfoperación que se encuentra en muchos lenguajes; 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 son meros actores" ; i = indexOf ( "el" , s ); write ( i );       

Esto escaneará la cadena s, encontrará la primera ocurrencia de "the" y devolverá ese índice, en este caso 4. Sin embargo, la cadena contiene dos instancias de la cadena "the", por lo que para devolver el segundo ejemplo se utiliza una sintaxis alternativa:

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

Esto le indica que debe escanear a partir de la ubicación 5, por lo que no coincidirá con la primera instancia que encontramos anteriormente. Sin embargo, puede que no haya una segunda instancia de "the" (tampoco puede haber una primera), por lo que el valor de retorno de indexOfdebe 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 son meros actores" ; i = indexOf ( "el" , s ); while i != - 1 { write ( i ); i = indexOf ( "el" , s , i + 1 ); }                  

En Icon, el equivalente findes 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 son meros actores"  every  write ( find ( "the" ,  s ))

Por supuesto, hay ocasiones en las que uno desea encontrar una cadena después de un punto de entrada, por ejemplo, si se 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 omitir los números de línea:

 cada  escritura ( 5  <  find ( "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 la escritura no se realizará.

El everyoperador es similar a while, recorre cada elemento devuelto por un generador y sale en caso de falla: [24]

 cada  k  :=  i  a  j  escribe  ( algunaFuncion ( k ) )

Existe una diferencia clave entre everyy while; whilereevalúa el primer resultado hasta que falla, mientras que everyobtiene el siguiente valor de un generador. everyen realidad inyecta valores en la función de una manera similar a los bloques de Smalltalk . Por ejemplo, el bucle anterior se puede reescribir de esta manera: [24]

 cada  escritura ( algunaFuncion ( i  a  j ))

En este caso, los valores de i a j se inyectarán someFunctiony (potencialmente) escribirán múltiples líneas de salida. [24]

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 utilizando la sintaxis bang. Por ejemplo:

 líneas  :=  []  # crea una lista vacía  mientras  línea  :=  read ()  hacer  {  # bucle leyendo líneas desde la entrada estándar  push ( líneas ,  línea )  # usa una sintaxis similar a la de una pila para insertar la línea en la lista  }  mientras  línea  :=  pop ( líneas )  hacer  {  # bucle mientras las líneas se puedan sacar de la lista  write ( línea )  # escribe la línea  }

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

 líneas  :=  []  # crea una lista vacía  while  push ( líneas ,  read ())  # empuja hasta que esté vacía  while  write ( pop ( líneas ))  # escribe hasta que esté vacía

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

 líneas  :=  []  cada  inserción ( líneas ,  ! &entrada )  cada  escritura ( ! líneas )

En este caso, el clic en writehace que Icon devuelva una línea de texto una por una desde la matriz y finalmente falle al final. &inputes un análogo basado en generador de readque lee una línea desde la entrada estándar , por lo que !&inputcontinúa leyendo líneas hasta que finaliza el archivo.

Como Icon no tiene tipo, las listas pueden contener cualquier tipo de valor:

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

Los elementos pueden incluir otras estructuras. Para crear listas más grandes, Icon incluye el listgenerador; i := list(10, "word")genera una lista que contiene 10 copias de "word". Al igual que las matrices en otros lenguajes, Icon permite buscar elementos por posición, por ejemplo, weight := aCat[4]. Se incluye la segmentación 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  :=  tabla ( 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 claves "allí" y "aquí", y los valores 1 y 2.

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

Instrumentos de cuerda

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

 escribe ( ! "¡Hola, mundo!" )

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

Las subcadenas se pueden extraer de una cadena utilizando una especificación de rango entre corchetes. 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 como entre los caracteres 1 A 2 B 3 C 4 y se pueden especificar desde la derecha −3 A −2 B −1 C 0

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índices se puede utilizar como un valor l dentro de una expresión. Esto se puede utilizar para insertar cadenas en otra cadena o eliminar partes de una cadena. Por ejemplo:

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

Escaneo de cadenas

Una simplificación adicional para el manejo de cadenas es el sistema de escaneo , invocado con ?, que llama funciones en una cadena:

 s  ?  escribir ( encontrar ( "el" ))

Icon hace referencia al lado izquierdo de la función ?como sujeto y lo pasa a funciones de cadena. Recuerde que la función findtoma dos parámetros, el texto de búsqueda como parámetro uno y la cadena a buscar en el parámetro dos. El uso ?del segundo parámetro es implícito y no tiene que ser especificado por el programador. En los casos comunes en los que se invocan múltiples 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 funciones de icono identifican el parámetro sujeto en sus definiciones, por lo que el parámetro se puede elevar de esta manera.

El ?no es simplemente una forma de azúcar sintáctica, también establece un "entorno de escaneo de cadenas" para cualquier operación de cadena posterior. Esto se basa en dos variables internas, &subjecty &pos; &subjectes simplemente un puntero a la cadena original, mientras que &poses la posición actual dentro de ella, o cursor. Los diversos procedimientos de manipulación de cadenas de Icon utilizan estas dos variables, por lo que no tienen que ser suministradas explícitamente por el programador. Por ejemplo:

 s  :=  "esto es una cadena"  s  ?  write ( "subject=[" , &subject , "], pos=[" , &pos , "]" )

Produciría:

asunto=[esta es una cadena], pos=[1]

Se pueden utilizar funciones integradas y definidas por el usuario para desplazarse por la cadena que se está escaneando. Todas las funciones integradas tendrán como valor predeterminado &subjecty &pospara permitir el uso de la sintaxis de escaneo. El siguiente código escribirá todas las "palabras" delimitadas por espacios en blanco en una cadena:

 s  :=  "esta es una cadena"  s  ?  {  # Establecer el entorno de escaneo de cadenas  while  not  pos ( 0 )  do  {  # Probar el final de la cadena  tab ( many ( ' ' ))  # Saltar los espacios en blanco  word  :=  tab ( upto ( ' ' )  |  0 )  # la siguiente palabra es hasta el siguiente espacio en blanco -o- el final de la línea  write ( word )  # escribir la palabra  }  }

En este ejemplo se han introducido varias funciones nuevas. posdevuelve el valor actual de &pos. Puede que no resulte inmediatamente obvio por qué se necesitaría esta función y no simplemente utilizar el valor de &posdirectamente; la razón es que &poses una variable y, por lo tanto, no puede tomar el valor &fail, que el procedimiento possí puede. Por lo tanto, posproporciona un contenedor ligero &posque permite que el control de flujo dirigido a objetivos de Icon se utilice fácilmente sin tener que proporcionar pruebas booleanas escritas a mano contra . En este caso, la prueba es "es &pos cero", que, en la numeración impar de las ubicaciones de cadena de Icon, es el final de la línea. Si no&pos es cero, devuelve , que se invierte con el y el bucle continúa.pos&failnot

manyencuentra uno o más ejemplos del parámetro Cset proporcionado comenzando en el actual &pos. En este caso, busca caracteres de espacio, por lo que el resultado de esta función es la ubicación del primer carácter que no sea un espacio después de que &pos. tabse mueva &posa esa ubicación, nuevamente con un potencial &failen caso de que, por ejemplo, manyse caiga del final de la cadena. uptoes esencialmente lo opuesto de many; devuelve la ubicación inmediatamente anterior a su Cset proporcionado, al que el ejemplo luego establece &poscon otro tab. La alternancia también se usa para detenerse al final de una línea.

Este ejemplo se puede hacer más sólido mediante el uso de un conjunto de reglas de "separación de palabras" más adecuado que podría incluir puntos, comas y otros signos de puntuación, así como otros caracteres de espacio en blanco como tabulaciones y espacios indivisibles. Ese conjunto de reglas se puede utilizar en manyy upto.

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

 procedimiento  principal ()  s  :=  "Lun Dic 8"  s  ?  write ( Mdate ()  |  "no es una fecha válida" )  end  # Define una función coincidente que retorna  # una cadena que coincide con un día mes dayofmonth  procedure  Mdate ()  # Define algunos valores iniciales  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 ))  ||  # Coincidir con un día  = " "  ||  # Seguido de una  pestaña en blanco ( match ( ! months ))  ||  # Seguido del mes  = " "  ||  # Seguido de un  dígito coincidente en blanco ( 2 )  # Seguido de al menos 2 dígitos  )  &  ( = " "  |  pos ( 0 )  )  &  # Un espacio en blanco o el final de la cadena  retval  # Y finalmente devuelve la cadena  end  # Función coincidente que devuelve una cadena de n dígitos  procedimiento  matchdigits ( n )  suspend  ( v  :=  tab ( many ( &digits ))  &  * v  <=  n )  &  v  end

Críticas

Laurence Tratt escribió un artículo sobre Icon en el que examinaba sus aplicaciones en el mundo real y señalaba una serie de áreas de preocupación. Entre ellas, 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. [24] Entre ellas:

La decisión de fallar por defecto al final de los procedimientos tiene sentido en el contexto de los generadores, pero no tanto en el caso de los procedimientos generales. Volviendo al ejemplo mencionado anteriormente, write(f(-1))no se obtendrá el resultado que cabría esperar. Sin embargo: [24]

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

El resultado será la impresión de 10. Este tipo de problema no es del todo obvio, ya que incluso en un depurador interactivo se invoca todo el código pero xnunca se obtiene el valor esperado. Esto podría descartarse como uno de esos "problemas" que los programadores deben tener en cuenta en cualquier lenguaje, 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 utiliza una pequeña minoría de sus construcciones, pero representa una fuente importante de errores potenciales en todos los demás. [24]

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

 procedimiento  principal ()  si  c  entonces  {  escribir ( "tomado" )  }  fin

Este programa imprimirá "tomado". La razón es que la prueba, c, devuelve un valor; ese valor es &null, el valor predeterminado para todas las variables que no se han iniciado. [26] &null es un valor válido, por lo que if ctiene éxito. Para probar esto, es necesario hacer que la prueba sea explícita, c === &null. Tratt supuso que esto le resta valor al código autodocumentado, al haber supuesto erróneamente que está probando "es c cero" o "existe c". [25]

Véase también

Notas

  1. ^ Según una entrevista de 1985, Griswold afirma que el término «icono» no se utilizó hasta que Smalltalk se lanzó al público algún tiempo después. Expresó su enojo por el hecho de que el término ahora confundía a la gente que pensaba que el lenguaje tenía elementos gráficos. [12]
  2. ^ En este caso no failes necesario ya que está inmediatamente antes del end. Se ha añadido para mayor claridad.
  3. ^ Aunque, como señala Tratt, K&R C también carece de un tipo booleano explícito y utiliza 0 para falso y cualquier valor distinto de cero para verdadero. [24]

Referencias

Citas

  1. ^ Townsend, Gregg (26 de enero de 2024). "Actualizar versión a 9.5.22e". GitHub .
  2. ^ "Goaldi". GitHub .
  3. ^ Schemenauer, Neil; Peters, Tim; Hetland, Magnus Lie (18 de mayo de 2001). "PEP 255 – Generadores simples". Propuestas de mejora de Python . Python Software Foundation . Consultado el 9 de febrero de 2012 .
  4. ^ Griswold 1981, págs. 601, 602.
  5. ^ Griswold 1981, págs. 602.
  6. ^ Griswold 1981, págs. 606.
  7. ^ Griswold 1981, págs. 608.
  8. ^ Griswold 1981, págs. 609.
  9. ^ Griswold 1981, págs. 629.
  10. ^ Shapiro 1985, págs. 346.
  11. ^ abcde Griswold y Griswold 1993, pág. 53.
  12. ^ Shapiro 1985, pág. 350.
  13. ^ Griswold y Griswold 2002, pág. xv.
  14. ^ Griswold y Griswold 2002, pág. xvi.
  15. ^ Griswold y Griswold 2002, pág. 10.
  16. ^ Griswold y Griswold 2002, pág. 1.
  17. ^ Griswold y Griswold 2002, pág. 4.
  18. ^ abcdef Tratt 2010, pág. 74.
  19. ^ "Array.prototype.indexOf()". Documentos web de MDN . 27 de junio de 2023.
  20. ^ ab Lane, Rupert (26 de julio de 2015). "SNOBOL - Introducción". Pruebe MTS .
  21. ^ Tratt 2010, pág. 73.
  22. ^abc Griswold 1996, pág. 2.1.
  23. ^ Griswold 1996, pág. 1.
  24. ^ abcdefgh Tratt 2010, pág. 75.
  25. ^ abcd Tratt 2010, pág. 76.
  26. ^ Griswold y Griswold 2002, pág. 128.

Bibliografía

Enlaces externos