Codifica della Chiesa - Church encoding

In matematica , la codifica di Church è un mezzo per rappresentare dati e operatori nel lambda calcolo . I numeri della Chiesa sono una rappresentazione dei numeri naturali utilizzando la notazione lambda. Il metodo prende il nome da Alonzo Church , che per primo ha codificato i dati nel calcolo lambda in questo modo.

I termini che di solito sono considerati primitivi in ​​altre notazioni (come interi, booleani, coppie, elenchi e unioni con tag) sono mappati a funzioni di ordine superiore sotto la codifica Church. La tesi di Church-Turing afferma che qualsiasi operatore calcolabile (ei suoi operandi) può essere rappresentato con la codifica di Church. Nel lambda calcolo non tipizzato l'unico tipo di dati primitivo è la funzione.

La codifica Church non è intesa come un'implementazione pratica di tipi di dati primitivi. Il suo uso è mostrare che altri tipi di dati primitivi non sono necessari per rappresentare alcun calcolo. La completezza è rappresentativa. Sono necessarie funzioni aggiuntive per tradurre la rappresentazione in tipi di dati comuni, per la visualizzazione alle persone. Non è possibile in generale decidere se due funzioni sono estensionalmente uguali a causa dell'indecidibilità dell'equivalenza dal teorema di Church . La traduzione può applicare la funzione in qualche modo per recuperare il valore che rappresenta o cercare il suo valore come un termine lambda letterale.

Il calcolo lambda viene solitamente interpretato come l'uso dell'uguaglianza intensionale . Ci sono potenziali problemi con l'interpretazione dei risultati a causa della differenza tra la definizione intensionale ed estensionale di uguaglianza.

numeri della chiesa

I numeri della chiesa sono le rappresentazioni dei numeri naturali sotto la codifica della chiesa. La funzione di ordine superiore che rappresenta il numero naturale n è una funzione che mappa qualsiasi funzione alla sua composizione n volte . In termini più semplici, il "valore" del numero è equivalente al numero di volte in cui la funzione incapsula il suo argomento.

Tutti i numeri di chiesa sono funzioni che accettano due parametri. I numeri di chiesa 0 , 1 , 2 , ..., sono definiti come segue nel lambda calcolo .

Partendo da 0 non applicando affatto la funzione, procedi con 1 applicando la funzione una volta, 2 applicando la funzione due volte, 3 applicando la funzione tre volte, ecc .:

Il numero di chiesa 3 rappresenta l'azione di applicare una data funzione tre volte a un valore. La funzione fornita viene prima applicata a un parametro fornito e quindi successivamente al proprio risultato. Il risultato finale non è il numero 3 (a meno che il parametro fornito non sia 0 e la funzione sia una funzione successore ). La funzione stessa, e non il suo risultato finale, è il numero di Chiesa 3 . Il numero 3 della Chiesa significa semplicemente fare qualsiasi cosa tre volte. È una dimostrazione ostensiva di cosa si intende per "tre volte".

Calcolo con i numeri della Chiesa

Le operazioni aritmetiche sui numeri possono essere rappresentate da funzioni sui numeri di Chiesa. Queste funzioni possono essere definite in lambda calcolo o implementate nella maggior parte dei linguaggi di programmazione funzionali (vedi conversione di espressioni lambda in funzioni ).

La funzione di addizione utilizza l'identità .

La funzione successore è -equivalente a .

La funzione di moltiplicazione utilizza l'identità .

La funzione di elevamento a potenza è data dalla definizione dei numeri di Chiesa, . Nella definizione sostituire per ottenere e,

che dà l'espressione lambda,

La funzione è più difficile da capire.

Un numero di Chiesa applica una funzione n volte. La funzione predecessore deve restituire una funzione che applica il suo parametro n - 1 volte. Ciò si ottiene costruendo un contenitore attorno a f e x , che viene inizializzato in modo tale da omettere l'applicazione della funzione la prima volta. Vedi predecessore per una spiegazione più dettagliata.

La funzione di sottrazione può essere scritta in base alla funzione precedente.

Tabella delle funzioni sui numeri della Chiesa

Funzione Algebra Identità Definizione della funzione Espressioni lambda
Successore ...
aggiunta
Moltiplicazione
elevazione a potenza
Predecessore *

Sottrazione * ...

* Nota che nella codifica della Chiesa,

Derivazione della funzione predecessore

La funzione precedente utilizzata nella codifica della Chiesa è,

.

Per costruire il predecessore abbiamo bisogno di un modo per applicare la funzione 1 in meno tempo. Un numero n applica la funzione f n volte a x . La funzione predecessore deve utilizzare il numero n per applicare la funzione n -1 volte.

