158 votes

Qu'est-ce que la programmation fonctionnelle, déclarative et impérative ?

  1. En un mot, ce qui est :

    • Programmation fonctionnelle
    • Programmation déclarative
    • Programmation impérative
  2. Existe-t-il d'autres types (plus exotiques) ?

  3. Quel est le type de jQuery ? J'aime beaucoup ce produit, mais je ne sais pas comment il s'appelle.

131voto

rtperson Points 7065

La programmation fonctionnelle est un sous-type de la programmation déclarative. Vous avez donc réellement posé la question "qu'est-ce que la programmation fonctionnelle/déclarative par rapport à la programmation impérative" ?

Programmation impérative est ce que la plupart des programmeurs professionnels utilisent dans leur travail quotidien. C'est le nom donné à des langages comme C, C++, Java, COBOL, etc. Dans la programmation impérative, vous dites à l'ordinateur ce qu'il doit faire. "Ordinateur, ajoute x et y" ou "Ordinateur, affiche une boîte de dialogue à l'écran". Et (généralement) l'ordinateur s'exécute. C'est là que la plupart d'entre nous passent leur vie, dans des structures en boucle et des instructions "si-ens-else", etc.

Programmation fonctionnelle Pour autant que je sache, la programmation impérative cherche à décrire ce que vous voulez faire plutôt qu'à spécifier comment vous voulez que quelque chose soit fait. Il est probablement mieux compris par opposition à la programmation impérative. Par exemple, si vous avez une liste en C et que vous voulez en extraire chaque Nième élément, vous devez pointer sur le premier élément, mettre un compteur à un, passer à l'élément suivant, incrémenter le compteur, vérifier si vous êtes au Nième élément et ainsi de suite. L'équivalent fonctionnel serait d'écrire une fonction qui reconnaît quand la taille d'une liste est un multiple de N, puis de passer cette fonction à la liste, éventuellement avec un autre bout de code pour rendre la tête de la liste si votre N-recognizer évalue à true et la jeter si elle évalue à false. Les deux fonctions parcourent la liste, et renvoient finalement une liste composée de chaque Nième élément.

Cette dernière méthode peut sembler la plus confuse, et c'est parce qu'elle l'est. La programmation fonctionnelle peut être une véritable casse-tête, ce qui explique en partie pourquoi Lisp, Scheme et Haskell n'ont jamais vraiment dépassé C, C++, Java et COBOL en termes de popularité commerciale. Mais la méthode fonctionnelle présente des avantages. Tout d'abord, si la logique est correcte, la programmation fonctionnelle nécessite beaucoup moins de code que la programmation impérative. Cela signifie moins de points de défaillance, moins de code à tester et une vie de programmation plus productive (et, pour beaucoup, plus heureuse). Les systèmes devenant de plus en plus gros, cet aspect est devenu de plus en plus important.

Existe-t-il des types plus exotiques ? Pas encore. Il existe des hybrides entre les deux (comme Scala), mais ils cherchent simplement à tirer parti des forces des deux types. Ensuite, il y a la programmation orientée objet, qui n'est en fait qu'une nouvelle façon d'organiser les données dans un programme impératif. Et même avec des nouvelles technologies étranges comme informatique quantique les langages sous-jacents (prévus) se situent quelque part dans le spectre déclaratif/impératif.

