Translate

lunes, 9 de marzo de 2020

HTML + javascript + Haskell = ELM, parte 4


Seguimos con el post anteriro.

Como con cualquier lenguaje funcional, la base de Elm es la función. Definir una es trivial. Veamos algunas funciones :

> add x y = x + y
<function> : number -> number -> number
> double x = x * 2
<function> : number -> number
> anonymousInc = \x -> x + 1
<function> : number -> number
> double (add 1 2)
6 : number
> List.map anonymousInc [1, 2, 3]
[2,3,4] : [number]

La sintaxis para crear funciones es muy simple e intuitiva. add es una función con nombre con dos argumentos, x e y. Las funciones anónimas expresan parámetros como \ x, y el cuerpo de la función sigue los caracteres ->.
Como Elixir, Elm tiene el operador de tubería que permite componer funciones, de esta manera:


Tomamos 5 y lo pasamos como el primer argumento a anonymousInc, para obtener 6. Luego, lo pasamos como el primer argumento para duplicar. También podemos hacer que esa expresión se ejecute de derecha a izquierda:

> double <| anonymousInc <| 5
12 : number

Evan Czaplicki, creador de Elm, dice que obtuvo esta función de F#, que a su vez obtuvo la idea de las tuberías de Unix, por lo que esta idea ha existido por un tiempo, ¡pero es buena!
Al igual que con cualquier lenguaje funcional, hay muchas funciones que le permitirán trabajar con funciones de todo tipo de formas:

> List.map double [1..3]
[2,4,6] : List number
> List.filter (\x -> x < 3) [1..20]
[1,2] : List comparable

[1..3] es un rango. Puede explorar más funciones de la Lista con la biblioteca de listas.

Cuando está componiendo una solución con Elm, puede tener la tentación de codificar cada caso como un cuerpo de función separado como lo haría en Haskell, Erlang o Elixir, pero no se puede :( :

> factorial 1 = 1
<function> : number -> number'
> factorial x = x * factorial (x - 1)
<function> : number -> number
RangeError: Maximum call stack size exceeded

Parece que la segunda llamada reemplazó a la primera. En cambio, debe usar el mismo cuerpo de función y dividir el problema usando mayúsculas y minúsculas o si, de esta manera:

> factorial x = \
|  if | x == 0 -> 1 \
|      | otherwise -> x * factorial (x - 1)
<function> : number -> number
> factorial 5
120 : number

Suficientemente simple. factorial 0 es 1; de lo contrario, factorial x es x * factorial (x-1). Manejaría la recursividad de la lista de la misma manera:

> count list = \
| case list of \
| [] -> 0 \
| head::tail -> 1 + count tail
<function> : [a] -> number
> count [4, 5, 6]
3 : number

La cantidad de elementos de una lista vacía es cero y la cantidad de elementos de cualquier otra lista es 1 más la cantidad del resto. Veamos cómo atacar problemas similares con la coincidencia de patrones.

Por ahora vamos bien, pero seguimos en otro post...