2013-04-03 14 views
5

Czy istnieje sposób w Clojure, aby napisać makro (lub użyć istniejącego), które zwraca dwa lub więcej wyrażeń s?Clojure makro zwraca dwa lub więcej s-wyrażeń

Przykład. Powiedzieć, że staram się produkować 10 pierwszych kwadraty:

(map * (range 10) (range 10)) 

Teraz chcę spróbować skorzystać powtórki tak, że mogę później dostarczyć mocy (2 na razie) jako parametr:

(map * (repeat 2 (range 10))) 

Powyższe nie działa jednak jako powtórz zwraca pojedyncze wyrażenie s z dwoma zakresami, a nie dwoma zakresami.

Proszę nie dostarczać alternatywnych implementacji funkcji "zwracaj pierwsze 10 pól". Interesują mnie idiomatyczne sposoby radzenia sobie z takimi sytuacjami lub ogólnie stosowane obejścia.

Przypuszczam szukam sposobu realizacji eksplodować poniżej:

(explode '(a b c)) ;; evals to a b c 
(map * (explode (repeat 2 (range 10))) 
+0

Twoje pytanie jest nieco mylące, ponieważ sformułowane.Byłoby pomocne, gdybyś mógł podać przykład składni, którą chciałbyś zobaczyć; na razie używasz 'map' i' repeat', które mają już określone definicje w Clojure. – JohnJ

+0

@JohnJ zobacz zaktualizowany ogon mojego posta –

Odpowiedz

4

Pojedynczy makro nie może tego zrobić.

Makro jest funkcją, która przyjmuje wyrażenie s i przekształca ją w inne wyrażenie s. Dane wejściowe mogą być dowolną sekwencją wyrażeń (symbole, prymitywy, inne wyrażenia itp.), A wynik jest pojedynczym wyrażeniem wstawianym zamiast pierwotnego wywołania makr.

ogólnie makro musiałaby otaczają wezwanie do map i przekształcić cały formularz

(your-macro-here (map * (repeat 2 (range 10)))) 

Jeśli masz dwa makra, jedną, która produkuje wyrażeń i innego, który obejmuje całą formę zewnętrzną, zewnętrzny makro może znaleźć pojedyncze wyrażenie zawierające wynik makra, w twoim przykładzie dwa zakresy i podnieść je o jeden poziom, aby uzyskać niezależne wyrażenia. Nie mogłem tego zalecić w praktyce, służy jedynie zilustrowaniu możliwości makr.

2

Jak mówi Artur, nie można zrobić dokładnie tego, czego szukasz za pomocą makr. Obejścia są możliwe, w zależności od tego, co chcesz zrobić z tymi formularzami.

Jeśli chcesz po prostu ocenić wiele formularzy utworzonych przez makro, np. uproszczenie kodu szablonowe, można owinąć te różnorodne formy w do postaci:

(defmacro defn-foos [& foos] 
    `(do [email protected](map (fn [foo] `(defn ~foo [])) foos))) 

(defn-foos my-fn-1 my-fn-2) 
;; expands as: 
;; (do (defn my-fn-1 []) 
;;  (defn my-fn-2 [])) 

Jeśli chcesz korzystać z rozbudowanych form jak pozycyjnych argumentów w wywołaniu funkcji, jak wydaje się to zrobić, to najlepiej jest prawdopodobnie do zawinięcia ich w list, a następnie użycia apply, która rozpakowuje listę jako argumenty pozycyjne do funkcji.

Aby zobaczyć jak to działa, trzeba pamiętać, że drugi przykład w oryginalnym pytanie można trywialnie zmodyfikowane do pracy przy użyciu apply:

(apply map * (repeat 2 (range 10))) 
Powiązane problemy