Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/powerbi/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure:通过doseq将绑定变量传递给另一个函数的问题_Clojure - Fatal编程技术网

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

Clojure:通过doseq将绑定变量传递给另一个函数的问题,clojure,Clojure,我真的不知道这里有什么问题。我开始体验这种代码的“问题”: 首先,我用一些元数据定义了该字符串: (def ^{:meta-attr ["foo" "bar"] :meta-attr2 "some value"} foo "some value") 然后我创建了以下两个函数: (defn second-fn [values] (for [x values] (println x))) (defn first-fn [value] (doseq [[meta-key meta-v

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

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

(def ^{:meta-attr ["foo" "bar"]
   :meta-attr2 "some value"} foo "some value")
然后我创建了以下两个函数:

(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中运行此命令时:

(first-fn #'foo)
user> (first-fn #'foo)
[foo bar]
nil
我得到了
nil

但是,如果我将第二个fn更改为:

(defn second-fn [values]
  (println values))
如果我再次运行该命令,我将在REPL中得到:

(first-fn #'foo)
user> (first-fn #'foo)
[foo bar]
nil
我希望通过函数的第一个版本在REPL中获得以下内容:

user> (first-fn #'foo)
foo
bar
nil
但不知何故,我认为有一些我没有得到的东西与
doseq
的绑定变量有关

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

(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"]])
我想我缺少了一些知识来理解这里发生了什么。为什么当我
println
pprint
第二个函数中的值,但
不起作用时,它看起来很好

更新和最后想法 正如对这个问题的回答,这个问题与
for
函数的懒散性有关。让我们举一个最简单的例子来说明发生了什么

(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。这意味着序列存在,但它从未实现(因此,每个步骤还没有计算)。按原样,这两个函数不会发生任何变化,因为
返回的值都没有实现

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

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

(defn test-1 [values]
  (doseq [x values]
    (test-2 x)))
doall
在这里所做的是强制实现
for
循环返回的序列。这样,我们将以预期的结果结束

此外,我们还可以使用其他函数实现
返回的lazy seq,如:

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

(defn test-2 [values]
  (count (for [x values] (println x))))
所有这些都没有意义,但所有这些示例都用于实现由
for
返回的lazy seq

此外,我们可以简单地使用如下两种
doseq

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

(defn test-1 [values]
  (doseq [x values]
    (test-2 x)))
这样,我们就不需要使用任何懒惰的seq,因此我们不需要实现任何东西,因为没有任何东西是懒惰地进行评估的。

  • for
    是懒惰的,而
    doseq
    是渴望的
  • for
    为“功能性”(值),而
    doseq
    为“强制性”(副作用)
换句话说,您不应该在第二个fn中使用
for
,因为您似乎只担心副作用。您在那里实际做的是构建一个惰性序列(似乎永远不会执行)


有关更多信息,请参阅。

太棒了!我知道我在这里遗漏了一个核心概念:)我将继续根据你所说的进行测试,并在相应更新我的问题之前要求进一步澄清。然而,你说“因为你似乎只担心副作用”。也许我不明白你在说什么,但事实恰恰相反:我不担心副作用,因为这些都是纯功能,没有一个问题。似乎我可以通过在两个函数中仅使用
doseq
或仅使用
for
来“修复”此问题。我不清楚的是我应该做什么,以及每种方法的后果是什么?我以为你想要副作用,因为你使用了
println
(一种不纯函数)。正因为如此,
第二个fn
第一个fn
都是不纯的,因为不纯可以说是“传染性的”。另外,如果我的回答不够清楚,很抱歉,英语不是我的第一语言不用担心,它也不是我的;)是的,这就是我发现的:println是不纯净的;但实际上,我只是用它来看看为什么它不能像我想象的那样工作:)所以不,这些函数都是纯函数。考虑到这一点,我应该使用lazy-seq(
for
),而不是
doseq
。但我仍然不能100%确定使用其中一个的后果是什么。有什么想法吗?