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ça

https://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 igreja

Como 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 JavaScript

O 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 user633183

eu 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ê.

questionAnswers(4)

yourAnswerToTheQuestion