Taller de Elixir #3 – Tipos de datos

Los tipos básicos en elixir son enteros, flotantes, booleanos, átomos, cadenas, listas y tuplas.

iex> 1          # integer
iex> 0x1F       # integer
iex> 1.0        # float
iex> true       # boolean
iex> :atom      # atom / symbol
iex> "elixir"   # string
iex> [1, 2, 3]  # list
iex> {1, 2, 3}  # tuple

Aritmética básica

Las operaciones básicas son comunes:

iex> 1 + 2
3
iex> 2 - 1
1
iex> 5 * 5
25
iex> 10 / 2
5.0

Para que al dividir devuelva un entero en vez de un flotante se usa la función div/1 y para el modulo usamos rem/1.

iex> div(10, 2)
5
iex> div 10, 2
5
iex> rem 10, 3
1

Elixir le permite quitar los paréntesis al invocar funciones con nombre. Esta característica proporciona una sintaxis más limpia.

También admite anotaciones de acceso directo para ingresar números binarios, octales y hexadecimales:

iex> 0b1010
10
iex> 0o777
511
iex> 0x1F
31

Los números flotantes requieren un punto seguido de al menos un dígito y también admiten e para notación científica:

iex> 1.0
1.0
iex> 1.0e-10
1.0e-10

Las flotantes son de doble precisión de 64 bits.

La función “round” devuelve el número entero más cercano a un flotante y la función “trunc” para obtener la parte entera de un flotante.

iex> round(3.58)
4
iex> trunc(3.58)
3

Booleanos

Tenemos las palas claves true y false:

iex> true
true
iex> true == false
false

También tenemos la función “is_boolean”:

iex> is_boolean(true)
true
iex> is_boolean(1)
false

Atoms

Un átomo es una constante cuyo valor es su propio nombre. Algunos lenguajes llaman a estas símbolos. A menudo son útiles para enumerar valores distintos, como:

iex> :apple
:apple
iex> :orange
:orange
iex> :watermelon
:watermelon

Los átomos son iguales si sus nombres son iguales:

iex> :apple == :apple
true
iex> :apple == :orange
false

A menudo se utilizan para expresar el estado de una operación, mediante el uso de valores como :ok y :error.

Los booleanos verdadero y falso también son átomos:

iex> true == :true
true
iex> is_atom(false)
true
iex> is_boolean(:false)
true

Elixir te permite omitir el líder: para los átomos falso, verdadero y nulo.

Finalmente, Elixir tiene una construcción llamada alias que exploraremos más adelante. Los alias comienzan en mayúsculas y también son átomos:

iex> is_atom(Hello)
true

Strings

Las cadenas están delimitadas por comillas dobles, y están codificadas en UTF-8:

iex> "hellö #{:world}"
"hellö world"

Las cadenas pueden tener saltos de línea en ellas. Puedes presentarlos usando secuencias de escape:

ex> "hello
...> world"
"hello\nworld"
iex> "hello\nworld"
"hello\nworld"

Se puede imprimir una cadena usando la función IO.puts/1 desde el módulo IO:

iex> IO.puts "hello\nworld"
hello
world
:ok

Podemos ver que la función IO.puts/1 devuelve el átomo :ok después de imprimir.

Las cadenas están representadas internamente por secuencias contiguas de bytes conocidas como binarios:

iex> is_binary("hellö")
true

Para saber el número de bytes en una cadena:

iex> byte_size("hellö")
6

Observamos que el número de bytes en esa cadena es 6, a pesar de que tiene 5 caracteres. Esto se debe a que el carácter “ö” toma 2 bytes para ser representado en UTF-8. Podemos obtener la longitud real de la cadena, en función del número de caracteres, utilizando la función String.length/1:

iex> String.length("hellö")
5

El String module  contiene un montón de funciones para operar:

iex> String.upcase("hellö")
"HELLÖ"

Funciones anónimas

Estas funciones nos permiten almacenar y pasar código ejecutable como si fuera un entero o una cadena. Están delimitados por las palabras clave fn y end:

iex> add = fn a, b -> a + b end
#Function<12.71889879/2 in :erl_eval.expr/5>
iex> add.(1, 2)
3
iex> is_function(add)
true

Las funciones anónimas también se identifican por la cantidad de argumentos que reciben. Podemos verificar si una función usando is_function / 2:

iex> is_function(add, 2)
true

iex> is_function(add, 1)
false

