【问题标题】:Is there a complete list of lazy functions of Clojure's core module?Clojure 核心模块的惰性函数有完整的列表吗?
【发布时间】:2016-02-04 15:51:04
【问题描述】:

在使用 Clojure 一段时间后,我积累了一些关于它的惰性的知识。我知道诸如 map 之类的常用 API 是否是惰性的。但是,当我开始使用 with-open 等不熟悉的 API 时,我仍然感到怀疑。

是否有任何文档显示 Clojure 核心模块的惰性 API 的完整列表?

【问题讨论】:

  • 我认为您对 Clojure 中的惰性概念有点困惑。没有惰性函数,只有惰性序列。另外,with-open 根本不是一个函数;这是一个宏。考虑到这些信息,with-open 是否是惰性函数的问题毫无意义。

标签: clojure


【解决方案1】:

您可以通过打开 Clojure 代码 https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj 找到返回惰性序列的函数 并搜索“返回一个懒惰的人”

我不知道他们的任何精选列表。

经验法则是:如果它返回一个序列,它将是一个惰性序列,如果它返回一个值,它将强制求值。

使用新函数、宏或特殊形式时,请阅读文档字符串。大多数开发环境都有一个显示文档字符串的键,或者至少导航到源(可以看到文档字符串的地方),并且总是有http://clojure.org/api/api

在with-open的情况下:

打开 宏 用法:(打开绑定和正文) bindings => [name init ...]

在名称绑定到值的 try 表达式中评估 body inits 和 finally 子句在每个子句上调用 (.close name) 倒序命名。

我们可以看到调用 with-open 的结果是对表达式的求值,最后关闭。所以我们知道没有什么懒惰的。然而,这并不意味着你不需要考虑 with-open 内部的惰性,恰恰相反!

(with-open [r (io/reader "myfile")]
  (line-seq r))

这是一个常见的陷阱。 line-seq 返回一个惰性序列!这里的问题是文件关闭后才会实现惰性序列,因为退出with-open的范围时文件是关闭的。所以你需要在退出 with-open 范围之前完全处理惰性序列。

我的建议是避免试图将您的程序视为具有“惰性位”和“立即位”,而是要注意当涉及 io 或副作用时,您需要注意当事情发生时以及应该发生的事情。

【讨论】:

    【解决方案2】:

    挖掘 Timothy Pratley 在文档中搜索的建议:

    让我们变得有趣!

    您的 repl 拥有查找惰性函数列表所需的一切。

    首先,有一个clojure.repl/doc宏,将文档打印到repl中的out

    user> (doc +)
    -------------------------
    clojure.core/+
    ([] [x] [x y] [x y & more])
      Returns the sum of nums. (+) returns 0. Does not auto-promote
      longs, will throw on overflow. See also: +'
    nil
    

    不幸的是我们不能简单地得到它的字符串,但我们总是可以将*out*重新绑定为StringWriter,然后得到它的字符串值。

    所以,如果我们想从clojure.core 命名空间中获取所有符号,获取它们的文档,将它们全部写入字符串,然后找到每个包含“returns a lazy”的符号。帮助来了:clojure.core/ns-publics,将公共名称映射返回到他们的变量:

    user> (take 10 (ns-publics 'clojure.core))
    ([primitives-classnames #'clojure.core/primitives-classnames] 
     [+' #'clojure.core/+'] 
     [decimal? #'clojure.core/decimal?] 
     [restart-agent #'clojure.core/restart-agent] 
     [sort-by #'clojure.core/sort-by] 
     [macroexpand #'clojure.core/macroexpand] 
     [ensure #'clojure.core/ensure] 
     [chunk-first #'clojure.core/chunk-first] 
     [eduction #'clojure.core/eduction] 
     [tree-seq #'clojure.core/tree-seq])
    

    所以我们只需要从那里获取所有密钥并查找他们的文档。 让我们为此制作一个宏:

    user> (defmacro all-docs []
            (let [names (keys (ns-publics 'clojure.core))]
              `(binding [*out* (java.io.StringWriter.)]
                 (do ~@(map #(list `doc %) names))
                 (str *out*))))
    #'user/all-docs
    

    它就像我所说的那样,将所有公众的文档变成字符串。

    现在我们简单地处理它:

    user> (def all-doc-items (clojure.string/split 
                               (all-docs) 
                               #"-------------------------"))
    #'user/all-doc-items
    
    user> (nth all-doc-items 10)
    "\nclojure.core/tree-seq\n([branch? children root])\n  Returns a lazy sequence of the nodes in a tree, via a depth-first walk.\n   branch? must be a fn of one arg that returns true if passed a node\n   that can have children (but may not).  children must be a fn of one\n   arg that returns a sequence of the children. Will only be called on\n   nodes for which branch? returns true. Root is the root node of the\n  tree.\n"
    

    现在只需过滤它们:

    user> (def all-lazy-fns (filter #(re-find #"(?i)returns a lazy" %) all-doc-items))
    #'user/all-lazy-fns
    
    user> (count all-lazy-fns)
    30
    
    user> (println (take 3 all-lazy-fns))
    (
    clojure.core/tree-seq
    ([branch? children root])
      Returns a lazy sequence of the nodes in a tree, via a depth-first walk.
       branch? must be a fn of one arg that returns true if passed a node
       that can have children (but may not).  children must be a fn of one
       arg that returns a sequence of the children. Will only be called on
       nodes for which branch? returns true. Root is the root node of the tree.
    
    clojure.core/keep-indexed
    ([f] [f coll])
      Returns a lazy sequence of the non-nil results of (f index item). Note,
      this means false return values will be included.  f must be free of
      side-effects.  Returns a stateful transducer when no collection is
      provided.
    
    clojure.core/take-nth
    ([n] [n coll])
      Returns a lazy seq of every nth item in coll.  Returns a stateful
      transducer when no collection is provided.
    )
    nil
    

    现在可以随意使用这些all-lazy-fns

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-27
      • 2012-09-06
      • 2010-12-08
      • 1970-01-01
      • 2015-05-16
      • 1970-01-01
      相关资源
      最近更新 更多