在宏内部调用匿名函数n次,具体取决于作为参数传递给它的数据结构的大小

时间:2019-03-01 12:34:56

标签: clojure macros

我在这里添加我的练习代码以供参考。说明如下。

aes_()

在运行上述代码时,它将仅打印library(shiny) library(ggplot2) ui <- (fluidPage( titlePanel("Pig Breeds"), sidebarLayout( sidebarPanel( selectInput(inputId = "x", label = "Pig Breeds:", choices = c("total_pigs", "female_breeding_herd", "in_pig_sows", "in_pig_gifts", "other_sows", "maiden_gilts", "boars_for_service", "other_pigs"), selected = "total_pigs"), selectInput(inputId = "y", label = "Year by year change:", choices = c(2016, 2017, 2018, "year_on_year_change"), selected = 2016), actionButton(inputId = "update", label = "update") ), mainPanel = ( plotOutput(outputId = "scatterplot") ) ) ) ) server <- (function(input, output) { output$scatterplot <- renderPlot({ ggplot(data=(read.csv("eu_pigs.csv")), aes(x = output$x, y = output$y) + geom_point()) observeEvent(input$update, {print(as.numeric(input$update))}) } ) } ) shinyApp(ui, server) 一次。这是用于此宏中的 (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,我将3个必选参数传递给uia

元数据auto1

ctx uia

种族{mt "dt"}

现在[{ et1 "wa" s "a1"} {et1 "wa" s "a2"} {et1 "um" s "a3"}]是一个带有3个映射的向量。我想在[et id cid]内部调用匿名函数3次。这样它将立即打印;

ctx uia "got" "x" 11 22 wa a1 "dt" --> on first call

因此根据代码的相应输出语句将为;

"got" "x" 11 22 wa a2 "dt" --> on second call

请给我建议一种可以实现它的方法。

注意

  • 它不应一次打印出ctx的所有元素。
  • 所做的任何更改都必须在"got" "x" 11 22 um a3 "dt" --> on third call内部完成。

如果需要一些与此有关的额外信息,请告诉我。

1 个答案:

答案 0 :(得分:1)

您通过调用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)))

结果是使用您指定的ariety的函数,并且将封闭的自由变量mt绑定到“ dt”-找不到上下文映射。

我怀疑您对block的定义不是您想要的,或者至少签名是错误的。

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

您传递给块的实际参数是元数据映射,而不是上下文映射。如果有意,我将更改签名以反映在签名和正文中将ctx替换为mt

关于为什么它只打印3次,请看上面的最后扩展应该清楚-返回的闭包接受3个参数,然后将它们与metdata一起打印在向量中(由闭合符号{{1引用}}从外部mt

let

有了此更改,现在当您调用(defmacro uia [metadata ctx arity & expr] `(block ~metadata (fn ~arity (dotimes [n# ~(count ctx)] (prn "got" ~arity ~'mt))))) 时,以下打印内容:

uia

这是朝着正确方向迈出的一步,但您的问题表明您还希望将地图内的值以及封闭的元数据和3个函数参数一起打印出来。要基于上下文映射中的项目进行打印,需要进行两项更改:

首先,上下文映射键需要用引号符号"got" ["x" 11 22] "dt" "got" ["x" 11 22] "dt" "got" ["x" 11 22] "dt" 而不是'et或关键字。这是因为返回的映射试图在运行时评估未绑定的未引用符号键(假设您没有绑定它们的某些全局上下文(未提供)。

第二,您需要遍历返回函数内的每个映射,并提取相关值。除了将映射键从符号更改为关键字之外,唯一的其他更改是根据请求对et进行更改,对我而言,无论如何都将更改保留在其中最容易。

uia