2

我正在读一本书来教自己Clojure称为Clojure的勇敢和真实。第9章介绍基本的并发编程,包括延迟,期货和承诺。本章末尾的第一个练习是:期货永远不会解决并兑现承诺

“编写一个函数,它接受一个字符串作为参数,并使用slurp函数在Bing和Google上搜索它,您的函数应返回返回的第一页的HTML通过搜索”

我的解决方案如下:

(defn search-bing-google 
    [search-term] 
    (let [search-results (promise)] 
     (future (deliver search-results 
        (slurp (str "https://www.bing.com/search?q%3D" search-term)))) 
     (future (deliver search-results 
        (slurp (str "https://www.google.com/search?q%3D" search-term)))) 
     @search-results)) 

可以称得上像:

(search-bing-google "clojure") 

第二个练习是统计编辑为:

“更新您的功能,因此它需要第二个参数组成的搜索引擎使用。”

我试图编辑我的第一个解决方案,以满足新的参数要求如下:

(def search-engines 
    {:bing "https://www.bing.com/" 
    :google "https://www.google.com/"}) 

(defn search 
    [search-term & engines] 
    (let [results (promise)] 
     (map #(future (deliver results 
           (slurp (str (% search-engines) 
              "search?q%3D" 
              search-term)))) engines) 
      @results)) 

,可以这样调用:

(search "clojure" :bing :google) 

但是这种实现挂起不像它的前身。它好像在第二次实现中由于“映射”而从不被调用。任何人都可以帮我弄清楚,当我在REPL中加载它并执行它时,是什么导致它挂起?

编辑:

与Josh的回答下面我想出了以下的解决方案,不再挂起使用doseq代替dorunmap

(def search-engines 
    {:bing "https://www.bing.com/" 
    :google "https://www.google.com/"}) 

(defn search 
    [search-term & engines] 
    (let [results (promise)] 
     (doseq [engine engines] 
      (future (deliver results 
          (slurp (str (engine search-engines) 
             "search?q%3D" 
             search-term))))) 
     @results)) 

回答

3

因为map导致懒惰的评价,东西为了实现它而需要。在你的代码中,这些都不是,所以期货从来没有真正创造过。而不仅仅是map,请执行:

(dorun (map ... 
+0

我没有在地图上使用'dorun'。相反,我使用'doseq'来迭代关键字列表。但是,谢谢你让我在“dorun”,“doall”,“doseq”等方面进行强制评估。 – webermaster