Definamos una nueva función anónima que usa la función agregar anónimo que hemos definido previamente:

iex> double = fn a -> add.(a, a) end
#Function<6.71889879/1 in :erl_eval.expr/5>
iex> double.(2)
4

Una variable asignada dentro de una función no afecta a su entorno:

iex> x = 42
42
iex> (fn -> x = 0 end).()
0
iex> x
42

Listas

Se usan corchetes para especificar una lista de valores. Los valores pueden ser de cualquier tipo:

iex> [1, 2, true, 3]
[1, 2, true, 3]
iex> length [1, 2, 3]
3

Se pueden concatenar o restar dos listas utilizando los operadores ++ / 2 y – / 2 respectivamente:

iex> [1, 2, 3] ++ [4, 5, 6]
[1, 2, 3, 4, 5, 6]
iex> [1, true, 2, false, 3, true] -- [true, false]
[1, 2, 3, true]

Los operadores de listas nunca modifican la lista existente. Concatenar o eliminar elementos de una lista devuelve una nueva lista. Decimos que las estructuras de datos de Elixir son inmutables. Una ventaja de la inmutabilidad es que conduce a un código más claro. Puede pasar libremente los datos con la garantía de que nadie los mutará en la memoria, solo los transformará.

La cabeza es el primer elemento de una lista y la cola es el resto de la lista. Se pueden recuperar con las funciones hd/1 y tl/1. Asignemos una lista a una variable y recuperemos su cabeza y cola:

iex> list = [1, 2, 3]
iex> hd(list)
1
iex> tl(list)
[2, 3]

Obtener la cabeza o la cola de una lista vacía arroja un error:

iex> hd []
** (ArgumentError) argument error

A veces creará una lista y devolverá un valor entre comillas simples. Por ejemplo:

iex> [11, 12, 13]
'\v\f\r'
iex> [104, 101, 108, 108, 111]
'hello'

Cuando Elixir ve una lista de números ASCII imprimibles, Elixir lo imprimirá como una lista de caracteres (literalmente, una lista de caracteres). Las listas de caracteres son bastante comunes al interactuar con el código Erlang existente. Siempre que vea un valor en IEx y no esté seguro de cuál es, puede usar el i/1 para recuperar información al respecto:

iex> i 'hello'
Term
  'hello'
Data type
  List
Description
  ...
Raw representation
  [104, 101, 108, 108, 111]
Reference modules
  List
Implemented protocols
  ...

Las representaciones con comillas simples y dobles no son equivalentes en Elixir, ya que están representadas por diferentes tipos:

iex> 'hello' == "hello"
false

Las comillas simples son charlists, las comillas dobles son cadenas.

Tuplas

Elixir usa llaves para definir tuplas. Al igual que las listas, las tuplas pueden contener cualquier valor:

iex> {:ok, "hello"}
{:ok, "hello"}
iex> tuple_size {:ok, "hello"}
2

Las tuplas almacenan elementos contiguos en la memoria. Esto significa que acceder a un elemento de tupla por índice u obtener el tamaño de la tupla es una operación rápida. Los índices comienzan desde cero:

iex> tuple = {:ok, "hello"}
{:ok, "hello"}
iex> elem(tuple, 1)
"hello"
iex> tuple_size(tuple)
2

También es posible poner un elemento en un índice particular en una tupla con put_elem/3:

iex> tuple = {:ok, "hello"}
{:ok, "hello"}
iex> put_elem(tuple, 1, "world")
{:ok, "world"}
iex> tuple
{:ok, "hello"}

Observamos que put_elem/3 devolve una nueva tupla. La tupla original almacenada en la variable tupla no se modificó. Al igual que las listas, las tuplas también son inmutables. Cada operación en una tupla devuelve una nueva tupla, nunca cambia la dada.

¿Listas o tuplas?

Las listas se almacenan en la memoria como listas vinculadas, lo que significa que cada elemento de una lista mantiene su valor y apunta al siguiente elemento hasta llegar al final de la lista. Esto significa que acceder a la longitud de una lista es una operación lineal: debemos recorrer toda la lista para determinar su tamaño.

Del mismo modo, el rendimiento de la concatenación de listas depende de la longitud de la lista de la izquierda:

iex> list = [1, 2, 3]

iex> [0] ++ list
[0, 1, 2, 3]

iex> list ++ [4]
[1, 2, 3, 4]

