Translate

Mostrando las entradas con la etiqueta Gleam. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Gleam. Mostrar todas las entradas

viernes, 18 de octubre de 2024

Respaldos externos de Gleam


import gleam/io


@external(erlang, "lists", "reverse")

pub fn reverse_list(items: List(e)) -> List(e) {

  tail_recursive_reverse(items, [])

}


fn tail_recursive_reverse(items: List(e), reversed: List(e)) -> List(e) {

  case items {

    [] -> reversed

    [first, ..rest] -> tail_recursive_reverse(rest, [first, ..reversed])

  }

}


pub fn main() {

  io.debug(reverse_list([1, 2, 3, 4, 5]))

  io.debug(reverse_list(["a", "b", "c", "d", "e"]))

}

Y el resultado es: 

[5, 4, 3, 2, 1]
["e", "d", "c", "b", "a"]

Es posible que una función tenga tanto una implementación de Gleam como una implementación externa. Si existe una implementación externa para el objetivo compilado actualmente, se utilizará; de lo contrario, se utilizará la implementación de Gleam.

Esto puede resultar útil si tiene una función que se puede implementar en Gleam, pero hay una implementación optimizada que se puede utilizar para un objetivo. Por ejemplo, la máquina virtual Erlang tiene una función de inversión de lista incorporada que se implementa en código nativo. El código aquí utiliza esta implementación cuando se ejecuta en Erlang, ya que está disponible en ese momento.

lunes, 14 de octubre de 2024

Implementaciones externas para varios destinos


import gleam/io


pub type DateTime


@external(erlang, "calendar", "local_time")

@external(javascript, "./my_package_ffi.mjs", "now")

pub fn now() -> DateTime


pub fn main() {

  io.debug(now())

}


Se pueden especificar varias implementaciones externas para la misma función, lo que permite que la función funcione tanto en Erlang como en JavaScript.

Si una función no tiene una implementación para el destino compilado actualmente, el compilador devolverá un error.

Se debe implementar funciones para todos los destinos, pero esto no siempre es posible debido a incompatibilidades en cómo funcionan la E/S y la concurrencia en Erlang y JavaScript. Con Erlang, la E/S simultánea se maneja de forma transparente por el entorno de ejecución, mientras que en JavaScript la E/S simultánea requiere el uso de promesas o devoluciones de llamadas. Si su código utiliza el estilo Erlang, normalmente no es posible implementarlo en JavaScript, mientras que si se utilizan devoluciones de llamadas, no será compatible con la mayoría del código Gleam y Erlang, ya que obliga a cualquier código que llame a la función a utilizar también devoluciones de llamadas.

Las bibliotecas que utilizan E/S simultáneas normalmente tendrán que decidir si admiten Erlang o JavaScript y documentar esto en su README.

miércoles, 9 de octubre de 2024

Externals en Gleam


import gleam/io


// A type with no Gleam constructors

pub type DateTime


// An external function that creates an instance of the type

@external(javascript, "./my_package_ffi.mjs", "now")

pub fn now() -> DateTime


// The `now` function in `./my_package_ffi.mjs` looks like this:

// export function now() {

//   return new Date();

// }


pub fn main() {

  io.debug(now())

}


El resultado es : 

//js(Date("2024-10-05T17:29:39.958Z"))


A veces, en nuestros proyectos, queremos usar código escrito en otros lenguajes, más comúnmente Erlang y JavaScript, dependiendo del entorno de ejecución que se esté usando. Las funciones externas y los tipos externos de Gleam nos permiten importar y usar este código que no es de Gleam.

Un tipo externo es aquel que no tiene constructores. Gleam no sabe qué forma tiene ni cómo crear uno, solo sabe que existe.

Una función externa es aquella que tiene el atributo @external, que indica al compilador que use la función del módulo especificado como implementación, en lugar del código de Gleam.

El compilador no puede determinar los tipos de funciones escritas en otros lenguajes, por lo que cuando se proporciona el atributo externo, se deben proporcionar anotaciones de tipo. Gleam confía en que el tipo proporcionado sea correcto, por lo que una anotación de tipo inexacta puede generar un comportamiento inesperado y fallas en el entorno de ejecución. ¡Ten cuidado!

