Elixir: cuarto asalto

Éste es el cuarto asalto en mi aventura aprendiendo Elixir. En esta ocasión trato con tipos de datos binarios, cadenas y sigils. No es mucho, pero las cadenas son una parte esencial de cualquier lenguaje de programación. Y dominarlas significa dominar una gran parte del lenguaje.

Por supuesto, sigo aprendiendo con el método descrito en el post sobre aprender Elixir:

Fourth fight

Imagen basada en Muñeco de Gohan y Bu peleando de Alonso Javier Torres, algunos derechos reservados, licencia: CC BY 2.0

Aprender lo suficiente para comenzar

Para definir una cadena se pueden usar comillas simples o comillas dobles. También se puede usar comillas triples, para escribir lo que llaman heredocs, y se suelen usar para escribir comentarios para documentar métodos y módulos.

En Elixir, existe lo que llaman sigils (que se podría traducir como código, señal o símbolo mágico). Comienzan con ~, seguido de una letra que determina el tipo de símbolo:

y cuyo valor se puede enmarcar en distintos delimitadores: <..>, {...}, [...],…

Un uso muy típico es para escribir expresiones regulares:

~r{[0-9]+[A-Z]*}

Los sigils pueden incluso personalizarse, y crear los tuyos propios.

Las cadenas definidas mediante comillas dobles, son lo que se conoce en otros lenguajes como strings. Las cadenas con comillas simples, se llaman character lists (o char list), listas de carácteres, y son listas, arrays.

Cadenas con comillas simples

Son una lista de códigos que representan los carácteres. Y como son una lista, podemos usar métodos de List: ++, --, List.zip, [ head | tail ],…

Para saber el número entero que representa un carácter, se puede usar la notación ?<chr>, por ejemplo, ?a o ?4, para saber los valores numéricos de los carácteres a y 4 respectivamente.

Binarios

Qué mejor que un poco de código para ver cómo se usa este tipo de datos

# el tipo *binario* representa una secuencia de bits
iex> b = << 1, 2, 3 >>
<<1, 2, 3>>
iex> byte_size b
3
iex> bit_size b
24

# se puede especificar también la cantidad de bits que queremos que ocupen
iex> b = << 1::size(2), 1::size(3) >>
<<9::size(5)>>
iex> byte_size b
1
iex> bit_size b
5

# también se pueden almacenar enteros, floats y otros binarios
iex> an_int = << 1 >>
<<1>>
iex> a_float = << 2.5 :: float >>
<<64, 4, 0, 0, 0, 0, 0, 0>>
iex> mix = << an_int :: binary, a_float :: binary >>
<<1, 64, 4, 0,......>>

# extraer valores (echa un vistazo a cómo se codifican los floats según
# el estándar IEEE 754)
iex> << sign::size(1), exp::size(11), mantissa::size(52) >> = << 3.14159::float >>
iex> (1 + mantissa / :math.pow(2, 52)) * :math.pow(2, exp-1023)
3.14159

# las cadenas con comillas dobles "" (dqs: double quoted string) son de
# tipo binario, y están codificadas en UTF-8 lo que significa que la
# longitud de la cadena no tiene por qué coincidir con el tamaño en bytes
iex> dqs = "∂x/∂y"
"∂x/∂y"
iex> String.length dqs
5
iex> byte_size dqs
9

Procesando cadenas

Igual que podemos dividir una lista en head y tail, podemos extraer el primer carácter (se refiere a él como grapheme, grafema/grafo/…) de una cadena binaria o dqs especificando que head es de tipo utf8 y que tail sigue siendo de tipo binario:

defp each(<< head::utf8, tail::binary >>), do [ head | each(tail) ]
defp each(<<>>), do []

Experimentar, jugar, buscar puntos desconocidos, hacerse preguntas

Está claro que hay que ver la documentación del módulo String, que contiene métodos para manipular cadenas encerradas en comillas dobles (recuerda, son de tipo binario).

Las expresiones regulares son bastante comunes, y en Elixir se suelen usar mediante sigils. Son un aspecto bastante curioso del lenguaje y pueden ser personalizados.

Aprender lo suficiente para hacer algo de utilidad

Enseñar lo aprendido, y repetir desde el paso 7

Aquí está, este post, mis notas, mis pensamientos, mis dudas y mi código. Hasta el siguiente asalto.