Las tuplas, por otro lado, se almacenan contiguamente en la memoria. Esto significa que obtener el tamaño de tupla o acceder a un elemento por índice es rápido. Sin embargo, actualizar o agregar elementos a las tuplas es costoso porque requiere crear una nueva tupla en la memoria:

iex> tuple = {:a, :b, :c, :d}
iex> put_elem(tuple, 2, :e)
{:a, :b, :e, :d}

Hay que tener en cuenta que esto solo se aplica a la tupla en sí, no a su contenido. Por ejemplo, cuando actualiza una tupla, todas las entradas se comparten entre la tupla antigua y la nueva, excepto la entrada que ha sido reemplazada. En otras palabras, las tuplas y las listas en Elixir son capaces de compartir sus contenidos. Esto reduce la cantidad de asignación de memoria que necesita realizar el idioma y solo es posible gracias a la semántica inmutable del idioma.

Esas características de rendimiento dictan el uso de esas estructuras de datos. Un caso de uso muy común para las tuplas es usarlas para devolver información adicional de una función. Por ejemplo, File.read/1 es una función que se puede usar para leer el contenido del archivo. Devuelve una tupla:

iex> File.read("path/to/existing/file")
{:ok, "... contents ..."}
iex> File.read("path/to/unknown/file")
{:error, :enoent}

Si la ruta dada a File.read/1 existe, devuelve una tupla con el átomo :ok como el primer elemento y el contenido del archivo como el segundo. De lo contrario, devuelve una tupla con :error y la descripción del error.

La mayoría de las veces, Elixir te guiará para hacer lo correcto. Por ejemplo, hay una función elem/2 para acceder a un elemento de tupla, pero no hay un equivalente incorporado para las listas:

iex> tuple = {:ok, "hello"}
{:ok, "hello"}
iex> elem(tuple, 1)
"hello"

Hasta ahora hemos utilizado 4 funciones de conteo: byte_size/1 (para el número de bytes en una cadena), tuple_size/1 (para el tamaño de la tupla), length/1 (para la longitud de la lista) y String.length/1 ( para el número de grafemas en una cadena). Usamos byte_size para obtener el número de bytes en una cadena, una operación barata. Recuperar el número de caracteres Unicode, por otro lado, usa String.length, y puede ser costoso ya que depende de un recorrido de toda la cadena.

Elixir también proporciona puertos, referencias y PID como tipos de datos (generalmente utilizados en la comunicación de procesos).

Taller de Elixir #2 – Primeros pasos

Documentación

Modo Interactivo

Cuando tenemos instalado Elixir. Tendremos 3 ejecutables: iex, elixir, mix.

El primero que vamos a ver es iex o iex.bat en windows. Que significa Interactive Elixir. En este shell, podremos escribir cualquier expresión de Elixir y obtener su resultado.

Un ejemplo sencillo sería.

Erlang/OTP 21.0 [64-bit] [smp:2:2] [...]

Interactive Elixir (1.10.2) - press Ctrl+C to exit
iex(1)> 40 + 2
42
iex(2)> "hello" <> " world"
"hello world"

Para salir de iex, presione Ctrl + C dos veces.

Ejecutar scripts

Creamos un fichero llamado “simple.exs” y le añadimos la siguiente linea.

IO.puts "Hello world from Elixir"

Salvamos el fichero y ejecutamos en la consola.

$ elixir simple.exs
Hello world from Elixir

Crear un proyecto

Creemos nuestro primer proyecto con “mix new” desde la línea de comandos. Pasaremos el nombre del proyecto como argumento (kv, en este caso), y le diremos a Mix que nuestro módulo principal debería ser el KV en mayúsculas, en lugar del predeterminado, que habría sido Kv:

$ mix new kv --module KV

Lo que nos devolverá algo parecido a esto:

* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/kv.ex
* creating test
* creating test/test_helper.exs
* creating test/kv_test.exs

El fichero responsable de la compilación del proyecto (Opciones, dependencias.. etc) es mix.exs y se genera automáticamente.

defmodule KV.MixProject do
  use Mix.Project

  def project do
    [
      app: :kv,
      version: "0.1.0",
      elixir: "~> 1.9",
      start_permanent: Mix.env == :prod,
      deps: deps()
    ]
  end

  # Run "mix help compile.app" to learn about applications
  def application do
    [
      extra_applications: [:logger]
    ]
  end

  # Run "mix help deps" to learn about dependencies
  defp deps do
    [
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
    ]
  end
end

