首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Clojure:通过doseq将绑定变量传递给另一个函数的问题

Clojure:通过doseq将绑定变量传递给另一个函数的问题
EN

Stack Overflow用户
提问于 2014-05-21 19:09:00
回答 1查看 215关注 0票数 1

我真的不知道这里有什么问题。我开始体验这种代码的“问题”:

首先,我用一些元数据定义了这个字符串:

代码语言:javascript
复制
(def ^{:meta-attr ["foo" "bar"]
   :meta-attr2 "some value"} foo "some value")

然后,我创建了以下两个函数:

代码语言:javascript
复制
(defn second-fn [values]
  (for [x values] (println x)))

(defn first-fn [value]
  (doseq [[meta-key meta-val] (seq (meta value))]
    (if (= meta-key :meta-attr)
      (second-fn meta-val))))

现在,当我在REPL中运行这个命令时:

代码语言:javascript
复制
(first-fn #'foo)

我要去接nil

但是,如果我将second-fn更改为:

代码语言:javascript
复制
(defn second-fn [values]
  (println values))

如果我再次运行这个命令,我将在REPL中得到这个命令:

代码语言:javascript
复制
user> (first-fn #'foo)
[foo bar]
nil

我期望在REPL中使用我的函数的第一个版本的内容如下:

代码语言:javascript
复制
user> (first-fn #'foo)
foo
bar
nil

但不知怎么的,我认为有些东西我没有得到,这与doseq的绑定变量有关。

下面是具有完全相同行为的另一组函数:

代码语言:javascript
复制
(defn test-2 [values]
;  (println values))
  (for [x values] (println x)))

(defn test-1 [values]
  (doseq [x values]
    (test-2 x)))

(test-1 [["1.1" "1.2"] ["2"] ["3"]])

我想我错过了一些克洛法尔的知识来理解这里发生了什么。为什么当我printlnpprint第二个函数中的值时它看起来很好,但是for不工作.

更新和最后的想法

这个问题的答案是,这个问题与for函数的松散性有关。让我们以最简单的例子来说明正在发生的事情。

代码语言:javascript
复制
(defn test-2 [values]
  (for [x values] (println x)))

(defn test-1 [values]
  (doseq [x values]
    (test-2 x)))

test-1中发生的情况是,每次doseq“迭代”,就会创建一个新的非惰性序列。这意味着它们可以像“循环”期间的任何其他集合一样访问。

当您使用可能会产生副作用的非纯函数时,或者当您使用相对较小的集合时,通常应该使用doseq

然后,当test-2被调用时,for将创建一个延迟-seq。这意味着序列存在,但它从未实现(因此,每个步骤还没有被计算)。实际上,这两个函数不会发生任何变化,因为for返回的任何值都没有实现。

如果我们想保持这个doseq和这个for循环,那么我们必须确保fortest-2中得到实现。我们可以这样做:

代码语言:javascript
复制
(defn test-2 [values]
  (doall (for [x values] (println x))))

(defn test-1 [values]
  (doseq [x values]
    (test-2 x)))

doall在这里所做的就是强制完全实现for循环返回的序列。这样,我们将以预期的结果结束。

此外,我们还可以使用以下其他函数实现for返回的延迟-seq:

代码语言:javascript
复制
(defn test-2 [values]
  (first (for [x values] (println x))))

(defn test-2 [values]
  (count (for [x values] (println x))))

所有这些都没有意义,但所有这些示例都用于实现for返回的延迟-seq。

此外,我们可以简单地使用两个doseq,如下所示:

代码语言:javascript
复制
(defn test-2 [values]
  (doseq [x values] (println x)))

(defn test-1 [values]
  (doseq [x values]
    (test-2 x)))

这样的话,我们就不会使用任何懒散的seq,所以我们不必意识到任何事情,因为没有任何东西是懒惰地评估的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-05-21 19:26:23

  • for是懒惰的,而doseq是渴望的。
  • for是“函数”(值),doseq是“命令式”(副作用)。

换句话说,您不应该在second-fn中使用second-fn,因为您似乎只担心副作用。实际上,您在那里所做的是构建一个惰性序列(似乎从未执行过)。

更多信息请参见Difference between doseq and for in Clojure

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23791802

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档