Quelles sont les choses pour lesquelles vous avez utilisé des macros de schéma? [fermé]

StackOverflow https://stackoverflow.com/questions/245677

  •  05-07-2019
  •  | 
  •  

Question

De nombreux exemples de macros semblent concerner le fait de cacher des lambdas, par exemple. with-open-file dans CL. Je recherche des utilisations plus exotiques de macros, en particulier dans le schéma PLT. J'aimerais savoir quand utiliser une macro ou utiliser des fonctions.

Était-ce utile?

La solution

Je n'utilise que des macros de schéma (define-syntax) pour de petites choses telles qu'une meilleure syntaxe lambda:

(define-syntax [: x]
  (syntax-case x ()
    ([src-: e es ...]
     (syntax-case (datum->syntax-object #'src-: '_) ()
       (_ #'(lambda (_) (e es ...)))))))

Ce qui vous permet d'écrire

[: / _ 2]  ; <-- much better than (lambda (x) (/ x 2))

Dan Friedman a une implémentation hallucinante de l’utilisation de macros: http: // www.cs.indiana.edu/~dfried/ooo.pdf

Mais honnêtement, toutes les macros utiles que j'ai définies ont été volées sur de Paul Graham Lisp et sont généralement plus faciles à écrire avec defmacro (define-macro dans le schéma PLT). Par exemple, aif est assez moche avec syntax-rules.

(define-syntax (aif x)
  (syntax-case x ()
    [(src-aif test then else)
     (syntax-case (datum->syntax-object (syntax src-aif) '_) ()
       [_ (syntax (let ([_ test]) (if (and _ (not (null? _))) then else)))])]))

syntax-case est étrange dans la mesure où il n’est facile à utiliser que pour les macros très simples, où vous êtes heureux de l’impossibilité de capturer des variables; et des macros DSL très compliquées, où vous êtes heureux de l’impossibilité de capturer les variables facilement . Dans le premier cas, vous voulez écrire le code sans y penser, et dans le second, vous avez suffisamment réfléchi à la DSL pour pouvoir en écrire une partie dans le langage <=> / <=> qui n'est pas Scheme. afin d'éviter de mystifier les bugs.

Mais je n’utilise pas beaucoup les macros dans Scheme. Idiomatic Scheme est tellement fonctionnel que souvent, vous voulez juste écrire un programme fonctionnel et ensuite cacher quelques lambdas. Je suis dans le train fonctionnel et je crois maintenant que si vous avez un langage paresseux ou une bonne syntaxe pour lambda, même si ce n'est pas nécessaire, les macros ne sont donc pas très utiles dans un style purement fonctionnel.

Je recommanderais donc Lisp en pratique et Sur Lisp . Si vous souhaitez utiliser le schéma PLT, je pense que la plupart de leurs macros fonctionneront avec <=>. Ou utilisez simplement Common Lisp.

Autres conseils

Des macros sont nécessaires pour mettre en œuvre de nouvelles structures de contrôle et de nouvelles structures de liaison.

Recherchez donc ce type de construction dans http://planet.plt-scheme.org . Chez PLaneT, vous parcourez la documentation et le code.

Exemples de nouvelles structures de contrôle:

http://planet.plt-scheme.org/package-source/soegaard/control.plt/2/0/planet-docs/manual/index.html

Pour trouver des exemples de nouveaux formulaires de liaison, recherchez les macros commençant par & "; par - &"; Un exemple utile se trouve dans math.plt, également de PLaneT.

  ; Within a (with-modulus n form1 ...) the return values of
  ; the arithmetival operations +, -, * and ^ are automatically
  ; reduced modulo n. Furthermore (mod x)=(modulo x n) and
  ; (inv x)=(inverse x n).

  ; Example: (with-modulus 3 (^ 2 4)) ==> 1

  (define-syntax (with-modulus stx)
    (syntax-case stx ()
      [(with-modulus e form ...)
       (with-syntax ([+   (datum->syntax-object (syntax with-modulus) '+)]
                     [-   (datum->syntax-object (syntax with-modulus) '-)]
                     [*   (datum->syntax-object (syntax with-modulus) '*)]
                     [^   (datum->syntax-object (syntax with-modulus) '^)]
                     [mod (datum->syntax-object (syntax with-modulus) 'mod)]
                     [inv (datum->syntax-object (syntax with-modulus) 'inv)])
         (syntax (let* ([n e]
                        [mod    (lambda (x)   (modulo x n))]
                        [inv    (lambda (x)   (inverse x n))]
                        [+      (compose mod +)]
                        [-      (compose mod -)]
                        [*      (compose mod *)]
                        [square (lambda (x) (* x x))]
                        [^      (rec ^ (lambda (a b)
                                         (cond
                                           [(= b 0)   1]
                                           [(even? b) (square (^ a (/ b 2)))]
                                           [else      (* a (^ a (sub1 b)))])))])
                   form ...)))]))

Je vais commencer à répondre à la dernière question. Quand utiliser une macro au lieu d'une fonction. Les macros font des choses que les fonctions ne peuvent pas, et les fonctions font des choses que les macros ne peuvent pas, donc ce sera difficile de les mélanger, mais allons plus loin.

Vous utilisez des fonctions lorsque vous souhaitez que les arguments soient évalués et des macros lorsque vous souhaitez que les arguments ne soient pas évalués. Ce n'est pas très utile, n'est-ce pas? Vous utilisez des macros lorsque vous souhaitez écrire quelque chose d'une manière différente, lorsque vous voyez un motif et que vous souhaitez effectuer un résumé. Par exemple: Je définis trois fonctions appelées foo-create, foo-process et foo-destroy pour différentes valeurs de foo et avec des corps similaires dans lesquels le seul changement est foo. Il existe un modèle mais un niveau trop élevé pour une fonction, vous créez donc une macro.

Dans mon humble expérience, les macros dans Scheme doivent être utilisées autant que dans d’autres Lisps, comme Common Lisp ou Clojure . Je suppose que cela prouve que les macros hygiéniques ne sont peut-être pas une si bonne idée. Dans ce cas, je ne suis pas d'accord avec Paul Graham sur les raisons. Ce n'est pas parce que parfois vous voulez être sale (non hygiénique) mais parce que les macros hygiéniques finissent par être complexes ou compliquées.

Practical Common Lisp, de Peter Seibel, est une bonne introduction aux macros. On Lisp, de Paul Graham, pourrait constituer une bonne source d’exemples plus complexes. Regardez également les macros intégrées dans, par exemple, Common Lisp.

Le Automata via Macros paper présente une perle de programmation fonctionnelle sur la mise en œuvre de machines à états finis via des macros dans Scheme.

Le livre Le schème raisonné se termine par un implémentation complète basée sur macro de miniKanren, le langage de programmation logique utilisé dans le livre. Ce document présente miniKanren et sa mise en œuvre de manière plus formelle et concise que dans le livre.

Un exemple de macro plus avancée qui n'est pas une forme lambda déguisée est la macro with-slots de Common Lisp, qui permet à l'accès aux emplacements d'objet de ressembler à un accès de variable ordinaire:

(with-slots (state door) car
  (when (eq state :stopped)
    (setq state :driving-around)
    (setq door :closed)))

Notez que cela n’est pas la même chose que lier les valeurs d’emplacement aux variables locales et y accéder, car with-slots vous permet de modifier les emplacements à l’aide de SETQ et de voir immédiatement les modifications externes.

J'avais une curry macro quand je faisais beaucoup de jeu sur la paume de la main. C'était très pratique.

Les macros de schéma vous permettent d'ajouter des fonctionnalités que les auteurs du langage d'origine ne se sont pas inclus; c'est toute la philosophie des macros.

Voici un petit exemple: PLT Scheme fournit un langage pour la rédaction de présentations appelé Slideshow. J'ai utilisé des macros pour associer un numéro de diapositive à une diapositive afin de pouvoir les gérer plus facilement.

I & # 8217; J'ai écrit une macro qui fournit une syntaxe infixe. Rien d'extraordinaire aucune préséance. Bien que & # 8217; m fonctionne généralement bien avec la syntaxe préfixe, je préfère infixe pour & Lt; et >.

Je les utilise lorsque les procédures ne suffisent pas.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top