Ahora ya tenemos un proyecto. Se podría crea módulos y funciones. Para usarlo como librería de otra app. Pero queremos que se ejecute. Para ello modificamos el archivo mix.exs el apartado application. Tiene que ser algo parecido a esto.

  def application do
    [
      mod: {KV, []},
      extra_applications: [:logger]
    ]
  end

Eso hará que cuando ejecutemos la app nos llame a la función “start” del método “KV”. Nos vamos a fichero “lib/kv.ex” y cambiamos su contenido que es de ejemplo por:

defmodule KV do
  @moduledoc """
  Documentation for `KV`.
  """

  @doc """
    Run to start app.
  """
  def start(_type, _args) do
    IO.puts "starting"
    :timer.sleep(1000)
    Task.start(fn -> :timer.sleep(1000); IO.puts("done sleeping") end)
  end
end

Una vez realizado esto. Ejecutamos en consola:

$ mix run

Lo que nos devolverá el siguiente texto con un pequeño delay.

Compiling 1 file (.ex)
starting

Taller de Elixir #1 – Conceptos e instalación

Este taller estará basado en Elixir guides. Es básicamente una traducción del mismo con algunos cambios y apuntes.

¿Qué es?

Elixir es un lenguaje de programación funcionalconcurrente, de propósito general que se ejecuta sobre la máquina virtual de Erlang (BEAM). Elixir está escrito sobre Erlang y comparte las mismas abstracciones para desarrollar aplicaciones distribuidas y tolerantes a fallos. Elixir también proporciona un diseño extensible con herramientas productivas. Incluye soporte para metaprogramación en tiempo de compilación con macros y polimorfismo mediante protocolos.

Características

Instalación en Linux (Ubuntu)

wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb 
sudo dpkg -i erlang-solutions_1.0_all.deb
sudo apt-get update
sudo apt-get install esl-erlang
sudo apt-get install elixir

Instalación en Mac

brew install elixir (utilizando Homebrew)

Instalación en Windows

Descarga el instalador y sigue los pasos

Modificadores de acceso en Java

Este post es un resumen de los modificadores de Java. Pensado para las personas que estén preparándose los exámenes de grado superior a modo de guía rápida.

Los modificadores de acceso permiten el encapsulamiento. El cual busca la forma controlar el acceso a los datos de un objeto o instancia.

Los modificadores dan seguridad a las aplicaciones limitando el acceso a diferentes atributos, métodos, constructores asegurando una “ruta” especificada acceder a la información.

Si nuestra aplicación es usada por programadores. Con modificadores de acceso aseguramos que un valor no será modificado incorrectamente. Para eso usaremos el acceso a los atributos con los métodos get y set.

  • Private

Este modificador solo nos permitirá acceder desde la misma clase. En caso de un método solo se podrá llamar internamente. Para los atributos, se crearan métodos públicos GETTERS y SETTERS.

package app.ejemplo;
public class Ejemplo1
{
	// Atributo y sus metodos
	private int atributo;

	public int getatributo()
	{
	  return atributo;
	}

	public void setAtributo(int atributo)
	{
	  this.atributo = atributo;
	}

	// Metodo
	private int metodo(){
	  //code;
	}
}
  • Default

Este acceso por defecto que permite que tanto la propia clase como las clases del mismo paquete.

package app.ejemplo;
public class Ejemplo2
{
    static int atributo = 0;
}
package app.ejemplo2;
public class Ejemplo2_1
{
    public static int getAtributo()
    {
            return Ejemplo2.atributo;
    }
}
  • Protected

Nos permite acceder a las propiedades de la clase padre, cuando estemos haciendo herencias. Fuera de las clases hijas es equivalente a private.

package app.ejemplo;
public class Ejemplo3
{
    protected static int atributo = 0;    
}
package app.ejemplo3_1;
import app.ejemplo3.Ejemplo3;
public class Ejemplo3_1 extends Ejemplo3
{
    public static void main(String[] args)
    {
        System.out.println(atributo)
    }
}
  • Public

Es el mas permisivo. Cualquier clase tendra acceso a el sin importar paquete o procedencia.

package app.ejemplo4;
public class Ejemplo4
{
    public static int atributo = 0;

    public static void metodo()
    {
        System.out.println("Metodo Publico");
    }
}
package otro.paquete;
import app.ejemplo4.Ejemplo4;

public class OtraExterna
{
    public static void main(String[] args)
    {
        System.out.println(Ejemplo4.atributo);
        Ejemplo4.metodo(); 
    }
}
  • La directiva Static