Et, comme d'autres l'ont souligné, JQuery est une bibliothèque qui se trouve au-dessus de JavaScript, qui est lui-même un langage hybride fonctionnel/impératif. Sans entrer dans les détails, JavaScript est comme la fille laide et aux dents de lapin que vos parents vous ont forcé à emmener au bal de fin d'année. JQuery est comme la bonne fée qui arrive et, d'un coup de baguette magique, la transforme en un véritable bébé sous vos yeux. (Voir l'article de Douglas Crockford JavaScript : les bons côtés pour en savoir plus).

70voto

Shelby Moore III Points 2088

À l'heure où nous écrivons ces lignes, les réponses les plus votées sur cette page sont imprécises et confuses sur la définition de déclaratif vs impératif, y compris la réponse qui cite Wikipedia. Certaines réponses confondent les termes de différentes manières.

Voir aussi mon explication de pourquoi la programmation des feuilles de calcul est déclarative, indépendamment du fait que les formules mutent les cellules.

En outre, plusieurs réponses affirment que la programmation fonctionnelle doit être un sous-ensemble de la programmation déclarative. Sur ce point, tout dépend de la différence entre "fonction" et "procédure". Traitons d'abord l'impératif et le déclaratif.

Définition de l'expression déclarative

Le site uniquement peut éventuellement différencier un déclaratif d'une expression impératif est la transparence référentielle (RT) de ses sous-expressions. Tous les autres attributs possibles sont soit partagés avec impératif ou dérivés de la RT.

Un langage 100% déclaratif (c'est-à-dire que chaque expression possible est RT) ne permet pas (entre autres exigences RT) la mutation des valeurs stockées, par exemple HTML et la plupart de Haskell.

Définition de l'expression RT

La RT est souvent appelée "sans effets secondaires". Le terme effets n'a pas de définition précise, c'est pourquoi certaines personnes ne sont pas d'accord pour dire que "sans effets secondaires" est la même chose que la RT. La RT a un définition précise .

Puisque chaque sous-expression est conceptuellement un appel de fonction, la RT exige que l'implémentation d'une fonction (c'est-à-dire la ou les expressions à l'intérieur de la fonction appelée) ne puisse accéder à mutable l'état qui est externe à la fonction (en accédant mutable local état est autorisé). La fonction (mise en œuvre) doit être précisément pur .

Définition de la fonction pure

On dit souvent d'une fonction pure qu'elle n'a "aucun effet secondaire". Le terme effets n'a pas de définition précise, c'est pourquoi certaines personnes ne sont pas d'accord.

Les fonctions pures ont les attributs suivants.

  • la seule sortie observable est la valeur de retour.
  • la seule dépendance de sortie est celle des arguments.
  • Les arguments sont entièrement déterminés avant que toute sortie ne soit générée.

Rappelez-vous que la RT s'applique aux expressions (ce qui inclut les appels de fonction) et que la pureté s'applique aux (implémentations des) fonctions.

Un exemple obscur de fonctions impures qui font des expressions RT est la concurrence, mais c'est parce que la pureté est brisée au niveau de la couche d'abstraction des interruptions. Vous n'avez pas vraiment besoin de le savoir. Pour créer des expressions RT, vous appelez des fonctions pures.

Attributs dérivés de la RT

Tout autre attribut cité pour la programmation déclarative, par exemple le citation de 1999 utilisée par Wikipedia, dérive de la RT, ou est partagée avec la programmation impérative. Ce qui prouve que ma définition précise est correcte.

Note, l'immuabilité de valeurs externes est un sous-ensemble des exigences de la RT.

  • Les langages déclaratifs n'ont pas de structures de contrôle en boucle, par ex. for et while parce que en raison de l'immuabilité la condition de la boucle ne changera jamais.

  • Les langages déclaratifs n'expriment pas de flux de contrôle autre que l'ordre des fonctions imbriquées (c'est-à-dire les dépendances logiques), car en raison de l'immuabilité Les autres choix d'ordre d'évaluation ne changent pas le résultat (voir ci-dessous).

  • Les langages déclaratifs expriment des "étapes" logiques (c'est-à-dire l'ordre d'appel des fonctions RT imbriquées), mais le fait que chaque appel de fonction soit une sémantique de plus haut niveau (c'est-à-dire "quoi faire") n'est pas une exigence de la programmation déclarative. La distinction avec l'impératif est que en raison de l'immuabilité (c'est-à-dire plus généralement RT), ces "étapes" ne peuvent pas dépendre d'un état mutable, mais seulement de l'ordre relationnel de la logique exprimée (c'est-à-dire l'ordre d'imbrication des appels de fonctions, c'est-à-dire des sous-expressions).

    Par exemple, le paragraphe HTML <p> ne peut être affiché avant que les sous-expressions (c'est-à-dire les balises) du paragraphe aient été évaluées. Il n'y a pas d'état mutable, seulement une dépendance d'ordre due à la relation logique de la hiérarchie des balises (imbrication de sous-expressions, qui sont des appels de fonctions imbriquées de manière analogue ).

  • Il y a donc l'attribut dérivé d'immutabilité (plus généralement RT), selon lequel les expressions déclaratives, exprimées uniquement le site logique des relations des parties constitutives (c'est-à-dire des arguments de la fonction de sous-expression) et non pas état mutable relations.

Ordre d'évaluation

Le choix de l'ordre d'évaluation des sous-expressions ne peut donner un résultat variable que si l'un des appels de fonction n'est pas RT (c'est-à-dire que la fonction n'est pas pure), par exemple si l'on accède à un état mutable externe à une fonction à l'intérieur de celle-ci.

Par exemple, étant donné certaines expressions imbriquées, par exemple f( g(a, b), h(c, d) ) l'évaluation avide et paresseuse des arguments de la fonction donnera les mêmes résultats si les fonctions f , g et h sont purs.

Alors que, si les fonctions f , g et h ne sont pas purs, alors le choix de l'ordre d'évaluation peut donner un résultat différent.

Notez que les expressions imbriquées sont conceptuellement des fonctions imbriquées, puisque les opérateurs d'expression sont juste des appels de fonction déguisés en préfixe unaire, postfixe unaire ou notation binaire infixe.

Tangentiellement, si tous les identifiants, par ex. a , b , c , d sont immuable partout, il n'est pas possible d'accéder à un état externe au programme (c'est-à-dire les E/S), et il n'y a pas de rupture de la couche d'abstraction, alors les fonctions sont toujours pures.

Au fait, Haskell a une syntaxe différente, f (g a b) (h c d) .

Détails de la commande d'évaluation

Une fonction est une transition d'état (pas une valeur stockée mutable) de l'entrée à la sortie. Pour les compositions RT d'appels à pur l'ordre d'exécution de ces transitions d'état est indépendant. La transition d'état de chaque appel de fonction est indépendante des autres, en raison de l'absence d'effets secondaires et du principe qu'une fonction La fonction RT peut être remplacée par sa valeur en cache. . Pour corriger une idée fausse et répandue la composition monadique pure est toujours déclaratif et RT malgré le fait que l'approche de Haskell IO La monade est sans doute impur et donc impératif par rapport au World état externe au programme (mais au sens de la mise en garde ci-dessous, les effets secondaires sont isolés).

L'évaluation rapide signifie que les arguments de la fonction sont évalués avant l'appel de la fonction, et l'évaluation paresseuse signifie que les arguments de la fonction sont évalués avant l'appel de la fonction. les arguments ne sont pas évalués jusqu'à ce que (et si) on y accède dans la fonction.

Définition : fonction paramètres sont déclarés à la fonction définition site, et fonction arguments sont fournis à la fonction appelez site. Connaître la différence entre paramètre et argument .

Conceptuellement, toutes les expressions sont des (compositions de) appels de fonctions, par exemple, les constantes sont des fonctions sans entrées, les opérateurs unaires sont des fonctions avec une entrée, les opérateurs binaires infixes sont des fonctions avec deux entrées, les constructeurs sont des fonctions, et même les instructions de contrôle (par exemple if , for , while ) peuvent être modélisés par des fonctions. Le site pour que ces argument L'ordre d'évaluation des fonctions (à ne pas confondre avec l'ordre d'appel des fonctions imbriquées) n'est pas déclaré par la syntaxe, par ex. f( g() ) pourrait évaluer avec enthousiasme g puis f sur g ou il peut évaluer le résultat de f et n'évalue que paresseusement g lorsque son résultat est nécessaire dans f .

Avertissement, non Complète de Turing (c'est-à-dire qui autorise la récursion sans limite) est parfaitement déclaratif, par exemple l'évaluation paresseuse introduit l'indéterminisme en mémoire et en temps. Mais ces effets secondaires dus au choix de l'ordre d'évaluation, sont isolés à la consommation de mémoire, au temps d'exécution, à la latence, à la non-terminaison, et à l'indétermination. hystérésis externe Ainsi, par exemple, la synchronisation externe.

Programmation fonctionnelle

Comme la programmation déclarative ne peut pas avoir de boucles, la seule façon d'itérer est la récursion fonctionnelle. C'est dans ce sens que la programmation fonctionnelle est liée à la programmation déclarative.

Mais la programmation fonctionnelle ne se limite pas à la programmation déclarative . La composition fonctionnelle peut être par opposition au sous-typage notamment en ce qui concerne le Problème d'expression où l'extension peut être obtenue par soit l'ajout de sous-types ou la décomposition fonctionnelle . L'extension peut être un mélange des deux méthodologies.

La programmation fonctionnelle fait généralement de la fonction un objet de première classe, ce qui signifie que le type de fonction peut apparaître dans la grammaire à n'importe quel endroit où un autre type peut apparaître. Il en résulte que les fonctions peuvent entrer et opérer sur des fonctions, ce qui permet la séparation des préoccupations en mettant l'accent sur la composition des fonctions, c'est-à-dire en séparant les dépendances entre les sous-calculs d'un calcul déterministe.

Par exemple, au lieu d'écrire une fonction séparée (et en employant la récursion au lieu des boucles si la fonction doit également être déclarative) pour chacune des infinies actions spécialisées possibles qui pourraient être appliquées à chaque élément d'une collection, la programmation fonctionnelle emploie des fonctions d'itération réutilisables, par ex. map , fold , filter . Ces fonctions d'itération entrent une fonction d'action spécialisée de première classe. Ces fonctions d'itération itèrent la collection et appellent la fonction d'action spécialisée en entrée pour chaque élément. Ces fonctions d'action sont plus concises car elles n'ont plus besoin de contenir les instructions de bouclage pour itérer la collection.

Toutefois, notez que si une fonction n'est pas pure, il s'agit en réalité d'une procédure. Nous pouvons peut-être affirmer que la programmation fonctionnelle qui utilise des fonctions impures est en fait une programmation procédurale. Ainsi, si nous sommes d'accord sur le fait que les expressions déclaratives sont RT, alors nous pouvons dire que la programmation procédurale n'est pas la programmation déclarative, et donc nous pourrions soutenir que la programmation fonctionnelle est toujours RT et doit être un sous-ensemble de la programmation déclarative.

Parallélisme

Cette composition fonctionnelle avec des fonctions de première classe peut exprimer la profondeur dans le parallélisme en séparant la fonction indépendante.

Principe de Brent : un calcul avec un travail w et une profondeur d peut être être implémenté dans une PRAM à p-processeurs en un temps O(max(w/p, d)).

La concurrence et le parallélisme sont également nécessitent une programmation déclarative c'est-à-dire l'immuabilité et la RT.

Alors, d'où vient cette dangereuse supposition que parallélisme = = concussion. est née ? C'est une conséquence naturelle des langages avec des effets de bord : quand votre langage a des effets secondaires partout, alors à chaque fois que vous essayez de faire plus d'une chose à la fois, vous avez essentiellement non-déterminisme causé par l'imbrication des effets de chaque opération. opération. Donc, dans les langages à effets secondaires, la seule façon d'obtenir d'obtenir du parallélisme est la concurrence ; il n'est donc pas surprenant que nous Il n'est donc pas surprenant que nous voyions souvent les deux confondus.

Ordre d'évaluation des PF

Notez que l'ordre d'évaluation a également un impact sur la terminaison et les effets secondaires de la composition fonctionnelle.

L'ardeur (CBV) et la paresse (CBN) sont des duels catégoriels [ 10 ], car leur ordre d'évaluation est inversé, c'est-à-dire que les fonctions extérieures ou intérieures sont respectivement évaluées en premier. Imaginez un arbre à l'envers, alors eager évalue depuis les extrémités des branches de l'arbre des fonctions en remontant la hiérarchie des branches jusqu'au tronc de la fonction de niveau supérieur ; alors que la lazy évalue depuis le tronc jusqu'aux extrémités des branches. Eager n'a pas de produits conjonctifs ("and", a/k/a "produits" catégoriques) et lazy n'a pas de coproduits disjonctifs ("or", a/k/a "sommes" catégoriques) . 11 ].

Performance

  • Eager

    Comme pour la non-termination, eager est trop empressé avec la composition fonctionnelle conjonctive, c'est-à-dire que la structure de contrôle de la composition effectue un travail inutile qui n'est pas fait avec lazy. Pour exemple La liste est composée d'un pli qui se termine par le premier élément vrai, ce qui est inutile.

    Ce travail inutile est à l'origine de la réclamation d'un supplément " jusqu'à ". facteur log n dans la complexité temporelle séquentielle de eager versus lazy, dans les deux cas avec des fonctions pures. Une solution consiste à utiliser des foncteurs (par exemple des listes) avec des constructeurs paresseux (c'est-à-dire avides avec des produits paresseux optionnels), car avec avide, l'incorrection de l'avidité provient de la fonction interne. Ceci est dû au fait que les produits sont des types constructifs, c'est-à-dire des types inductifs avec une algèbre initiale sur un point fixe initial[ 11 ]

  • Paresseux

    Comme avec la non-termination, lazy est trop paresseux avec la composition fonctionnelle disjonctive, c'est-à-dire que la finalité coïnductive peut se produire plus tard que nécessaire, ce qui entraîne à la fois un travail inutile et un non-déterminisme de la latence, ce qui n'est pas le cas avec eager[ 10 ][ 11 ]. Les exemples de finalité sont l'état, le timing, la non-terminaison et les exceptions d'exécution. Ce sont des effets secondaires impératifs, mais même dans un langage purement déclaratif (par exemple Haskell), il y a un état dans la monade impérative IO (note : toutes les monades ne sont pas impératives !), implicite dans l'allocation d'espace, et le timing est un état relatif au monde réel impératif. L'utilisation de la paresse, même avec des coproduits avides optionnels, fait fuir la "paresse" dans les coproduits internes, parce qu'avec la paresse, l'incorrection de la paresse est la suivante provient de la fonction externe (voir l'exemple dans la section Non-termination, où == est une fonction d'opérateur binaire externe). Ceci est dû au fait que les coproduits sont limités par la finalité, c'est-à-dire les types coïnductifs avec une algèbre finale sur un objet final[ 11 ].

    Lazy provoque un indéterminisme dans la conception et le débogage des fonctions de latence et d'espace, dont le débogage est probablement au-delà des capacités de la majorité des programmeurs, à cause de la dissonance entre la hiérarchie des fonctions déclarées et l'ordre d'évaluation à l'exécution. Les fonctions pures paresseuses évaluées avec eager peuvent potentiellement introduire une non-termination inédite au moment de l'exécution. Inversement, les fonctions pures eager évaluées avec lazy pourraient potentiellement introduire un indéterminisme d'espace et de latence inédit à l'exécution.

Non-résiliation

Au moment de la compilation, en raison du problème de Halting et de la récursion mutuelle dans un langage complet de Turing, la terminaison des fonctions ne peut généralement pas être garantie.

  • Eager

    Avec impatience mais pas paresseusement, pour la conjonction de Head "et" Tail si l'un ou l'autre Head ou Tail ne se termine pas, alors respectivement soit List( Head(), Tail() ).tail == Tail() ou List( Head(), Tail() ).head == Head() n'est pas vrai car le côté gauche ne se termine pas, et le côté droit se termine.

    Considérant que, avec la paresse, les deux parties se terminent. Ainsi, eager est trop empressé avec les produits conjonctifs, et ne se termine pas (y compris les exceptions d'exécution) dans les cas où cela n'est pas nécessaire.

  • Paresseux

    Avec paresse mais sans impatience, pour la disjonction de 1 "ou" 2 si f ne se termine pas, alors List( f ? 1 : 2, 3 ).tail == (f ? List( 1, 3 ) : List( 2, 3 )).tail n'est pas vrai car le côté gauche se termine, et le côté droit ne se termine pas.

    Alors qu'avec eager, les deux côtés ne se terminent pas et le test d'égalité n'est jamais atteint. Ainsi, lazy est trop paresseux avec les coproduits disjonctifs, et dans ces cas-là, il ne se termine pas (y compris les exceptions d'exécution) après avoir fait plus de travail que eager ne l'aurait fait.

[ 10 ] Declarative Continuations and Categorical Duality, Filinski, sections 2.5.4 A comparison of CBV and CBN, et 3.6.1 CBV and CBN in the SCL.

[ 11 ] Declarative Continuations and Categorical Duality, Filinski, sections 2.2.1 Products and coproducts, 2.2.2 Terminal and initial objects, 2.5.2 CBV with lazy products, and 2.5.3 CBN with eager coproducts.


Il existe des concepts plus exotiques en programmation, par exemple le sous-typage supérieur, le typage dépendant, le fonctionnel réactif, etc.


Je ne connais pas suffisamment jQuery pour répondre à votre question à ce sujet.

46voto

Jason Baker Points 56682

1) Il n'existe pas vraiment de définition objective et non ambiguë de ces termes. Voici comment I les définiraient :

Impératif - L'accent est mis sur les mesures que l'ordinateur doit prendre plutôt que sur ce qu'il fera. faire (ex. C, C++, Java).

Déclaratif - L'accent est mis sur ce que l'ordinateur doit faire plutôt que sur la manière dont il doit le faire (ex. SQL).

Fonctionnel - un sous-ensemble de langages déclaratifs qui met fortement l'accent sur la récursion

2) Il existe des langues multiparadigmes qui sont à cheval entre les deux. Par exemple, C#, Python et JavaScript sont principalement des langages impératifs qui comportent quelques éléments fonctionnels ou déclaratifs. Il existe également des langages de programmation logique (comme prolog) qui se concentrent principalement sur la satisfaction des contraintes.

3) Je pense que JQuery fait partie de la catégorie multiparadigme ci-dessus (comme le langage dans lequel il est implémenté, JavaScript).

20voto

mdja Points 369

En un mot :

Un site langage impératif specfies une série d'instructions que l'ordinateur exécute en séquence (faites ceci, puis faites cela).

A langage déclaratif déclare un ensemble de règles concernant les sorties qui devraient résulter de quelles entrées (par exemple, si vous avez A, alors le résultat est B). Un moteur appliquera ces règles aux entrées, et donnera une sortie.

A langage fonctionnel déclare un ensemble de fonctions mathématiques/logiques qui définissent la manière dont les entrées sont traduites en sorties. par exemple, f(y) = y * y. Il s'agit d'un type de langage déclaratif.

jQuery est une bibliothèque.

Il est construit dans un langage impératif (JavaScript, qui a absorbé certains des paradigmes de la programmation fonctionnelle) qui utilise des règles de sélection déclaratives (basées sur CSS) pour interagir avec les objets du navigateur (le DOM).

17voto

TheTXI Points 24470

De Wikipedia

En informatique, la programmation déclarative déclarative est un paradigme de programmation qui exprime la logique d'un calcul sans décrire son flux de contrôle. Elle tente de minimiser ou éliminer les effets secondaires en décrivant ce que le programme doit accomplir, plutôt que de décrire comment comment s'y prendre pour l'accomplir. Ce site contraste avec la programmation impérative programmation impérative, qui nécessite une description description détaillée de l'algorithme à exécuter.

La programmation déclarative considère les programmes comme des théories d'une logique logique formelle, et les calculs comme des déductions dans cet espace logique. Déclarative déclarative a suscité un intérêt particulier intérêt particulier récemment, car elle peut simplifier l'écriture de programmes parallèles.

Les langages déclaratifs courants comprennent ceux des expressions régulières, de la logique logique et de la programmation fonctionnelle.

De Wikipedia :

En informatique, la programmation fonctionnelle programmation fonctionnelle est un paradigme de programmation qui traite le calcul comme l'évaluation l'évaluation de fonctions mathématiques et évite l'état et les données mutables. Elle met l'accent sur l'application de fonctions, contrairement à la style de programmation impératif, qui qui met l'accent sur les changements d'état. La programmation fonctionnelle trouve ses racines dans le lambda calculus, un système formel système formel développé dans les années 1930 pour étudier la définition des fonctions, l'application des fonctions et la récursion. De nombreux langages de programmation fonctionnelle peuvent être considérés comme des embellissements du lambda calculus.

De Wikipedia :

En informatique, la programmation impérative programmation impérative est un paradigme de programmation qui décrit le calcul en termes de d'instructions qui modifient l'état programme. De la même manière que le l'impératif dans les langues naturelles exprime des ordres d'action, les programmes impératifs définissent des séquences de commandes que l'ordinateur doit exécuter.

Le terme est utilisé en opposition à la programmation déclarative, qui exprime ce qui doit être fait sans prescrire la manière de le faire en en termes de séquences d'actions à effectuer à entreprendre. Fonctionnel et logique logique sont des exemples d'une approche plus déclarative.

jQuery n'est pas un langage de programmation, c'est une bibliothèque pour le langage de programmation JavaScript.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X