Codificação da igreja de listas usando dobras à direita e listas de diferenças
Aqui está a pergunta seqüencial depois
Como armazenar dados de uma cadeia funcional da Lista Monoidal?
e
Extraindo dados de uma cadeia de funções sem matrizes
e aqui gostaria de expressar meu respeito e apreço pelos colaboradores das minhas perguntas, especialmente por @Aadit M Shah e @ user633183
Agora, esta questão está aberta para esclarecer as semelhanças e diferenças ou relação entreLista de diferença eLista da igreja.
Lista de diferençahttps://stackoverflow.com/a/51320041/6440264
A lista de diferença é uma função que pega uma lista e acrescenta outra lista a ela. Por exemplo:
const concat = xs => ys => xs.concat(ys); // This creates a difference list.
const f = concat([1,2,3]); // This is a difference list.
console.log(f([])); // You can get its value by applying it to the empty array.
console.log(f([4,5,6])); // You can also apply it to any other array.
O legal das listas de diferenças é que elas formam um monóide porque são apenasendofunções:
const id = x => x; // The identity element is just the id function.
const compose = (f, g) => x => f(g(x)); // The binary operation is composition.
compose(id, f) = f = compose(f, id); // identity law
compose(compose(f, g), h) = compose(f, compose(g, h)); // associativity law
Melhor ainda, você pode agrupá-los em uma pequena classe, na qual a composição da função é o operador de ponto:
class DList {
constructor(f) {
this.f = f;
this.id = this;
}
cons(x) {
return new DList(ys => this.f([x].concat(ys)));
}
concat(xs) {
return new DList(ys => this.f(xs.concat(ys)));
}
apply(xs) {
return this.f(xs);
}
}
const id = new DList(x => x);
const cons = x => new DList(ys => [x].concat(ys)); // Construct DList from value.
const concat = xs => new DList(ys => xs.concat(ys)); // Construct DList from array.
id . concat([1, 2, 3]) = concat([1, 2, 3]) = concat([1, 2, 3]) . id // identity law
concat([1, 2]) . cons(3) = cons(1) . concat([2, 3]) // associativity law
Você pode usar oapply
método para recuperar o valor doDList
do seguinte modo:
class DList {
constructor(f) {
this.f = f;
this.id = this;
}
cons(x) {
return new DList(ys => this.f([x].concat(ys)));
}
concat(xs) {
return new DList(ys => this.f(xs.concat(ys)));
}
apply(xs) {
return this.f(xs);
}
}
const id = new DList(x => x);
const cons = x => new DList(ys => [x].concat(ys));
const concat = xs => new DList(ys => xs.concat(ys));
const identityLeft = id . concat([1, 2, 3]);
const identityRight = concat([1, 2, 3]) . id;
const associativityLeft = concat([1, 2]) . cons(3);
const associativityRight = cons(1) . concat([2, 3]);
console.log(identityLeft.apply([])); // [1,2,3]
console.log(identityRight.apply([])); // [1,2,3]
console.log(associativityLeft.apply([])); // [1,2,3]
console.log(associativityRight.apply([])); // [1,2,3]
Uma vantagem do uso de listas de diferenças em relação às listas regulares (listas funcionais, e não matrizes JavaScript) é que a concatenação é mais eficiente porque as listas são concatenadas da direita para a esquerda. Portanto, ele não copia os mesmos valores repetidamente se você estiver concatenando várias listas.
Lista de codificação da igrejaComo alternativa à codificação usando pares da Igreja, uma lista pode ser codificada identificando-a com sua função de dobra à direita. Por exemplo, uma lista de três elementos x, ye z pode ser codificada por uma função de ordem superior que, quando aplicada a um combinador c e um valor n, retorna c x (c y (c z n)).
https://stackoverflow.com/a/51420884/6440264
solução de user633183 é brilhante. Ele usa oCodificação da igreja de listas usando dobras à direita para aliviar a necessidade de continuações, resultando em um código mais simples e fácil de entender. Aqui está a solução dela, modificada para fazerfoldr
parece quefoldl
:
const L = g => function (x, a) {
switch (arguments.length) {
case 1: return L((f, a) => f(g(f, a), x));
case 2: return g(x, a);
}
};
const A = L((f, a) => a);
const xs = A(1)(2)(3)(4)(5);
console.log(xs((x, y) => x + y, 0)); // 15
console.log(xs((x, y) => x * y, 1)); // 120
console.log(xs((a, x) => a.concat(x), [])); // [1,2,3,4,5]
Aquig
é a lista codificada da Igreja acumulada até agora. Inicialmente, é a lista vazia. Chamandog
dobra-o da direita. No entanto, também construímos a lista da direita. Portanto, parece que estamos construindo a lista e dobrando-a da esquerda por causa da maneira como a escrevemos.
Se todas essas funções o confundem, o que o user633183 está realmente fazendo é:
const L = g => function (x, a) {
switch (arguments.length) {
case 1: return L([x].concat(g));
case 2: return g.reduceRight(x, a);
}
};
const A = L([]);
const xs = A(1)(2)(3)(4)(5);
console.log(xs((x, y) => x + y, 0)); // 15
console.log(xs((x, y) => x * y, 1)); // 120
console.log(xs((a, x) => a.concat(x), [])); // [1,2,3,4,5]
Como você pode ver, ela está construindo a lista ao contrário e depois usandoreduceRight
dobrar a lista para trás. Portanto, parece que você está construindo e dobrando a lista para a frente.
O que eu gosto de ver na Lista de Diferenças é
Parece natural e direto de entender.Com concatenação (achatar), forma monoidesO elemento de identidade é uma função de identidade e não é necessário fornecer valores iniciais externos.Do que eu não gosto
Pelo menos, o código de exemplo fornecido depende da matriz JavaScriptO que eu gosto / detesto na Lista da Igreja é, de fato, o opoosito do que foi dito acima.
Eu gosto
É independente da implementação da matriz JavaScript e pode definir operações por si só:solução de user633183eu não gosto
Não sei por que não deve ser deixado, mas dobra à direita?uma lista pode ser codificada identificando-a com sua função de dobra à direita
Não está claro para a realização do Monoids
Especificamente, Nil não é um elemento Identity (= função de identidade) e o código de exemplo precisa de valores iniciais externos fornecidos.
Então, o que estou curioso é que existe alguma formalização da lista de Diferenças, como a lista da Igreja.
A especificação seria
Basicamente, é uma lista de diferenças
Independente da implementação do JavaScipt Array
O valor inicial é a função de identidade interna.
Thsnk você.