2010-09-14 4 views
12

Sto provando a scrivere un'esercitazione macro e ora ho bisogno di alcuni esempi che siano semplici da capire e tuttavia avvincenti.Esempi di macro semplici ma avvincenti che non sono già presenti in Clojure

Il problema è che molte delle cose ovvie sono già in clojure e contrib. E sento che "guarda, possiamo reimplementare tutte le funzioni della libreria" potrebbe non essere l'argomento migliore per spiegare perché le macro sono così grandi.

Qualcuno ha qualche esempio carino (one-liners sono i migliori) che non mi dispiacerebbe usare?

Ecco le prime tre parti del tutorial. Al momento è un po 'approssimativo, quindi qualsiasi commento su come potrebbe essere migliorato sarebbe accolto con gratitudine.

http://learnclojure.blogspot.com/2010/09/clojure-macro-tutorial-part-i-getting.html

http://learnclojure.blogspot.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html

http://learnclojure.blogspot.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html

+2

Forse il mio esempio preferito, che non sono sicuro sia possibile in clojure (forse un sottoinsieme limitato con clj-cont, ma completamente nello schema), sta implementando 'yield', come in python, tramite' chiamare/cc'. È un esempio potente che fa davvero capire che le macro possono aiutarti a costruire anche il più selvaggio dei costrutti nella lingua. – apg

risposta

4

parlerei più su modelli: quando e come è una macro utilizzata. es. ...

  • Protezione di una risorsa. Esempi: binding, with-open, ...
    (let [~x (get-resource)] (try [email protected] (finally (release-resource ~x))))
  • Definizione di cose. Esempi: defn, defsnippet (viva voce), defservice (anello)
  • Divisione macro/driver. Soprattutto questa tecnica toglie un sacco di dolore macro. Come più valutazione o acquisizione. Esempio: with-bindings
  • Codice brutto abbellimento. per esempio. quando Taming multi-dim arrays
6

Sto lavorando su alcuni software di crittografia in clojure. È davvero divertente e l'utilizzo dei test unitari lo rende più divertente perché non mi innervosisco nel rompere le cose. Il problema è che tutte le funzioni crittografiche generano risultati diversi ogni volta perché sono guidate da un buon generatore di numeri casuali di psudo IMHO.

Come si eseguono test delle funzioni randomizzate?

con una macro bind, ovviamente!

(defmacro with-fake-prng [ & exprs ] 
    "replaces the prng with one that produces consisten results" 
    `(binding [com.cryptovide.split/get-prng (fn [] (cycle [1 2 3])) 
      com.cryptovide.modmath/mody 719 
      com.cryptovide.modmath/field-size 10] 
     [email protected])) 

poi avvolgere le mie funzioni di test in (with-fake-prng (deftest mytest ....))

clojure ha un sacco di questi "macroes legano". come with-out-string e così via.

Ho anche una macro che carica ogni spazio dei nomi nel repl. (Non uso questo molto ora che ho passato a torta)

(defmacro load-all [] 
    '(use 
    :reload-all 
    'com.cryptovide.modmath 
    ... 
    'com.cryptovide.gui 
    'com.cryptovide.checksum 
    'com.cryptovide.log)) 

ps: mente sempre la prima regola di macro del club

+0

Ottimo esempio! L'alternativa è usare un framework di "dipendenza da iniezione", che è estremamente brutto in così tanti casi. – apg

+0

A partire da Clojure 1.3, questo non funzionerà più, poiché 'binding' può ridefinire solo i mapping per Vars dichiarato dinamico (che probabilmente le tue funzioni non lo sono). Invece, dovremmo ora usare la macro predefinita 'with-redefs': http://clojuredocs.org/clojure_core/clojure.core/with-redefs. Tuttavia, i punti più grandi si ergono: questo è un grande esempio della potenza dei macro. Proprio ora è già definito per noi. – quux00

+0

Quando ho portato questo codice a 1.4 ho dichiarato get-prng, mody e field-size per essere dinamici. –