2021.02.19 05:38 reprezentacja Churcha w javaskrypcie

Jakiś czas temu dla zabawy spróbowałem zaimplementować w Javaskrypcie reprezentację Churcha liczb naturalnych. Proszę, oto ona:
const zero = (funkcja, start) => start
const nastepnik = czego => ((funkcja, start) => funkcja(czego(funkcja, start)))

const jeden = nastepnik(zero)
const dwa = nastepnik(jeden)
const trzy = nastepnik(dwa)

const gwiazdki = liczba => liczba(zapis => zapis + '*', '')

const dodaj = (a, b) => a(nastepnik, b)
const pomnoz = (a, b) => a(x => dodaj(x, b), zero)

const prawda = (a, b) => a
const falsz = (a, b) => b
const boolNaNapis = b => b('prawda', 'fałsz')
const czyZero = (liczba) => liczba(_ => falsz, prawda)
const oraz = (a, b) => a(b(prawda, falsz), falsz)
const lub = (a, b) => a(prawda, b(prawda, falsz))
const nie = (a) => a(falsz, prawda)

const para = (a, b) => (selektor => selektor(a, b))

const poprzednik = liczba => {
    // każda para ma dwa elementy: pewną liczbę oraz jej następnik
    const dojdzParamiDoLiczby = liczba => liczba(
        poprzedniaPara => {
            const czyPierwszaPara = oraz(czyZero(poprzedniaPara(prawda)), czyZero(poprzedniaPara(falsz)))
            return czyPierwszaPara(para(zero, jeden), para(nastepnik(poprzedniaPara(prawda)), nastepnik(poprzedniaPara(falsz))))
        },
        para(zero, zero)
    )
    return dojdzParamiDoLiczby(liczba)(prawda)
}

const odejmij = (a, b) => b(poprzednik, a)

// Tak się oczywiście nie da: zapomnij o rekurencji, jak nie masz ani kawałka leniwej ewaluacji.
/*
const czyMniejsza = (a, b) => oraz(czyZero(a), czyZero(b))(
    falsz,
    czyZero(a)(
        prawda,
        czyZero(
            b,
            czyMniejsza(poprzednik(a), poprzednik(b))
        )
    )
)
*/

const petlaZeStopem = (ileRazy, coZrobic, sprawdzCzyZatrzymac, stanPoczatkowy) => ileRazy(
    poprzedniaPara => {
        const poprzedniStan = poprzedniaPara(prawda)
        const poprzednieCzyZatrzymac = poprzedniaPara(falsz)
        return poprzednieCzyZatrzymac(
            poprzedniaPara,
            (() => {
                const czyZatrzymac = sprawdzCzyZatrzymac(poprzedniStan)
                const nowyStan = coZrobic(poprzedniStan)
                return para(nowyStan, czyZatrzymac)
            })()
        )
    },
    para(stanPoczatkowy, falsz)
)

const czyRowne = (a, b) => {
    const sprawdzCzyRowne = (a, b) => petlaZeStopem(
        dodaj(jeden, dodaj(a, b)), // jeśli nie dodam tej jedynki, to jeli oba argumenty będą zerami, nie wykona się ani jeden obieg pętli i nie dowiemy się, że są równe
        poprzedniStan => {
            const licznikA = poprzedniStan(prawda)(prawda)
            const licznikB = poprzedniStan(prawda)(falsz)
            const rowne = oraz(czyZero(licznikA), czyZero(licznikB))
            return para(para(poprzednik(licznikA), poprzednik(licznikB)), rowne)
        },
        poprzedniStan =>  {
            const licznikA = poprzedniStan(prawda)(prawda)
            const licznikB = poprzedniStan(prawda)(falsz)
            return lub(czyZero(licznikA), czyZero(licznikB))
        },
        para(para(a, b), falsz)
    )
    return sprawdzCzyRowne(a, b)(prawda)(falsz)
}

const czyWieksze = (a, b) => oraz(
    nie(czyRowne(a, b)),
    czyZero(odejmij(b, a))
)