Prima di implementare la funzione predecessore, ecco uno schema che racchiude il valore in una funzione contenitore. Definiremo nuove funzioni da usare al posto di f e x , chiamate inc e init . La funzione contenitore è chiamata value . Il lato sinistro della tabella mostra un numero n applicato a inc e init .

La regola generale di ricorrenza è,

Se c'è anche una funzione per recuperare il valore dal contenitore (chiamata extract ),

Quindi estrarre può essere usato per definire la funzione samenum come,

La funzione samenum non è intrinsecamente utile. Tuttavia, poiché inc delega la chiamata di f al suo argomento contenitore, possiamo fare in modo che sulla prima applicazione inc riceva un contenitore speciale che ignori il suo argomento consentendo di saltare la prima applicazione di f . Chiama questo nuovo contenitore iniziale const . Il lato destro della tabella sopra mostra le espansioni di n inc const . Quindi sostituendo init con const nell'espressione per la stessa funzione otteniamo la funzione predecessore,

Come spiegato di seguito le funzioni inc , init , const , value ed extract possono essere definite come,

Che dà l'espressione lambda per pred as,

Contenitore di valore

Il contenitore del valore applica una funzione al suo valore. è definito da,

così,

Inc

La funzione inc dovrebbe prendere un valore contenente v e restituire un nuovo valore contenente fv .

Lasciando g il contenitore del valore,

poi,

così,

Estratto

Il valore può essere estratto applicando la funzione identità,

Usando io ,

così,

Const

Per implementare pred la funzione init viene sostituita con la const che non si applica f . Abbiamo bisogno di const per soddisfare,

Che è soddisfatto se,

O come espressione lambda,

Un altro modo di definire pred

Pred può anche essere definito utilizzando le coppie:

Questa è una definizione più semplice, ma porta a un'espressione più complessa per pred. L'espansione per :

Divisione

La divisione dei numeri naturali può essere attuata da,

Il calcolo richiede molte riduzioni beta. A meno che non si faccia la riduzione a mano, questo non importa molto, ma è preferibile non dover fare questo calcolo due volte. Il predicato più semplice per testare i numeri è IsZero, quindi considera la condizione.

Ma questa condizione è equivalente a , non . Se si usa questa espressione, la definizione matematica di divisione data sopra viene tradotta in funzione sui numeri di Chiesa come,

Come desiderato, questa definizione ha una singola chiamata a . Tuttavia il risultato è che questa formula fornisce il valore di .

Questo problema può essere corretto aggiungendo 1 a n prima di chiamare divide . La definizione di divisione è quindi,

divide1 è una definizione ricorsiva. Il combinatore Y può essere utilizzato per implementare la ricorsione. Crea una nuova funzione chiamata div by;

  • Nel lato sinistro
  • Nel lato destro

ottenere,

Quindi,

dove,

Dà,

O come testo, usando \ per λ ,

divide = (\n.((\f.(\x.x x) (\x.f (x x))) (\c.\n.\m.\f.\x.(\d.(\n.n (\x.(\a.\b.b)) (\a.\b.a)) d ((\f.\x.x) f x) (f (c d m f x))) ((\m.\n.n (\n.\f.\x.n (\g.\h.h (g f)) (\u.x) (\u.u)) m) n m))) ((\n.\f.\x. f (n f x)) n))

Ad esempio, 9/3 è rappresentato da

divide (\f.\x.f (f (f (f (f (f (f (f (f x))))))))) (\f.\x.f (f (f x)))

Usando un calcolatore di lambda calcolo, l'espressione sopra si riduce a 3, usando l'ordine normale.

\f.\x.f (f (f (x)))

Numeri firmati

Un approccio semplice per estendere Church Numeri di numeri firmato è usare una coppia Chiesa, contenente numeri Chiesa rappresentano un positivo ed un valore negativo. Il valore intero è la differenza tra i due numeri di Chiesa.

Un numero naturale viene convertito in un numero con segno da,

La negazione viene eseguita scambiando i valori.

Il valore intero è rappresentato più naturalmente se una delle coppie è zero. La funzione OneZero realizza questa condizione,

La ricorsione può essere implementata utilizzando il combinatore Y,

Più e meno

L'addizione è definita matematicamente sulla coppia da,

L'ultima espressione è tradotta in lambda calcolo come,

Allo stesso modo la sottrazione è definita,

dando,

Moltiplicare e dividere

La moltiplicazione può essere definita da,

L'ultima espressione è tradotta in lambda calcolo come,