Static es una directiva no un modificador de acceso, pero por utilidad vamos desarrollarla un poco.

Una clase, método o campo declarado como estático puede ser accedido o invocado sin la necesidad de tener que instanciar un objeto de la clase. Uno de los ejemplos típicos de uso de métodos y variables estáticas es la clase java.lang.Math.

public class MathTest {
     public static void main(String[] args) {
        double floorOfPi = Math.floor(Math.PI);
        System.out.println(floorOfPi);
    }
}

Resumen PL/SQL

Este post es un resumen de PL/SQL. Pensado para las personas que estén preparándose los exámenes de grado superior a modo de guía rápida.

PL/SQL nos permite un pequeño ámbito de programación dentro de las bases de datos. Enfocado a administración, eventos o tareas en la misma.

La éxtasis para ejecutar un código arbitrario:

DECLARE 
   <declarations section> 
BEGIN 
   <executable command(s)>
[EXCEPTION
   exception_section]
END;

Un hola mundo seria:

DECLARE 
   message  varchar2(20):= 'Hello, World!'; 
BEGIN 
   dbms_output.put_line(message); 
END; 
/ 

Se usa “/” para declarar que hemos terminado la ejecución de código.

Un delimitador es un símbolo con un significado especial. La siguiente es la lista de delimitadores en PL/SQL:

Como en cualquier lenguaje tendremos procedimientos:

---- Procedimiento
-- Sintaxis 
CREATE [OR REPLACE] PROCEDURE procedure_name 
[(parameter_name [IN | OUT | IN OUT] type [, ...])] 
{IS | AS} 
BEGIN 
  < procedure_body > 
[EXCEPTION
   exception_section]
END procedure_name; 
-- Ejemplo
CREATE OR REPLACE PROCEDURE greetings 
AS 
BEGIN 
   dbms_output.put_line('Hello World!'); 
END; 
/

Y funciones:

---- Función
-- Sintaxis
CREATE [OR REPLACE] FUNCTION function_name 
[(parameter_name [IN | OUT | IN OUT] type [, ...])] 
RETURN return_datatype 
{IS | AS} 
BEGIN 
   < function_body > 
END [function_name];
-- Ejemplo
CREATE OR REPLACE FUNCTION totalCustomers 
RETURN number IS 
   total number(2) := 0; 
BEGIN 
   SELECT count(*) into total 
   FROM customers; 
    
   RETURN total; 
END; 

Lo mejor de PL/SQL es que permite controlar los datos a través de los eventos o triggers:

---- Triggers
-- Sintaxis
CREATE [OR REPLACE ] TRIGGER trigger_name  
{BEFORE | AFTER | INSTEAD OF }  
{INSERT [OR] | UPDATE [OR] | DELETE}  
[OF col_name]  
ON table_name  
[REFERENCING OLD AS o NEW AS n]  
[FOR EACH ROW]  
WHEN (condition)   
DECLARE 
   Declaration-statements 
BEGIN  
   Executable-statements 
EXCEPTION 
   Exception-handling-statements 
END;
-- Ejemplo
CREATE OR REPLACE TRIGGER display_salary_changes 
BEFORE DELETE OR INSERT OR UPDATE ON customers 
FOR EACH ROW 
WHEN (NEW.ID > 0) 
DECLARE 
   sal_diff number; 
BEGIN 
   sal_diff := :NEW.salary  - :OLD.salary; 
   dbms_output.put_line('Old salary: ' || :OLD.salary); 
   dbms_output.put_line('New salary: ' || :NEW.salary); 
   dbms_output.put_line('Salary difference: ' || sal_diff); 
END;

Se recomienda la lectura del siguiente link, con toda la documentación oficial en ingles.

Resumen comandos de SQL

Este post es un resumen de los comandos SQL. Pensado para las personas que estén preparándose los exámenes de grado superior a modo de guía rápida.

  • DDL

Los comandos DDL, son los que nos permiten crear y denominar las tablas, indices y todos aquellos componentes de la estructura de las bases de datos y sus tablas.

---- CREATE
-- Crear tabla:
CREATE TABLE tablename (
   column1 datatype(size) constraint[optional], 
   column2 datatype(size) constraint[optional]
);

---- ALTER
-- Añadir columna a tabla existente:
ALTER TABLE tablename ADD column_name datatype(size);
-- Cambiar tipo a columna a tabla existente:
ALTER TABLE tablename MODIFY column_name datatype(size);
-- Borrar columna en una tabla:
ALTER TABLE tablename DROP column_name ;