Las funciones externas son útiles, pero se deben usar con moderación. Es preferible escribir código de Gleam cuando sea posible.

sábado, 5 de octubre de 2024

Let assert de Gleam


import gleam/io


pub fn main() {

  let a = unsafely_get_first_element([123])

  io.debug(a)


  let b = unsafely_get_first_element([])

  io.debug(b)

}


pub fn unsafely_get_first_element(items: List(a)) -> a {

  // This will panic if the list is empty.

  // A regular `let` would not permit this partial pattern

  let assert [first, ..] = items

  first

}

El resultado: 

123

Error: Pattern match failed, no pattern matched the value.


let assert es la última forma de bloquear intencionalmente su programa Gleam. Es similar a la palabra clave panic en el sentido de que bloquea cuando el programa ha llegado a un punto al que nunca debería llegar.

let assert es similar a let en el sentido de que es una forma de asignar valores a las variables, pero es diferente en el sentido de que el patrón puede ser parcial. El patrón no necesita coincidir con todos los valores posibles del tipo que se está asignando.

Al igual que panic, esta función debe usarse con moderación y probablemente no debe usarse en absoluto en las bibliotecas.

jueves, 3 de octubre de 2024

Panic en Gleam


import gleam/io


pub fn main() {

  print_score(10)

  print_score(100_000)

  print_score(-1)

}


pub fn print_score(score: Int) {

  case score {

    score if score > 1000 -> io.println("High score!")

    score if score > 0 -> io.println("Still working on it")

    _ -> panic as "Scores should never be negative!"

  }

}


La palabra clave panic es similar a la palabra clave todo, pero se utiliza para bloquear el programa cuando este ha llegado a un punto al que nunca debería llegar.

¡Esta palabra clave casi nunca debería utilizarse! Puede ser útil en prototipos y scripts iniciales, pero su uso en una biblioteca o aplicación de producción es una señal de que el diseño podría mejorarse. Con tipos bien diseñados, el sistema de tipos se puede utilizar normalmente para hacer que estos estados no válidos sean irrepresentables.

viernes, 27 de septiembre de 2024

ToDo de Gleam


pub fn main() {

  todo as "I haven't written this code yet!"

}


pub fn todo_without_reason() {

  todo

}

warning: Todo found

  ┌─ /src/main.gleam:6:3

  │

6 │   todo

  │   ^^^^ This code is incomplete


This code will crash if it is run. Be sure to finish it before

running your program.


La palabra clave todo se utiliza para especificar que algún código aún no se ha implementado.

En el todo podemos especificar una descripción, aunque es posible que desee incluir el mensaje si tiene más de un bloque de código marcado como todo en su código.

Cuando se utiliza, el compilador de Gleam imprimirá una advertencia para recordarle que el código no está terminado y, si se ejecuta el código, el programa se bloqueará con el mensaje indicado.

domingo, 22 de septiembre de 2024

Use de Gleam parte 2


La expresión use es una sintaxis simplificada para una llamada a una función normal y una función anónima.


Este código:

use a, b <- my_function

next(a)

next(b)


Es igual que este código:


my_function(fn(a, b) {

  next(a)

  next(b)

})


Para garantizar que la expresión use funcione y sea lo más comprensible posible, lo ideal es que el lado derecho sea una llamada de función en lugar de una secuencia de comandos u otra expresión, que suele ser más difícil de leer.

use es una expresión como todo lo demás en Gleam, por lo que se puede colocar dentro de bloques.


domingo, 15 de septiembre de 2024

Use de Gleam


import gleam/io

import gleam/result


pub fn main() {

  let _ = io.debug(without_use())

  let _ = io.debug(with_use())

}


pub fn without_use() {

  result.try(get_username(), fn(username) {

    result.try(get_password(), fn(password) {

      result.map(log_in(username, password), fn(greeting) {

        greeting <> ", " <> username

      })

    })

  })

}


