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

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.

sábado, 6 de julio de 2024

Registros en Gleam



import gleam/io


pub type SchoolPerson {

  Teacher(name: String, subject: String)

  Student(String)

}


pub fn main() {

  let teacher1 = Teacher("Mr Schofield", "Physics")

  let teacher2 = Teacher(name: "Miss Percy", subject: "Physics")

  let student1 = Student("Koushiar")

  let student2 = Student("Naomi")

  let student3 = Student("Shaheer")


  let school = [teacher1, teacher2, student1, student2, student3]

  io.debug(school)

}

Una variante de un tipo personalizado puede contener otros datos. En este caso la variante se llama registro.

A los campos de un registro se les pueden asignar etiquetas y, al igual que las etiquetas de argumentos de funciones, se pueden usar opcionalmente al llamar al constructor del registro. Normalmente se utilizarán etiquetas para las variantes que las definen.

Es común tener un tipo personalizado con una variante que contiene datos; este es el equivalente de Gleam de una estructura u objeto en otros lenguajes.

martes, 2 de julio de 2024

Tipos personalizados en Gleam



import gleam/io

pub type Season {
  Spring
  Summer
  Autumn
  Winter
}

pub fn main() {
  io.debug(weather(Spring))
  io.debug(weather(Autumn))
}

fn weather(season: Season) -> String {
  case season {
    Spring -> "Mild"
    Summer -> "Hot"
    Autumn -> "Windy"
    Winter -> "Cold"
  }
}


Gleam tiene algunos tipos integrados como Int y String, pero los tipos personalizados permiten la creación de tipos completamente nuevos.

Un tipo personalizado se define con la palabra clave type seguida del nombre del tipo y un constructor para cada variante del tipo. Tanto el nombre del tipo como los nombres de los constructores comienzan con letras mayúsculas.

Las variantes de tipos personalizados pueden coincidir con patrones utilizando una expresión de caso.

lunes, 1 de julio de 2024

Tuplas en Gleam



 import gleam/io


pub fn main() {

  let triple = #(1, 2.2, "three")

  io.debug(triple)


  let #(a, _, _) = triple

  io.debug(a)

  io.debug(triple.1)

}


Las listas son buenas cuando queremos una colección de un tipo, pero a veces queremos combinar múltiples valores de diferentes tipos. En este caso las tuplas son una opción rápida y cómoda.

La sintaxis de acceso a tupla se puede utilizar para obtener elementos de una tupla sin coincidencia de patrones. some_tuple.0 obtiene el primer elemento, some_tuple.1 obtiene el segundo elemento, etc.

Las tuplas son tipos genéricos, tienen parámetros de tipo para los tipos que contienen. #(1, "¡Hola!") tiene el tipo #(Int, String) y #(1.4, 10, 48) tiene el tipo #(Float, Int, Int).

Las tuplas se usan más comúnmente para devolver 2 o 3 valores de una función. A menudo es más claro utilizar un tipo personalizado donde se podría utilizar una tupla.

viernes, 28 de junio de 2024

Guards en Gleam


import gleam/io


pub fn main() {

  let numbers = [1, 2, 3, 4, 5]

  io.debug(get_first_larger(numbers, 3))

  io.debug(get_first_larger(numbers, 5))

}


fn get_first_larger(numbers: List(Int), limit: Int) -> Int {

  case numbers {

    [first, ..] if first > limit -> first

    [_, ..rest] -> get_first_larger(rest, limit)

    [] -> 0

  }

}

La palabra clave if se puede utilizar con expresiones para agregar una protección a un patrón. Una guardia es una expresión que debe evaluarse como Verdadera para que el patrón coincida.

Solo se puede utilizar un conjunto limitado de operadores y no se puede invocar ninguna función.

lunes, 17 de junio de 2024

Alias ​​en patrones en Gleam


import gleam/io


pub fn main() {

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

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

  io.debug(get_first_non_empty([[], [], []]))

}


fn get_first_non_empty(lists: List(List(t))) -> List(t) {

  case lists {

    [[_, ..] as first, ..] -> first

    [_, ..rest] -> get_first_non_empty(rest)

    [] -> []

  }

}