Una definizione simile è data qui per la divisione, tranne che in questa definizione, un valore in ogni coppia deve essere zero (vedi OneZero sopra). La funzione divZ ci permette di ignorare il valore che ha una componente zero.

divZ viene quindi utilizzato nella formula seguente, che è la stessa della moltiplicazione, ma con mult sostituito da divZ .

Numeri razionali e reali

I numeri reali razionali e calcolabili possono anche essere codificati nel lambda calcolo. I numeri razionali possono essere codificati come una coppia di numeri con segno. I numeri reali calcolabili possono essere codificati mediante un processo di limitazione che garantisce che la differenza dal valore reale differisca di un numero che può essere ridotto quanto necessario. I riferimenti forniti descrivono software che potrebbe, in teoria, essere tradotto in lambda calcolo. Una volta definiti i numeri reali, i numeri complessi vengono codificati naturalmente come una coppia di numeri reali.

I tipi di dati e le funzioni sopra descritti dimostrano che qualsiasi tipo di dati o calcolo può essere codificato nel lambda calcolo. Questa è la tesi di Church-Turing .

Traduzione con altre rappresentazioni

La maggior parte delle lingue del mondo reale supporta gli interi nativi della macchina; le funzioni di chiesa e non di chiesa convertono tra numeri interi non negativi e i loro corrispondenti numeri di chiesa. Le funzioni sono date qui in Haskell , dove la \corrisponde al del Lambda calcolo. Le implementazioni in altre lingue sono simili.

type Church a = (a -> a) -> a -> a

church :: Integer -> Church Integer
church 0 = \f -> \x -> x
church n = \f -> \x -> f (church (n-1) f x)

unchurch :: Church Integer -> Integer
unchurch cn = cn (+ 1) 0

Booleani della chiesa

I booleani della chiesa sono la codifica della chiesa dei valori booleani vero e falso. Alcuni linguaggi di programmazione li usano come modello di implementazione per l'aritmetica booleana; esempi sono Smalltalk e Pico .

La logica booleana può essere considerata come una scelta. La codifica della Chiesa del vero e del falso sono funzioni di due parametri:

  • true sceglie il primo parametro.
  • false sceglie il secondo parametro.

Le due definizioni sono conosciute come Church Booleans:

Questa definizione consente ai predicati (cioè alle funzioni che restituiscono valori logici ) di agire direttamente come clausole if. Una funzione che restituisce un valore booleano, che viene quindi applicato a due parametri, restituisce il primo o il secondo parametro:

restituisce then-clause se predicato-x restituisce true , e else-clause se predicato-x restituisce false .

Poiché true e false scelgono il primo o il secondo parametro, possono essere combinati per fornire operatori logici. Nota che ci sono più implementazioni possibili di not .

Qualche esempio:

predicati

Un predicato è una funzione che restituisce un valore booleano. Il predicato più fondamentale è , che restituisce se il suo argomento è il numero di Chiesa e se il suo argomento è qualsiasi altro numero di Chiesa:

Il predicato seguente verifica se il primo argomento è minore o uguale al secondo:

,

A causa dell'identità,

Il test per l'uguaglianza può essere implementato come,

coppie di chiese

Le coppie di chiese sono la codifica di chiesa del tipo coppia (due tuple). La coppia è rappresentata come una funzione che accetta un argomento di funzione. Quando viene fornito il suo argomento, applicherà l'argomento ai due componenti della coppia. La definizione in lambda calcolo è,

Per esempio,

Elenco codifiche

Una lista ( immutabile ) è costruita dai nodi della lista. Le operazioni di base sulla lista sono;

Funzione Descrizione
zero Costruisci una lista vuota.
isil Verifica se l'elenco è vuoto.
contro Anteponi un dato valore a un elenco (possibilmente vuoto).
testa Ottieni il primo elemento della lista.
coda Prendi il resto della lista.

Di seguito diamo quattro diverse rappresentazioni degli elenchi:

  • Costruisci ogni nodo di lista da due coppie (per consentire liste vuote).
  • Costruisci ogni nodo della lista da una coppia.
  • Rappresenta l'elenco utilizzando la funzione di piegatura a destra .
  • Rappresenta l'elenco usando la codifica di Scott che accetta casi di espressioni di corrispondenza come argomenti

Due coppie come nodo di lista

Una lista non vuota può essere implementata da una coppia di chiese;

  • Il primo contiene la testa.
  • Il secondo contiene la coda.

Tuttavia questo non fornisce una rappresentazione della lista vuota, perché non c'è un puntatore "null". Per rappresentare null, la coppia può essere avvolta in un'altra coppia, dando valori liberi,

  • Primo : è il puntatore nullo (elenco vuoto).
  • Second.First contiene la testa.
  • Second.Second contiene la coda.

