Skip to content

Commit 510e75d

Browse files
authored
Merge pull request #77 from rerades/fix-deletion
fixing accidental deletion
2 parents 710c1dc + 1ada977 commit 510e75d

File tree

8 files changed

+931
-141
lines changed

8 files changed

+931
-141
lines changed

public/search-index.json

Lines changed: 2 additions & 141 deletions
Large diffs are not rendered by default.
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
---
2+
title: "Notación Hindley-Milner"
3+
description: "Entendiendo la notación de tipo Hindley-Milner en programación funcional para expresar firmas de funciones y relaciones de tipo"
4+
pubDate: "2019-04-11"
5+
tags:
6+
- declarative
7+
- Pure functions
8+
- Inmutable
9+
- currying
10+
- Hindley-Milner
11+
categories:
12+
- functional
13+
draft: false
14+
heroImage: "/blog-placeholder-13.jpg"
15+
---
16+
17+
Una forma de crear una notación para expresar qué tipos de parámetro toma una función y qué devuelve.
18+
19+
## Lo básico
20+
21+
Una función que toma un valor primario ("tipo antiguo" como cadena, número, booleano, matriz, función ...) y devuelve otro valor primario:
22+
23+
`instruction :: String -> String`
24+
25+
```javascript
26+
const instruction = function (verb) {
27+
return verb + " me";
28+
};
29+
```
30+
31+
la función instruction toma una cadena y devuelve una cadena
32+
33+
También podría hacer algo así:
34+
35+
`length :: String → Number`
36+
37+
```javascript
38+
const length = function (s) {
39+
return s.length;
40+
};
41+
```
42+
43+
En el caso de una matriz de números:
44+
45+
`length :: [Number] → Number`
46+
47+
```javascript
48+
const length = function(arr){
49+
retrun arr.length
50+
}
51+
```
52+
53+
## Trabajando con funciones
54+
55+
En el caso de una función, envolvemos nuestra función entre paréntesis y dentro de los paréntesis tenemos nuestro tipo de entrada y nuestro tipo de salida:
56+
57+
`addOneToAll :: ((Number → Number),[Number]) → [Number]`
58+
59+
```javascript
60+
const addOne = function (x) {
61+
return x + 1;
62+
};
63+
const addOneToAll = (addOne, arr) => arr.map(addOne);
64+
```
65+
66+
En este caso tenemos una función llamada addOneToAll que espera como primer parámetro una función (en nuestro caso addOne) y esta función aceptará un número y devolverá un número.
67+
Y como segundo parámetro una matriz de números y devolverá otra matriz de números.
68+
69+
### Funciones de currying
70+
71+
Ahora, ¿qué pasa con una función que devuelve una función que devuelve otra función ....
72+
73+
Siguiendo lo anterior, tendríamos algo como esto:
74+
`replace :: String -> (String -> (String -> String))`
75+
76+
```javascript
77+
var replace = curry(function (find, replacement, str) {
78+
var regex = new RegExp(find, "g");
79+
return str.replace(regex, replacement);
80+
});
81+
```
82+
83+
En este caso también hacemos que la función sea curry para tomar parámetros uno por uno
84+
85+
Y en la programación funcional podemos asumir que todo es curry, así que tendemos a dejar caer los corchetes y algo como esto:
86+
87+
` replace :: String -> String -> String -> String`
88+
89+
## Trabajando con funciones que toman múltiples parámetros como entrada (Variables arbitrarias de Hindley-Milner)
90+
91+
Mostramos el ejemplo con la función de longitud donde podríamos tener:
92+
`length :: [Number] → Number`
93+
o
94+
`length :: string → Number`
95+
96+
En este caso podríamos escribir ambos con una variable arbitraria como:
97+
`length :: [a] → Number`
98+
99+
Otro ejemplo común es la identidad:
100+
`identity :: a -> a`
101+
102+
Y un ejemplo más complejo:
103+
`map :: (a -> b) -> [a] -> [b]`
104+
105+
```javascript
106+
const map = curry(function (callback, array) {
107+
return array.map(callback);
108+
});
109+
```
110+
111+
La función de mapa toma una función que toma una variable de tipo `a` y devuelve una variable de tipo `b`.
112+
Luego toma una **matriz de valores**, todos de tipo `a`, y devuelve una **matriz de valores**, todos de tipo `b`.
113+
114+
---
115+
116+
## Trabajando con Ramda
117+
118+
## Tipos parametrizados
119+
120+
Podemos imaginar fácilmente un tipo que representa una colección de elementos similares,
121+
llamémoslo una Caja. Pero ninguna instancia es una Caja arbitraria; cada uno solo puede contener un tipo de elemento.
122+
123+
`makeBox :: Number -> Number -> Number -> [a] -> Box a`
124+
125+
```javascript
126+
const makeBox = curry((height, width, depth, items) => /* ... */);
127+
```
128+
129+
## Alias de tipo
130+
131+
Si tuviéramos un tipo parametrizado Usuario String, donde la String se supone que representa un nombre, y quisieramos ser más específicos acerca del tipo de String que se representa al generar una URL, podríamos crear un alias de tipo así:
132+
133+
`toUrl :: User Name u => Url -> u -> Url`
134+
135+
`Name = String`
136+
137+
` Url = String`
138+
139+
```javascript
140+
const toUrl = curry(
141+
(base, user) => base + user.name.toLowerCase().replace(/\W/g, "-")
142+
);
143+
toUrl("http://example.com/users/", { name: "Fred Flintstone", age: 24 });
144+
//=> 'http://example.com/users/fred-flintstone'
145+
```
146+
147+
## Restricciones de tipo [Ord]
148+
149+
A veces queremos restringir los tipos genéricos que podemos usar en alguna firma de alguna manera u otra.
150+
151+
Podríamos querer una función máxima que pueda operar sobre Números, en Cadenas, en Fechas, pero no en Objetos arbitrarios.
152+
153+
Queremos describir tipos ordenados, aquellos para los cuales **a < b siempre devolverá un resultado significativo**
154+
155+
`maximum :: Ord a => [a] -> a`
156+
157+
```javascript
158+
const maximum = (vals) =>
159+
reduce((curr, next) => (next > curr ? next : curr), head(vals), tail(vals));
160+
maximum([3, 1, 4, 1]); //=> 4
161+
maximum(["foo", "bar", "baz", "qux", "quux"]); //=> 'qux'
162+
maximum([
163+
new Date("1867-07-01"),
164+
new Date("1810-09-16"),
165+
new Date("1776-07-04"),
166+
]); //=> new Date("1867-07-01")
167+
```
168+
169+
`Ord a ⇒ [a] → a` dice que la máxima toma una colección de elementos de algún tipo, pero ese tipo debe adherirse a Ord.
170+
171+
En JS, no hay forma de garantizar que el usuario no nos pasará [1, 2, 'a', false, undefined, null].
172+
Así que toda nuestra anotación de tipo es **descriptiva y aspiracional** en lugar de ser impuesta por el compilador, como sería en, digamos, Haskell.
173+
174+
## Firmas múltiples
175+
176+
A veces, en lugar de tratar de encontrar la versión más genérica de una firma, es más sencillo enumerar varias firmas relacionadas por separado.
177+
Podríamos hacer eso como abajo:
178+
179+
`getIndex :: a -> [a] -> Number`
180+
`:: String -> String -> Number`
181+
182+
```javascript
183+
const getIndex = curry((needle, haystack) => haystack.indexOf(needle));
184+
getIndex("ba", "foobar"); //=> 3
185+
getIndex(42, [7, 14, 21, 28, 35, 42, 49]); //=> 5
186+
```
187+
188+
## Funciones variadicas (específicas para Ramda)
189+
190+
En Haskell, todas las funciones tienen una aridad fija. Pero Javsacript tiene que lidiar con funciones variadicas.
191+
`flip :: (a -> b -> ... -> z) -> (b -> a -> ... -> z)`
192+
193+
```javascript
194+
const flip = (fn) =>
195+
function (b, a) {
196+
return fn.apply(this, [a, b].concat([].slice.call(arguments, 2)));
197+
};
198+
flip((x, y, z) => x + y + z)("a", "b", "c"); //=> 'bac'
199+
```
200+
201+
## Objetos simples
202+
203+
Cuando un objeto se utiliza como un diccionario de valores de tipo similar (a diferencia de su otro papel como un Registro), entonces los tipos de las claves y los valores pueden volverse relevantes.
204+
Entonces podríamos representarlos así:
205+
`keys :: {k: v} -> [k]`
206+
`values :: {k: v} -> [v]`
207+
208+
```javascript
209+
keys({ a: 86, b: 75, c: 309 }); //=> ['a', 'b', 'c']
210+
values({ a: 86, b: 75, c: 309 }); //=> [86, 75, 309]
211+
```
212+
213+
## Ejemplo complejo
214+
215+
`Lens s a -> (a -> a) -> s -> s`
216+
`Lens s a = Functor f => (a -> f a) -> s -> f s`
217+
218+
Comenzamos con el alias de tipo, Lens s a = Functor f ⇒ (a → f a) → s → f s.
219+
Esto nos dice que el tipo Lens **está parametrizado por dos variables genéricas, s, y a**.
220+
Sabemos que hay una restricción en el tipo de la variable f utilizada en una Lens: **debe ser un Functor**.
221+
Con eso en mente, vemos que una Lens es una función acurruada de dos parámetros, el primero siendo una función de
222+
un valor del tipo genérico a a uno del tipo parametrizado f a, y el segundo siendo un valor del tipo genérico s.
223+
224+
**El resultado** es un valor del tipo parametrizado `f・s`
225+
226+
<div class="bibliography">
227+
Bibliografía:<br><br>
228+
229+
- [gentle introduction to functional javascript style](https://jrsinclair.com/articles/2016/gentle-introduction-to-functional-javascript-style#hindley-milnertypesignatures)
230+
- [function type signatures in Javascript](https://hackernoon.com/function-type-signatures-in-javascript-5c698c1e9801)
231+
- [Type signatures in Ramda](https://github.com/ramda/ramda/wiki/Type-Signatures)
232+
</div>
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
---
2+
title: "combinadores"
3+
description: "Comprendiendo los combinadores en la programación funcional como funciones puras de orden superior para componer y controlar el flujo del programa"
4+
pubDate: "2019-01-10"
5+
tags:
6+
- declarative
7+
- Pure functions
8+
- Inmutable
9+
- currying
10+
- combinator
11+
categories:
12+
- functional
13+
draft: false
14+
heroImage: /blog-placeholder-10.jpg
15+
---
16+
17+
Un combinator es una función de orden superior, **funciones puras** que no tienen ninguna **variable libre** y
18+
pueden combinar artefactos primitivos como otras funciones (u otros combinators) y comportarse como lógica de control.
19+
20+
Las **variables libres** son simplemente variables en el contexto de una función que no se pasan explícitamente
21+
como argumento.
22+
23+
Nuestro compromiso es que todas las dependencias se pasen por parámetro.
24+
25+
Los combinators desbloquean la libertad y facilitan la programación libre de puntos.
26+
Debido a que los combinators son puros, se pueden componer en otros combinators,
27+
proporcionando un número infinito de alternativas para expresar y reducir la complejidad de la escritura
28+
cualquier tipo de aplicación.
29+
30+
Por ejemplo, una función de composición será un combinator:
31+
32+
```javascript
33+
const compose = (f, g) => (x) => f(g(x));
34+
35+
const addTwo = (x) => x + 2;
36+
const multByThree = (x) => x * 3;
37+
38+
const operator = compose(addTwo, multByThree);
39+
40+
console.log(operator(7)); // 23
41+
// NOTA: recuerda que compose se ejecutará de derecha a izquierda
42+
```
43+
44+
En Ramda hay muchos combinators que podemos usar:
45+
46+
- compose
47+
- pipe
48+
- identity
49+
- tap
50+
- alternation
51+
- sequence
52+
- fork (join)
53+
54+
## identity
55+
56+
El combinator identity es una función que devuelve el mismo valor que se le proporcionó como argumento:
57+
58+
`identity :: (a) -> a`
59+
60+
Se utiliza ampliamente al examinar las propiedades matemáticas de las funciones,
61+
pero también tiene otras aplicaciones prácticas:
62+
63+
- Proporcionar datos a funciones de orden superior que lo esperan al evaluar un argumento de función.
64+
- Pruebas unitarias del flujo de combinators de funciones donde necesita un resultado de función simple sobre el cual
65+
hacer afirmaciones.
66+
- Extracción de datos de manera funcional de tipos encapsulados.
67+
68+
## Tap
69+
70+
tap es extremadamente útil para enlazar funciones vacías (como registrar o escribir un archivo o una página HTML)
71+
en su composición sin tener que crear ningún código adicional. Lo hace pasándose a sí mismo
72+
en una función y retornándose a sí mismo. Aquí está la firma de la función:
73+
74+
`tap :: (a -> *) -> a -> a`
75+
76+
## Alternation [OR - combinator]
77+
78+
El combinator alt permite realizar **lógica condicional simple** al proporcionar comportamiento predeterminado
79+
en respuesta a una llamada de función.
80+
Este combinator toma dos funciones y devuelve el resultado de la primera si el valor está
81+
definido (no falso, nulo o indefinido); de lo contrario, devuelve el resultado de la segunda función.
82+
83+
## Sequence (S-combinator)
84+
85+
El combinator seq se utiliza para recorrer una secuencia de funciones. Toma dos o más funciones
86+
como parámetros y devuelve una nueva función, que ejecuta todas ellas en secuencia contra el mismo valor.
87+
88+
El combinator seq no devuelve un valor; solo realiza un conjunto de acciones una tras otra.
89+
90+
## Fork (join) combinator
91+
92+
El combinator fork es útil en casos donde necesitas procesar un solo recurso de dos
93+
maneras diferentes y luego combinar los resultados.
94+
95+
<br><br>
96+
97+
<div class="bibliography">
98+
Bibliografía:<br>
99+
100+
- Programación Funcional en JavaScript . Ed: MANNING SHELTER ISLAND. Autor: Luis Atencio.<br>
101+
- [Guía Más Que Adecuada para la programación funcional](https://drboolean.gitbooks.io/mostly-adequate-guide-old/content/).
102+
Professor Frisby's<br>
103+
- [Creando una aplicación declarativa usando JavaScript funcional](https://www.packtpub.com/web-development/building-declarative-apps-using-functional-javascript-video).
104+
Michael Rosata
105+
</div>

0 commit comments

Comments
 (0)