Clojure 如何使用宏迭代列表?

Clojure 如何使用宏迭代列表?,clojure,Clojure,我试图通过调用REPL中的以下表达式来打印给定命名空间中所有函数的文档: (doseq [f (dir-fn 'clojure.repl)] (doc f)) 但是,调用此表达式将返回nil,而不将文档打印到REPL。我知道这可能与doc是一个宏有关,但我是一个Clojure新手,不完全确定如何理解这个问题 为什么此表达式在不打印文档的情况下返回nil 如何修改此表达式,使其打印给定命名空间中每个函数的文档 谢谢 更新:将两个答案结合起来: (defn ns-docs [ns']

我试图通过调用REPL中的以下表达式来打印给定命名空间中所有函数的文档:

(doseq
  [f (dir-fn 'clojure.repl)]
  (doc f))
但是,调用此表达式将返回
nil
,而不将文档打印到REPL。我知道这可能与
doc
是一个宏有关,但我是一个Clojure新手,不完全确定如何理解这个问题

  • 为什么此表达式在不打印文档的情况下返回
    nil
  • 如何修改此表达式,使其打印给定命名空间中每个函数的文档
  • 谢谢

    更新:将两个答案结合起来:

    (defn ns-docs [ns']
      (doseq [[symbol var] (ns-interns ns')]
      (newline)
      (println symbol)
      (print "  ")
      (println (:doc (meta var)))))
    (ns-docs 'clojure.repl)
    

    我想从这里开始:

    • (名称相似,但不同)
    • API和参考部分位于
    请注意,
    doc
    位于命名空间
    clojure.repl
    中,它反映了它的预期用途(由repl中的人使用)。下面是一些代码,它们也将在名称空间上迭代&打印文档字符串(使用不同的技术):

    其中
    demo.core
    是感兴趣的名称空间

    请注意,
    ns实习生
    为您提供了一个符号和变量,如:

    fn-symbol  => <#clojure.lang.Symbol -main>
    fn-var     => <#clojure.lang.Var #'demo.core/-main>
    

    我想从这里开始:

    • (名称相似,但不同)
    • API和参考部分位于
    请注意,
    doc
    位于命名空间
    clojure.repl
    中,它反映了它的预期用途(由repl中的人使用)。下面是一些代码,它们也将在名称空间上迭代&打印文档字符串(使用不同的技术):

    其中
    demo.core
    是感兴趣的名称空间

    请注意,
    ns实习生
    为您提供了一个符号和变量,如:

    fn-symbol  => <#clojure.lang.Symbol -main>
    fn-var     => <#clojure.lang.Var #'demo.core/-main>
    
    为什么这个表达式在不打印文档的情况下返回nil

    因为
    doc
    宏正在从循环接收符号
    f
    ,而不是直接接收函数符号

    如何修改此表达式,使其打印给定命名空间中每个函数的文档

    然后,如果需要,可以打印这些贴图/字符串

    为什么这个表达式在不打印文档的情况下返回nil

    因为
    doc
    宏正在从循环接收符号
    f
    ,而不是直接接收函数符号

    如何修改此表达式,使其打印给定命名空间中每个函数的文档


    然后,如果需要,您可以打印这些映射/字符串。

    虽然这可能无法帮助您回答问题,但在学习Clojure时,评估宏的问题会出现很多

    宏负责评估其参数。在这种情况下,
    clojure.repl/doc
    将忽略当前的词法上下文,并假定您提供的符号
    f
    是要查看文档的函数名。它这样做是因为它打算在REPL中使用,并且假设您不想一直键入引号

    由于
    f
    不存在,因此它不会打印任何内容。然后
    doseq
    返回
    nil
    ,因为它的存在只是为了做一些副作用-因此从
    do
    开始。为了将参数传递给拒绝这样尊重词法上下文的宏,需要为列表中的每个元素编写代码

    您可以手动执行,也可以将代码构造为数据,并将其传递给
    eval
    执行。您可以使用命令式风格,使用
    doseq

    (doseq [f (ns-interns 'clojure.repl)]
      (eval `(doc ~(symbol "clojure.repl" (str (first f))))))
    
    或者以一种更接近Clojurey的方式(这将允许您通过从末尾删除
    eval
    并在REPL处运行它来查看它将执行的代码):

    在这两种方法中,我们都使用quote和syntax quote从名称空间反映的符号列表中构造一些代码,并将其传递给
    eval
    ,以实际执行它。应该为你指出正确的方向来理解这里发生的事情


    这是一个不应该编写宏的例子,除非您没有其他选择。宏不构成,通常很难使用。进行更深入的讨论,都是很好的谈话

    虽然这可能无助于回答您的问题,但在学习Clojure时,评估宏的问题经常出现

    宏负责评估其参数。在这种情况下,
    clojure.repl/doc
    将忽略当前的词法上下文,并假定您提供的符号
    f
    是要查看文档的函数名。它这样做是因为它打算在REPL中使用,并且假设您不想一直键入引号

    由于
    f
    不存在,因此它不会打印任何内容。然后
    doseq
    返回
    nil
    ,因为它的存在只是为了做一些副作用-因此从
    do
    开始。为了将参数传递给拒绝这样尊重词法上下文的宏,需要为列表中的每个元素编写代码

    您可以手动执行,也可以将代码构造为数据,并将其传递给
    eval
    执行。您可以使用命令式风格,使用
    doseq

    (doseq [f (ns-interns 'clojure.repl)]
      (eval `(doc ~(symbol "clojure.repl" (str (first f))))))
    
    或者以一种更接近Clojurey的方式(这将允许您通过从末尾删除
    eval
    并在REPL处运行它来查看它将执行的代码):

    在这两种方法中,我们都使用quote和syntax quote从名称空间反映的符号列表中构造一些代码,并将其传递给
    eval
    ,以实际执行它。应该为你指出正确的方向来理解这里发生的事情

    这是一个不应该编写宏的例子,除非您没有其他选择。宏
    (doseq [f (ns-interns 'clojure.repl)]
      (eval `(doc ~(symbol "clojure.repl" (str (first f))))))
    
    (->> (ns-interns 'clojure.repl)
         (map #(list 'clojure.repl/doc (symbol "clojure.repl" (str (first %)))))
         (cons `do)
         eval)