Este é um transformador de mônada válido em Javascript?
Para entender melhor os transformadores de mônada, implementei um. Como o Javascript é digitado dinamicamente, não imito construtores de tipo ou de dados, mas declaro apenas objetos Javascript antigos simples, que contêm as funções estáticas correspondentes para formar um monad / transformador específico. A ideia subjacente é aplicar esses métodos a um valor / valores em um tipo de contêiner. Tipos e recipientes são separados por assim dizer.
Array
s pode conter qualquer número de elementos. É trivial estenderArray
s para que eles implementem a interface de mônada.Array
s também pode representar as duas variantes domaybe
tipo. Um vazioArray
corresponde anothing
. AArray
com um único elemento corresponde ajust(a)
. Consequentemente vou usarArray
s como meu tipo de contêiner. Observe que esta é uma implementação rápida e suja apenas para aprender:
const array = {
of: x => Array.of(x),
map: f => ftor => ftor.map(f),
ap: ftor => gtor => array.flatten(array.map(f => array.map(f) (gtor)) (ftor)),
flatten: ftor => ftor.reduce((xs, y) => xs.concat(y), []),
chain: mf => ftor => array.flatten(array.map(mf) (ftor))
}
const maybe = {
of: array.of,
empty: () => [],
throw: ftor => { if (ftor.length > 1) throw Error("indeterministic value"); return ftor },
map: f => ftor => maybe.throw(ftor).map(f),
ap: ftor => gtor => maybe.flatten(maybe.map(f => maybe.map(f) (gtor)) (ftor)),
flatten: array.flatten,
chain: mf => ftor => maybe.flatten(maybe.map(mf) (ftor)),
T: M => {
return {
of: x => M.of(maybe.of(x)),
empty: () => M.of(maybe.empty()),
map: f => ftor => M.map(gtor => maybe.map(f) (gtor)) (ftor),
ap: ftor => gtor => M.flatten(M.map(htor => M.map(itor => maybe.ap(htor) (itor)) (gtor)) (ftor)),
flatten: maybe.flatten,
chain: mf => ftor => M.chain(gtor => maybe.chain(mf) (gtor)) (ftor)
};
}
};
Agora eu combino um talvez transformador com a matriz monádica para obter uma mônada que possa suportararray
s demaybe
s.
const arraym = maybe.T(array);
const add = x => y => x + y;
const addm = x => y => [x + y];
const arrayOfMaybes = [[1],[],[3]]
Quando eu tratoarraym
como um aplicador funcional, tudo funciona como esperado:
// yields: [[11],[],[13]] as expected
arraym.ap(arraym.map(add) (arrayOfMaybes)) (arraym.of(10));
No entanto, quando eu aplicochain
algo der errado:
// yields: [11,13] but [[11],[13]] expected
arraym.chain(x => arraym.chain(y => addm(x) (y)) (arrayOfMaybes)) ([[10]])
É a causa deste problema
que este não é um transformador de mônada válido?que a maneira como aplico a cadeia está errada?que minha expectativa em relação ao resultado está errada?