Raku es miembro de la familia de lenguajes de programación Perl . [6] Anteriormente conocido como Perl 6 , se le cambió el nombre en octubre de 2019. [7] [8] Raku introduce elementos de muchos lenguajes modernos e históricos. La compatibilidad con Perl no era un objetivo, aunque un modo de compatibilidad es parte de la especificación. El proceso de diseño de Raku comenzó en el año 2000.
En Perl 6, decidimos que sería mejor arreglar el idioma que arreglar al usuario.
-Larry Wall [9]
El proceso de diseño de Raku fue anunciado por primera vez el 19 de julio de 2000, en el cuarto día de la Conferencia Perl de ese año , [10] por Larry Wall en su charla State of the Onion 2000 . [11] En ese momento, los objetivos principales eran eliminar "verrugas históricas" del idioma; "las cosas fáciles deberían seguir siendo fáciles, las difíciles deberían volverse más fáciles y las imposibles deberían volverse difíciles"; una limpieza general del diseño interno y las API . El proceso comenzó con una serie de solicitudes de comentarios o "RFC". Este proceso estuvo abierto a todos los contribuyentes y no dejó ningún aspecto del lenguaje cerrado al cambio. [12]
Una vez completado el proceso RFC, Wall revisó y clasificó cada una de las 361 solicitudes recibidas. Luego comenzó el proceso de escribir varios "Apocalipsis", utilizando el significado original del término, "revelador". [13] Si bien el objetivo original era escribir un Apocalipsis para cada capítulo de Programación Perl , se hizo obvio que, a medida que se escribía cada Apocalipsis, los Apocalipsis anteriores estaban siendo invalidados por cambios posteriores. Por este motivo se publicaron un conjunto de Sinopsis, cada una de las cuales relataba el contenido de un Apocalipsis, pero los cambios posteriores se reflejaban en actualizaciones. Hoy en día, la especificación Raku se gestiona a través del conjunto de pruebas "asado", [14] mientras que las sinopsis se mantienen como referencia histórica. [15]
También hay una serie de exégesis escritas por Damian Conway que explican el contenido de cada Apocalipsis en términos de uso práctico. Cada exégesis consta de ejemplos de código junto con una discusión sobre el uso y las implicaciones de los ejemplos. [dieciséis]
Hay tres métodos principales de comunicación utilizados en el desarrollo de Raku en la actualidad. El primero es el canal raku IRC en Libera Chat . El segundo es un conjunto de listas de correo . [17] El tercero es el repositorio de código fuente de Git alojado en GitHub . [18]
El objetivo principal que Wall sugirió en su discurso inicial fue la eliminación de las verrugas históricas. Estos incluían la confusión en torno al uso de sigilos para contenedores, la ambigüedad entre las select
funciones y el impacto sintáctico de los identificadores de archivos con palabras simples . Había muchos otros problemas que los programadores de Perl habían discutido solucionar durante años y que Wall abordó explícitamente en su discurso. [ cita necesaria ]
Una implicación de estos objetivos fue que Perl 6 no tendría compatibilidad con el código base de Perl existente. Esto significaba que algún código que fuera interpretado correctamente por un compilador de Perl 5 no sería aceptado por un compilador de Perl 6. Dado que la compatibilidad con versiones anteriores es un objetivo común al mejorar el software, los cambios importantes en Perl 6 debían indicarse explícitamente. La distinción entre Perl 5 y Perl 6 se hizo tan grande que finalmente Perl 6 pasó a llamarse Raku.
La mascota del idioma es "Camelia, el insecto Raku". [1] Su nombre es un guiño a la mascota camello asociada con Perl , y su forma, en la tradición amante de los juegos de palabras de la comunidad Perl, es un juego de palabras con " error de software ". Los diseños en espiral incrustados en sus alas de mariposa se parecen a los caracteres "P6", el apodo favorito de Perl 6, y la ubicación descentrada de los ojos es un juego de palabras intencional con "Wall-eyed". [19]
Uno de los objetivos detrás del diseño alegre y colorido del logo era desalentar la misoginia en la comunidad y que fuera una oportunidad para que aquellos de "persuasión masculina" mostraran su lado sensible. [20]
A partir de 2017 [actualizar], solo la implementación de Rakudo está en desarrollo activo. Ninguna implementación será designada como implementación oficial de Raku; más bien, "Raku es cualquier cosa que pase el conjunto de pruebas oficial". [21]
Rakudo Perl 6 [22] [23] se dirige a varias máquinas virtuales, como MoarVM , Java Virtual Machine y JavaScript . MoarVM es una máquina virtual creada especialmente para Rakudo [24] y NQP Compiler Toolchain. [25] Hay una capa entre Raku y las máquinas virtuales llamada Not Quite Perl 6, o NQP, que implementa reglas de Raku para analizar Raku, así como un árbol de sintaxis abstracta y generación de código específico de backend . Grandes porciones de Rakudo están escritas en el propio Raku o en su subconjunto NQP. Rakudo no es una implementación completamente autohospedada , ni hay planes concretos en este momento para hacer de Rakudo un compilador de arranque .
Pugs fue una implementación inicial de Perl 6 escrita en Haskell . Pugs solía ser la implementación más avanzada de Perl 6, pero desde mediados de 2007 está mayormente inactiva (con actualizaciones realizadas sólo para rastrear la versión actual de GHC ). En noviembre de 2014, los Pugs no recibían mantenimiento activo. [26]
En 2007, v6-MiniPerl6 ("mp6") y su reimplementación, v6-KindaPerl6 ("kp6") se escribieron como un medio para iniciar Perl-6.0.0 STD, utilizando Perl 5. STD es una gramática completa para Perl. 6 y está escrito en Perl 6. En teoría, cualquier cosa capaz de analizar el STD y generar código ejecutable es un sistema de arranque adecuado para Perl 6. kp6 actualmente está compilado por mp6 y puede funcionar con múltiples servidores. [27] [28] mp6 y kp6 no son implementaciones completas de Perl 6 y están diseñados solo para implementar el conjunto de características mínimo requerido para iniciar un compilador completo de Perl 6.
Yapsi era un compilador de Perl 6 y un tiempo de ejecución escrito en el propio Perl 6. Como resultado, para ejecutarse requería un intérprete de Perl 6 existente, como una de las versiones de Rakudo Star. [29]
Niecza, otro importante esfuerzo de implementación de Perl 6, se centró en la optimización y la investigación de implementación eficiente. Está dirigido a la infraestructura del lenguaje común . [30]
La especificación Raku solicita que los módulos se identifiquen por nombre, versión y autoridad. [31] Es posible cargar solo una versión específica de un módulo, o incluso dos módulos del mismo nombre que difieren en versión o autoridad. Para su comodidad, se proporciona un alias para un nombre corto.
CPAN , el sistema de distribución de módulos Perl, aún no maneja módulos Raku. En su lugar, se utiliza un sistema de módulos prototipo. [32]
Perl y Raku difieren fundamentalmente, aunque en general la intención ha sido "mantener Raku Perl", de modo que Raku sea claramente "un lenguaje de programación Perl". La mayoría de los cambios tienen como objetivo normalizar el lenguaje, hacerlo más fácil de entender tanto para programadores novatos como expertos, y hacer "las cosas fáciles más fáciles y las difíciles más posibles".
Una diferencia no técnica importante entre Perl y Raku es que Raku comenzó como una especificación. [21] Esto significa que Raku se puede volver a implementar si es necesario, y también significa que los programadores no tienen que leer el código fuente para tener la máxima autoridad sobre una característica determinada. Por el contrario, en Perl, la documentación oficial no se considera autorizada y sólo describe informalmente el comportamiento del intérprete de Perl real. Cualquier discrepancia encontrada entre la documentación y la implementación puede llevar a que cualquiera de ellas se modifique para reflejar la otra, una dinámica que impulsa el desarrollo continuo y el refinamiento de las versiones de Perl.
En Raku, el sistema de tipos dinámicos de Perl se ha ampliado con la adición de tipos estáticos . [33] Por ejemplo:
mi Int $i = 0 ; mi Rata $r = 3.142 ; my Str $s = "Hola mundo" ;
Sin embargo, la escritura estática sigue siendo opcional , por lo que los programadores pueden hacer la mayoría de las cosas sin necesidad de escribir de forma explícita:
mi $i = "25" + 10 ; # $i es 35
Raku ofrece un sistema de escritura gradual , mediante el cual el programador puede optar por usar escritura estática, usar escritura dinámica o mezclar los dos.
Perl define subrutinas sin listas formales de parámetros (aunque se puede realizar un recuento simple de parámetros y algunas comprobaciones de tipos utilizando los "prototipos" de Perl). Los argumentos de subrutina pasados tienen un alias en los elementos de la matriz @_
. Si se modifican los elementos de @_
, los cambios se reflejan en los datos originales.
Raku introduce verdaderos parámetros formales al lenguaje. [34] En Raku, una declaración de subrutina se ve así:
sub hacer_algo ( Str $cosa , Int $otro ) { ...}
Como en Perl, los parámetros formales (es decir, las variables en la lista de parámetros) son alias de los parámetros reales (los valores pasados), pero de forma predeterminada, los alias son constantes , por lo que no se pueden modificar. Pueden declararse explícitamente como alias de lectura y escritura para el valor original o como copias usando las directivas is rw
o is copy
respectivamente en caso de que el programador requiera que se modifiquen localmente.
Raku proporciona tres modos básicos de paso de parámetros: parámetros posicionales, parámetros con nombre y parámetros slurpy.
Los parámetros posicionales son la lista ordenada típica de parámetros que utilizan la mayoría de los lenguajes de programación. Todos los parámetros también se pueden pasar utilizando su nombre de forma desordenada. Los parámetros sólo con nombre (indicados por un :
antes del nombre del parámetro) sólo se pueden pasar especificando su nombre, es decir, nunca capturan un argumento posicional. Los parámetros Slurpy (indicados por un *
antes del nombre del parámetro) son la herramienta de Raku para crear funciones variadas . Un hash slurpy capturará los parámetros restantes pasados por nombre, mientras que una matriz slurpy capturará los parámetros restantes pasados por posición.
A continuación se muestra un ejemplo del uso de los tres modos de paso de parámetros:
sub alguna función ( $a , $b , : $c , : $d , * @e ) { ...}alguna función ( 1 , 2 ,: d ( 3 ), 4 , 5 , 6 ); # $a=1, $b=2, $d=3, @e=(4,5,6)
Los parámetros posicionales, como los utilizados anteriormente, siempre son obligatorios a menos que vayan seguidos de ?
para indicar que son opcionales. Los parámetros con nombre son opcionales de forma predeterminada, pero se pueden marcar según sea necesario agregándolos !
después del nombre de la variable. Los parámetros de Slupy son siempre opcionales.
Los parámetros también se pueden pasar a bloques arbitrarios, que actúan como cierres . Así es como se nombran , por ejemplo, for
los iteradores de bucle. while
En el siguiente ejemplo, se recorre una lista, 3 elementos a la vez, y se pasa al bloque del bucle como variables $a, $b, $c
. [35]
para @lista -> $a , $b , $c { ...}
Esto generalmente se conoce como "subprograma puntiagudo" o "bloque puntiagudo", y la flecha se comporta casi exactamente como la sub
palabra clave, introduciendo un cierre anónimo (o subrutina anónima en la terminología de Perl). [34]
En Perl, los sigilos (los caracteres de puntuación que preceden al nombre de una variable) cambian dependiendo de cómo se usa la variable:
# código Perlmi @ matriz = ('a', 'b', 'c');mi $elemento = $ matriz[1]; # $elemento es igual a 'b',mi @extracto = @matriz [1, 2]; # @extract es igual a ('b', 'c')mi $elemento = @ matriz[1]; # 'b' viene con una advertencia (opción 5.10)
En Raku, los sigilos son invariantes, lo que significa que no cambian dependiendo de si lo que se necesita es la matriz o el elemento de la matriz: [33]
# Código Rakumi @ matriz = 'a', 'b', 'c';mi $elemento = @ matriz[1]; # $elemento es igual a 'b'mi @extracto = @ matriz[1]; # @extract es igual a ('b')mi @extracto = @matriz [1, 2]; # @extract es igual a ('b', 'c')
La variación en Perl está inspirada en la concordancia numérica en inglés y muchos otros lenguajes naturales:
" Esta manzana." # $a CORRECTO" Estas manzanas." # @a CORRECTO" Esta tercera manzana." # $a[3] CORRECTO" Estas tercera manzana." # @a[3] MAL
Sin embargo, este mapeo conceptual se rompe cuando se utilizan referencias , ya que pueden hacer referencia a estructuras de datos aunque sean escalares. Por lo tanto, trabajar con estructuras de datos anidadas puede requerir una expresión tanto en singular como en plural en un solo término:
# Código Perl: recupera una lista de la hoja de un hash que contiene hashes que contienen matrices my @trans_verbs = @ { $dictionary { 'verb' }{ 'transitive' } };
Esta complejidad no tiene equivalente ni en el uso común del lenguaje natural ni en otros lenguajes de programación, [ dudoso ] y provoca una alta carga cognitiva al escribir código para manipular estructuras de datos complejas. Este es el mismo código en Raku:
# Código Raku: recupera una lista de la hoja de un hash que contiene hashes que contienen matrices my @trans_verbs = %dictionary<verb><transitive><> ;
Perl admite la programación orientada a objetos mediante un mecanismo conocido como bendición . Cualquier referencia puede convertirse en un objeto de una clase particular. A un objeto bendecido se le pueden invocar métodos usando la "sintaxis de flecha", lo que hará que Perl localice o "envíe" una subrutina apropiada por su nombre y la llame con la variable bendecida como primer argumento.
Si bien es extremadamente poderoso, hace que el caso más común de orientación a objetos, un objeto tipo estructura con algún código asociado, sea innecesariamente difícil. Además, como Perl no puede hacer suposiciones sobre el modelo de objetos en uso, la invocación de métodos no se puede optimizar muy bien.
Con el espíritu de hacer "las cosas fáciles fáciles y las difíciles posibles", Raku conserva el modelo de bendición y proporciona un modelo de objetos más sólido para los casos comunes. [36] Por ejemplo, una clase para encapsular un punto cartesiano podría definirse y usarse de esta manera:
El punto de clase es rw { tiene $.x ; tiene $.y ; método distancia ( Punto $p ) { sqrt (( $!x - $p . x ) ** 2 + ( $!y - $p . y ) ** 2 ) } método distancia al centro { self . distancia: Punto . nuevo ( x => 0 , y => 0 ) }}mi $punto = Punto . nuevo ( x => 1,2 , y => - 3,7 ); diga "Ubicación del punto: (" , $punto . x , ', ' , $punto . y , ')' ; # SALIDA: Ubicación del punto: (1.2, -3.7)# Cambiar x e y (tenga en cuenta los métodos "x" e "y" utilizados como valores l): $point . x = 3 ; $punto . y = 4 ; diga "Ubicación del punto: (" , $punto . x , ', ' , $punto . y , ')' ; # SALIDA: Ubicación del punto: (3, 4)mi $otro-punto = Punto . nuevo ( x => - 5 , y => 10 ); $punto . distancia ( $otro-punto ); #=> 10 $punto . distancia al centro ; #=> 5
El punto reemplaza a la flecha en un guiño a muchos otros lenguajes (por ejemplo, C++ , Java , Python , etc.) que se han fusionado alrededor del punto como sintaxis para la invocación de métodos.
En la terminología de Raku, $.x
se denomina "atributo". Algunos idiomas llaman a estos campos o miembros . El método utilizado para acceder a un atributo se denomina "accesor". Un método de acceso automático es un método creado automáticamente y que lleva el nombre del atributo, como el método x
en el ejemplo anterior. Estas funciones de acceso devuelven el valor del atributo. Cuando una clase o atributo individual se declara con el is rw
modificador (abreviatura de "lectura/escritura"), a los accesos automáticos se les puede pasar un nuevo valor para establecer el atributo, o se les puede asignar directamente como un valor l (como en el ejemplo). Los accesos automáticos pueden ser reemplazados por métodos definidos por el usuario, si el programador desea una interfaz más rica para un atributo. Solo se puede acceder a los atributos directamente desde una definición de clase a través de la $!
sintaxis, independientemente de cómo se declaren los atributos. Todos los demás accesos deben pasar por los métodos de acceso.
El sistema de objetos Raku ha inspirado el marco Moose que introduce muchas de las características de programación orientada a objetos de Raku en Perl. [ se necesita aclaración ]
La herencia es la técnica mediante la cual un objeto o tipo puede reutilizar código o definiciones de objetos o tipos existentes. Por ejemplo, un programador puede querer tener un tipo estándar pero con un atributo adicional. La herencia en otros lenguajes, como Java, se proporciona permitiendo que las Clases sean subclases de clases existentes.
Raku proporciona herencia a través de Clases, que son similares a las Clases en otros idiomas, y Roles.
Los roles en Raku asumen la función de interfaces en Java , mixins en Ruby y rasgos [37] en PHP y en la variante de Smalltalk , Squeak . Son muy parecidas a las clases, pero proporcionan un mecanismo de composición más seguro. [38] Estos se utilizan para realizar la composición cuando se usan con clases en lugar de agregarlos a su cadena de herencia . Los roles definen tipos nominales; Proporcionan nombres semánticos para colecciones de comportamiento y estado. La diferencia fundamental entre un rol y una clase es que se pueden crear instancias de clases; los roles no lo son. [39]
Aunque los Roles son distintos de las Clases, es posible escribir código Raku que cree directamente una instancia de un Role o use un Role como un objeto de tipo, Raku creará automáticamente una clase con el mismo nombre que el rol, lo que permitirá usar un rol de forma transparente. como si fuera una clase. [40]
Esencialmente, un rol es un conjunto de métodos y atributos (posiblemente abstractos) que se pueden agregar a una clase sin usar herencia. Incluso se puede agregar un rol a un objeto individual; en este caso, Raku creará una subclase anónima, agregará el rol a la subclase y cambiará la clase del objeto a la subclase anónima.
Por ejemplo, un perro es un mamífero porque los perros heredan ciertas características de los mamíferos, como las glándulas mamarias y (a través del padre del mamífero, el vertebrado ) una columna vertebral . Por otro lado, los perros también pueden tener uno de varios tipos distintos de comportamiento, y estos comportamientos pueden cambiar con el tiempo. Por ejemplo, un Perro puede ser una Mascota , un Callejero (una mascota abandonada adquirirá comportamientos para sobrevivir no asociados a una mascota), o un Guía para ciegos (los perros guía están entrenados, por lo que no comienzan su vida como perros guía) . Sin embargo, estos son conjuntos de comportamientos adicionales que se pueden agregar a un Perro. También es posible describir estos comportamientos de tal manera que puedan aplicarse de manera útil a otros animales; por ejemplo, un gato puede ser igualmente una mascota o un callejero. Por lo tanto, Perro y Gato son distintos entre sí, mientras que ambos permanecen dentro de la categoría más general de Mamífero. Entonces Mammal es una clase y Dog y Cat son clases que heredan de Mammal. Pero los comportamientos asociados con Pet, Stray y Guide son Roles que se pueden agregar a Clases u objetos instanciados a partir de Clases.
clase Mamífero es Vertebrado { ...}clase Perro es Mamífero { ...}rol mascota { ...}papel perdido { ...} Guía de rol { ...}
Los roles se agregan a una clase u objeto con la does
palabra clave. Para mostrar la herencia de una clase, existe una palabra clave diferente is
. Las palabras clave reflejan los diferentes significados de las dos características: la composición de roles le da a una clase el comportamiento del rol, pero no indica que sea realmente lo mismo que el rol.
clase PerroGuía es Perro guía { ...} # La subclase compone el rolmi $perro = nuevo Perro ; $ perro hace guía ; # El objeto individual compone el rol
Aunque los roles son distintos de las clases, ambos son tipos, por lo que un rol puede aparecer en una declaración de variable donde normalmente se colocaría una clase. Por ejemplo, un rol de Ciego para un Humano podría incluir un atributo de tipo Guía; este atributo podría contener un perro guía, un caballo guía , un humano guía o incluso una máquina guía.
clase Humano { tiene Perro $perro ; # Puede contener cualquier tipo de Perro, ya sea que haga el ... # Papel de guía o no}rol Ciego { tiene Guía $guía ; # Puede contener cualquier objeto que cumpla la función de Guía, ... # ya sea un Perro u otra cosa}
La compatibilidad con expresiones regulares y procesamiento de cadenas de Perl siempre ha sido una de sus características definitorias. [41] Dado que las construcciones de coincidencia de patrones de Perl han excedido las capacidades de las expresiones del lenguaje regular durante algún tiempo, [42] la documentación de Raku se refiere exclusivamente a ellas como expresiones regulares , distanciando el término de la definición formal.
Raku proporciona un superconjunto de características de Perl con respecto a las expresiones regulares, combinándolas en un marco más amplio llamado " reglas " que proporciona capacidades de formalismos de análisis sensibles al contexto (como los predicados sintácticos de gramáticas de expresión de análisis y ANTLR ), además de actuar como cierre respecto de su alcance léxico . [43] Las reglas se introducen con la palabra clave que tiene un uso bastante similar a la definición de subrutina. Las reglas anónimas también se pueden introducir con la palabra clave (o ), o simplemente se pueden usar en línea como las expresiones regulares en Perl a través de los operadores (coincidente) o (sustituto).rule
regex
rx
m
s
En Apocalipsis 5 , Larry Wall enumeró 20 problemas con la "cultura de expresiones regulares actual". Entre ellos se encontraban que las expresiones regulares de Perl eran "demasiado compactas y 'bonitas'", "dependeban demasiado de muy pocos metacaracteres", "poco soporte para capturas con nombre", "poco soporte para gramáticas" y "pobre integración con elementos 'reales'". idioma". [44]
Algunas construcciones de Perl se han modificado en Raku y se han optimizado para diferentes claves sintácticas en los casos más comunes. Por ejemplo, los paréntesis (corchetes ) necesarios en las construcciones de flujo de control en Perl ahora son opcionales: [35]
si es verdadero () { para @array { ... }}
Además, el ,
operador (coma) ahora es un constructor de listas, por lo que ya no es necesario incluir paréntesis alrededor de las listas. El código
@matriz = 1 , 2 , 3 , 4 ;
ahora crea @array
una matriz con exactamente los elementos '1', '2', '3' y '4'.
Raku permite comparaciones para "encadenar". Es decir, se permite una secuencia de comparaciones como la siguiente:
if 20 <= $temperatura <= 25 { diga "¡La temperatura ambiente está entre 20 y 25!"}
Esto se trata como si cada comparación de izquierda a derecha se realizara por sí sola y el resultado se combina lógicamente mediante la and
operación.
Raku utiliza la técnica de evaluación diferida de listas que ha sido una característica de algunos lenguajes de programación funcionales como Haskell : [45]
@enteros = 0 .. Inf ; # números enteros de 0 a infinito
El código anterior no fallará al intentar asignar una lista de tamaño infinito a la matriz @integers
, ni se bloqueará indefinidamente al intentar expandir la lista si se busca un número limitado de espacios.
Esto simplifica muchas tareas comunes en Raku, incluidas operaciones de entrada/salida, transformaciones de listas y paso de parámetros.
Relacionada con la evaluación diferida está la construcción de listas diferidas usando gather
y take
, comportándose de manera similar a generadores en lenguajes como Icon o Python .
mis $cuadrados = reunión perezosa para 0 .. Inf { take $_ * $_ ; };
$squares
Será una lista infinita de números cuadrados, pero la evaluación perezosa de gather
garantiza que los elementos solo se calculen cuando se acceda a ellos.
Raku introduce el concepto de uniones : valores que son compuestos de otros valores. [45] En su forma más simple, las uniones se crean combinando un conjunto de valores con operadores de unión :
# Ejemplo para | ("cualquiera") Cruce: my $color = 'blanco' ; a menos que $color eq 'blanco' | 'negro' | 'gris' | 'gris' { die "No se admite la impresión en color\n" ;}# Ejemplo de unión & ("todos"): my $contraseña = 'secret!123' ; if $contraseña ~~ /<:alpha>/ & / <:digit> / & / <:punct> / { say "Su contraseña es razonablemente segura" ;}
|
indica un valor que es igual a sus argumentos de la izquierda o de la derecha. &
indica un valor que es igual a sus argumentos de la izquierda y de la derecha. Estos valores se pueden utilizar en cualquier código que utilice un valor normal. Las operaciones realizadas en un cruce actúan sobre todos los miembros del cruce por igual y se combinan según el operador del cruce. Entonces, ("apple"|"banana") ~ "s"
cedería "apples"|"bananas"
. En las comparaciones, las uniones devuelven un único resultado verdadero o falso para la comparación. " any
" los cruces devuelven verdadero si la comparación es verdadera para cualquiera de los elementos del cruce. " all
" los cruces devuelven verdadero si la comparación es verdadera para todos los elementos del cruce.
Las uniones también se pueden utilizar para aumentar de manera más rica el sistema de tipos introduciendo un estilo de programación genérica que se limita a uniones de tipos:
subconjunto Color de Cualquier lugar RGB_Color | Color_CMYK ; sub get_tint ( Color $color , Num $opacidad ) { ...}
En lenguajes de bajo nivel, el concepto de macros se ha convertido en sinónimo de sustitución textual del código fuente debido al uso generalizado del preprocesador C. Sin embargo, los lenguajes de alto nivel como Lisp son anteriores a C en el uso de macros que eran mucho más poderosas. [46] Es este concepto macro similar a Lisp el que Raku aprovechará. [34] El poder de este tipo de macro surge del hecho de que opera en el programa como una estructura de datos de alto nivel , en lugar de como un simple texto, y tiene todas las capacidades del lenguaje de programación a su disposición.
Una definición de macro Raku se verá como una subrutina o una definición de método, y puede operar en cadenas no analizadas, un AST que represente código previamente analizado o una combinación de ambos. Una definición macro se vería así: [47]
macro hola ( $qué ) { cuasi { decir "Hola {{{$qué}}} }" };}
En este ejemplo particular, la macro no es más compleja que una sustitución textual estilo C, pero debido a que el análisis del parámetro de la macro ocurre antes de que la macro opere en el código de llamada, los mensajes de diagnóstico serían mucho más informativos. Sin embargo, debido a que el cuerpo de una macro se ejecuta en tiempo de compilación cada vez que se utiliza, se pueden emplear muchas técnicas de optimización . Incluso es posible eliminar cálculos complejos de los programas resultantes realizando el trabajo en tiempo de compilación.
En Perl, los nombres de los identificadores pueden utilizar caracteres alfanuméricos ASCII y guiones bajos, también disponibles en otros idiomas. En Raku, los alfanuméricos pueden incluir la mayoría de los caracteres Unicode. Además, se pueden utilizar guiones y apóstrofos (con ciertas restricciones, como no ir seguidos de un dígito). El uso de guiones en lugar de guiones bajos para separar palabras en un nombre conduce a un estilo de denominación llamado " caso kebab ".
El programa hola mundo es un programa común que se utiliza para presentar un idioma. En Raku, hola mundo es:
diga 'Hola mundo' ;
—aunque hay más de una manera de hacerlo .
La función factorial en Raku, definida de diferentes maneras:
# Usando recursividad (con construcción `if\else`) subfact ( UInt $n --> UInt ) { if $n == 0 { 1 } else { $n * fact ( $n-1 ) } }# Usando recursividad (con `if` como modificador de declaración) sub fact ( UInt $n --> UInt ) { return 1 if $n == 0 ; devolver $n * hecho ( $n-1 );}# Usando recursividad ( con construcción `cuando`) subhecho ( UInt $n --> UInt ) { cuando $n == 0 { 1 } predeterminado { $n * hecho ( $n-1 ) } }# Usando el subhecho del operador ternario ( UInt $n --> UInt ) { $n == 0 ?? 1 !! $n * hecho ( $n-1 ) }# Usando envío múltiple multi fact ( 0 ) { 1 } multi fact ( UInt $n --> UInt ) { $n * fact ( $n - 1 )}# Usando el subhecho del metaoperador de reducción ( UInt $n --> UInt ) { [*] 1 .. $n}# Creando un operador factorial y usando el subfijo del metaoperador de reducción : <!>( UInt $n --> UInt ) { [*] 1 .. $n }# Usando el declarador `estado` para crear un subhecho factorial memorizado ( UInt $n --> UInt ) { estado %conocido = 0 => 1 ; devolver %conocido { $n } si %conocido { $n }: existe ; % conocido { $n } = $n * hecho ( $n-1 ); devolver % conocido { $n };}
Quicksort es un algoritmo de clasificación muy conocido. Una implementación funcional [a] que utiliza el paradigma de programación funcional se puede escribir de manera sucinta en Raku:
# La lista vacía se ordena según la lista vacía de clasificación rápida múltiple ([]) { () }# De lo contrario, extraiga el primer elemento como pivote... multi quicksort ([ $pivot , * @rest ]) { # Partition. mi @antes = @rest . grep (* < $pivote ); mi @después = @rest . grep (* >= $pivote ); # Ordenar las particiones. plano ( ordenación rápida ( @before ), $pivote , clasificación rápida ( @after ))}
log2(list_length)
iterando en la partición más grande before
y after
y recurriendo solo en la partición más pequeña.La Torre de Hanoi se utiliza a menudo para introducir la programación recursiva en informática. Esta implementación utiliza el mecanismo de envío múltiple y restricciones paramétricas de Raku:
multi sub hanoi ( 0 , $, $, $) { } # Sin disco, así que no hagas nada multi sub hanoi ( $n , $a = 'A' , $b = 'B' , $c = 'C' ) { # Comience con $n discos y tres clavijas A, B, Chanoi $n - 1 , $a , $c , $b ; # primero mueva los $n - 1 discos superiores de A a B, diga "Mover el disco $n de la clavija $a a la clavija $c" ; # luego mueve el último disco de A a Chanoi $ n - 1 , $b , $a , $c ; # por último mover $n - 1 discos de B a C}
En la historia de Raku hubo dos oleadas de escritura de libros. La primera ola siguió al anuncio inicial de Perl 6 en 2000. Esos libros reflejan el estado del diseño del lenguaje de esa época y contienen material en su mayor parte obsoleto. La segunda ola, que siguió al anuncio de la Versión 1.0 en 2015, incluye varios libros que ya han sido publicados y algunos otros que están en proceso de escritura.
Además, en 2009 se publicó un libro dedicado a una de las primeras máquinas virtuales Perl 6, Parrot.
"Perl" es una familia de lenguajes, "Raku" (antes conocido como "Perl 6") es parte de la familia, pero es un lenguaje separado que tiene su propio equipo de desarrollo. Su existencia no tiene ningún impacto significativo en el desarrollo continuo de "Perl".
{{cite web}}
: Mantenimiento CS1: nombres numéricos: lista de autores ( enlace )Las expresiones regulares de Perl "no lo son", es decir, no son "regulares" porque también se admiten las referencias inversas per sed y grep, lo que hace que el lenguaje ya no sea estrictamente regular.