47 votes

Évaluation paresseuse vs macros

Je suis habitué à l'évaluation différée de Haskell, et je me retrouve à obtenir irritée avec hâte par défaut langues maintenant que j'ai utilisé l'évaluation différée correctement. C'est tout à fait dommageable, comme les autres langues que j'utilise principalement faire de la paresseusement l'évaluation des trucs très bizarre, normalement impliquant le déploiement de la coutume des itérateurs et ainsi de suite. Donc, juste par l'acquisition de certaines connaissances, en fait, j'ai fait moi-même de moins en moins productifs dans ma langue d'origine. Soupir.

Mais j'ai entendu dire que AST macros offrent un autre moyen propre de faire la même chose. J'ai souvent entendu des déclarations comme " Paresseux évaluation des macros redondant et vice-versa, la plupart de sparring Haskell, Lisp et les communautés.

J'ai flirté avec les macros dans les différents Lisp variantes. Ils semblaient vraiment comme un manière organisée de copier et coller les morceaux de code autour de à être traités au moment de la compilation. Ils n'étaient certainement pas le saint graal que Lispers aime à penser qu'il est. Mais c'est presque certainement parce que je ne peux pas les utiliser correctement. Bien sûr, avoir le macro système fonctionne sur la même base de données de la structure de la langue elle-même est assemblé avec est vraiment utile, mais c'est encore essentiellement une manière organisée de faire un copier-coller du code autour. Je reconnais que baser un système de macro sur le même AST comme la langue qui permet la pleine exécution de l'altération est puissant.

Ce que je voudrais savoir, c'est comment les macros être utilisé de manière concise et succincte faire ce paresseux-évaluation n'? Si je veux traiter un fichier ligne par ligne, sans aspirer la totalité de la chose, je viens de retourner une liste qui avait une ligne de routine de lecture mappé sur elle. C'est l'exemple parfait de la DWIM (faire ce que je veux dire). Je n'ai même pas à y penser.

De toute évidence, je ne reçois pas les macros. Je l'ai utilisé et n'a pas été particulièrement impressionné étant donné le battage médiatique. Donc, il y a quelque chose qui me manque, que je ne suis pas en lisant la documentation en ligne. Quelqu'un peut-il expliquer tout cela à moi?

60voto

Ryan Culpepper Points 4809

Évaluation différée rend macros redondant

C'est un pur non-sens. (Pas de votre faute; je l'ai entendu avant.) Il est vrai que vous pouvez utiliser des macros pour modifier l'ordre, le contexte de l'évaluation de l'expression, mais c'est l'utilisation la plus fondamentale de macros, et c'est vraiment pas pratique pour simuler un paresseux de la langue à l'aide ad hoc macros au lieu des fonctions. Donc, si vous êtes arrivé au macros provenant de cette direction, vous serait en effet d'être déçu.

Les Macros sont pour l'extension de la langue avec de nouvelles formes syntaxiques. Certaines des capacités spécifiques de macros sont

  1. modifier l'ordre, le contexte de l'évaluation de l'expression
  2. la création de nouveaux formulaires obligatoires (c'est à dire touchant la portée d'une expression est évaluée en)
  3. l'exécution de la compilation en temps de calcul, y compris le code d'analyse et de transformation

Les Macros qui ne (1) peut être assez simple. Par exemple, dans la Raquette, la gestion des exceptions forme, with-handlers, c'est une macro qui se développe en call-with-exception-handler, à certaines conditions, et d'une continuité dans le code. Il est utilisé comme ceci:

(with-handlers ([(lambda (e) (exn:fail:network? e))
                 (lambda (e)
                   (printf "network seems to be broken\n")
                   (cleanup))])
  (do-some-network-stuff))

La macro implémente la notion de "prédicat-et-gestionnaire de clauses dans le contexte dynamique de l'exception", basé sur la primitive call-with-exception-handler qui gère toutes les exceptions au point qu'ils sont soulevées.

