【问题标题】:How to properly use "iterate" and "partial" in Clojure?如何在 Clojure 中正确使用“迭代”和“部分”?
【发布时间】:2013-11-03 05:47:45
【问题描述】:

iterate 的大多数引用都是针对运算符的,所有函数上的应用程序都非常混乱,以至于我仍然不知道如何在我的代码中使用 iterate,以及 partial 是什么。

我正在做一个编程作业,尝试使用牛顿法求数字 n 的平方根。也就是说,以猜测作为初始近似值,通过计算近似值和 n/近似值的平均值来继续计算新的近似值。继续,直到两个最近的近似值之间的差异小于 epsilon。

我试图先做近似部分,我相信这是我需要使用迭代和部分的东西。后来epsilon是我需要使用“take”的东西?

这是我在没有 epsilon 的情况下进行近似的代码:

(defn sqrt [n guess]
  (iterate (partial sqrt n) (/ (+ n (/ n guess)) 2)))

此代码无法正常工作,当我输入(sqrt 2 2) 时,它给了我(3/2 user=> ClassCastException clojure.lang.Cons cannot be cast to java.lang.Number clojure.lang.Numbers.divide (Numbers.java:155)

我想这是我需要一遍又一遍地迭代的部分?有人可以给我一些提示吗?同样,这是一个家庭作业问题,所以请不要为我提供整个问题的直接解决方案,我需要一些可以学习的想法和解释。

【问题讨论】:

  • 什么是operator?我认为clojure中没有任何称为运算符的东西。像+-*/ 这样的东西在另一种语言中将是一个运算符,它们只是clojure 中的函数。您可以使用任何其他可以使用它们的函数(只要它采用相同的参数)。
  • 大家好,非常感谢你们的帮助!我把一切都弄清楚了。由于这是尚未完成的作业,我认为我不能发布我的代码。

标签: clojure functional-programming square-root


【解决方案1】:

partial 接受一个函数和该函数的至少一个参数,并返回一个需要其余参数的新函数。

(def take-five (partial take 5))
(take-five [1 2 3 4 5 6 7 8 9 10])
;=> (1 2 3 4 5)

iterate 通过两个参数生成一个无限序列:一个函数和一个种子值。种子值用作生成列表中的第一个元素,第二个元素通过将函数应用于种子来计算,第二个值用作函数的输入以获得第三个值,依此类推。

(take-five (iterate inc 0))
;=> (0 1 2 3 4)

ClojureDocs 提供了关于这两个函数的良好文档:http://clojuredocs.org/clojure_core/clojure.core/iteratehttp://clojuredocs.org/clojure_core/clojure.core/partial

【讨论】:

  • 感谢您的帮助!这个我已经搞定了!
【解决方案2】:

所以,@ponzao 很好地解释了 iteratepartial 的作用,@yonki 指出您并不真正需要它。如果您想探索更多 seq 函数,无论如何尝试它可能是一个好主意(尽管惰性序列的开销可能会导致性能不太理想)。

提示:

  • (iterate #(sqrt n %) initial-approximation) 将为您提供一系列近似值。
  • 您可以使用partition 创建成对的后续近似值。
  • 使用drop-while 丢弃不满足 epsilon 条件的所有内容
  • 得到结果。

使用序列解决这个问题可能会非常有益,因为您接触到了很多有用的序列函数。

注意:在这个答案的编辑历史中某处有一个完整的解决方案。抱歉,没有完全得到“作业”部分。

【讨论】:

  • 谢谢!我得到了答案!
【解决方案3】:

我认为你没有抓住重点。你不需要iterate 也不需要partial

如果您需要执行一些计算直到满足条件,您可以使用易于理解的loop/recur 指令。 loop/recur可以理解为:做一些计算,检查是否满足条件,如果满足则返回计算值,如果不重复计算。

由于您不想要完整的解决方案,只需要建议去哪里,正确查看loop/recur,一切都会好起来的。

@noisesmith 说得很好。 reduce 不适用于在条件满足之前进行计算,但在执行某些步数有限的计算时可能很有用。

【讨论】:

  • 如果您不习惯函数式编程,loop / recur 会很有帮助,因为它更接近于命令式的做事方式,但通常不是解决问题的最佳方式。此外,reduce 不是在满足条件之前做某事,而是用于折叠集合(在特殊情况下,您可以使用reduced 命令式地跳出)。
  • 我知道循环/递归不是最好的方法,当你进入函数式编程时。但是,正如您所说,它接近于命令式循环,并且当某人对函数的了解不是很好时,它可能会很有用。是的,我知道什么是减少。尽管如此,用有限的步数执行一些计算可能还是有用的。问题不是关于惯用的、功能性的 Clojure,而是关于解决实际问题的可能性。我选择循环/重复因为它很容易理解。
  • 我认为这是个坏建议。 Iterate 和 Partial 是非常有用的工具,比循环/递归更惯用,OP 的问题是 iterate 的一个很好的用例。
  • 非常感谢!我完全明白你为什么要说服我使用循环/递归。我同意它们是好主意。但我认为这项家庭作业的重点是帮助我更好地理解迭代/部分。但再次感谢您的帮助!
猜你喜欢
  • 2012-07-05
  • 2014-07-01
  • 2011-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-09
  • 2019-11-02
  • 2015-09-05
相关资源
最近更新 更多