首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从宏调用函数

从宏调用函数
EN

Stack Overflow用户
提问于 2022-04-08 21:22:45
回答 2查看 129关注 0票数 1

我有一个带有宏的ns。im处理的令人讨厌的事情是,taoensso.timbre宏只作为一个可变表达式(timbre/info "a" "b" "c")工作。一个项目列表不会正确地记录(timbre/info ["a" "b" "c"])。我试图创建一个包装宏,它允许代码以相同的变量形式调用(logger/info),然后处理所有元素,然后传递到timbre/info

代码语言:javascript
复制
(ns logger
  (:require [taoensso.timbre :as timbre :include-macros true])) ; a third party logger

;; A bit of pseudo code here. If you pass in a vector of args, you should get a vector of args with some changes
(defn scrub [args]
  (if (listy)
     (mapv (fn [a] (scrub args) args)
     (if (is-entry a) {:a "xxx"} a)

(defmacro info
  [& args]
  `(timbre/info ~@(scrub args)))

这是不起作用的,因为它会被立即调用,并且不会解析传入的符号。我需要像这两种都不起作用的东西。

代码语言:javascript
复制
(defmacro info
  [& args]
  `(timbre/info @(scrub-log-pii ~args)))

(defmacro info
  [& args]
  `(timbre/info ~@('scrub-log-pii args)))

我的最后一个想法是尝试将音色宏包装成一个函数,这样宏和评估就会按正确的顺序进行。然而,没有办法“应用”到一个宏。

代码语言:javascript
复制
(defn info3
  [& args]
  (timbre/info (scrub-log-pii (vec args))))

有什么想法吗?

EN

回答 2

Stack Overflow用户

发布于 2022-04-08 21:40:20

你遇到了一个使用宏的问题,这种宏被称为“海龟一路向下”。也就是说,不使用函数组合,您可能需要编写一个包装器宏,然后再编写另一个包装器宏,等等。

这个答案描述了编写宏的详细步骤:

对于你的具体问题,我们可以这样做:

代码语言:javascript
复制
(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test)
  (:require
    [clojure.pprint :as pp]))

(defn infix-impl
  [a op b]
  (list op a b))

(defmacro infix
  "Allows user to have Java-style infix operators:

        (infix 2 + 3)
  "
  [a op b] (infix-impl a op b))

(defn infix-seq-impl
  [args]
  `(let [form#   (cons 'infix ~args)
         result# (eval form#)]
     result#))

(defmacro infix-seq
  [args] (infix-seq-impl args))

(dotest
  (is= 5 (infix 2 + 3))

  (let [params '[2 + 3]]
    (pp/pprint (infix-seq-impl 'params))

    (is= 5 (infix-seq params))))

在这里,我们使用infix宏来演示如何创建一个包装宏infix-seq,该宏接受一个参数序列而不是N个标量参数。打印的输出显示生成的代码:

代码语言:javascript
复制
(clojure.core/let
  [form__24889__auto__    (clojure.core/cons 'tst.demo.core/infix params)
   result__24890__auto__  (clojure.core/eval form__24889__auto__)]
 result__24890__auto__)

--更通用的版本

下面的applied宏允许您传入要“应用”到param序列的宏的名称:

代码语言:javascript
复制
(defn applied-impl
  [f args]
  `(let [form#   (cons ~f ~args)
         result# (eval form#)]
     result#))

(defmacro applied 
  [f args] (applied-impl f args))

(dotest
  (nl)
  (let [params '[2 + 3]]
    ;      (applied 'infix params)   ; using a single quote fails
    (is= 5 (applied `infix params)) ; using a backquote works
    (is= 5 (applied 'tst.demo.core/infix params)) ; can also use fully-qualified symbol with single-quote
    (is= 5 (applied (quote tst.demo.core/infix) params)) ; single-quote is a "reader macro" for (quote ...)
    ))
票数 2
EN

Stack Overflow用户

发布于 2022-04-09 07:57:03

对于这个问题(宏应用程序)的回答不是确切的,而是实用的timbre解决方案,它可能适用于您的具体情况:

这里 --您可以看到所有音色宏都使用log!宏,而后者又接受args的集合。

所以,只是将您的过程实现为

代码语言:javascript
复制
(defmacro info* [args] `(log! :info :p ~args ~{:?line (fline &form)}))

应该能起作用。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71803261

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档