---- DROP
-- Borrar una tabla:
DROP TABLE tablename;

---- RENAME
-- Cambiar nombre a una tabla:
RENAME existing_column_name to new_column_name;

---- TRUNCATE
-- Vaciar contenido de una tabla:
TRUNCATE TABLE tablename;

  • DML

Aquí se agrupan los comando que sirven para añadir, modificar o eliminar datos en las tablas.

---- SELECT
-- Mostramos toda las filas y columnas de una tabla: 
SELECT * FROM table_name;
-- Mostramos todas las fila pero solo las columnas declaradas: 
SELECT column1, column2 FROM table_name;
-- Buscamos filas que coincidan en la condición y mostramos todas las columnas:
SELECT * FROM table_name WHERE some_column=some_value
-- Buscamos filas que coincidan en la condición y mostramos las columnas declaradas:
SELECT column1, column2 FROM table_name WHERE some_column=some_value

---- UPDATE
-- Actualizamos las filas que cumplan las condiciones:
UPDATE table_name SET column1=value, column2=value2,... WHERE some_column=some_value

---- DELETE
-- Borramos las filas que cumplan las condicion
-- https://www.youtube.com/watch?v=i_cVJgIz_Cs
DELETE FROM table_name [WHERE condition];

  • DCL

Este es el apartado donde agruparemos los comandos relacionados con permisos de usuarios. Básicamente dos comandos GRANT(Añadir permiso) y REVOKE(Revocar permisos).

---- GRANT
-- Permite crear sesión al usuario 
GRANT CREATE SESSION TO username;
-- Permite al usuario crear tablas
GRANT CREATE TABLE TO username;
-- En ocasiones, el usuario no puede crear tablas con nombres reservados para las tablas del sistema
GRANT CREATE ANY TABLE TO username 
-- Permite al usuario borrar tablas
GRANT DROP ANY TABLE TO username

---- ALTER
-- Cambia la cuota que puede usar el usuario.
ALTER USER username QUOTA UNLIMITED ON SYSTEM;

---- REVOKE
-- Revocamos al usuario 
REVOKE CREATE TABLE FROM username

  • TCL

En este grupo no nos vamos a extender. Pues no se suele pedir en los grados superior. Pero está bien tener en cuenta el comando COMMIT. Que nos asegura que los comandos que introdujimos antes que él. Se sincronicen con el servidor. Ya que existe la posibilidad de que algunos comando, sobretodo los relacionados con permisos de usuario. No se hagan efectivos al ejecutarlos y el servidor espera a reiniciar o a dicho comando.

---- COMMIT
-- Confirma que se guarden los cambios efectuados referentes a permisos de usuario:
COMMIT;

Los mapas de Elixir tienen una sintaxis incorporada para actualizar

Esto es una traducción de un post de Marin Abernethy  en el blog dockyard.com. En modo de homenaje y agradecimiento. Con la intención de que la comunidad hispana pueda disfrutarlo en su idioma nativo.

En Elixir a menudo, encontramos que hay muchas formas de implementar una sola tarea. Por ejemplo, cuando queremos actualizar un valor clave en un mapa, tenemos varias opciones por delante…

Dado,    expenses = %{groceries: 200, rent: 1000, commute: 70}  podría emplear:

  • Si deseamos actualizar varios pares de valores clave y / o varios nuevos.
# Sintaxis
Map.merge(map1, map2)
# Ejemplo
Map.merge(expenses, %{ rent: 1200, comcast: 100 }) 
  • Si actualizamos o agregamos un solo valor de clave.
# Sintaxis
Map.put(map, key, val)
# Ejemplo
Map.put(expenses, :booze, 100) 
  •  Si queremos incrementar un valor en cierto grado.
# Sintaxis
Map.update(map, key, initial, fun)
# Ejemplo
Map.update(expenses, :misc, 300, &(&1 * 2)) 
  • Si queremos actualizar un valor en una estructura anidada.
# Sintaxis
Kernel.put_in(data, keys, value) 
# Ejemplo
expenses = %{groceries: %{milk: 5}, apartment: %{rent: 1000, comcast: 100}}
put_in(expenses, [:rent, :comcast], "too much")
  • Sin embargo, los mapas vienen con una sintaxis integrada para actualizar uno o más valores clave.
%{expenses | groceries: 150, commute: 75}