Codage de l'église - Church encoding

En mathématiques , l' encodage Church est un moyen de représenter les données et les opérateurs dans le calcul lambda . Les chiffres de l'Église sont une représentation des nombres naturels en notation lambda. La méthode porte le nom d' Alonzo Church , qui a d'abord encodé les données dans le calcul lambda de cette façon.

Les termes qui sont généralement considérés comme primitifs dans d'autres notations (comme les entiers, les booléens, les paires, les listes et les unions étiquetées) sont mappés à des fonctions d'ordre supérieur sous le codage Church. La thèse de Church-Turing affirme que tout opérateur calculable (et ses opérandes) peut être représenté sous le codage Church. Dans le calcul lambda non typé, le seul type de données primitif est la fonction.

Le codage Church n'est pas conçu comme une implémentation pratique des types de données primitifs. Son utilisation est de montrer que d'autres types de données primitifs ne sont pas nécessaires pour représenter un calcul. La complétude est représentationnelle. Des fonctions supplémentaires sont nécessaires pour traduire la représentation en types de données communs, pour l'affichage aux personnes. Il n'est pas possible en général de décider si deux fonctions sont égales en extension en raison de l' indécidabilité de l'équivalence du théorème de Church . La traduction peut appliquer la fonction d'une manière ou d'une autre pour récupérer la valeur qu'elle représente, ou rechercher sa valeur en tant que terme lambda littéral.

Le calcul lambda est généralement interprété comme utilisant l' égalité intentionnelle . Il existe des problèmes potentiels avec l'interprétation des résultats en raison de la différence entre la définition intensionnelle et extensionnelle de l'égalité.

Chiffres de l'église

Les chiffres d'église sont les représentations des nombres naturels sous le codage d'église. La fonction d'ordre supérieur qui représente l'entier naturel n est une fonction qui mappe n'importe quelle fonction à sa composition n- fold . En termes plus simples, la "valeur" du chiffre équivaut au nombre de fois que la fonction encapsule son argument.

Tous les chiffres de l'Église sont des fonctions qui prennent deux paramètres. Les chiffres d'église 0 , 1 , 2 , ..., sont définis comme suit dans le calcul lambda .

En commençant par 0 n'appliquant pas du tout la fonction, passez à 1 appliquant la fonction une fois, 2 appliquant la fonction deux fois, 3 appliquant la fonction trois fois, etc. :

Le chiffre d'église 3 représente l'action d'appliquer une fonction donnée trois fois à une valeur. La fonction fournie est d'abord appliquée à un paramètre fourni puis successivement à son propre résultat. Le résultat final n'est pas le chiffre 3 (sauf si le paramètre fourni est 0 et que la fonction est une fonction successeur ). La fonction elle-même, et non son résultat final, est le chiffre de l'Église 3 . Le chiffre de l'Église 3 signifie simplement faire n'importe quoi trois fois. C'est une démonstration ostentatoire de ce que l'on entend par "trois fois".

Calcul avec les chiffres de l'église

Les opérations arithmétiques sur les nombres peuvent être représentées par des fonctions sur les chiffres de l'Église. Ces fonctions peuvent être définies dans le calcul lambda , ou implémentées dans la plupart des langages de programmation fonctionnels (voir conversion d'expressions lambda en fonctions ).

La fonction d'addition utilise l'identité .

La fonction successeur est -équivalente à .

La fonction de multiplication utilise l'identité .

La fonction d'exponentiation est donnée par la définition des chiffres d'église, . Dans la définition substituer à obtenir et,

ce qui donne l'expression lambda,

La fonction est plus difficile à comprendre.

Un chiffre d'église applique une fonction n fois. La fonction prédécesseur doit renvoyer une fonction qui applique son paramètre n - 1 fois. Ceci est réalisé en construisant un conteneur autour de f et x , qui est initialisé d'une manière qui omet l'application de la fonction la première fois. Voir prédécesseur pour une explication plus détaillée.

La fonction de soustraction peut être écrite sur la base de la fonction prédécesseur.

Table des fonctions sur les chiffres de l'église

Fonction Algèbre Identité Définition de la fonction Expressions lambda
Successeur ...
Une addition
Multiplication
Exponentiation
Prédécesseur *

Soustraction * ...

* Notez que dans l'encodage Church,

Dérivation de la fonction prédécesseur

La fonction prédécesseur utilisée dans l'encodage Church est,

.