Une version plus sophistiquée de l'utilisation de macros est une implémentation d'un LALR(1) analyseur générateur. Au lieu d'un fichier distinct qui a besoin de pré-traitement, l' parser forme est tout simplement un autre type d'expression. Il prend une grammaire de description, calcule les tables au moment de la compilation, et produit un analyseur de fonction. L'action routines sont lexicalement d'étendue, de sorte qu'ils peuvent se rapporter à d'autres définitions dans le fichier ou même lambda-variables liées. Vous pouvez même utiliser d'autres extensions de langage dans l'action routines.

À l'extrême fin, Typé Raquette est tapé un dialecte de Raquette mis en œuvre via des macros. Il a un système sophistiqué de type système conçu pour correspondre à la idiomes de Raquette/Régime de code, et il interagit avec le type de modules en protégeant tapé fonctions dynamiques pour les contrats de logiciels (également mis en œuvre via des macros). Il est mis en œuvre par un "tapé module de macro" qui s'affiche, tapez-les contrôles, et transforme le module de corps ainsi que des macros auxiliaires pour attacher des informations de type de définitions, etc.

FWIW, il y a aussi Paresseux Raquette, un paresseux, un dialecte de la Raquette. Il n'est pas mis en œuvre par la transformation de la fonction dans une macro, mais par la reliaison lambda, define, et la fonction de l'application de la syntaxe pour les macros créer et à force de promesses.

En résumé, l'évaluation différée et les macros ont un petit point d'intersection, mais ils sont extrêmement différentes choses. Et les macros ne sont certainement pas subsumé par l'évaluation différée.

23voto

Conal Points 9874

La paresse est denotative, tandis que les macros ne sont pas. Plus précisément, si vous ajoutez des non-rigueur à un denotative langue, le résultat est toujours denotative, mais si vous ajoutez des macros, le résultat n'est pas denotative. En d'autres termes, la signification d'une expression dans un paresseux pur langage est une fonction uniquement de la signification des expressions; tandis que les macros peuvent rendement sémantiquement distinctes résultats de sémantique de l'égalité des arguments.

En ce sens, les macros sont de plus en plus puissants, tandis que la paresse est d'autant plus sage du point de vue sémantique.

Edit: plus précisément, les macros sont non-denotative sauf à l'égard de l'identité/trivial dénotation (où la notion de "denotative" devient vide de sens).

23voto

sclv Points 25335