pub fn with_use() {

  use username <- result.try(get_username())

  use password <- result.try(get_password())

  use greeting <- result.map(log_in(username, password))

  greeting <> ", " <> username

}


// Here are some pretend functions for this example:


fn get_username() {

  Ok("alice")

}


fn get_password() {

  Ok("hunter2")

}


fn log_in(_username: String, _password: String) {

  Ok("Welcome")

}


El resultado es : 

Ok("Welcome, alice")
Ok("Welcome, alice")

Gleam carece de excepciones, macros, clases de tipos, retornos anticipados y una variedad de otras características, en lugar de eso, se centra en funciones de primera clase y coincidencia de patrones. Esto hace que el código de Gleam sea más fácil de entender, pero a veces puede resultar en una sangría excesiva.

La expresión use de Gleam ayuda en este caso al permitirnos escribir código que utiliza devoluciones de llamadas en un estilo sin sangría, como se muestra en el código anterior. 

La función de orden superior que se llama va del lado derecho del operador <-. Debe tomar una función de devolución de llamada como argumento final.

Los nombres de los argumentos para la función de devolución de llamada van del lado izquierdo del operador <-. La función puede tomar cualquier cantidad de argumentos, incluido cero.

Todo el código restante en el bloque {} que lo encierra se convierte en el cuerpo de la función de devolución de llamada.

Esta es una característica muy útil y capaz, pero la aplicación excesiva de use puede resultar en un código poco claro, especialmente para principiantes. ¡Por lo general, la sintaxis de llamada de función regular da como resultado un código más accesible!

viernes, 13 de septiembre de 2024

Tipos opacos de Gleam


import gleam/io


pub fn main() {

  let positive = new(1)

  let zero = new(0)

  let negative = new(-1)


  io.debug(to_int(positive))

  io.debug(to_int(zero))

  io.debug(to_int(negative))

}


pub opaque type PositiveInt {

  PositiveInt(inner: Int)

}


pub fn new(i: Int) -> PositiveInt {

  case i >= 0 {

    True -> PositiveInt(i)

    False -> PositiveInt(0)

  }

}


pub fn to_int(i: PositiveInt) -> Int {

  i.inner

}


El Resultado : 

1
0
0

Los tipos opacos son tipos en los que el tipo personalizado es público y puede ser utilizado por otros módulos, pero los constructores del tipo son privados y solo pueden ser utilizados por el módulo que define el tipo. Esto evita que otros módulos construyan o realicen una coincidencia de patrones con el tipo.

Esto es útil para crear tipos con constructores inteligentes. Un constructor inteligente es una función que construye un valor de un tipo, pero es más restrictivo que si el programador utilizara uno de los constructores del tipo directamente. Esto puede ser útil para garantizar que el tipo se utilice correctamente.

Por ejemplo, este tipo personalizado PositiveInt es opaco. Si otros módulos quieren construir uno, deben utilizar la nueva función, que garantiza que el entero sea positivo.

viernes, 6 de septiembre de 2024

Módulo de opciones



import gleam/io

import gleam/option.{type Option, None, Some}


pub type Person {

  Person(name: String, pet: Option(String))

}


pub fn main() {

  let person_with_pet = Person("Al", Some("Nubi"))

  let person_without_pet = Person("Maria", None)


  io.debug(person_with_pet)

  io.debug(person_without_pet)

}


Person(name: "Al", pet: Some("Nubi"))
Person(name: "Maria", pet: None)


Los valores en Gleam no son nulos, por lo que el módulo de la biblioteca estándar gleam/option define el tipo Option de Gleam, que se puede utilizar para representar un valor que está presente o ausente.

El tipo option es muy similar al tipo result, pero no tiene un valor de error. Algunos lenguajes tienen funciones que devuelven una opción cuando no hay detalles de error adicionales que proporcionar, pero Gleam siempre utiliza result. Esto hace que todas las funciones falibles sean consistentes y elimina cualquier código repetitivo que se requeriría al mezclar funciones que utilizan cada tipo.

Módulo Dict de Gleam

 


import gleam/dict

import gleam/io