Pour construire le prédécesseur, nous avons besoin d'un moyen d'appliquer la fonction 1 moins de temps. Un chiffre n applique la fonction f n fois à x . La fonction prédécesseur doit utiliser le chiffre n pour appliquer la fonction n -1 fois.

Avant d'implémenter la fonction prédécesseur, voici un schéma qui encapsule la valeur dans une fonction conteneur. Nous allons définir de nouvelles fonctions à utiliser à la place de f et x , appelées inc et init . La fonction conteneur est appelée value . Le côté gauche du tableau montre un chiffre n appliqué à inc et init .

La règle générale de récurrence est,

S'il existe également une fonction pour récupérer la valeur du conteneur (appelée extract ),

Ensuite, extract peut être utilisé pour définir la fonction samenum comme,

La fonction samenum n'est pas intrinsèquement utile. Cependant, comme inc délègue l'appel de f à son argument conteneur, nous pouvons faire en sorte que sur la première application, inc reçoive un conteneur spécial qui ignore son argument permettant de sauter la première application de f . Appelez ce nouveau conteneur initial const . Le côté droit du tableau ci-dessus montre les expansions de n inc const . Ensuite, en remplaçant init par const dans l'expression de la même fonction, nous obtenons la fonction prédécesseur,

Comme expliqué ci-dessous, les fonctions inc , init , const , value et extract peuvent être définies comme,

Ce qui donne l'expression lambda pour pred as,

Conteneur de valeur

Le conteneur de valeur applique une fonction à sa valeur. Il est défini par,

donc,

Inc

La fonction inc doit prendre une valeur contenant v et renvoyer une nouvelle valeur contenant fv .

Soit g le conteneur de valeur,

alors,

donc,

Extrait

La valeur peut être extraite en appliquant la fonction identité,

En utilisant je ,

donc,

Const

Pour implémenter pred, la fonction init est remplacée par la const qui ne s'applique pas à f . Nous avons besoin de const pour satisfaire,

Ce qui est satisfait si,

Ou comme une expression lambda,

Une autre façon de définir pred

Pred peut également être défini à l'aide de paires :

C'est une définition plus simple, mais conduit à une expression plus complexe pour pred. L'extension pour :

Division

La division des nombres naturels peut être mise en œuvre par,

Le calcul nécessite de nombreuses réductions bêta. A moins de faire la réduction à la main, cela n'a pas beaucoup d'importance, mais il est préférable de ne pas avoir à refaire ce calcul deux fois. Le prédicat le plus simple pour tester les nombres est IsZero, alors considérez la condition.

Mais cette condition équivaut à , non . Si cette expression est utilisée, la définition mathématique de la division donnée ci-dessus est traduite en fonction sur les chiffres de l'Église comme,

Comme souhaité, cette définition a un seul appel à . Cependant, le résultat est que cette formule donne la valeur de .

Ce problème peut être corrigé en ajoutant 1 à n avant d'appeler diviser . La définition de la division est alors,

divise1 est une définition récursive. Le combinateur Y peut être utilisé pour implémenter la récursivité. Créez une nouvelle fonction appelée div by ;

  • Dans le côté gauche
  • Dans le côté droit

obtenir,

Puis,

où,

Donne,

Ou sous forme de texte, en utilisant \ pour λ ,

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

Par exemple, 9/3 est représenté par

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

En utilisant une calculatrice de calcul lambda, l'expression ci-dessus se réduit à 3, en utilisant l'ordre normal.

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

Numéros signés

Une approche simple pour étendre les chiffres d'église aux nombres signés consiste à utiliser une paire d'églises, contenant des chiffres d'église représentant une valeur positive et une valeur négative. La valeur entière est la différence entre les deux chiffres de l'Église.

Un nombre naturel est converti en nombre signé par,

La négation est effectuée en échangeant les valeurs.

La valeur entière est plus naturellement représentée si l'un des couples est nul. La fonction OneZero remplit cette condition,

La récursivité peut être implémentée à l'aide du combinateur Y,

Plus et moins

L'addition est définie mathématiquement sur la paire par,

La dernière expression est traduite en lambda calcul comme,

De même la soustraction est définie,

donnant,

Multiplier et diviser

La multiplication peut être définie par,

La dernière expression est traduite en lambda calcul comme,

Une définition similaire est donnée ici pour la division, sauf que dans cette définition, une valeur dans chaque paire doit être zéro (voir OneZero ci-dessus). La fonction divZ nous permet d'ignorer la valeur qui a une composante nulle.

