Como armazenar dados de uma cadeia funcional da Lista Monoidal?

Este é um tópico avançado da minha pergunta anterior aqui:

Como armazenar dados de uma cadeia funcional?

A breve ideia é

Uma função simples abaixo:

const L = a => L;

formulários

L
L(1)
L(1)(2)
...

Isso parece formar uma lista, mas os dados reais não são armazenados, portanto, se for necessário armazenar dados como [1,2], qual é a prática mais inteligente para executar a tarefa?

Uma das idéias de destaque é de @ user633183, que marquei como resposta aceita (consulte o link da pergunta), e outra versão da função ao curry também é fornecida pelo @ Matías Fidemraizer.

Então aqui vai:

const L = a => {
  const m = list => x => !x
    ? list
    : m([...list, x]);
  return m([])(a);
}; 

const list1 = (L)(1)(2)(3); //lazy : no data evaluation here
const list2 = (L)(4)(5)(6);

console.log(list1()) // now evaluated by the tail ()
console.log(list2())  

O que eu realmente gosto é a avaliação preguiçosa.

Embora a abordagem fornecida satisfaça o que mencionei, essa função perdeu a estrutura externa ou devo mencionar:

Estrutura algébrica
 const L = a => L;

lista de formulários e, mais fundamentalmente, nos fornece umaestrutura algébrica doelemento de identidade, potencialmente junto comMonoid ouMagma.

Deixou uma identidade à direita

Um dos exemplos mais fáceis de Monoids e identidade é o número e"Strings" e[Array] em JavaScript.

0 + a === a === a + 0
1 * a === a === a * 1

Em Strings, o quoate vazio"" é o elemento de identidade.

  "" + "Hello world" === "Hello world" === "Hello world" + ""

O mesmo vale para[Array].

O mesmo vale paraL:

(L)(a) === (a) === (a)(L)

const L = a => L;

const a = L(5); // number is wrapped or "lift" to Type:L
                // Similarity of String and Array
                // "5"  [5]

//left identity
console.log(
  (L)(a) === (a)    //true 
);
 
//right identity
console.log(
  (a) === (a)(L)    //true
); 

e a óbvia imutabilidade de identidade:

const L = a => L;
 
console.log(
  (L)(L) === (L)    //true
); 
console.log(
  (L)(L)(L) === (L)    //true
); 
console.log(
  (L)(L)(L)(L) === (L)    //true
); 

Também o abaixo:

const L = a => L;

const a = (L)(1)(2)(3);
const b = (L)(1)(L)(2)(3)(L);

 
console.log(
   (a) === (b)    //true 
);
 

Questões

Qual é a maneira mais inteligente ou elegante (muito funcional e sem mutações (semArray.push, também)) para implementarL que satisfaça três requisitos:

Requisito 0 - Identidade

Uma função simples:

const L = a => L;

já satisfaz a lei de identidade como já vimos.

Requisito 1 - método eval ()

ApesarL satisfaça a lei de identidade, não há método para acessar os dados listados / acumulados.

(As respostas fornecidas na minha pergunta anterior fornecem a capacidade de acumulação de dados, mas infringem a lei de identidade.)

A avaliação preguiçosa parece a abordagem correta, fornecendo uma especificação mais clara:

providenciareval método deL
const L = a => L; // needs to enhance to satisfy the requirements

const a = (L)(1)(2)(3);
const b = (L)(1)(L)(2)(3)(L);


console.log(
   (a) === (b)    //true 
);

console.log(
   (a).eval()    //[1, 2, 3]
);

console.log(
   (b).eval()    //[1, 2, 3]
);
Requisito 3 - Direito associativo monóide

Além da proeminente estrutura Identify, o Monoids também satisfazDireito associativo

(a * b) * c === a * b * c === a * (b * c)

Isso significa simplesmente "achatar a lista"; em outras palavras, a estrutura não contém listas aninhadas.

[a, [b, c]] não é bom.

Amostra:

const L = a => L; // needs to enhance to satisfy the requirements

const a = (L)(1)(2);
const b = (L)(3)(4);
const c = (L)(99);

const ab = (a)(b);
const bc = (b)(c);
const abc1 = (ab)(c);
const abc2 = (a)(bc);

console.log(
   abc1 === abc2  // true for Associative
);

console.log(
   (ab).eval()    //[1, 2, 3, 4]
);

console.log(
   (abc1).eval()   //[1, 2, 3, 4, 99]
);
console.log(
   (abc2).eval()   //[1, 2, 3, 4, 99]
);

Isso é tudo para 3 requisitos para implementarL como um monóide.

Esse é um grande desafio para a programação funcional para mim e, na verdade, tentei por um tempo, mas, fazendo as perguntas anteriores, é uma prática muito boa compartilhar meu próprio desafio, ouvir as pessoas e ler seu código elegante.

Obrigado.

questionAnswers(3)

yourAnswerToTheQuestion