Est-il possible d'imprimer la chaîne qui a été transmise dans la macro du schéma?

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

  •  15-11-2019
  •  | 
  •  

Question

Je travaille sur un traducteur linguistique dans le schéma Guile et je dois gérer le cas de base, où vous essayez de convertir un seul mot.

(define var 5)
(translate var)

Cela devrait renvoyer la chaîne var Et pas le numéro 5.
Comment puis-je faire cela en utilisant des macros de schéma R5RS (le define-syntax style)?

Éditer:
Je traduis du schéma à CoffeeScript.

Était-ce utile?

La solution

(define-syntax translate
  (syntax-rules ()
    [(_ v) 'v]))

Et si vous voulez une chaîne:

(define-syntax translate
  (syntax-rules ()
    [(_ v) (symbol->string 'v)]))

Espérons que le compilateur de Guile est assez intelligent pour plier l'expression résultante afin qu'elle devienne essentiellement une chaîne constante.

Autres conseils

Avec syntax-case Et son soutien à la garde:

(define-syntax translate
  (lambda (stx)
    (syntax-case stx ()
      [(_ v) (identifier? #'v)
       #'(symbol->string 'v)]
      [(_ v) (number? (syntax-e #'v))
       #'(number->string v)])))

(J'ai utilisé des crochets pour une comparaison facile avec la réponse d'Eli, cependant, ce n'est pas mon style habituel. ;-))

Mais si tu utilises syntax-case, alors vous pouvez tout aussi bien effectuer la conversion au niveau de la syntaxe au lieu de produire du code qui le fait à l'exécution:

(define-syntax translate
  (lambda (stx)
    (syntax-case stx ()
      [(_ v) (identifier? #'v)
       (datum->syntax stx (symbol->string (syntax->datum #'v)))]
      [(_ v) (number? (syntax-e #'v))
       (datum->syntax stx (number->string (syntax->datum #'v)))])))

L'essentiel ici est que la macro-code est désormais un schéma simple, par exemple, vous pouvez résumer les parties communes dans un aide:

(define-syntax translate
  (lambda (stx)
    (define (rewrap convert x)
      (datum->syntax stx (convert (syntax->datum x))))
    (syntax-case stx ()
      [(_ v) (identifier? #'v) (rewrap symbol->string #'v)]
      [(_ v) (number? (syntax-e #'v)) (rewrap number->string #'v)])))

Dans le même sens, si cette macro est si simple, alors il n'y a aucun besoin réel de syntax-case, à part retirer la sous-expression:

(define-syntax translate
  (lambda (stx)
    (syntax-case stx ()
      [(_ v) (let ([d (syntax->datum #'v)])
               (datum->syntax
                stx
                ((cond [(number? d) number->string]
                       [(symbol? d) symbol->string])
                 d)))])))

Remarque, btw, qu'il n'y a pas de magie dans syntax-case - et dans le cas de ce modèle simple, vous pouvez simplement retirer la valeur vous-même:

(define-syntax translate
  (lambda (stx)
    (let ([d (cadr (syntax->datum #'v))])
      (datum->syntax
       stx
       ((cond [(number? d) number->string]
              [(symbol? d) symbol->string])
        d)))))

Il y a des trucs passe-partout qui syntax-case Est-ce que cette dernière version perd:

  • Si vous utilisez la macro d'une manière inattendue comme (translate) Ensuite, cette version lancera une erreur sur cadr au lieu d'une erreur de syntaxe plus compréhensible

  • De même, si vous utilisez (translate 1 2) Ensuite, cette version ignorera silencieusement le 2 au lieu d'une erreur.

  • Et s'il est utilisé avec quelque chose qui n'est ni un identifiant ni un nombre (par exemple, (translate (+ 1 2))) alors cela dépendra de la valeur non spécifiée qui cond Renvoie plutôt que de lancer une erreur de syntaxe.

Les autres réponses sont déjà suffisamment utiles, mais je pensais que je soulignerais qu'il est possible de généraliser cette technique de manière très utile: les macros pour imprimer des expressions et leurs résultats pour le débogage:

(define-syntax log-expr
  (syntax-rules ()
    ((_ expr)
     (let ((result expr))
       (write (quote expr))
       (display " evaluates to ")
       (write result)
       (newline)
       result))))
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top