Clojure 宏:根据条件将过滤后的映射和数量传递给其他宏

2024-03-26

(defmacro action1 [] `(prn "action1" ~'start ~'etype1))

(defmacro block [bindings & body] 
  `(let [~@(mapcat (fn [[k v]] [(if (symbol? k) k (symbol (name k))) `'~v]) (cond
                     (map? bindings) bindings
                     (symbol? bindings) (var-get (resolve bindings))
                     :else (throw (Exception. "bindings must be map or symbol"))))]
       ~body))

(defmacro bar [ctx arity & expr]
      `(let [~'t1 "lv" ~'np (prn "bar_1st_let" '~ctx ~ctx '~arity ~arity '~arity(resolve (first '~arity)) )
            ] 
            (block ~ctx ;;~ctx = {start "s1" top "x"}
              (fn '~arity ;; '~arity = [etype1 cid1 id1 pl1]
                (let [~'__execonceresult 1]
                  (do ~@expr)     
                )
              )
            )
        )
  )

(defmacro foo_multi [metadata ctxv aritym & expr]
  `(let [~@(mapcat (fn [[k v]] [k `~v]) metadata) ~'np (prn "foo_multi_1st_let" '~aritym)] 
  (fn ~aritym 
      (for [~'ctx (filter #(= (% (some (fn [~'m] (if (= (name ~'m) "top") ~'m)) (keys %))) ~'etype) '~ctxv)]
        (do (prn "foo_multi_b4_case" ~'ctx ~'etype ~aritym)
        (case ~'etype
        "x"
          (let [[~'etype1 ~'cid1 ~'id1 ~'pl1] ~aritym ~'np (prn "foo_multi_2nd_let" ~'ctx ~'etype1 ~'cid1 ~'id1 ~'pl1)]
            (bar ~'ctx [~'etype1 ~'cid1 ~'id1 ~'pl1] ~@expr))
        "y"
          (let [[~'etype2 ~'cid2 ~'id2 ~'pl2] ~aritym]
            (bar ~'ctx [~'etype2 ~'cid2 ~'id2 ~'pl2] ~@expr))
        ))))))

(def foo (foo_multi { meta1 "m1" meta2 "m2" } [{start "s1" top "x"} 
  {start "s3" top "x"} {start "s2" top "y"}] [etype a1 a2 a3] (block {toc "c"} 
   (block {c1 "d"} (action1)) "end"))
   )

(let [myarr ["x" 100 200 {"p" 1 "q" 2}]] (apply foo myarr))

无法将数量从条形宏传递到块宏并获取java.lang.NullPointerException。 如果我注释来自 bar 宏的块调用,则执行其余代码。

(defmacro bar [ctx arity & expr]
      `(let [~'t1 "lv" ~'np (prn "bar_1st_let" '~ctx ~ctx '~arity ~arity '~arity(resolve (first '~arity)) )
            ] 
            (comment block ~ctx ;;~ctx = {start "s1" top "x"}
              (fn '~arity ;; etype specific ~arity eg: [etype1 cid1 id1 pl1]
                (let [~'__execonceresult 1]
                  (do ~@expr) ;; uses etype1     
                )
              )
            )
        )
  )

以下评论后是调试行的输出:

"foo_multi_1st_let" [etype a1 a2 a3]
"foo_multi_b4_case" {start "s1", top "x"} "x" ["x" 100 200 {"p" 1, "q" 2}]
"foo_multi_2nd_let" {start "s1", top "x"} "x" 100 200 {"p" 1, "q" 2}
"bar_1st_let" ctx {start "s1", top "x"} [etype1 cid1 id1 pl1] ["x" 100 200 {"p" 1, "q" 2}] [etype1 cid1 id1 pl1] nil
"foo_multi_b4_case" {start "s3", top "x"} "x" ["x" 100 200 {"p" 1, "q" 2}]
"foo_multi_2nd_let" {start "s3", top "x"} "x" 100 200 {"p" 1, "q" 2}
"bar_1st_let" ctx {start "s3", top "x"} [etype1 cid1 id1 pl1] ["x" 100 200 {"p" 1, "q" 2}] [etype1 cid1 id1 pl1] nil

根据上面打印的调试行,在 bar 宏中,我无法解析第一个数量符号,并且它被打印为零(不知道原因)。目标是将数量从条宏正确传递到块宏,并能够访问和打印 action1 宏中的 start 和 etype1 值。


我得到一个由你引起的 NullPointeraction1宏返回nilblock宏尝试执行响应action1。拼接引号可以解决这个问题。另外,在我看来,绑定值上有太多引号block,所以我也把它们拿出来了。

(defmacro block [bindings & body]
  (let [bs (->>
            (cond
              (map? bindings)    bindings
              (symbol? bindings) []
              :else              (throw (Exception. "bindings must be map or symbol")))
            (mapcat (fn [[k v]] [(if (symbol? k) k (symbol (name k))) v])))]
    `(let [~@bs]
     ~@body)))

