Kyrkans kodning - Church encoding

I matematik är kyrkans kodning ett sätt att representera data och operatörer i lambda -kalkylen . De Kyrkans siffror är en representation av de naturliga talen med hjälp av lambda notation. Metoden är uppkallad efter Alonzo -kyrkan , som först kodade data i lambda -kalkylen på detta sätt.

Termer som vanligtvis anses primitiva i andra notationer (som heltal, booleaner, par, listor och taggade fackföreningar) mappas till högre ordningsfunktioner under kyrkans kodning. Den Church-Turings hypotes hävdar att någon beräkningsbar operatören (och dess operander) kan representeras enligt Church kodning. I den oskrivna lambda -kalkylen är funktionen den enda primitiva datatypen .

Kyrkans kodning är inte avsedd som en praktisk implementering av primitiva datatyper. Dess användning är att visa att andra primitiva datatyper inte krävs för att representera någon beräkning. Fullständigheten är representativ. Ytterligare funktioner behövs för att översätta representationen till vanliga datatyper för visning för människor. Det är i allmänhet inte möjligt att avgöra om två funktioner är extensivt lika på grund av att det inte går att bestämma likvärdighet från kyrkans sats . Översättningen kan tillämpa funktionen på något sätt för att hämta värdet den representerar, eller slå upp dess värde som en bokstavlig lambda -term.

Lambda calculus brukar tolkas som att den använder intensiv jämlikhet . Det finns potentiella problem med tolkningen av resultat på grund av skillnaden mellan den intensiva och extensiva definitionen av jämlikhet.

Kyrkliga siffror

Kyrkliga siffror är representationer av naturliga nummer under kyrkans kodning. Den högre ordningens funktion som representerar naturliga tal n är en funktion som avbildar varje funktion till dess n -faldig komposition . I enklare termer motsvarar siffrans "värde" det antal gånger funktionen inkapslar sitt argument.

Alla kyrkliga siffror är funktioner som har två parametrar. Kyrkans siffror 0 , 1 , 2 , ..., definieras enligt följande i lambda -beräkningen .

Börja med att 0 inte använder funktionen alls, fortsätt med 1 tillämpa funktionen en gång, 2 tillämpa funktionen två gånger, 3 tillämpa funktionen tre gånger, etc .:

Kyrkans siffra 3 representerar handlingen att tillämpa en given funktion tre gånger på ett värde. Den levererade funktionen tillämpas först på en levererad parameter och sedan successivt på sitt eget resultat. Slutresultatet är inte siffran 3 (om inte den angivna parametern råkar vara 0 och funktionen är en efterföljande funktion ). Själva funktionen, och inte dess slutresultat, är kyrkans siffra 3 . Kyrkans siffra 3 betyder helt enkelt att göra vad som helst tre gånger. Det är en påtaglig demonstration av vad som menas med "tre gånger".

Beräkning med kyrkliga siffror

Aritmetiska operationer på tal kan representeras av funktioner på kyrkans siffror. Dessa funktioner kan definieras i lambda -kalkyl eller implementeras på de flesta funktionella programmeringsspråk (se hur du konverterar lambda -uttryck till funktioner ).

Tilläggsfunktionen använder identiteten .

Efterföljarfunktionen är β-ekvivalent med .

Multiplikationsfunktionen använder identiteten .

Den exponentieringsfunktionen ges av definitionen av kyrkans siffror, . I definitionen ersätt för att få och,

vilket ger lambda uttryck,

Den funktionen är svårare att förstå.

En kyrklig siffra använder en funktion n gånger. Föregångarfunktionen måste returnera en funktion som tillämpar dess parameter n - 1 gånger. Detta uppnås genom att bygga en behållare runt f och x , som initieras på ett sätt som utelämnar tillämpningen av funktionen första gången. Se föregångaren för en mer detaljerad förklaring.

Subtraktionsfunktionen kan skrivas utifrån föregångarfunktionen.

Tabell över funktioner på kyrkliga siffror

Fungera Algebra Identitet Funktionsdefinition Lambda uttryck
Efterträdare ...
Tillägg
Multiplikation
Exponentiering
Föregångare *