Usando questa idea, le operazioni di base dell'elenco possono essere definite in questo modo:

Espressione Descrizione
Il primo elemento della coppia è vero, il che significa che l'elenco è nullo.
Recupera l'indicatore nullo (o elenco vuoto).
Crea un nodo di lista, che non è null, e assegnagli una testa h e una coda t .
second.first è la testa.
second.second è la coda.

In un nodo nullo il secondo non è mai accessibile, a condizione che head e tail vengano applicati solo a liste non vuote.

Una coppia come nodo di lista

In alternativa, definire

dove l'ultima definizione è un caso speciale del generale

Rappresenta la lista usando la piega a destra

In alternativa alla codifica tramite coppie di Chiesa, è possibile codificare un elenco identificandolo con la sua funzione di piegatura a destra . Ad esempio, un elenco di tre elementi x, yez può essere codificato da una funzione di ordine superiore che, applicata a un combinatore ce un valore n, restituisce cx (cy (czn)).

Questa rappresentazione dell'elenco può essere data di tipo in System F .

Rappresenta l'elenco usando la codifica Scott

Una rappresentazione alternativa è la codifica Scott, che utilizza l'idea delle continuazioni e può portare a un codice più semplice. (vedi anche codifica Mogensen-Scott ).

In questo approccio, utilizziamo il fatto che gli elenchi possono essere osservati utilizzando l'espressione di corrispondenza del modello. Ad esempio, utilizzando la notazione Scala , se listdenota un valore di tipo Listcon elenco vuoto Nile costruttore Cons(h, t), possiamo ispezionare l'elenco e calcolare nilCodenel caso in cui l'elenco sia vuoto e consCode(h, t)quando l'elenco non è vuoto:

list match {
  case Nil        => nilCode
  case Cons(h, t) => consCode(h,t)
}

La 'lista' è data da come agisce su 'nilCode' e 'consCode'. Definiamo quindi una lista come una funzione che accetta tali 'nilCode' e 'consCode' come argomenti, così che invece del pattern match sopra possiamo semplicemente scrivere:

Indichiamo con 'n' il parametro corrispondente a 'nilCode' e con 'c' il parametro corrispondente a 'consCode'. La lista vuota è quella che restituisce l'argomento nil:

La lista non vuota con testa 'h' e coda 't' è data da

Più in generale, un tipo di dato algebrico con alternative diventa una funzione con parametri. Quando il costruttore ha argomenti, anche il parametro corrispondente della codifica accetta argomenti.

La codifica Scott può essere eseguita nel calcolo lambda non tipizzato, mentre il suo utilizzo con i tipi richiede un sistema di tipi con ricorsione e polimorfismo di tipo. Un elenco con tipo di elemento E in questa rappresentazione che viene utilizzato per calcolare valori di tipo C avrebbe la seguente definizione di tipo ricorsivo, dove '=>' indica il tipo di funzione:

type List = 
  C =>                    // nil argument
  (E => List => C) =>     // cons argument
  C                       // result of pattern matching

Un elenco che può essere usato per calcolare tipi arbitrari avrebbe un tipo che quantifica su C. Un elenco generico in Eprenderebbe anche Ecome argomento di tipo.

Guarda anche

Appunti

  1. ^ Questa formula è la definizione di un numero di Chiesa n con f -> m, x -> f.
  2. ^ Allison, Lloyd. "Lambda Calcolo Interi" .
  3. ^ Bauer, Andrej. "La risposta di Andrej a una domanda; "Rappresentare numeri negativi e complessi usando il lambda calcolo " " .
  4. ^ "Aritmetica reale esatta" . Haskell .
  5. ^ Bauer, Andrej. "Software di calcolo dei numeri reali" .
  6. ^ Pierce, Benjamin C. (2002). Tipi e linguaggi di programmazione . MIT Press . P. 500. ISBN 978-0-262-16209-8.
  7. ^ Tromp, John (2007). "14. Calcolo lambda binario e logica combinatoria". In Calude, Cristian S (a cura di). Casualità e complessità, da Leibniz a Chaitin . Scientifico mondiale. pp. 237-262. ISBN 978-981-4474-39-9.
    Come PDF: Tromp, John (14 maggio 2014). "Calcolo binario Lambda e logica combinatoria" (PDF) . Estratto il 24-11-2017 .
  8. ^ Jansen, Jan Martin (2013). "Programmazione nel λ-Calculus: Dalla Chiesa a Scott e ritorno". LNCS . 8106 : 168–180. doi : 10.1007/978-3-642-40355-2_12 .

Riferimenti