循环和转换表单序列的宏

  • 本文关键字:表单 转换 循环 hy
  • 更新时间 :
  • 英文 :


我正在编写宏来简化使用matplotlib制作绘图的过程。我的第一次尝试,如下所示,工作正常:

(defmacro insert-ax [body] `((getattr g!ax (str '~(first body))) ~@(rest body)))
(defmacro/g! plot [main &optional title [fig-kwargs {}]]
`(do
(import [matplotlib.pyplot :as plt] [time [ctime]])
(setv [g!fig g!ax] (plt.subplots #**~fig-kwargs))
(insert-ax ~main)
(when ~title  (.set-title g!ax ~title))
(.savefig g!fig (if ~title ~title (ctime)))))

然后,以下代码按预期工作:

(plot (scatter xs ys) "Data"))

其中(在惯用的 Python 中(相当于

fig, ax = plt.subplots()
ax.scatter(xs,ys)
ax.set_title("Data")
fig.savefig("Data")

这很好,但我希望能够通过多个表单,每个表单都可以用insert-ax进行转换,这样我就可以向ax添加多个图,传递其他选项等。具体来说,这将do-plot

这样
(do-plot ((scatter xs ys) (scatter ys xs) "Data 2"))

相当于(再次在惯用的 Python 中(

fig, ax = plt.subplots()
ax.scatter(xs,ys)
ax.scatter(ys,xs)
ax.set_title("Data 2")
fig.savefig("Data 2")

但是以下幼稚的尝试不起作用:

(defmacro/g! do-plot [main &optional title [fig-kwargs {}]]
`(do
(import [matplotlib.pyplot :as plt] [time [ctime]])
(setv [g!fig g!ax] (plt.subplots #**~fig-kwargs))
(do (lfor cmd ~main (insert-ax cmd)))
(when ~title  (.set-title g!ax ~title))
(.savefig g!fig (if ~title ~title (ctime)))))

这将返回一个NameError: name 'scatter' is not definedNameError: name 'scatter' is not defined。但这是可以理解的:在insert-ax处理之前,我过早取消引用main.所以下一个自然尝试:

现在我得到的错误是expanding macro do-plot NameError: name 'cmd' is not defined.这可能是因为main不是为了 lfor 循环/列表理解工作而没有引用。因此,下一步是尝试取消引用整个循环:

(defmacro/g! do-plot [main &optional title [fig-kwargs {}]]
`(do
(import [matplotlib.pyplot :as plt] [time [ctime]])
(setv [g!fig g!ax] (plt.subplots #**~fig-kwargs))
(do ~(lfor cmd main (insert-ax cmd)))
(when ~title  (.set-title g!ax ~title))
(.savefig g!fig (if ~title ~title (ctime)))))

然后我的下一个错误是expanding macro do-plot AttributeError: 'HySymbol' object has no attribute 'c'.这似乎表明(因为 AttributeError 似乎与getattr有关(insert-ax定义中的~(first body))正在被评估为c

最后,出于货物崇拜行为,我尝试了以下方法

(defmacro/g! do-plot [main &optional title [fig-kwargs {}]]
`(do
(import [matplotlib.pyplot :as plt] [time [ctime]])
(setv [g!fig g!ax] (plt.subplots #**~fig-kwargs))
(do ~@(lfor cmd main (insert-ax cmd)))
(when ~title  (.set-title g!ax ~title))
(.savefig g!fig (if ~title ~title (ctime)))))

(尽管认为取消引号拼接会融合我的表单(。这将以静默方式失败,并且不产生任何输出。然而,在这里 hy2py 返回相同的错误expanding macro do-plot AttributeError: 'HySymbol' object has no attribute 'c'

我还能尝试什么?

宏的子例程通常比宏更好地编写为函数。函数使用起来更灵活(它们是一类对象(,混淆的可能性更小,并且更易于测试。以下是我将insert-ax作为函数执行此操作的方法:

(eval-and-compile (defn insert-ax [body]
`((. g!ax ~(first body)) ~@(rest body))))
(defmacro/g! do-plot [main &optional title [fig-kwargs {}]]
`(do
(import [matplotlib.pyplot :as plt] [time [ctime]])
(setv [g!fig g!ax] (plt.subplots #**~fig-kwargs))
~@(map insert-ax main)
(when ~title  (.set-title g!ax ~title))
(.savefig g!fig (if ~title ~title (ctime)))))

请注意,eval-and-compile(或eval-when-compile(是必要的,以确保函数在编译时(当(do-plot …)展开时(可用。我也在内部简化了insert-ax,尽管这不是必需的。

此外,您在调用do-plot时放错了 paren .你想要的是:

(do-plot ((scatter xs ys) (scatter ys xs)) "Data 2")

为完整起见,要使用原始insert-ax宏编写do-plot,请将上述~@(map insert-ax main)替换为~@(lfor cmd main `(insert-ax ~cmd))

最新更新