微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

关于Clojure中的堆和垃圾的初学者问题

我有一个关于Clojure的问题:
我试图通过浏览 Project Euler学习语言,我不明白幕后发生了什么:下面的代码旨在使用返回所有素数列表到lim.我认为它应该是堆空间中的O(n),因为我列出了所有数字到lim的列表,然后逐个过滤它们,同时将第一个数字移动到新的列表. (我知道我实际上是在制作新的列表,但是我认为它们不会占用更多内存吗?)无论如何我运行这个
(defn getAllPrimes [lim] 
  (defn getPrimes [primes numlist]
    (if (not-empty numlist) ;base case;
    (recur (cons (first numlist) primes) ;put the prime on to the prime list 
           (filter
        (fn [x] (not (div? x (first numlist)))) ;remove the prime and all its multiples from the numlist
        (rest numlist)))
      primes)); return the primes
  (getPrimes () (range 2 lim))) ;call the recursive function with and empty prime list to be filled up and a full numlist to be emptied

当我打电话时,我的堆空间不断用完

(apply + (getAllPrimes 2000000))

,但我没有用完空间

(apply + (filter even? (range 2000000)))

所以我认为我不能理解如何在调用recur并且实际上使用O(n * n)堆或其他东西时收集垃圾.

解决方法

我相信问题在于,每次重复时,你都会创建一个新的延迟序列,指向最后一个,所以在几次迭代之后,你持有一个seq,它包含一个seq的头部,它包含一个seq的头部.掌握一个seq的头. ……所有的中间序列都填满了你的堆.

虽然写一个主要筛子是值得的,但如果你想得到答案,Clojure确实在其标准库中包含了素数序列:clojure.contrib.lazy-seqs / primes.这种特殊欧拉问题的标准解决方案是单线程.

作为一种风格点,内在的定义并不是一个好主意.实际效果与defn处于顶层时相同,但如果我没有弄错,每次调用getAllPrimes时都会重新分配var,并且非常强烈建议不要在运行时重新定义变量.由于代码只是定义一个var,getPrimes仍然像getAllPrimes一样可见.在这种情况下,getPrimes可以很容易地重写为没有内部函数,匿名或命名的循环/重复.这对你的懒惰seqs问题没有帮助,但它确实使代码更具标准性:

(defn getAllPrimes [lim]
  (loop [primes ()
         numlist (range 2 lim)]
    (if (not-empty numlist)
      (recur (cons (first numlist) primes)
             (filter (fn [x] (not (div? x (first numlist))))
                     (rest numlist)))
      primes)))

我也会避免使用camelCase.该函数的Clojure标准名称将是get-all-primes.

但是,回到实际问题,你可以做的最少的工作就是在每次迭代时强制每个seq,即将你的过滤器调用包装在doall中.我试过这个,虽然它仍然运行缓慢,但它至少会运行完成而不会耗尽堆:

(defn get-all-primes [lim]
  (loop [primes ()
         numlist (range 2 lim)]
    (if (not-empty numlist)
      (recur (cons (first numlist) primes)
             (doall (filter #(not (div? % (first numlist)))
                            (rest numlist))))
      primes)))

原文地址:https://www.jb51.cc/java/129465.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