para "La conciencia del lenguaje del código" A, no hay mejor me Se ha visto que Lisp y su facilidad macro, específicamente, Common Lisp. Pero el comercio allí es que la mayoría de las veces no se conoce el tipo de un objeto en tiempo de compilación o macroexpansión. Para los literales, los tipos son conocidos, por lo que puede encontrar ejemplos de macros agresivas que prueban para ver si un objeto es literal y, de ser así, trátelo de una manera, tal vez según su tipo, y prepare la variable detectada. para la inspección de tipo de tiempo de ejecución.
Aquí hay un ejemplo que adapté de la biblioteca CLLIB (parte de la biblioteca CLOCC) hace varios años. El objetivo es proporcionar funciones que corten una cadena de prefijo de otra cadena con un prefijo coincidente. El prefijo puede conocerse en el momento de macroexpansión o puede que no. Si es así, podemos hacer una optimización: calcular la longitud del prefijo primero e incrustarlo como un literal, de modo que no se vuelva a calcular en cada llamada a la función generada. La macro es desalentadora al principio, pero el código generado real es pequeño.
(defmacro after-prefix-core (comparison-op prefix string &optional length)
"Similar to cllib:string-beg-with-cs."
(flet ((chop (prefix prefix-length string string-length)
`(when (and (>= ,string-length ,prefix-length)
(,comparison-op ,prefix ,string :end2 ,prefix-length))
(subseq ,string ,prefix-length ,string-length))))
(let* ((gstring (gensym "STRING-"))
(gstring-length (gensym "STRING-LENGTH-")))
`(let* ((,gstring ,string)
(,gstring-length ,(or length `(length ,gstring))))
,(if (stringp prefix)
;; Constant -- length known at expansion time.
(let ((prefix-length (length prefix)))
(chop prefix prefix-length gstring gstring-length))
;; Other form -- length not known at expansion time.
(let ((gprefix (gensym "PREFIX-"))
(gprefix-length (gensym "PREFIX-LENGTH-")))
`(let* ((,gprefix ,prefix)
(,gprefix-length (length ,gprefix)))
,(chop gprefix gprefix-length gstring gstring-length))))))))
(defmacro after-prefix (prefix string &optional length)
"Similar to cllib:string-beg-with."
`(after-prefix-core string-equal ,prefix ,string ,length))
(defmacro after-prefix-cs (prefix string &optional length)
"Similar to cllib:string-beg-with-cs."
`(after-prefix-core string= ,prefix ,string ,length))
Ver la forma
(if (stringp prefix)
en el medio? Eso es inspeccionar el primer argumento en el tiempo de macroexpansión y, dependiendo de si el argumento es literal o simbólico, su tipo puede o no ser conocido.Si el tipo es un símbolo, suponemos que debemos esperar hasta el tiempo de ejecución para reconsiderarlo como una variable que apunta a algún otro valor.
Aquí está la expansión de la forma (after-prefix foo bar)
:
(LET* ((#:STRING-5340 BAR) (#:STRING-LENGTH-5341 (LENGTH #:STRING-5340)))
(LET* ((#:PREFIX-5342 FOO) (#:PREFIX-LENGTH-5343 (LENGTH #:PREFIX-5342)))
(WHEN
(AND (>= #:STRING-LENGTH-5341 #:PREFIX-LENGTH-5343)
(STRING-EQUAL #:PREFIX-5342 #:STRING-5340 :END2 #:PREFIX-LENGTH-5343))
(SUBSEQ #:STRING-5340 #:PREFIX-LENGTH-5343 #:STRING-LENGTH-5341))))
Tenga en cuenta que la variable #:PREFIX-LENGTH-5343
está obligado a la longitud calculada de FOO
, con destino a la variable #:PREFIX-5342
aquí.
Ahora mira la expansión de la forma (after-prefix "foo" bar)
, donde el prefijo es ahora una cadena literal:
(LET* ((#:STRING-5463 BAR) (#:STRING-LENGTH-5464 (LENGTH #:STRING-5463)))
(WHEN (AND (>= #:STRING-LENGTH-5464 3) (STRING-EQUAL "foo" #:STRING-5463 :END2 3))
(SUBSEQ #:STRING-5463 3 #:STRING-LENGTH-5464)))
Ahora no hay cómputo de la longitud de "foo"; está en línea como 3.
Puede parecer demasiado trabajo en este ejemplo, pero ser capaz de hacer tales cosas es un buen poder tener, como su pregunta opina.
Muchos compiladores de C y C++ eliminarán el código no utilizado si la expresión en 'if' se puede determinar en tiempo de compilación. Sin embargo, no estoy seguro si esto responde completamente su pregunta. –
No: el ejemplo anterior no se compilaría porque el código en algunos bloques de la static no sería válido. P.ej. si T fuera type int, entonces value .__ repr __() sería un error de compilación. – Grumdrig
Necesita hacer que "static if (is (typeof (value .__ repr__)))" para que se compile lo anterior. O "estático si (__ rasgos (compila, valor .__ repr__))". – Baxissimo