Subtraktion * ...

* Observera att i kyrkans kodning,

Avledning av föregångarfunktionen

Föregångarfunktionen som används i kyrkans kodning är,

.

För att bygga föregångaren behöver vi ett sätt att tillämpa funktionen 1 färre tid. En siffra n tillämpar funktionen f n gånger på x . Föregångarfunktionen måste använda siffran n för att tillämpa funktionen n -1 gånger.

Innan du implementerar föregångarfunktionen, här är ett schema som omsluter värdet i en behållarfunktion. Vi kommer att definiera nya funktioner som ska användas istället för f och x , kallade inc och init . Behållarfunktionen kallas värde . Den vänstra sidan av tabellen visar en siffra n som tillämpas på inc och init .

Den allmänna återkommande regeln är,

Om det också finns en funktion för att hämta värdet från behållaren (kallat extrakt ),

Sedan kan extrakt användas för att definiera samma funktion som,

Den samenum funktion är inte i sig användbar. Men som inc delegater som anropar f till dess containerargument kan vi ordna att inc på den första applikationen får en speciell behållare som ignorerar dess argument så att den första applikationen av f kan hoppas över . Kalla denna nya initiala behållare konst . Höger sida av tabellen ovan visar expansioner av n inc const . Genom att ersätta init med const i uttrycket för samma funktion får vi föregångarfunktionen,

Som förklaras nedan kan funktionerna inc , init , const , värde och extrakt definieras som,

Vilket ger lambda -uttrycket för pred som,

Värdebehållare

Värdebehållaren tillämpar en funktion på dess värde. Det definieras av,

så,

Inc.

Den inc funktionen bör ta ett värde som innehåller v och returnera ett nytt värde som innehåller fv .

Låt g vara värdebehållaren,

sedan,

så,

Extrahera

Värdet kan extraheras genom att använda identitetsfunktionen,

Med I ,

så,

Konst

För att genomföra pred den init funktion ersätts med const som inte gäller f . Vi behöver konst för att tillfredsställa,

Vilket är tillfredsställt om,

Eller som ett lambda -uttryck,

Ett annat sätt att definiera pred

Pred kan också definieras med par:

Detta är en enklare definition, men leder till ett mer komplext uttryck för pred. Expansionen för :

Division

Uppdelning av naturliga nummer kan genomföras av,

Beräkning tar många betareduktioner. Om det inte görs för hand, spelar det ingen roll så mycket, men det är att föredra att inte behöva göra denna beräkning två gånger. Det enklaste predikatet för att testa siffror är IsZerotänk på villkoret.

Men detta villkor motsvarar , inte . Om detta uttryck används, översätts den matematiska definitionen av division som ges ovan till funktion på kyrkliga siffror som,

Som önskat har denna definition ett enda samtal till . Resultatet är dock att denna formel ger värdet av .

Detta problem kan åtgärdas genom att lägga till 1 till n innan du kallar divide . Definitionen av splittring är då,

divide1 är en rekursiv definition. Den Y Combinator kan användas för att implementera rekursion. Skapa en ny funktion som heter div by;

  • I vänster sida
  • I höger sida

att få,

Sedan,

var,

Ger,

Eller som text, med \ för λ ,

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))

Till exempel representeras 9/3 av

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

Med hjälp av en lambda -kalkylator minskar ovanstående uttryck till 3, med normal ordning.

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

Signerade nummer

Ett enkelt tillvägagångssätt för att utvidga kyrkans siffror till signerade nummer är att använda ett kyrkopar som innehåller kyrkosiffror som representerar ett positivt och ett negativt värde. Heltalet är skillnaden mellan de två kyrkans siffror.

Ett naturligt tal konverteras till ett signerat nummer med,

Negation utförs genom att byta värden.

Heltalet är mer naturligt representerat om ett av paret är noll. Den OneZero funktionen uppnår detta tillstånd,

Rekursionen kan implementeras med hjälp av Y -kombinatorn,

Plus och minus

Tillägg definieras matematiskt på paret av,

Det sista uttrycket översätts till lambda calculus som,

På samma sätt definieras subtraktion,

ger,

Multiplicera och dela

