【问题标题】:I don't understand the (doc fn)...it says I can name a function, but I can't invoke it by its name?我不明白(doc fn)......它说我可以命名一个函数,但我不能通过它的名字调用它?
【发布时间】:2015-06-06 16:43:38
【问题描述】:

我是 Clojure 的新手,正在努力理解这些概念。 REPL 帮助我获得“东西”的文档。所以我想定义一个函数...

clojure-noob.core> (doc fn)
-------------------------
clojure.core/fn
  (fn name? [params*] exprs*)
  (fn name? ([params*] exprs*) +)
Special Form
  ...
  name => symbol

...文档建议我可以命名我的函数。 REPL 接受我的函数,但我无法调用它,“无法解析符号..”...

clojure-noob.core> (fn add-pair [a b] (+ a b))
#<core$eval3364$add_pair__3365 clojure_noob.core$eval3364$add_pair__3365@6fb5a33b>
clojure-noob.core> (add-pair 1 2)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: add-pair in this context, compiling:(/private/var/folders/1g/fnytl2x93sx6hp2f1rsf4h1r5xtqv_/T/form-init6828995349142227131.clj:1:1) 
clojure-noob.core> 

省略名称并构建适当的 fn def 确实可以完成工作,就像利用 defn 宏一样...

clojure-noob.core> (def another-add-pair (fn [a b] (+ a b)))
clojure-noob.core> (another-add-pair 1 2)
3
clojure-noob.core> (defn yet-another-add-pair [a b] (+ a b))
#'clojure-noob.core/yet-another-add-pair
clojure-noob.core> (yet-another-add-pair 3 4)
7

(doc fn) 的输出显然有些我不明白的地方。特别是,那里的name? 是什么,你能用它做什么?我一直在努力学习如何阅读文档以及理解 fn 特殊形式。谢谢。

【问题讨论】:

    标签: clojure


    【解决方案1】:

    从 REPL 调用 (fn add-pair [a b] (+ a b)) 会构建该函数的实例,然后将其打印到屏幕上。之后它就消失了,没有保存在任何地方。这就是为什么您无法使用 doc 函数获取它的文档的原因。 fn 文字中的 name 参数通常用于进行递归调用,并不意味着它将以该名称保存在任何地方。

    如果您调用(defn add-pair [a b] (+ a b)),那么它将函数保存到命名空间中,然后doc 函数可以稍后查找并打印它的文档字符串。

    【讨论】:

    • fn 的名称 arg 也用于使堆栈跟踪更具可读性,并更容易识别哪个匿名 fn 看到了错误
    • s/only/often/ ...已修复;-)
    • @noisesmith 啊哈!而已。我明白了。
    • repl 通常将最后三个评估的东西绑定到 *1 *2 和 *3 所以它没有保存在任何地方是不正确的。
    • @LeonGrapenthin (clojure.repl/doc *1) => "clojure.core/*1 bound in a repl thread to the most recent value printed" 所以它不适用于 this 问题。它描述了 *1 的值,它是自身而不是当前的内容。
    【解决方案2】:
    • fn 表单的计算结果为 函数对象

    • 您可以立即应用函数对象:

      ((fn [a b] (+ a b)) 1 1) ;=&gt; 2

    • 如果要在本地引用函数对象,请使用let 绑定:

      (let [add-pair (fn [a b] (+ a b))] (add-pair 1 1)) ;=&gt; 2

    • 函数对象和1一样是一个值 或[3 :a]:

      (let [double (fn [n] (* 2 n))] (({double (comp double double)} double) 3) ;=> 12

    • let 绑定在 fn 表单中不存在 - 您需要一个 名称参数:

      ((fn fact [n] (case n, 0 1, (* n (fact (dec n))))) 5) ;=&gt; 120

    • letfn 两者都做:

      (letfn [(fact [n] (case n, 0 1, (* n (fact (dec n)))))] (fact 5)) ;=&gt; 120

    • 如果您希望该函数可全局访问,请将其绑定到 var 使用 def:

      (def fact (fn fact [n] (case n, 0 1, (* n (fact (dec n))))))

      (fact 5) ;=&gt; 120

    • defn 宏的作用更简洁:

      (defn fact [n] (case n, 0 1, (* n (fact (dec n)))))

      (fact 5) ;=&gt; 120

    【讨论】:

      猜你喜欢
      • 2021-08-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-28
      • 2011-09-18
      • 2022-09-30
      相关资源
      最近更新 更多