清理其频道地图

时间:2016-03-10 04:38:19

标签: clojure clojurescript core.async

假设我们有一个具有以下结构的地图m

{:a (go "a") 
  :b "b" 
  :c "c" 
  :d (go "d")}

如图所示,m有四个键,其中两个包含通道。

问题:如何编写一般函数(或宏?)cleanse-map,它会获取m之类的地图并输出其无关版本(在这种情况下,将是{:a "a" :b "b" :c "c" :d "d"})?

这个问题的一个好帮手函数可能如下:

(defn chan? [c]
  (= (type (chan)) (type c)))

如果cleanse-map(或其所谓的任何内容)的返回值本身就是一个频道,那也无关紧要。即:

`(cleanse-map m) ;=> (go {:a "a" :b "b" :c "c" :d "d"})

2 个答案:

答案 0 :(得分:3)

core.async的{​​{3}} Limitations使cleanse-map的实施并不那么简单。但是下面的一个应该有效:

(defn cleanse-map [m]
  (let [entry-chs (map
                   (fn [[k v]]
                     (a/go
                       (if (chan? v)
                         [k (a/<! v)]
                         [k v])))
                   m)]
    (a/into {} (a/merge entry-chs))))

基本上,这里做了什么:

  1. 每个地图条目都会转换为包含此地图条目的频道。如果map条目的值是一个通道,则它将在映射函数中的go - 块内提取。
  2. 带有地图条目的频道为merge - d为单一频道。完成此步骤后,您将拥有一个包含地图条目集合的频道。
  3. 带有地图条目的频道将转换为包含所需地图(a/into步骤)的频道。

答案 1 :(得分:1)

(ns foo.bar
  (:require
    [clojure.core.async :refer [go go-loop <!]]
    [clojure.core.async.impl.protocols :as p]))

(def m
  {:a (go "a")
   :b "b"
   :c "c"
   :d (go "d")
   :e "e"
   :f "f"
   :g "g"
   :h "h"
   :i "i"
   :j "j"
   :k "k"
   :l "l"
   :m "m"})

(defn readable? [x]
  (satisfies? p/ReadPort x))

(defn cleanse-map
  "Takes from each channel value in m,
   returns a single channel which will supply the fully realized m."
  [m]
  (go-loop [acc {}
            [[k v :as kv] & remaining] (seq m)]
    (if kv
      (recur (assoc acc k (if (readable? v) (<! v) v)) remaining)
      acc)))

(go (prn "***" (<! (cleanse-map m))))

=&GT; &#34; ***&#34; {:m&#34; m&#34;,:e&#34; e&#34;,:l&#34; l&#34;,:k&#34; k&#34;,:g&#34 ; g&#34;,:c&#34; c&#34;,:j&#34; j&#34;,:h&#34; h&#34;,:b&#34; b&#34;, :d&#34; d&#34;,:f&#34; f&#34;,:i&#34; i&#34;,:a&#34; a&#34;}