El operador as se puede utilizar para asignar subpatrones a variables.

El patrón [_, ..] como primero coincidirá con cualquier lista que no esté vacía y asignará esa lista a la variable first.

viernes, 14 de junio de 2024

Patrones alternativos en Gleam


import gleam/int

import gleam/io


pub fn main() {

  let number = int.random(10)

  io.debug(number)


  let result = case number {

    2 | 4 | 6 | 8 -> "This is an even number"

    1 | 3 | 5 | 7 -> "This is an odd number"

    _ -> "I'm not sure"

  }

  io.debug(result)

}


Se puede realizar una acción con varias cohicidencias de patrones con el operador | . Si alguno de los patrones coincide, entonces la cláusula coincide.

Si un patrón define una variable, entonces todos los patrones alternativos para esa cláusula también deben definir una variable con el mismo nombre y el mismo tipo.

Actualmente no es posible tener patrones alternativos anidados, por lo que el patrón [1 | 2 | 3] no es válido.

martes, 11 de junio de 2024

Patrones con múltiples valores en Gleam


import gleam/int

import gleam/io


pub fn main() {

  let x = int.random(2)

  let y = int.random(2)

  io.debug(x)

  io.debug(y)


  let result = case x, y {

    0, 0 -> "Both are zero"

    0, _ -> "First is zero"

    _, 0 -> "Second is zero"

    _, _ -> "Neither are zero"

  }

  io.debug(result)

}

A veces necesitaamos patrones en múltiples valores.  Para hacer esto, puedes dar múltiples temas y múltiples patrones, separados por comas.

Al hacer coincidir varios temas, debe haber la misma cantidad de patrones que temas.


domingo, 9 de junio de 2024

Recursividad de listas en Gleam



import gleam/io


pub fn main() {

  let sum = sum_list([18, 56, 35, 85, 91], 0)

  io.debug(sum)

}


fn sum_list(list: List(Int), total: Int) -> Int {

  case list {

    [first, ..rest] -> sum_list(rest, total + first)

    [] -> total

  }

}


Si bien es más común usar funciones en el módulo gleam/list para iterar a través de una lista, en ocasiones es posible que prefieras trabajar con la lista directamente.

El patrón [primero, ..rest] coincide en una lista con al menos un elemento, asignando primero el primer elemento a la variable y el resto de la lista a la variable resto. Al usar este patrón y un patrón para la lista vacía [], una función puede ejecutar código en cada elemento de una lista hasta llegar al final.

Este código suma una lista recurriendo a la lista y agregando cada int a un argumento total, devolviéndolo cuando se llega al final.

martes, 4 de junio de 2024

Recursión por cola en Gleam


import gleam/io


pub fn main() {

  io.debug(factorial(5))

  io.debug(factorial(7))

}


pub fn factorial(x: Int) -> Int {

  // The public function calls the private tail recursive function

  factorial_loop(x, 1)

}


fn factorial_loop(x: Int, accumulator: Int) -> Int {

  case x {

    0 -> accumulator

    1 -> accumulator


    // The last thing this function does is call itself

    // In the previous lesson the last thing it did was multiply two ints

    _ -> factorial_loop(x - 1, accumulator * x)

  }

}


Cuando se llama a una función, se crea un nuevo marco de pila en la memoria para almacenar los argumentos y las variables locales de la función. Si se crean muchos de estos fotogramas durante la recursividad, entonces el programa utilizará una gran cantidad de memoria o incluso bloqueará el programa si se alcanza algún límite.

Para evitar este problema, Gleam admite la optimización de llamadas de cola, lo que permite al compilador reutilizar el marco de pila para la función actual si una llamada a función es lo último que hace la función, eliminando el costo de memoria.

Las funciones recursivas no optimizadas a menudo se pueden reescribir en funciones optimizadas de llamada final mediante el uso de un acumulador. Un acumulador es una variable que se pasa además de los datos, similar a una variable mutable en un lenguaje con bucles while.

Los acumuladores deben estar ocultos a los usuarios de su código, son detalles de implementación interna. Para hacer esto, escriba una función pública que llame a una función privada recursiva con el valor inicial del acumulador.