Вызов анонимной функции внутри макроса n раз, в зависимости от размера структуры данных, передаваемой в качестве аргумента - PullRequest
0 голосов
/ 01 марта 2019

Я добавляю свой тренировочный код для справки.Описание приведено ниже.

  (defmacro block [ctx & expr] 
(println expr)
  `(let [~@(mapcat (fn [[k v]] [k `~v]) ctx)] ~@expr))

(defmacro uia [metadata ctx arity & expr]
  `(block ~metadata 
     (fn ~arity (prn "got" ~arity ~'mt))
)
)
(def auto1 (uia {mt "dt"} 
    [{ et "wa" s "a1"}
         {et "wa" s "a2"}
         {et "um" s "a3"}] [et1 id cid] 
     (block {} (prn "auto1"))
))

(let [myarr ["x" 11 22]] (apply auto1 myarr))

При запуске кода выше, он напечатает "got" ["x" 11 22] "dt" только один раз.Это для arity внутри этого макроса.
Теперь я хочу напечатать его, в зависимости от количества элементов, переданных внутри ctx в мою функцию uia.

Например,

из auto1, я передам 3 обязательных аргумента uia:

метаданные : {mt "dt"}

ctx : [{ et1 "wa" s "a1"} {et1 "wa" s "a2"} {et1 "um" s "a3"}]

arity : [et id cid]

Now ctx isвектор с 3 картами в нем.Я хочу вызвать анонимную функцию внутри uia 3 раза.Так что теперь он будет печатать;

"got" "x" 11 22 wa a1 "dt" --> on first call "got" "x" 11 22 wa a2 "dt" --> on second call "got" "x" 11 22 um a3 "dt" --> on third call

Таким образом, соответствующий оператор вывода в соответствии с кодом будет;

(prn "got" ~'et ~'id ~'cid ~'et1 ~'s ~'md) ;=> "got x 11 22 wa a1 "dt"  ;; on first call
(prn "got" ~'et ~'id ~'cid ~'et1 ~'s ~'md) ;=> "got x 11 22 wa a2 "dt"  ;; on second call 
(prn "got" ~'et ~'id ~'cid ~'et1 ~'s ~'md) ;=> "got x 11 22 um a3 "dt"  ;; on third call and 
and so on..   ;; on nth call (where n is the number or elements present inside ctx)

Пожалуйста, предложите мнеспособ, которым это может быть достигнуто.

Примечание :

  • Он не должен печатать все элементы ctx за одну итерацию.
  • Какие бы изменения ни были сделаны, они должны быть выполненывнутри uia.

И, пожалуйста, дайте мне знать, если требуется дополнительная информация, связанная с этим.

1 Ответ

0 голосов
/ 01 марта 2019

Ваша последняя функция, возвращенная после вызова uia, нигде не включает контекстную карту:

>>> (macroexpand-1 
     '(uia {mt "dt"} 
           [{ et "wa" s "a1"}
            {et "wa" s "a2"}
            {et "um" s "a3"}] 
           [et1 id cid] 
           (block {} (prn "auto1"))))

(user/block 
  {mt "dt"} 
  (clojure.core/fn [et1 id cid] 
    (clojure.core/prn "got" [et1 id cid] mt)))

>>>  (macroexpand-1
       '(user/block 
          {mt "dt"} 
          (clojure.core/fn [et1 id cid] 
            (clojure.core/prn "got" [et1 id cid] mt))))

(clojure.core/let [mt "dt"] 
  (clojure.core/fn [et1 id cid] (
    clojure.core/prn "got" [et1 id cid] mt)))

В результате получается функция, которая принимает заданное вами значение с закрытой над свободной переменной mtпривязан к «dt» - контекстную карту нигде не найти.

Я подозреваю, что ваше определение block не соответствует вашим ожиданиям или, по крайней мере, подпись неверна.

(defmacro block [ctx & expr] 
  `(let [~@(mapcat (fn [[k v]] [k v]) ctx)] ~@expr))

Фактическим аргументом, который вы передаете блоку, является карта метаданных, а не карта контекста.Если это преднамеренно, я бы изменил подпись, чтобы отразить замену ctx на mt в подписи и теле.

Что касается того, почему он печатается только три раза, то при рассмотрении окончательного расширения выше следует сделатьclear - возвращаемое замыкание принимает 3 аргумента и просто печатает их внутри вектора вместе с метаданными (на которые ссылается закрытый символ mt из внешнего let.

(defmacro uia [metadata ctx arity & expr]
  `(block ~metadata 
     (fn ~arity 
       (dotimes [n# ~(count ctx)]
         (prn "got" ~arity ~'mt)))))

Теперь с этим изменениемкогда вы набираете uia следующие отпечатки:

"got" ["x" 11 22] "dt"
"got" ["x" 11 22] "dt"
"got" ["x" 11 22] "dt"

Это шаг в правильном направлении, но ваш вопрос указывает, что вы также хотите, чтобы значения внутри карты печатались вместе с закрытыми метаданными и3 аргумента функции.Для печати на основе элементов в контекстной карте необходимо сделать два изменения:

Во-первых, ключи контекстной карты должны быть в кавычках символов 'et ине et, или ключевые слова. Это потому, что возвращаемая карта пытается оценить символы без кавычек во время выполнения, которые не связаны (предполагая, что у вас нет некоторого глобального контекста, в котором они связаны, что не было предоставлено).

Во-вторых, вам нужно перебрать каждую карту внутри возвращаемой функции и извлечь соответствующие значения.Помимо изменения ключей карты с символов на ключевые слова, единственными другими изменениями являются uia в соответствии с запросом, и для меня было проще всего сохранить изменения в любом случае.

(defmacro block [ctx & expr]
  `(let [~@(mapcat (fn [[k v]] [k v]) ctx)] ~@expr))

(defmacro uia [metadata ctx arity & expr]
  `(block ~metadata 
     (fn ~arity 
       (doseq [m# ~ctx]
         (prn "got" ~arity (:et m#) (:s m#) ~'mt)))))

(def auto1 
  (uia {mt "dt"} 
       [{:et "wa" :s "a1"}
        {:et "wa" :s "a2"}
        {:et "um" :s "a3"}] 
       [et1 id cid] 
     (block {} (prn "auto1"))))

(let [myarr ["x" 11 22]] (apply auto1 myarr))
...