divZ est ensuite utilisé dans la formule suivante, qui est la même que pour la multiplication, mais avec mult remplacé par divZ .

Nombres rationnels et réels

Les nombres réels rationnels et calculables peuvent également être codés dans le calcul lambda. Les nombres rationnels peuvent être codés comme une paire de nombres signés. Les nombres réels calculables peuvent être codés par un processus de limitation qui garantit que la différence par rapport à la valeur réelle diffère d'un nombre qui peut être rendu aussi petit que nécessaire. Les références données décrivent des logiciels qui pourraient, en théorie, être traduits en lambda calcul. Une fois les nombres réels définis, les nombres complexes sont naturellement encodés sous la forme d'une paire de nombres réels.

Les types de données et les fonctions décrits ci-dessus démontrent que tout type de données ou calcul peut être encodé dans le calcul lambda. C'est la thèse de Church-Turing .

Traduction avec d'autres représentations

La plupart des langages du monde réel prennent en charge les entiers natifs de la machine ; l' église et unchurch fonctions convertissent entre les nombres entiers non négatifs et leurs chiffres correspondants Eglise. Les fonctions sont données ici en Haskell , où le \correspond au du calcul Lambda. Les implémentations dans d'autres langages sont similaires.

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

Église booléenne

Les booléens d'église sont l'encodage d'église des valeurs booléennes vrai et faux. Certains langages de programmation les utilisent comme modèle d'implémentation pour l'arithmétique booléenne ; les exemples sont Smalltalk et Pico .

La logique booléenne peut être considérée comme un choix. L'encodage Church du vrai et du faux est fonction de deux paramètres :

  • true choisit le premier paramètre.
  • false choisit le deuxième paramètre.

Les deux définitions sont connues sous le nom de booléens d'église :

