Aiken: un impulso a Cardano - Parte I
Para crear un ecosistema rico en torno a una tecnología se requiere, en primer lugar —aunque parezca obvio—, de personas que la usen y, en segundo, personas que creen herramientas sobre ésta. Esto se vuelve más evidente si la tecnología de la que hablamos es una criptomoneda, pues su objetivo último se basa en su robustez y confianza. Es, evidente, porque se trabaja con transacciones de dinero. Para lograrlo, necesita de programadores que tengan interés en producir aplicaciones sobre su sistema para así ganar usuarios.
Cardano es una criptomoneda que utiliza una blockchain basada en la prueba de participación, considerada una alternativa a otras como Ethereum y Bitcoin y que emplea el algoritmo de prueba de trabajo. Pero, acaso, una de sus principales banderas de Cardano, que lo diferencia de su competencia, es su fiabilidad. Esto se traduce en un código más seguro, algo que precisa de un lenguaje de programación con un robusto sistema de tipos. Haskell fue el elegido de Cardano.
Por un lado, esta selección se agradece, pues evita cometer previsibles errores en los contratos inteligentes, y por otro, ha sido criticada porque es un lenguaje con una curva empinada de aprendizaje. Haskell no es fácil y esto es una barrera de entrada a más desarrollares se interesen por Cardano. Lo mismo pasa en otro tipo de industria: las empresas que usan Haskell son pocas si se comparan con las que usan Java, Python o incluso C++.
Este artículo se organiza de la siguiente forma: primero, comenzaré con una introducción de los lenguajes de programación presentes en Cardano. Luego, hablaré de Aiken, un nuevo lenguaje que da un nuevo impulso a Cardano, comenzando con la instalación. Posteriormente, mostraré sus características a través de simples ejemplos. Concluiré con algunas consideraciones antes de introducirse a Aiken.
Mi intención —y espero cumplirla— es que este sea la primera parte de una serie de artículos dedicados a Aiken.
Haskell y Plutus
El corazón de Cardano está escrito en Haskell, pero el lenguaje que utiliza para crear aplicaciones e interactuar con su blockchain se llama Plutus, creado por IOHK. Este es un DSL (Domain Specific Language) basado en Haskell y diseñado específicamente para entender el contexto de Cardano.
O sea, para trabajar con Cardano no empleas específicamente Haskell sino Plutus. Aunque, claro, para mantener una mayor compatibilidad con su implementación, Plutus es similar a Haskell. Por tanto, es prerrequisito un conocimiento en Haskell y, sobre todo, en algún lenguaje puro de programación funcional.
La arquitectura de Cardano cuenta con una máquina virtual que hace posible ejecutar otras herramientas sobre éste como, por ejemplo, otro lenguaje de programación. Y, como mencioné antes, Haskell no se ejecuta directamente en la blockchain de Cardano, sino que en cada nodo hay un intérprete de Plutus.
Dicho intérprete transforma su código en Plutus Core, que consta de dos tipos: Typed Plutus Core (TPC) y Untyped Plutus Core (UPC), lenguajes de bajo nivel basados en System F y Cálculo Lambda polimórfico (estas son construcciones teóricas, solo las menciono para los curiosos en la teoría de lenguaje de programación).
Por ejemplo, el código de UPC es el que al final se ejecuta en Cardano (véase la imagen inferior). Puede pensarse, de manera análoga, a lo que ocurre en Java, cuando su código se compila con su máquina virtual JVM y produce bytecodes.
Por tanto, nuestro siguiente invitado (Aiken) añade un nuevo intérprete, una alternativa a Plutus, mediante este nuevo lenguaje, encargado de generar el UPC.
Aiken: una alternativa para facilitar el camino hacia Cardano
Aiken fue originado por la Cardano Foundation y presentado en abril de 2023. Además, se encuentra bajo la licencia Apache 2.0. Un breve inciso: el nombre proviene de Howard H. Aiken, un físico americano y pionero en la ciencia de la computación.
Al igual que Plutus, Aiken es un DSL y fue diseñado para contratos inteligentes en Cardano, pero a diferencia de Plutus, Aiken cuenta con capacidades que lo hacen más simple de usar. Y fue inspirado en lenguajes como Rust, Gleam o Elm; todos ellos comparten un sistema de tipos seguros que implica menor posibilidad de errores en tiempo de ejecución. Cuestión que no todos los lenguajes proporcionan, a saber: Python.
Adicionalmente, cuando un lenguaje tiene un sistema de tipo robusto tiende a ser más complejo de programar que uno con tipado flexible, pues el compilador te pones más «barreras» para evitar que cometas errores. En cambio, en otro lenguaje, como JavaScript, esas barreras no existen, aumentando problemas en ejecución (aunque ganan en velocidad de desarrollo).
En la presentación de Aiken se mencionó lo siguiente:
Se presenta [Aiken] en una sintaxis fácil de aprender, diseñada para integrarse sin esfuerzo con otras herramientas y lenguajes, además de incluir diversas funciones de última generación que satisfacen las expectativas actuales de los desarrolladores.
Pero como mencioné en mi artículo anterior sobre el lenguaje de programación Mojo, estas son afirmaciones esperables que todos los creadores de tecnología repiten, ya sea para producir impacto en la comunidad o para ganar usuarios. En pocas palabras, hay que ser precavidos.
Antes de mostrar sus características y comprobar si estas palabras tienen sustento y se acercan a la realidad, pasamos a la instalación.
Instalación
Aiken está escrito en Rust, por lo que verás ficheros .rs
(extensión de ficheros Rust).
Linux y MacOS
Puedes abrir la terminal y escribir:
curl -sSfL https://install.aiken-lang.org | bash
Después, podrías necesitar reiniciar tu terminal para ejecutar:
aikup
En caso de que tu terminal no reconozca el programa aikup
, reiníciala.
MS Windows
Para el caso de Windows, puedes instalar primero cargo (gestor de paquetes de Rust) y entonces:
cargo install aiken
Aiken Playground
Puedes usar Aiken Playground en caso de que quieras escribir código sin necesidad de instalarlo en tu computador.
Características
Las características de Aiken se dividen en dos grupos: internas y externas.
- Las internas son propias del lenguaje: tipado estático fuerte, todo es una expresión (como los lenguajes del dialecto Lisp), tipos genéricos, tipos personalizados, cuenta con módulos y gestor de paquetes, entre otras cuestiones.
- Las externas corresponden a su entorno de desarrollo. Tiene integración con Visual Code y Vim/NeoVim, una buena documentación y los mensajes de errores son amenos.
Creando un nuevo proyecto
Los programas en Aiken tiene la extensión .ak
y se comienza un nuevo proyecto con:
Se crean los siguientes ficheros en el directorio actual:
.
├── README.md
├── aiken.toml
├── lib
│ └── foo
└── validators
Con el comando aiken build
compilas el proyecto, mientras que aiken check
permite revisar si el programa cumple con el correcto uso de tipos.
Nota: en el fichero .toml puede modificar la metadata del proyecto y agregar las dependencias que necesita su proyecto (este fichero es usado por lenguajes modernos como Julia y Rust). Más información en este enlace.
A continuación presentaré dos características del lenguaje.
(1) Sistemas de tipo robusto
Al mirar la sintaxis de Aiken podemos percatarnos de una cierta similitud con Rust y Haskell. Por ejemplo, consideré el siguiente código que evalúa si un número es par o no.
fn check_is_even(number: Int) -> Bool {
(number % 2 == 0)
}
test is_even_0() {
check_is_even(2) == True
}
El tipado fuerte se puede derivar del hecho que la función check_is_even
solo acepta un argumento de tipo Int
.
Ten en cuenta que la funciones en Aiken comienzan con fn
(al igual que Rust) y cuando se usa la palabra test
significa que será una función de prueba la que se ejecutará automáticamente.
Además, no es necesaria la palabra reservada return
para indicar que valor debe ser devuelto. Más bien asume que la última expresión evaluada es la que se devuelve (similar a como funciona Scala). En este caso, la última expresión evaluada es (number % 2 == 0)
.
Un caso de error: si le damos un decimal como argumento check_is_even(2.123)
, devolvería el siguiente mensaje:
I found an unexpected token '"123"'.
Esto evidencia que todavía los mensajes de errores en Aiken son inmaduros, ya que el error que devuelve no da la suficiente información como para captar, rápidamente, por qué se produjo el error. En cambio, un mejor mensaje de error podría advertir lo siguiente: "Estas intentando pasar un valor decimal en lugar de un Int"
. Esto, de seguro, se subsanará en las próximas versiones de Aiken.
También en Aiken es posible definir registro de tipos personalizados:
type Person {
Person { name : String, age: Int}
}
fn is_member(p : Person) -> Bool {
when p.age is {
x if (x > 30) -> True
_ -> False
}
}
test create_person() {
let p = Person { name: @"Aurora", age: 34 }
is_member(p) == True
}
Esto sería similar a definir una struct en C o una clase en Python. Una forma de encapsular registro bajo un tipo. Esto nos recuerda a Haskell (véase aquí).
Este programa crea un tipo Person
, que tiene un nombre (name
) y edad (age
). Después, verifica si esa persona es miembro. Para ello, es necesario que sea mayor de 30 años.
La función is_member
aplica pattern matching de forma análoga a lenguajes como Rust y Haskell. Si el atributo age
del tipo Person
es mayor a 30 devolverá True, si no, False. Nótese que la variable x
dentro del bloque when
es un alias de p.age
. Y el símbolo _
(conocido como wildcard) indica que acepta cualquier tipo, o sea, si no es mayor a 30 siempre devolverá False
.
(2) Contenedores
Los contenedores son estructuras de datos para almacenar valores con un tipo de dato respectivo.
Ejemplo: Quicksort, un algoritmo para ordenar listas de valores numéricos que divide la lista en dos partes (menores a un número y mayores a ese mismo número) hasta lograr que se ordene de menor a mayor. Empleando la estructura list
que viene con la biblioteca estándar de Aiken, podemos declarar una lista de valores enteros numéricos List<Int>
.
use aiken/list
fn quicksort(xs: List<Int>) -> List<Int> {
when xs is {
[] ->
[]
[p, ..tail] -> {
let before = tail |> list.filter(fn(x) { x < p }) |> quicksort
let after = tail |> list.filter(fn(x) { x >= p }) |> quicksort
list.concat(before, [p, ..after])
}
}
}
test quicksort_0() {
quicksort([]) == []
}
test quicksort_1() {
quicksort([3, 2, 1, 4]) == [1, 2, 3, 4]
}
test quicksort_2() {
quicksort([1, 2, 3, 4, 0, -4, 10]) == [-4, 0, 1, 2, 3, 4, 10]
}
El símbolo |> se conoce como operador de flujo o pipeline, pues opera de izquierda a derecha. Tomemos, por ejemplo, la línea siguiente:
tail |> list.filter(fn(x) { x < p }) |> quicksort
Aquí se aplica la lista tail
a la función filter
(izquierda a derecha), luego el resultado de la función filter
se pasa como argumento a quicksort
(de nuevo, de izquierda de derecha). Esta forma de invocar es similar a cómo funciona el operador |
en Unix. Esto es un mecanismo para ejecutar un flujo de operaciones encadenadas.
Después, si ejecutas el código de Quicksort, podrás verificar que las tres funciones test
pasan las pruebas.
Conclusión
Dejo algunas recomendaciones:
- Ve detrás de los fundamentos. Antes de comenzar con Aiken, aprende sobre Blockchain, Cardano y Smart Contracts (puedes encontrar artículos en esta comunidad) pues, al no ser un lenguaje de programación para todo tipo de problema, está diseñado para el contexto de criptomonedas y es primordial tener una base previa.
- Navega por su documentación. En el sitio web de Aiken encontrarás varios ejemplos para profundizar en el lenguaje. Aprovéchala, pues la documentación está bien concebida.
También es importante mencionar que, como todo lenguaje nuevo, seguramente evolucionará en el futuro, así que es buena idea revisar su repositorio, cada cierto tiempo, para estar al tanto de los últimos cambios.
En la parte II veremos cómo se crea un contrato inteligente en Aiken.
Referencias
Para una introducción general a Aiken podrías consultar:
Para entender aspectos teóricos de Plutus Core, remito a este excelente artículo:
Para una introducción a la programación funcional usando lenguajes de tipado fuerte como Haskell y Agda, recomiendo mi artículo.
Saludos
Listopro Community da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.