第二,clojure.core/resolve will 只在命名空间中查找变量 https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/ns-resolve,不是由以下人员创建的本地人clojure.core/let or clojure.core/fn。因此,如果您尝试解决本地问题,您将得到nil.

(defmacro bar [bindings arity & expr]
  `(block ~bindings ;;~bindings = {start "s1" top "x"}
          (fn ~arity ;; '~arity = [etype1 cid1 id1 pl1]
            (let [~'__execonceresult 1]
              (do ~@expr)))))

(macroexpand-1 '(bar {start "s1" top "x"} [etype1 cid1 id1 pl1] (action1)))
;; =>
(do
 (user/block
  {start "s1", top "x"}
  (clojure.core/fn
   [etype1 cid1 id1 pl1]
   (clojure.core/let [__execonceresult 1] (do (action1))))))

所以这部分foo_multi现在运行。

(block {toc "c"} (block {c1 "d"} (action1)) "end")
;;=>
"action1" :start :etype1
"end"

In foo_multi:

(defn named-top? [m]
  (when (= (name m) "top")
    m)) 

(defmacro foo_multi [metadata ctxv aritym & expr]
  (prn "foo_multi" (map #(get % (some named-top? (keys %))) ctxv))
  `(let [~@(mapcat (fn [[k v]] [k v]) metadata)]
     (prn "foo_multi_1st_let" '~aritym)
     (fn ~aritym
       (for [~'ctx (filter #(= (get % (some named-top? (keys %))) ~'etype) '~ctxv)]
         (do #_ (prn "foo_multi_b4_case" ~'ctx ~'etype ~aritym)
             (case ~'etype
               "x"
               (let [[~'etype1 ~'cid1 ~'id1 ~'pl1] ~aritym ~'np (prn "foo_multi_2nd_let" ~'ctx ~'etype1 ~'cid1 ~'id1 ~'pl1)]
                 (bar ~'ctx [~'etype1 ~'cid1 ~'id1 ~'pl1] ~@expr))
               "y"
               (let [[~'etype2 ~'cid2 ~'id2 ~'pl2] ~aritym]
                 (bar ~'ctx [~'etype2 ~'cid2 ~'id2 ~'pl2] ~@expr))))))))

过滤器(filter #(= (get % (some named-top? (keys %))) ~'etype) '~ctxv)似乎会出错,因为etype除非被迫存在,否则不会存在metadata争论。用~'idiom因为你永远不知道你在跟踪什么,而这只是远距离的幽灵行动。最好使用gensym的特征syntax-quote local# as 此处描述 https://clojure.org/guides/weird_characters#syntax_quote.

正如对调试策略的评论一样,尝试提取简化的最小案例可能会帮助您了解正在发生的情况。我认为这段代码相当混乱。有一大堆东西拼凑在一起。听起来好像您正在学习 Clojure 和宏,并且一口气咬掉了太多内容。我认为您正在尝试使用这些宏复制词法范围,但我不完全确定最终目标是什么。也许读完this https://clojure.org/reference/special_forms会有帮助的。

另外,我怀疑当你发现这一点时你会遇到麻烦clojure.core/for很懒。

foo_multi返回一个返回函数列表的函数。因此,要实际执行您编写的大部分代码,您需要调用这些函数。

(let [start  :start
      etype1 :etype1
      foo    (foo_multi {meta1 "m1" meta2 "m2" }
                        [{start "s1" top "x"} 
                         {start "s3" top "x"}
                         {start "s2" top "y"}]
                        [etype a1 a2 a3]
                        (block {toc "c"} 
                               (block {c1 "d"} (action1))
                               "end"))
      args   ["x" 100 200 {"p" 1 "q" 2}]
      fns    (apply foo args)]
  (map #(apply % args) fns))

如果您尝试使用映射而不是向量来复制词法范围,也许此代码片段将帮助您重新思考您的方法:

(defmacro my-let [bindings & body]
  (let [bs (vec (mapcat (fn [[k v]] [k v]) bindings))]
    `(let ~bs
       ~@body)))

(defmacro my-multi-let [bindings-list & body]
  (->> bindings-list
       (map (fn [b] `(my-let ~b ~@body)))
       (cons `list)))

(macroexpand-1 '(my-let {a "a1" b "b1"} [a b]))
(macroexpand-1 '(my-multi-let [{a "a1" b "b1"} {a "a2" b "b2"}] [a b]))
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Clojure 宏:根据条件将过滤后的映射和数量传递给其他宏 的相关文章

随机推荐

  • 如何在 C# 中解析 HTTP url?

    我的要求是解析 Http URL 并相应地调用函数 在我当前的实现中 我使用嵌套的 if else 语句 我认为这不是一种优化的方式 您能建议其他一些有效的方法吗 网址是这样的 server func1 server func1 SubFu
  • 使用服务主体对 GetReportInGroupAsync PowerBI Embedded API 调用进行未经授权的响应

    我正在尝试将 Power BI 报告嵌入到我的 Net Core 应用程序中 但是我无法从请求中获得有效的响应 我正在使用 Microsoft PowerBI API 包和通过服务主体注册的 azure 应用程序 据我所知 我已按照此处的说
  • 在没有包装器的情况下在 QT 上使用 OpenGL [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个与 OpenGL 结合使用的 GUI 工具包 QT 看起来很有前途 但不幸的是它将大多数
  • 在 Angular 中旋转伪 3D 轮播

    我正在尝试创建一个伪 3d 轮播 其中包含 5 个项目 如下所示 并让它们循环 我发现这很棒堆栈闪电战 https stackblitz com edit angular ivy sqt1uq file src 2Fapp 2Fapp co
  • 一般替换 Angular 2 路由参数并导航

    我正在构建一个 Angular 应用程序 其中大多数路由都属于给定项目并包含一个projectId 顶部导航区域将有一个项目的下拉列表 当用户从下拉列表中选择一个项目时 它需要导航到当前路线 但将 projectId 替换为新值 这非常类似
  • NameError:未定义全局名称“numpy”

    我正在尝试通过收集 essentia 一个 MIR 库 函数来编写一个特征提取器 流程图如下 单独的特征提取 池化 PoolAggregator 使用poolAggregator连接形成整个特征列表np concatenate 即使不导入
  • 如果屏幕上显示多个二维码,请扫描二维码

    我正在开发一个Android示例应用程序作为一个学术项目 我需要扫描二维码 我使用了二维码扫描库 如果屏幕上只有一个二维码 我能够成功检测到二维码 是的 我想扫描二维码 尽管相同的二维码一次显示在屏幕上的多个位置 例如 在我的笔记本电脑屏幕
  • Nginx:何时使用 proxy_set_header 主机 $host 与 $proxy_host

    我一直在阅读反向代理 想知道什么时候proxy set header Host host是适当的proxy set header Host proxy host 我做了一些研究本文 https www digitalocean com co
  • 在强制布局上拖动会阻止其他 mouseup 侦听器

    我想在 d3 js 强制布局中启用拖动 当拖动一个圆圈并释放鼠标按钮时 我想通过回调调用特定的函数 如下所示 this force d3 layout force nodes this nodes size this width this
  • Netty websocket客户端闲置5分钟后不从服务器读取新帧

    我在服务器端和客户端都使用 Netty 来建立和控制 websocket 连接 我在服务器端有一个空闲状态处理程序 http netty io 4 1 api io netty handler timeout IdleStateHandle
  • 在jsp页面中显示jfreechart

    我想显示一个jfreechartjsp 页面中的图表 我写的代码如下 img src chart jpg 哪里的createCategoryChart 方法创建所需的 jpg 它存储在 eclipse 文件夹中 我没有在文件名中添加任何路径
  • 强制 UIView/UIVIewController 方向

    我们正在编写一个专门处于横向模式的应用程序 我们对根视图使用变换将其旋转到 LandscapeRight 然后该视图加载的每个视图都共享坐标系 这一切都很好 除了我们的视图之一有一个由视图控制器加载的 UIWebView 对象 我们尝试查看
  • 如何将shadershop公式转换成glsl

    我最近一直在学习着色器的一些基础知识 并且想出了一个很棒的视觉工具 着色器商店 http www cdglabs org Shadershop 但我无法将我在此站点中创建的公式转换为 glsl 一个简单的例子 我在此网站中创建了一个公式 我
  • data.table 相当于 tidyr 中的complete/fill

    我有以下数据 library tidyr library dplyr gt gt Attaching package dplyr gt The following objects are masked from package stats
  • Android-状态栏通知

    我是安卓新手 我现在想知道如何在主页中创建状态通知栏 谁能帮我一些代码 提前致谢 notificationManager NotificationManager context getSystemService Context NOTIFI
  • JTable 单元格中的图像相差一个像素?

    因此 我现在可以将图像加载到 JTable 的单元格中 但由于某种原因 图形全部向右移动了一个像素 使我能够看到 JTable 的背景 有任何想法吗 抱歉 如果我的格式已关闭 仍然没有完全习惯这种标记 public static void
  • 使用 php cUrl 发送会话变量

    我正在尝试在我的应用程序内的脚本之间发送数据 问题是会话 ID 没有响应 脚本1是
  • 使用 bash 自动化点文件

    我想创建自己的自动点文件文件夹 我将使用 git 对我的点文件使用版本控制 但这与问题无关 我想要的只是符号链接中的所有文件和文件夹 dotfiles到我的主文件夹 由于我对 bash 一点都不擅长 所以我无法做到这一点 请在这件事上给予我
  • ravendb 结合搜索和Where

    我正在 C 中执行 raven 查询 并利用Where 和Search 扩展方法 我需要这两个功能 因为我只需要返回具有特定 Guid 字段的索引以及文本正文中存在的文本 不幸的是 Where 扩展方法似乎与 Search 扩展方法不兼容
  • Clojure 宏:根据条件将过滤后的映射和数量传递给其他宏

    defmacro action1 prn action1 start etype1 defmacro block bindings body let mapcat fn k v if symbol k k symbol name k v c