Expliquez - moi les langues concaténatives comme si j'avais 8 ans
J'ai lu l'article Wikipedia sur les langues concaténatives, et je suis maintenant plus confus que je ne l'étais quand j'ai commencé. :-)
Qu'est-ce qu'un langage concaténatif en termes de personnes stupides?
7 réponses
À votre question simple, voici une réponse subjective et argumentative.
J'ai regardé l'article et plusieurs pages web connexes. Les pages web disent eux-mêmes qu'il n'y a pas de vraie théorie, il n'est donc pas étonnant que les gens aient du mal à trouver une définition précise et compréhensible. Je dirais qu'à l'heure actuelle, il n'est pas utile de classer les langues comme "concaténatives" ou "non concaténatives".
Pour moi, cela ressemble à un terme qui donne Manfred von Thun {[8] } un endroit pour accrocher son chapeau, mais peut ne pas être utile pour les autres programmeurs.
Bien que PostScript et-vient valent la peine d'être étudiés, Je ne vois rien de terriblement nouveau ou intéressant dans le langage de programmation Joy de Manfred von Thun. En effet, si vous lisez le papier de Chris Okasaki sur Techniques d'intégration de langages Postfix dans Haskell Vous pouvez essayer toutes ces choses dans un cadre qui, par rapport à Joy, est totalement mainstream.
Donc ma réponse est Il n'y a pas de simple explication parce qu'il n'y a pas de théorie mature sous-jacente à l'idée d'un langage concaténatif. (Comme Einstein et Feynman l'ont dit, si vous ne pouvez pas expliquer votre idée à un étudiant de première année, vous ne le comprenez pas vraiment.) Je vais aller plus loin et dire bien que l'étude de certaines de ces langues, comme Forth et PostScript, soit une excellente utilisation du temps, essayer de comprendre exactement ce que les gens veulent dire quand ils disent "concaténatif" est probablement une perte de temps.
Dans les langages de programmation normaux, vous avez des variables qui peuvent être définies librement et vous appelez des méthodes en utilisant ces variables comme arguments. Ceux-ci sont simples à comprendre mais quelque peu limités. Souvent, il est difficile de réutiliser une méthode existante car vous ne pouvez tout simplement pas mapper les variables existantes dans les paramètres dont la méthode a a besoin ou la méthode a appelle une autre méthode B et A serait parfaite pour vous si vous pouviez seulement remplacer L'appel à B par un appel à C.
Utilisation du langage Concaténatif une structure de données fixe pour enregistrer des valeurs (généralement une pile ou une liste). Il n'y a pas de variables. Cela signifie que de nombreuses méthodes et fonctions ont la même "API": elles travaillent sur quelque chose que quelqu'un d'autre a laissé sur la pile. De plus, le code lui-même est considéré comme "data", c'est-à-dire qu'il est courant d'écrire du code qui peut se modifier ou qui accepte un autre code en tant que "paramètre" (c'est-à-dire en tant qu'élément sur la pile).
Ces attributs rendent ces langages parfaits pour chaîner le code existant pour créer quelque chose nouveau. La réutilisation est intégrée. Vous pouvez écrire une fonction qui accepte une liste et un morceau de code et appelle le code pour chaque élément dans la liste. Cela fonctionnera maintenant sur n'importe quel type de données tant qu'il se comporte comme une liste: résultats d'une base de données, une ligne de pixels d'une image, caractères dans une chaîne, etc.
Le plus gros problème est que vous n'avez aucune indication de ce qui se passe. Il n'y a que quelques types de données (liste, chaîne, Nombre), donc tout est mappé à cela. Lorsque vous obtenez un morceau de données, vous habituellement n'aime pas ce qu'il est ni d'où il vient. Mais cela rend difficile de suivre les données à travers le code pour voir ce qui lui arrive.
Je crois qu'il faut un certain état d'esprit pour utiliser les langues avec succès. Ils ne sont pas pour tout le monde.
[EDIT] Forth a une certaine pénétration mais pas tant que ça. Vous pouvez trouver PostScript dans n'importe quelle imprimante laser. Ce sont donc des langues de niche.
À partir d'un niveau fonctionnel, ils sont au même niveau que LISP, les langages de type C et SQL: tous ils sont Turing complet , de sorte que vous pouvez calculer n'importe quoi. C'est juste une question de combien de code vous devez écrire. Certaines choses sont plus simples en LISP, certains sont plus simples dans C, certains sont plus simples dans les langages de requête. La question qui est "meilleure" est futile sauf si vous avez un contexte.
Je vais d'abord réfuter L'affirmation de Norman Ramsey selon laquelle il n'y a pas de théorie.
Théorie des langages Concaténatifs
Un langage concaténatif est un langage de programmation fonctionnel, où l'opération par défaut (ce qui se passe lorsque deux termes sont côte à côte) est la composition de la fonction au lieu de l'application de la fonction. C'est aussi simple que cela.
Ainsi, par exemple dans le SKI Combinator calcul (l'un des langages fonctionnels les plus simples) deux termes côte à côte sont équivalents à appliquer le premier terme au deuxième terme. Par exemple: S K K
est équivalent à S(K)(K)
.
Dans un langage concaténatif S K K
serait équivalent à S . K . K
dans Haskell.
Alors, quel est le problème
Un langage concaténatif pur a la propriété intéressante que l'ordre d'évaluation des termes n'a pas d'importance. Dans un langage concaténatif (S K) K
est le même que S (K K)
. Cela ne s'applique pas au calcul de SKI ou à toute autre fonction langage de programmation basé sur l'application de la fonction.
Une raison pour laquelle cette observation est intéressante car elle révèle des opportunités de parallélisation dans l'évaluation du code exprimé en termes de composition de fonction au lieu d'application.
Maintenant pour le monde réel
La sémantique des langages basés sur la pile qui supportent des fonctions d'ordre supérieur peut être expliquée en utilisant un calcul concaténatif. Vous mappez simplement chaque terme (commande/expression/sous-programme) à une fonction qui prend une fonction en entrée et renvoie une fonction de sortie. L'ensemble du programme est effectivement une fonction de transformation de pile unique.
La réalité est que les choses sont toujours déformées dans le monde réel (par exemple, FORTH a un dictionnaire global, PostScript fait des choses étranges où l'ordre d'évaluation compte). La plupart des langages de programmation pratiques n'adhèrent pas parfaitement à un modèle théorique.
Les Derniers Mots De
Je ne pense pas qu'un programmeur typique ou 8 ans devrait jamais se soucier de ce qu'est un langage concaténatif. Je ne trouve pas non plus particulièrement utile les langages de programmation pigeon-hole comme étant de type X ou de type Y.
Après avoir lu http://concatenative.org/wiki/view/Concatenative%20language et en m'appuyant sur le peu de souvenirs que je me souviens de tripoter avec Forth à L'adolescence, je crois que la clé de la programmation concaténative a à voir avec:
- affichage des données en termes de valeurs sur des données spécifiques de la pile
- et les fonctions manipulant des choses en termes de valeurs popping / pushing sur la même pile de données
Consultez ces citations de la page Web ci-dessus:
Il y a deux termes qui sont jetés autour, empiler le langage et langage concaténatif. Ils définissent tous les deux classes similaires mais non égales de langue. Pour la plupart cependant, ils sont identiques.
La plupart des langues largement utilisées aujourd'hui sont des langages applicatifs: le central construire dans la langue est une forme d'appel de fonction, où une fonction est appliqué à un ensemble de paramètres, où chaque paramètre est lui-même le résultat de un appel de la fonction, le nom d'un variable, ou une constante. Dans la pile langues, un appel de fonction est effectué par écrivant simplement le nom de la fonction; les paramètres sont implicites, et ils doivent déjà être sur le de la pile lors de l'appel. Le résultat de l'appel de fonction (le cas échéant) est ensuite laissé sur la pile après le fonction retourne, pour la prochaine fonction à consommer, et ainsi de suite. Parce que les fonctions sont appelées simplement en mentionnant leur nom sans aucun syntaxe supplémentaire, Forth et facteur référez-vous aux fonctions en tant que "mots", parce que dans la syntaxe ils sont vraiment juste mot.
Cela contraste avec les langages applicatifs qui appliquent leurs fonctions directement à des variables spécifiques.
Exemple: ajout de deux nombres.
langage applicatif :
int foo(int a, int b)
{
return a + b;
}
var c = 4;
var d = 3;
var g = foo(c,d);
langage Concaténatif (Je l'ai inventé, censé être similaire à Forth... ;) )
push 4
push 3
+
pop
Bien que je ne pense pas que concaténatif language = stack language, comme les auteurs soulignent ci-dessus, il semble similaire.
Je pense que l'idée principale est 1. Nous pouvons créer de nouveaux programmes simplement en joignant d'autres programmes ensemble.
Aussi, 2. Tout morceau aléatoire du programme est une fonction valide (ou sous-programme).
Bon vieux pur RPN Forth a ces propriétés, à l'exclusion de toute syntaxe aléatoire non-RPN.
Dans le programme 1 2 + 3 *le sous-programme + 3 * prend 2 arguments, et donne 1 résultat. Le sous-programme 2 prend 0 args et renvoie 1 résultat. Tout morceau est une fonction, et c'est bien!
Vous peut créer de nouvelles fonctions en regroupant deux ou plusieurs autres ensemble, éventuellement avec un peu de colle. Cela fonctionnera mieux si les types correspondent!
Ces idées sont vraiment bonnes, nous apprécions la simplicité.
Il n'est pas limité au langage série de style RPN, ni à la programmation impérative ou fonctionnelle. Les deux idées fonctionnent également pour un langage graphique, où les unités de programme peuvent être par exemple des fonctions, des procédures, des relations ou des processus.
Dans un réseau de processus de communication, chaque sous-réseau peut agir comme un processus.
Dans un graphe de relations mathématiques, chaque sous-graphe est valide relation.
Ces structures sont 'concaténatives', nous pouvons les séparer de quelque manière que ce soit (dessiner des cercles), et les réunir de plusieurs façons (dessiner des lignes).
Eh bien, c'est comme ça que je le vois. Je suis sûr que j'ai manqué beaucoup d'autres bonnes idées du camp concaténatif. Alors que je suis passionné par la programmation graphique, je suis nouveau à cet accent sur la concaténation.
Ma définition pragmatique (et subjective) pour la programmation concaténative (maintenant, vous pouvez éviter de lire le reste):
- > composition de la fonction de manière extrême (avec la syntaxe RPN):
( Forth code )
: fib
dup 2 <= if
drop 1
else
dup 1 - recurse
swap 2 - recurse +
then ;
-> tout est une fonction, ou au moins, peut être une fonction:
( Forth code )
: 1 1 ; \ define a function 1 to push the literal number 1 on stack
- > les arguments sont passés implicitement sur les fonctions (ok, il semble être une définition pour la programmation tacite), mais, ceci dans Forth:
a b c
Peut être en Lisp:
(c a b)
(c (b a))
(c (b (a)))
Donc, c'est facile à générer code ambigu... vous pouvez écrire des définitions qui poussent le XT (jeton d'exécution) sur la pile et définir un petit alias pour 'execute':
( Forth code )
: <- execute ; \ apply function
Donc, vous obtiendrez:
a b c <- \ Lisp: (c a b)
a b <- c <- \ Lisp: (c (b a))
a <- b <- c <- \ Lisp: (c (b (a)))
Vous ne pouvez pas expliquer une langue, juste obtenir un (facteur , de préférence) et essayer quelques tutoriels sur elle. Les tutoriels sont meilleurs que les réponses de débordement de pile.