Multiplikation kan definieras av,

Det sista uttrycket översätts till lambda calculus som,

En liknande definition ges här för division, förutom i denna definition måste ett värde i varje par vara noll (se OneZero ovan). Den divZ Funktionen gör det möjligt att bortse från det värde som har ett nollkomponent.

divZ används sedan i följande formel, som är densamma som för multiplikation, men med mult ersatt av divZ .

Rationella och reella tal

Rationella och beräkningsbara reella tal kan också kodas i lambda -beräkning. Rationella nummer kan kodas som ett par signerade nummer. Beräkningsbara tal kan kodas av en begränsande process som garanterar att skillnaden från det verkliga värdet skiljer sig från ett tal som kan göras så litet som vi behöver. Referenserna beskriver programvara som i teorin kan översättas till lambda -kalkyl. När riktiga tal har definierats kodas naturligt komplexa tal som ett par riktiga tal.

Datatyperna och funktionerna som beskrivs ovan visar att vilken datatyp eller beräkning som helst kan kodas i lambda -kalkyl. Detta är Church-Turing-tesen .

Översättning med andra representationer

De flesta verkliga språk har stöd för maskinfödda heltal; de kyrkliga och unchurch funktioner konvertera mellan nonnegative heltal och deras motsvarande kyrkans siffror. Funktionerna ges här i Haskell , där \motsvarar λ i Lambda -kalkylen. Implementeringar på andra språk liknar varandra.

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

Kyrkobooleaner

Kyrkobooleaner är kyrkan som kodar för de booleska värdena sanna och falska. Vissa programmeringsspråk använder dessa som en implementeringsmodell för booleska räkningar; exempel är Smalltalk och Pico .

Boolsk logik kan betraktas som ett val. Kyrkans kodning av sant och falskt är funktioner av två parametrar:

  • true väljer den första parametern.
  • false väljer den andra parametern.

De två definitionerna är kända som Church Booleans:

Denna definition tillåter predikat (dvs. funktioner som returnerar logiska värden ) att direkt fungera som if-satser. En funktion som returnerar en booleska, som sedan tillämpas på två parametrar, returnerar antingen den första eller den andra parametern:

utvärderar till då-klausul om predikat-x utvärderas till sant , och till annat-klausul om predikat-x utvärderas till falskt .

Eftersom sant och falskt väljer den första eller andra parametern kan de kombineras för att tillhandahålla logiska operatörer. Observera att det finns flera möjliga implementeringar av inte .

Några exempel:

Predikat

Ett predikat är en funktion som returnerar ett booleskt värde. Det mest grundläggande predikatet är , som återkommer om dess argument är kyrkans siffra , och om dess argument är någon annan kyrkans siffra:

Följande predikat testar om det första argumentet är mindre än eller lika med det andra:

,

På grund av identiteten,

Testet för jämlikhet kan genomföras som,

Kyrkopar

Kyrkopar är kyrkans kodning av paret (två-tupel). Paret representeras som en funktion som tar ett funktionsargument. När den får sitt argument kommer den att tillämpa argumentet på parets två komponenter. Definitionen i lambda calculus är,

Till exempel,

Lista kodningar

En ( oföränderlig ) lista är konstruerad från listnoder. De grundläggande operationerna på listan är;

Fungera Beskrivning
noll Skapa en tom lista.
isnil Testa om listan är tom.
nackdelar Förbered ett visst värde till en (eventuellt tom) lista.
huvud Få det första elementet i listan.
svans Få resten av listan.

Vi ger fyra olika representationer av listor nedan:

  • Bygg varje listnod från två par (för att möjliggöra tomma listor).
  • Bygg varje listnod från ett par.
  • Representera listan med den högra vikningsfunktionen .
  • Representera listan med Scotts kodning som tar fall av matchuttryck som argument

Två par som listnod

En icke -undantagslista kan implementeras av ett par i kyrkan;

  • Först innehåller huvudet.
  • Andra innehåller svansen.

Detta ger dock inte en representation av den tomma listan, eftersom det inte finns någon "null" pekare. För att representera null kan paret vara inslaget i ett annat par, vilket ger fria värden,

  • Först - Är nollpekaren (tom lista).
  • För det andra. Först innehåller huvudet.
  • Second.Second innehåller svansen.

