tablero matrices hacer como ajedrez javascript ecmascript-6 generator yield

matrices - como hacer un tablero de ajedrez en javascript



rendimiento de una lista de generadores creados a partir de una matriz (5)

Tengo este generador recursivo

var obj = [1,2,3,[4,5,[6,7,8],9],10] function *flat(x) { if (Array.isArray(x)) for (let y of x) yield *flat(y) else yield ''foo'' + x; } console.log([...flat(obj)])

Funciona bien, pero no me gusta la parte. ¿Hay alguna manera de escribirlo funcionalmente? Lo intenté

if (Array.isArray(x)) yield *x.map(flat)

que no funcionó.

¿Hay alguna forma de escribir la función anterior sin bucles?


El map es una buena idea, pero debe reducir la matriz resultante de objetos generadores a un solo objeto generador:

function *flat(x) { if (Array.isArray(x)) yield *x.map(flat).reduce((a, b) => function*() { yield *a; yield *b }()); else yield ''foo'' + x; } var obj = [1,2,3,[4,5,[6,7,8],9],10]; console.log([...flat(obj)]);

.as-console-wrapper { max-height: 100% !important; top: 0; }


Podría reducir la matriz al generador. Pero esto se ve peor que el lazo para mí (aunque es funcional :))

var obj = [1, 2, 3, [4, 5, [6, 7, 8], 9], 10] function* flat(x) { if (Array.isArray(x)) yield * x.reduceRight( (f, y) => function*() { yield * flat(y); yield * f() }, function*() {} )() else yield ''foo'' + x; } console.log([...flat(obj)])


puede ser algo así como

var obj = [1, 2, 3, [4, 5, [6, 7, 8], 9], 10]; function* flat(x) { if (Array.isArray(x)) { yield x.map(v => { return [...flat(v)].join(); }); } else yield "foo" + x; } console.log([...flat(obj)]);


¿Hay alguna manera de escribirlo funcionalmente, sin bucles?

No en realidad no. (Por supuesto, siempre puede optar por la recursión, pero cuestionaré la utilidad de ese enfoque).

Lo que estamos buscando son combinadores funcionales para iteradores:

function* of(x) { // also known as `pure` or `return` yield x; } function map(f) { return function* (xs) { // also known as `fmap` for (const x of xs) yield f(x); } function* join(xss) { // also known as `concat` (not `append`!) or `flatten` (but non-recursive!) for (const xs of xss) for (const x of xs) yield x; } function chain(f) { return function* (xs) { // also known as `concatMap` or `bind` for (const x of xs) const ys = f(x); for (const y of ys) yield y; } // or const chain = f => compose(concat, map(f)) :-)

Ahora podemos tratar los iteradores como una mónada y no preocuparnos más por la implementación.

Como puede ver, no he usado la sintaxis yield* xs arriba que es (básicamente) solo azúcar para

for (const x of xs) yield x;

Lo que se ve extraño en su implementación es la disparidad entre el bucle externo y el no bucle interno. En un mundo óptimo, habría una sintaxis de yield** que hacía lo que join hace, pero no hay. Así que solo podemos implementar su función muy bien con las funciones auxiliares anteriores:

function* flat(x) { if (Array.isArray(x)) yield* chain(flat)(x); else yield* of(''foo'' + x); // foreshadowing }

o solo

function flat(x) { return Array.isArray(x) ? chain(flat)(x) : of(''foo'' + x); }


Puede usar parámetros de reposo ... y verificar la longitud de la matriz de reposo para otra llamada del generador

function* flat(a, ...r) { if (Array.isArray(a)) { yield* flat(...a); } else { yield ''foo'' + a; } if (r.length) { yield* flat(...r); } } var obj = [1, 2, 3, [4, 5, [6, 7, 8], 9], 10]; console.log([...flat(obj)])

.as-console-wrapper { max-height: 100% !important; top: 0; }

Un enfoque similar pero con un generador de spread para llamar al generador entregado con los valores de propagación.

function* spread(g, a, ...r) { yield* g(a); if (r.length) { yield* spread(g, ...r); } } function* flat(a) { if (Array.isArray(a)) { yield* spread(flat, ...a); } else { yield ''foo'' + a; } } var obj = [1, 2, 3, [4, 5, [6, 7, 8], 9], 10]; console.log([...flat(obj)])

.as-console-wrapper { max-height: 100% !important; top: 0; }