clojure.core/map-isn';行不通

clojure.core/map-isn';行不通,clojure,Clojure,我正在试图弄清楚为什么我的一个map调用不起作用。我正在构建一个爬虫,目的是学习Clojure (使用“[clojure.java.io]) 但是第二个调用(映射爬网URL)似乎被忽略了 crawl函数按预期工作,对url进行slurp,使用regex解析a标记获取href,并在循环中累积按预期工作,但是当我使用crawl调用map和页面上找到的url时,对map的调用被忽略 如果我尝试调用(映射爬网[“http://www.example.com“])此呼叫再次被忽略 几周前我开始了我的Cl

我正在试图弄清楚为什么我的一个map调用不起作用。我正在构建一个爬虫,目的是学习Clojure

(使用“[clojure.java.io])

但是第二个调用
(映射爬网URL)
似乎被忽略了

crawl
函数按预期工作,对url进行slurp,使用regex解析
a
标记获取href,并在
循环中累积
按预期工作,但是当我使用
crawl
调用
map
和页面上找到的
url
时,对
map
的调用被忽略

如果我尝试调用
(映射爬网[“http://www.example.com“])
此呼叫再次被忽略

几周前我开始了我的Clojure之旅,因此欢迎提出任何建议/批评


谢谢你

在Clojure,
map
是懒惰的。从文档中,映射:

返回一个惰性序列,该序列由将f应用于 每个coll的第一个项目集,然后将f应用于该集合 每个coll中的第二项,直到任何一个coll 筋疲力尽

您的爬网功能是一个具有副作用的功能-您正在
向文件中吐出一些结果,并
打印ln
-ing报告进度。但是,由于
map
返回一个惰性序列,这些事情都不会发生——结果序列永远不会显式实现,因此它可以保持惰性

实现惰性序列的方法有很多种(例如使用
map
创建的),但在这种情况下,当您想使用具有副作用的函数迭代序列时,最好使用
doseq

重复执行身体(可能是因为副作用)和 “for”提供的绑定和筛选。不保留 序列的首部。返回零

如果将对
(映射爬网URL)
的调用替换为
(doseq[u url](爬网u))
,则应该会得到所需的结果


注意:您对map的第一次调用按预期工作,因为您正在使用
(apply str)
实现结果。如果不计算顺序,就无法
(应用str)

检查访问过哪些页面的方式有一个小错误:检查
(str“theinternet/page”(md5 url))
是否存在,但将文件写入
(str“theinternet/(md5 url))
,因此,您将陷入循环中,因为即使在您抓取页面时,它看起来也没有抓取页面。另外:有用的提示:
defn
包含一个隐式
do
,这样就可以包含多个表达式-您不需要在
do
中显式地将它们分组在一起。感谢Daniel提供的提示。我已经编辑了文件名,我在其中编写了slurp的结果,我关注的是
map
为什么不起作用。如前所述,我已经用
doseq
更改了
map
,现在一切正常。太好了!我希望你喜欢你的Clojure冒险:)
(defn md5
  "Generate a md5 checksum for the given string"
  [token]
  (let [hash-bytes
         (doto (java.security.MessageDigest/getInstance "MD5")
               (.reset)
               (.update (.getBytes token)))]
       (.toString
         (new java.math.BigInteger 1 (.digest hash-bytes)) ; Positive and the size of the number
         16)))

(defn full-url [url base]
  (if (re-find #"^http[s]{0,1}://" url)
    url
    (apply str "http://" base (if (= \/ (first url))
                                url
                                (apply str "/" url)))))
(defn get-domain-from-url [url]
  (let [matcher (re-matcher #"http[s]{0,1}://([^/]*)/{0,1}" url)
        domain-match (re-find matcher)]
    (nth domain-match 1)))
(defn crawl [url]
  (do
    (println "-----------------------------------\n")
    (if (.exists (clojure.java.io/as-file (apply str "theinternet/page" (md5 url))))
      (println (apply str url " already crawled ... skiping \n"))
      (let [domain (get-domain-from-url url)
            text (slurp url)
            matcher (re-matcher #"<a[^>]*href\s*=\s*[\"\']([^\"\']*)[\"\'][^>]*>(.*)</a\s*>" text)]
        (do
          (spit (apply str "theinternet/page" (md5 url)) text)
          (loop [urls []
               a-tag (re-find matcher)]
            (if a-tag
              (let [u (nth a-tag 1)]
                (recur (conj urls (full-url u domain)) (re-find matcher)))
              (do
                (println (apply str "parsed: " url))
                (println (apply str (map (fn [u]
                                             (apply str "-----> " u "\n")) urls)))
                (map crawl urls)))))))))
(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (crawl "http://www.example.com/"))

(println (apply str (map (fn [u]
    (apply str "-----> " u "\n")) urls)))