Cette définition permet aux prédicats (c'est-à-dire aux fonctions renvoyant des valeurs logiques ) d'agir directement comme des clauses if. Une fonction renvoyant un booléen, qui est ensuite appliqué à deux paramètres, renvoie soit le premier, soit le deuxième paramètre :

est évalué à la clause then si predicate-x est évalué à true , et à else-clause si predicate-x est évalué à false .

Parce que vrai et faux choisissent le premier ou le deuxième paramètre, ils peuvent être combinés pour fournir des opérateurs logiques. Notez qu'il existe plusieurs implémentations possibles de not .

Quelques exemples:

Prédicats

Un prédicat est une fonction qui renvoie une valeur booléenne. Le prédicat le plus fondamental est , qui renvoie si son argument est le chiffre de l'Église , et si son argument est un autre chiffre de l'Église :

Le prédicat suivant teste si le premier argument est inférieur ou égal au second :

,

En raison de l'identité,

Le test d'égalité peut être mis en œuvre comme,

Paires d'églises

Les paires d'églises sont le codage d'églises du type paire (deux tuples). La paire est représentée comme une fonction qui prend un argument de fonction. Lorsqu'on lui donne son argument, il appliquera l'argument aux deux composants de la paire. La définition en lambda calcul est,

Par exemple,

Lister les encodages

Une liste ( immuable ) est construite à partir de nœuds de liste. Les opérations de base sur la liste sont ;

Fonction La description
néant Construisez une liste vide.
isil Testez si la liste est vide.
les inconvénients Ajouter une valeur donnée à une liste (éventuellement vide).
diriger Obtenez le premier élément de la liste.
queue Obtenez le reste de la liste.

Nous donnons ci-dessous quatre représentations différentes des listes :

  • Construisez chaque nœud de liste à partir de deux paires (pour permettre des listes vides).
  • Construisez chaque nœud de liste à partir d'une paire.
  • Représentez la liste en utilisant la fonction de pli à droite .
  • Représenter la liste en utilisant l'encodage de Scott qui prend les cas d'expression de correspondance comme arguments

Deux paires en tant que nœud de liste

Une liste non vide peut être implémentée par une paire d'Églises ;

  • Contient d' abord la tête.
  • Le deuxième contient la queue.

Cependant cela ne donne pas une représentation de la liste vide, car il n'y a pas de pointeur "null". Pour représenter null, la paire peut être enveloppée dans une autre paire, donnant des valeurs libres,

  • First - Est le pointeur nul (liste vide).
  • Second.First contient la tête.
  • Second.Second contient la queue.

En utilisant cette idée, les opérations de base sur les listes peuvent être définies comme ceci :

Expression La description
Le premier élément de la paire est vrai, ce qui signifie que la liste est nulle.
Récupérer l'indicateur nul (ou liste vide).
Créez un nœud de liste, qui n'est pas nul, et donnez-lui une tête h et une queue t .
deuxième.premier est la tête.
seconde.seconde est la queue.

Dans un nœud nil, on n'accède jamais à la seconde , à condition que la tête et la queue ne soient appliquées qu'aux listes non vides.

Une paire en tant que nœud de liste

Sinon, définissez

où la dernière définition est un cas particulier du général

Représenter la liste en utilisant le pli droit

Comme alternative à l'encodage à l'aide de paires Church, une liste peut être encodée en l'identifiant avec sa fonction de pli à droite . Par exemple, une liste de trois éléments x, y et z peut être codée par une fonction d'ordre supérieur qui, lorsqu'elle est appliquée à un combinateur c et une valeur n renvoie cx (cy (czn)).

Cette représentation de liste peut être donnée de type dans System F .

Représenter la liste en utilisant l'encodage Scott

Une représentation alternative est l'encodage Scott, qui utilise l'idée de continuations et peut conduire à un code plus simple. (voir aussi codage Mogensen-Scott ).

Dans cette approche, nous utilisons le fait que les listes peuvent être observées en utilisant une expression de filtrage de motifs. Par exemple, en utilisant la notation Scala , si listdésigne une valeur de type Listavec une liste vide Nilet un constructeur, Cons(h, t)nous pouvons inspecter la liste et calculer nilCodeau cas où la liste est vide et consCode(h, t)lorsque la liste n'est pas vide :

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

La 'liste' est donnée par la façon dont elle agit sur 'nilCode' et 'consCode'. Nous définissons donc une liste comme une fonction qui accepte de tels 'nilCode' et 'consCode' comme arguments, de sorte qu'au lieu de la correspondance de motif ci-dessus, nous pouvons simplement écrire :

Notons par 'n' le paramètre correspondant à 'nilCode' et par 'c' le paramètre correspondant à 'consCode'. La liste vide est celle qui renvoie l'argument nil :

La liste non vide avec en-tête 'h' et queue 't' est donnée par

Plus généralement, un type de données algébrique avec des alternatives devient une fonction avec des paramètres. Lorsque le e constructeur a des arguments, le paramètre correspondant de l'encodage prend également des arguments.

L'encodage de Scott peut être effectué dans un lambda calcul non typé, alors que son utilisation avec des types nécessite un système de types avec récursivité et polymorphisme de type. Une liste avec le type d'élément E dans cette représentation qui est utilisée pour calculer des valeurs de type C aurait la définition de type récursive suivante, où '=>' désigne le type de fonction :

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

Une liste qui peut être utilisée pour calculer des types arbitraires aurait un type qui quantifie sur C. Une liste générique dans Eprendrait également Ecomme argument de type.

Voir également

Remarques

  1. ^ Cette formule est la définition d'un chiffre d'Église n avec f -> m, x -> f.
  2. ^ Allison, Lloyd. « Entiers du calcul lambda » .
  3. ^ Bauer, Andrej. "Réponse d'Andrej à une question; "Représenter des nombres négatifs et complexes à l'aide du calcul lambda " " .
  4. ^ "Arithmétique réelle exacte" . Haskell .
  5. ^ Bauer, Andrej. "Logiciel de calcul de nombres réels" .
  6. ^ Pierce, Benjamin C. (2002). Types et langages de programmation . MIT Appuyez sur . p. 500. ISBN 978-0-262-16209-8.
  7. ^ Tromp, John (2007). "14. Calcul Lambda Binaire et Logique Combinatoire". Dans Calude, Cristian S (éd.). Aléatoire et complexité, de Leibniz à Chaitin . Scientifique du monde. p. 237-262. ISBN 978-981-4474-39-9.
    Au format PDF : Tromp, John (14 mai 2014). "Calcul lambda binaire et logique combinatoire" (PDF) . Récupéré le 2017-11-24 .
  8. ^ Jansen, Jan Martin (2013). « La programmation dans le -Calcul : De l'église à Scott et à l'arrière ». LNCS . 8106 : 168-180. doi : 10.1007/978-3-642-40355-2_12 .

Les références