Med hjälp av denna idé kan de grundläggande listoperationerna definieras så här:

Uttryck Beskrivning
Det första elementet i paret är sant vilket betyder att listan är null.
Hämta null (eller tom lista) indikator.
Skapa en listnod, som inte är noll, och ge den ett huvud h och en svans t .
andra. först är huvudet.
andra. andra är svansen.

I en noll nod andra aldrig nås, förutsatt att huvud och svans endast tillämpas på nonempty listor.

Ett par som listnod

Alternativt definiera

där den sista definitionen är ett specialfall av generalen

Representera listan med högervikt

Som ett alternativ till kodningen med hjälp av kyrkkopplar kan en lista kodas genom att identifiera den med sin högra vikningsfunktion . Till exempel kan en lista med tre element x, y och z kodas av en högre ordningsfunktion som när den appliceras på en kombinator c och ett värde n returnerar cx (cy (czn)).

Denna lista representation kan viss typ i System F .

Representera listan med Scott -kodning

En alternativ representation är Scott -kodning, som använder tanken på fortsättningar och kan leda till enklare kod. (se även kodning Mogensen – Scott ).

I detta tillvägagångssätt använder vi det faktum att listor kan observeras med hjälp av mönster matchande uttryck. Om vi till exempel använder Scala -notation, om det listbetecknar ett värde av typen Listmed tom lista Niloch konstruktör kan Cons(h, t)vi inspektera listan och beräkna nilCodeom listan är tom och consCode(h, t)när listan inte är tom:

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

'Listan' ges av hur den fungerar på 'nilCode' och 'consCode'. Vi definierar därför en lista som en funktion som accepterar sådana 'nilCode' och 'consCode' som argument, så att vi istället för ovanstående mönstermatchning helt enkelt kan skriva:

Låt oss beteckna parametern som motsvarar 'nilCode' och 'c' den parameter som motsvarar 'consCode'. Den tomma listan är den som returnerar nollargumentet:

Listan som inte är tom med huvudet 'h' och svansen 't' ges av

Mer allmänt blir en algebraisk datatyp med alternativ en funktion med parametrar. När den konstruktören har argument, tar motsvarande parameter för kodningen också argument.

Scott -kodning kan göras i otypad lambda -kalkyl, medan dess användning med typer kräver ett typsystem med rekursion och typpolymorfism. En lista med elementtyp E i denna representation som används för att beräkna värden av typ C skulle ha följande definition av rekursiv typ, där '=>' betecknar funktionstyp:

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

En lista som kan användas för att beräkna godtyckliga typer skulle ha en typ som kvantifierar över C. En generisk lista Eskulle också ta Esom typargument.

Se även

Anteckningar

  1. ^ Denna formel är definitionen av en kyrkans siffra n med f -> m, x -> f.
  2. ^ Allison, Lloyd. "Lambda Calculus heltal" .
  3. ^ Bauer, Andrej. "Andrejs svar på en fråga;" Representerar negativa och komplexa tal med lambda -kalkyl " " .
  4. ^ "Exakt riktig aritmetik" . Haskell .
  5. ^ Bauer, Andrej. "Beräkningsprogram för verkligt antal" .
  6. ^ Pierce, Benjamin C. (2002). Typer och programmeringsspråk . MIT Press . sid. 500. ISBN 978-0-262-16209-8.
  7. ^ Tromp, John (2007). "14. Binary Lambda Calculus and Combinatory Logic". I Calude, Cristian S (red.). Slumpmässighet och komplexitet, från Leibniz till Chaitin . World Scientific. s. 237–262. ISBN 978-981-4474-39-9.
    Som PDF: Tromp, John (14 maj 2014). "Binary Lambda Calculus and Combinatory Logic" (PDF) . Hämtad 2017-11-24 .
  8. ^ Jansen, Jan Martin (2013). "Programmering i λ-kalkylen: Från kyrkan till Scott och tillbaka". LNCS . 8106 : 168–180. doi : 10.1007/978-3-642-40355-2_12 .

Referenser