pub fn main() {

  let scores = dict.from_list([#("Lucy", 13), #("Drew", 15)])

  io.debug(scores)


  let scores =

    scores

    |> dict.insert("Bushra", 16)

    |> dict.insert("Darius", 14)

    |> dict.delete("Drew")

  io.debug(scores)

}

El resultado : 

dict.from_list([#("Drew", 15), #("Lucy", 13)])
dict.from_list([#("Darius", 14), #("Bushra", 16), #("Lucy", 13)])


El módulo estándar gleam/dict define el tipo Dict de Gleam y las funciones para trabajar con él. Un dict es una colección de claves y valores que otros lenguajes pueden llamar un mapa hash o una tabla.

new y from_list se pueden utilizar para crear nuevos dicts.

insert y delete se utilizan para agregar y eliminar elementos de un dict.

Al igual que las listas, los dicts son inmutables. Insertar o eliminar un elemento de un dict devolverá un nuevo dict con el elemento agregado o eliminado.

Los dicts no están ordenados. Si parece que los elementos de un dict están en un orden determinado, es incidental y no se debe confiar en ello. Cualquier orden puede cambiar sin previo aviso en futuras versiones o en diferentes entornos de ejecución.

domingo, 1 de septiembre de 2024

El Módulo Result de Gleam



import gleam/int

import gleam/io

import gleam/result


pub fn main() {

  io.println("=== map ===")

  let _ = io.debug(result.map(Ok(1), fn(x) { x * 2 }))

  let _ = io.debug(result.map(Error(1), fn(x) { x * 2 }))


  io.println("=== try ===")

  let _ = io.debug(result.try(Ok("1"), int.parse))

  let _ = io.debug(result.try(Ok("no"), int.parse))

  let _ = io.debug(result.try(Error(Nil), int.parse))


  io.println("=== unwrap ===")

  io.debug(result.unwrap(Ok("1234"), "default"))

  io.debug(result.unwrap(Error(Nil), "default"))


  io.println("=== pipeline ===")

  int.parse("-1234")

  |> result.map(int.absolute_value)

  |> result.try(int.remainder(_, 42))

  |> io.debug

}

=== map ===
Ok(2)
Error(1)
=== try ===
Ok(1)
Error(Nil)
Error(Nil)
=== unwrap ===
"1234"
"default"
=== pipeline ===
Ok(16)

El módulo de la biblioteca estándar gleam/result contiene funciones para trabajar con resultados. Los programas Gleam harán un uso intensivo de este módulo para evitar expresiones de caso anidadas excesivas al llamar a múltiples funciones que pueden fallar.

  • map actualiza un valor contenido dentro de Ok de un resultado llamando a una función dada sobre él. Si el resultado es un error, no se llama a la función.
  • try ejecuta una función que devuelve un resultado sobre el valor contenido dentro de Ok de un resultado. Si el resultado es un error, no se llama a la función. Esto es útil para encadenar varias llamadas de función que pueden fallar, una tras otra, deteniéndose en el primer error.
  • unwrap extrae el valor de éxito de un resultado o devuelve un valor predeterminado si el resultado es un error.

Las funciones de resultado se utilizan a menudo con canalizaciones para encadenar varias llamadas a funciones que devuelven resultados.

domingo, 25 de agosto de 2024

Módulo List de Gleam


import gleam/io

import gleam/list


pub fn main() {

  let ints = [0, 1, 2, 3, 4, 5]


  io.println("=== map ===")

  io.debug(list.map(ints, fn(x) { x * 2 }))


  io.println("=== filter ===")

  io.debug(list.filter(ints, fn(x) { x % 2 == 0 }))


  io.println("=== fold ===")

  io.debug(list.fold(ints, 0, fn(count, e) { count + e }))


  io.println("=== find ===")

  let _ = io.debug(list.find(ints, fn(x) { x > 3 }))

  io.debug(list.find(ints, fn(x) { x > 13 }))

}

=== map ===
[0, 2, 4, 6, 8, 10]
=== filter ===
[0, 2, 4]
=== fold ===
15
=== find ===
Ok(4)
Error(Nil)

El módulo de la biblioteca estándar gleam/list contiene funciones para trabajar con listas. Es probable que un programa Gleam haga un uso intensivo de este módulo, ya que las distintas funciones sirven como diferentes tipos de bucles sobre listas.

  • map crea una nueva lista ejecutando una función en cada elemento de la lista.
  • filter crea una nueva lista que contiene solo los elementos para los que una función devuelve verdadero.
  • fold combina todos los elementos de una lista en un único valor ejecutando una función de izquierda a derecha en cada elemento, pasando el resultado de la llamada anterior a la siguiente llamada.
  • find devuelve el primer elemento de una lista para el que una función devuelve verdadero.

Vale la pena familiarizarse con todas las funciones de este módulo al escribir código Gleam, ¡las usará mucho!

viernes, 9 de agosto de 2024

Paquete de la biblioteca estándar de Gleam


import gleam/io


pub fn main() {

  io.println("Hello, Joe!")

  io.println("Hello, Mike!")

}


La biblioteca estándar de Gleam es un paquete de Gleam normal que se ha publicado en el repositorio de paquetes Hex. Puede optar por no utilizarla si lo desea, aunque casi todos los proyectos de Gleam dependen de ella.

Todos los módulos importados que usamos, como gleam/io , son de la biblioteca estándar.

Toda la documentación de la biblioteca estándar está disponible en HexDocs. 

martes, 6 de agosto de 2024

Matrices de bits en Gleam


 import gleam/io


pub fn main() {

  // 8 bit int. In binary: 00000011

  io.debug(<<3>>)

  io.debug(<<3>> == <<3:size(8)>>)


  // 16 bit int. In binary: 0001100000000011

  io.debug(<<6147:size(16)>>)


  // A bit array of UTF8 data

  io.debug(<<"Hello, Joe!":utf8>>)


  // Concatenation

  let first = <<4>>

  let second = <<2>>

  io.debug(<<first:bits, second:bits>>)

}


Las matrices de bits representan una secuencia de 1 y 0, y son una sintaxis conveniente para construir y manipular datos binarios.

A cada segmento de una matriz de bits se le pueden dar opciones para especificar la representación utilizada para ese segmento.

  • size: el tamaño del segmento en bits.
  • unit: la cantidad de bits de los cuales el valor de tamaño es un múltiplo.
  • bits: una matriz de bits anidada de cualquier tamaño.
  • bytes: una matriz de bits anidada alineada con bytes.
  • float: un número de punto flotante de 64 bits.
  • int: un int con un tamaño predeterminado de 8 bits.
  • big: big endian.
  • little: little endian.
  • native: el orden de bits del procesador.
  • utf8: texto codificado en utf8.
  • utf16: texto codificado en utf16.
  • utf32: texto codificado en utf32.
  • utf8_codepoint: un punto de código utf8.
  • utf16_codepoint: un punto de código utf16.
  • utf32_codepoint: un punto de código utf32.
  • signed: un número con signo.
  • unsigned: un número sin signo.

Se pueden dar múltiples opciones a un segmento separándolas con un guion: x:unsigned-little-size(2).

Las matrices de bits tienen un soporte limitado al compilar en JavaScript, no se pueden usar todas las opciones. En el futuro se implementará un soporte completo para matrices de bits.

lunes, 5 de agosto de 2024

Results de Gleam


import gleam/int

import gleam/io


pub fn main() {

  let _ = io.debug(buy_pastry(10))

  let _ = io.debug(buy_pastry(8))

  let _ = io.debug(buy_pastry(5))

  let _ = io.debug(buy_pastry(3))

}


pub type PurchaseError {

  NotEnoughMoney(required: Int)

  NotLuckyEnough

}


fn buy_pastry(money: Int) -> Result(Int, PurchaseError) {

  case money >= 5 {

    True ->

      case int.random(4) == 0 {

        True -> Error(NotLuckyEnough)

        False -> Ok(money - 5)

      }

    False -> Error(NotEnoughMoney(required: 5))

  }

}


Gleam no utiliza excepciones, sino que los cálculos que pueden tener éxito o fallar devuelven un valor del tipo Result(value, error). Tiene dos variantes:

  • Ok, que contiene el valor de retorno de un cálculo exitoso.
  • Error, que contiene el motivo de un cálculo fallido.

El tipo es genérico con dos parámetros de tipo, uno para el valor de éxito y otro para el error. Con estos, el resultado puede contener cualquier tipo de éxito o fracaso.

Comúnmente, un programa o biblioteca de Gleam definirá un tipo personalizado con una variante para cada posible problema que pueda surgir, junto con cualquier información de error que pueda ser útil para el programador.

Esto es ventajoso sobre las excepciones, ya que puede ver inmediatamente qué errores puede devolver una función, si los hay, y el compilador se asegurará de que se gestionen. ¡No hay sorpresas desagradables con excepciones inesperadas!

Un valor de resultado se puede gestionar mediante la coincidencia de patrones con una expresión de case, pero dada la frecuencia con la que se devuelven los resultados, esto puede volverse difícil de manejar. El código Gleam comúnmente utiliza el módulo de biblioteca estándar gleam/result y utiliza expresiones cuando trabaja con resultados.


lunes, 29 de julio de 2024

Nil de Gleam


import gleam/io


pub fn main() {

  let x = Nil

  io.debug(x)

  let result = io.println("Hello!")

  io.debug(result == Nil)

}


Nil es el tipo de unidad de Gleam. Es un valor que devuelven las funciones que no tienen nada más que devolver, ya que todas las funciones deben devolver algo.

Nil no es un valor válido de ningún otro tipo. Por lo tanto, los valores en Gleam no son nulos. Si el tipo de un valor es Nil, entonces es el valor Nil. Si es otro tipo, entonces el valor no es Nil.


martes, 23 de julio de 2024

Tipos personalizados genéricos en Gleam

 


pub type Option(inner) {

  Some(inner)

  None

}


// An option of string

pub const name: Option(String) = Some("Annah")


// An option of int

pub const level: Option(Int) = Some(10) 


Al igual que las funciones, los tipos personalizados también pueden ser genéricos y tomar los tipos contenidos como parámetros.

Aquí se define un tipo Option genérico, que se utiliza para representar un valor que está presente o ausente. ¡Este tipo es bastante útil! El módulo gleam/option lo define para que puedas usarlo en tus proyectos Gleam.

martes, 16 de julio de 2024

Actualizaciones de registros en Gleam


import gleam/io


pub type SchoolPerson {

  Teacher(name: String, subject: String, floor: Int, room: Int)

}


pub fn main() {

  let teacher1 = Teacher(name: "Mr Dodd", subject: "ICT", floor: 2, room: 2)


  // Use the update syntax

  let teacher2 = Teacher(..teacher1, subject: "PE", room: 6)


  io.debug(teacher1)

  io.debug(teacher2)

}


La sintaxis de actualización de registros se puede utilizar para crear un nuevo registro a partir de uno existente del mismo tipo, pero con algunos campos modificados.

Gleam es un lenguaje inmutable, por lo que el uso de la sintaxis de actualización de registros no muta ni cambia el registro original.

lunes, 15 de julio de 2024

Coincidencia de patrones de registro en Gleam


 import gleam/io


pub type Fish {

  Starfish(name: String, favourite_color: String)

  Jellyfish(name: String, jiggly: Bool)

}


pub fn main() {

  let lucy = Starfish("Lucy", "Pink")


  case lucy {

    Starfish(_, favourite_color) -> io.debug(favourite_color)

    Jellyfish(name, ..) -> io.debug(name)

  }

}


Es posible establecer una coincidencia de patrones en un registro, lo que permite extraer múltiples valores de campo de un registro en variables distintas, similar a la coincidencia en una tupla o una lista.

La palabra clave let solo puede coincidir con tipos personalizados de variante única. Para tipos con más variantes se debe utilizar una expresión de caso.

Es posible utilizar el guión bajo _ o la sintaxis extendida... para descartar campos que no son obligatorios.