const czyMniejsze = (a, b) => oraz(
    nie(czyRowne(a, b)),
    czyZero(odejmij(a, b))
)

const podzielZReszta = (dzielna, dzielnik) => {
    const szukajIlorazuIReszty = (dzielna, dzielnik) => petlaZeStopem(
        dzielna,
        poprzedniStan => {
            const licznikDzielnej = poprzedniStan(prawda)(prawda)
            const dzielnik = poprzedniStan(prawda)(falsz)
            const dotychczasowyIloraz = poprzedniStan(falsz)(prawda)
            const licznikDzielnejMniejszyOdDzielnika = czyMniejsze(licznikDzielnej, dzielnik)
            return licznikDzielnejMniejszyOdDzielnika(
                para(para(licznikDzielnej, dzielnik), para(dotychczasowyIloraz, licznikDzielnej)),
                para(para(odejmij(licznikDzielnej, dzielnik), dzielnik), para(nastepnik(dotychczasowyIloraz), zero))
            )
        },
        poprzedniStan => {
            const dzielna = poprzedniStan(prawda)(prawda)
            const dzielnik = poprzedniStan(prawda)(falsz)
            return czyMniejsze(dzielna, dzielnik)
        },
        para(para(dzielna, dzielnik), para(zero, zero))
    )
    return szukajIlorazuIReszty(dzielna, dzielnik)(prawda)(falsz)
}

const czyPierwsza = liczba => {
    return poprzednik(poprzednik(liczba))(
        aktualnaPara => {
            const aktualnyDzielnik = aktualnaPara(prawda)
            const dotychczasowyWynik = aktualnaPara(falsz)
            const nieDzieliSie = nie(czyZero(podzielZReszta(liczba, aktualnyDzielnik)(falsz)))
            const nowyWynik = oraz(dotychczasowyWynik, nieDzieliSie)
            return para(nastepnik(aktualnyDzielnik), nowyWynik)
        },
        para(dwa, prawda)
    )(falsz)
}

// tu kończy się prawdziwy kod, a zaczyna się sprawdzanie, czy to wszystko dobrze działa

console.log(gwiazdki(trzy))
const piec = dodaj(dwa, trzy)
console.log(gwiazdki(piec))
console.log(gwiazdki(pomnoz(trzy, piec)))
console.log(boolNaNapis(prawda))
console.log(boolNaNapis(falsz))
console.log(boolNaNapis(czyZero(zero)))
console.log(boolNaNapis(czyZero(trzy)))
console.log(boolNaNapis(oraz(czyZero(zero), czyZero(zero))))
console.log(boolNaNapis(oraz(czyZero(zero), czyZero(trzy))))
console.log(boolNaNapis(lub(czyZero(zero), czyZero(trzy))))
console.log('-----')
const mojaPara = para(3, 5)
console.log(mojaPara(prawda))
console.log(mojaPara(falsz))
console.log(gwiazdki(poprzednik(piec)))
console.log(gwiazdki(odejmij(piec, dwa)))
console.log(boolNaNapis(czyRowne(zero, trzy)))
console.log(boolNaNapis(czyWieksze(trzy, zero)))
console.log(boolNaNapis(czyWieksze(trzy, trzy)))
console.log(boolNaNapis(czyMniejsze(trzy, trzy)))
console.log(boolNaNapis(czyMniejsze(dwa, trzy)))
console.log(boolNaNapis(czyMniejsze(piec, trzy)))
const zapis = liczba => liczba(x => x + 1, 0)
const wynik = podzielZReszta(piec, trzy)
const iloraz = wynik(prawda)
const reszta = wynik(falsz)
console.log(zapis(iloraz))
console.log(zapis(reszta))
console.log(boolNaNapis(czyPierwsza(dodaj(piec, jeden))))
console.log(boolNaNapis(czyPierwsza(dodaj(piec, dwa))))


komentarze:

ksywa:

tu wpisz cyfrę cztery: (to takie zabezpieczenie antyspamowe)

komentarze wulgarne albo co mi się nie spodobają będę kasował


powrot na strone glowna

RSS