Évaluation différée peut se substituer à certaines utilisations de macros (ceux qui retardent l'évaluation de créer de contrôle des constructions), mais l'inverse n'est pas vrai. Vous pouvez utiliser des macros pour faire retardé l'évaluation des constructions plus transparent -- voir DDRS 41 (cours d'eau) pour un exemple de la façon dont: http://download.plt-scheme.org/doc/4.1.5/html/srfi-std/srfi-41/srfi-41.html

En plus de cela, vous pouvez écrire votre propre paresseux IO primitives ainsi.

Dans mon expérience, cependant, subtilement paresseux code dans un strict de la langue tend à introduire une surcharge par rapport à profondément paresseux code dans un runtime conçue pour soutenir efficacement à partir du début, ce qui, vous l'esprit, est une question de mise en œuvre réellement.

10voto

Rainer Joswig Points 62532

Lisp a commencé à la fin des années 50 du dernier millénaire. Voir FONCTIONS RÉCURSIVES DES EXPRESSIONS SYMBOLIQUES ET LEUR CALCUL à la MACHINE. Les Macros étaient pas une partie de Lisp. L'idée était de faire des calculs avec des expressions symboliques, qui permettent de représenter toutes sortes de formules et programmes: les expressions mathématiques, logique des expressions, des phrases en langage naturel, les programmes d'ordinateur, ...

Plus tard, Lisp macros ont été inventés, et ils sont une application de l'idée ci-dessus à Lisp lui-même: les Macros transformer Lisp (ou Lisp comme des expressions à d'autres expressions Lisp en utilisant la totalité du langage Lisp comme un langage de transformation.

Vous pouvez imaginer qu'avec des Macros, vous pouvez mettre en œuvre puissante pré-processeurs et les compilateurs en tant qu'utilisateur de Lisp.

La typique du dialecte de Lisp utilise évaluation stricte des arguments: tous les arguments des fonctions sont évaluées avant qu'une fonction est exécutée. Lisp a également intégré plusieurs formes différentes règles d'évaluation. IF en est un exemple. En Common Lisp IF est un soi-disant particulière de l'opérateur.

Mais on peut définir une nouvelle Lisp comme des (sous-) langue qui utilise l'évaluation différée et nous pouvons écrire des Macros pour transformer cette langue en Lisp. Ce est une application pour les macros, mais de loin pas le seul.

Un exemple (assez vieux) pour un Lisp extension qui utilise des macros pour mettre en œuvre un code de transformateur qui fournit des structures de données d'évaluation différée est la SÉRIE de l'extension de Common Lisp.

5voto

6502 Points 42700

Les Macros peuvent être utilisées pour gérer l'évaluation différée, mais en partie seulement. Le principal point de macros est que, grâce à eux, fondamentalement, rien n'est figé dans la langue.

Si la programmation est comme jouer avec des briques de LEGO, avec des macros, vous pouvez également modifier la forme des briques ou de la matière qu'ils sont construits avec des.

Macros est plus que juste retardé d'évaluation. Qui était disponible en tant que fexpr (une macro précurseur dans l'histoire de lisp). Macros est sur le programme de réécriture, où fexpr est un cas particulier...

Par exemple, considérez que je suis en train d'écrire dans mon temps libre un petit lisp à compilateur javascript et de l'origine (dans le noyau javascript) je n'avais lambda avec le soutien de &rest arguments. Maintenant, il ya un soutien pour le mot-clé arguments et que parce que j'ai redéfini ce lambda signifie en lisp lui-même.

Je peux maintenant écrire:

(defun foo (x y &key (z 12) w) ...)

et appeler la fonction avec

(foo 12 34 :w 56)

Lors de l'exécution de cet appel, dans le corps de la fonction l' w paramètre sera lié à 56 et l' z paramètre à 12 parce qu'il n'était pas passé. Je vais également obtenir une erreur d'exécution si une non prise en charge argument mot-clé est transmis à la fonction. Je pourrais même ajouter sur le temps de compilation vérifier soutien par la redéfinition de ce qu'est la compilation d'une des expressions les moyens (c'est à dire l'ajout d'vérifie si "statique" appel de fonction, les formes sont de passage les paramètres corrects pour les fonctions).

Le point central est que l'original (noyau) de la langue n'ont pas de soutien pour le mot-clé arguments à tous, et j'ai pu ajouter à l'aide de la langue elle-même. Le résultat est exactement comme si elle était là depuis le début; c'est tout simplement partie de la langue.

La syntaxe est important (même si techniquement, il est possible d'utiliser une machine de turing). La syntaxe des formes de pensées que vous avez. Les Macros (et de lire les macros) vous donnent un contrôle total sur la syntaxe.

Un point clé est que le code de réécriture de code n'est pas à l'aide d'un paralysé abrutir brainf**k-comme de la merde que C++ template métaprogrammation (où de simplement faire une if est une réussite remarquable), ou avec un même dumber moins-que-regexp de substitution comme moteur de préprocesseur C.

Code de réécriture de code utilise la même part entière (et extensible) de la langue. C'est lisp tout le chemin vers le bas ;-)

Assurez-vous de l'écriture de macros est plus difficile que l'écriture régulière de code; mais c'est un "essentiel de la complexité du problème, pas une complexité artificielle parce que vous êtes obligés d'utiliser un monte-demi-langage comme C++ métaprogrammation.

L'écriture de macros est plus difficile parce que le code est une chose complexe, et lors de l'écriture de macros que vous écrivez des choses complexes que de bâtir des choses elles-mêmes. C'est même pas si rare pour remonter d'un niveau de plus et écrire la macro-générer des macros (c'est là que le vieux lisp blague du "je suis en train d'écrire du code qui écrit le code qui écrit le code que je suis payé pour" vient).

Mais la macro de puissance est tout simplement infini.

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