Domanda

Ci ho lavorato sopra Lisp comune pratico e come esercizio ho deciso di scrivere una macro per determinare se un numero è multiplo di un altro numero:

(defmacro multp (value factor)
`(= (rem ,value ,factor) 0))

affinché :(multp 40 10)restituisce true mentre(multp 40 13)non

La domanda è: fa questa macro perdere in qualche modo?Anche questo è "buono" Lisp?Esiste già una funzione/macro esistente che avrei potuto utilizzare?

È stato utile?

Soluzione

Siebel fornisce un ampio elenco (almeno per casi semplici) delle possibili fonti di perdite, e qui non ce n'è nessuna.Entrambi value E factor vengono valutati una sola volta e in ordine, e rem non ha effetti collaterali.

Questo però non è un buon Lisp, perché in questo caso non c'è motivo di usare una macro.Una funzione

(defun multp (value factor)
  (zerop (rem value factor)))

è identico per tutti gli scopi pratici.(Notare l'uso di zerop.Penso che in questo caso renda le cose più chiare, ma nei casi in cui è necessario evidenziare che il valore che stai testando potrebbe essere comunque significativo se è qualcosa di diverso da zero, (= ... 0) potrebbe essere migliore)

Altri suggerimenti

La tua macro mi sembra a posto.Non so cosa sia una macro che perde, ma la tua è piuttosto semplice e non richiede alcun gensym.Per quanto riguarda il Lisp "buono", la mia regola pratica è utilizzare una macro solo quando una funzione non funziona, e in questo caso è possibile utilizzare una funzione al posto della macro.Tuttavia, se questa soluzione funziona per te, non c'è motivo di non utilizzarla.

Bene, in linea di principio, un utente potrebbe fare questo:

(flet ((= (&rest args) nil))
  (multp 40 10))

che valuterebbe NIL...tranne che ANSI CL rende illegale riassociare la maggior parte dei simboli standard, incluso CL:=, quindi in questo caso particolare sei dalla parte della sicurezza.

In generale, ovviamente, dovresti essere consapevole sia della mancanza di trasparenza referenziale (catturare identificatori dal contesto in cui la macro è espansa) sia della macro non igiene (perdita di identificatori nel codice espanso).

No, nessun simbolo introdotto nella “chiusura lessicale” della macro viene rilasciato all'esterno.

Tieni presente che le perdite non sono NECESSARIAMENTE una cosa negativa, anche se le perdite accidentali lo sono quasi sempre.Per un progetto su cui ho lavorato, ho scoperto che era utile una macro simile a questa:

(defmacro ana-and (&rest forms)
  (loop for form in (reverse forms)
        for completion = form then `(let ((it ,form))
                                      (when it
                                       ,completion))
        finally (return completion)))

Ciò mi ha permesso di ottenere un "cortocircuito" delle cose che dovevano essere fatte in sequenza, con argomenti riportati dalle chiamate precedenti nella sequenza (e un fallimento segnalato restituendo NIL).Il contesto specifico da cui proviene questo codice è per un parser scritto a mano per un file di configurazione che ha una sintassi sufficientemente raffazzonata che scrivere un parser corretto utilizzando un generatore di parser era più lavoro che farlo manualmente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top