Clojure clojure.lang.LazySeq错误

时间:2013-08-06 13:48:26

标签: clojure lazy-sequences

我似乎对clojure I / O(或类型系统)有令人讨厌的问题。关键是这个函数,我希望它使用字符串和数字或字符串集合的集合,并返回与数字相关的字符串字典,如

(costlist '( '("Milk" 4) '("Bread" 2) '("Milk")))

给予

{"Milk" 4, "Bread" 2 }

定义
(defn costlist [lst]
    ;returns list of costs and appropriate names
          (let  [snds (filter (fn [x] (not (identical? nil x))) (seconds lst))]
          (zipmap 
                   (firsts (take (count snds) (firsts lst))) 
                   (snds  lst))))

当使用类型为clojure.lang.PersistentList(我从clojure.lang.LazySeq转换而来)的列表时抛出错误消息

clojure.lang.LazySeq cannot be cast to clojure.lang.IFn

这只会让我感到困惑,因为它的任何论据对我来说似乎都不是LazySeq。

3 个答案:

答案 0 :(得分:4)

问题是snds是懒惰的seq,因此(snds lst)会抛出错误。 filter总是返回一个懒惰的序列。

你的功能也太复杂了。尽量简化:

(defn costlist [lst]
  (zipmap (map first lst)
          (remove nil? (map second lst))))

现在你可以做你想做的事了:

(costlist (list '("Milk" 4) '("Bread" 2) '("Milk")))

我正在使用list,因为quote会阻止评估表达式(see ToBeReplaced's answer):

=> '( '("Milk" 4) '("Bread" 2) '("Milk"))
((quote ("Milk" 4)) (quote ("Bread" 2)) (quote ("Milk")))

因此,您应该避免使用quote来构建列表。

您的解决方案还建议nil值可能仅出现在列表的末尾。你可以轻松解决它:

(defn costlist [lst]
  (->>  (filter (comp #{2} count) lst)
        (map vec)
        (into {})))

所以,现在

(costlist (list '("Milk" 4) '("Milk") '("Bread" 2)))

也会奏效。

答案 1 :(得分:1)

很难给出一个精确的答案,因为你也在使用自己的一些功能(秒和第一)。但是,您应该考虑是否希望costlist成为您在上面提供的引用形式。

以上相当于:

((quote ("Milk" 4)) (quote ("Bread" 2)) (quote ("Milk")))

我想你想要更像的东西:

(list '("Milk" 4) '("Bread" 2) '("Milk"))

在您的示例中,最外面的引号导致引用内部引号!

答案 2 :(得分:0)

请勿在{{1​​}}内使用'。您不希望'() quote获得'。 鉴于您将列表写为:

quote

最优雅的可能是:

'(("Milk" 4)("Bread" 2)("Milk"))

类似于

(def costlist (comp (partial into {}) 
                    (partial map vec) 
                    (partial filter second))

不幸的是,这将创建两个lazy-seqs,其中一个会更好。 你可以(def costlist #(into {} (map vec (filter second %)))) 给自己一个很酷的减少功能:

(use '(clojure.core [reducers :as r])

让你离开

(def r-fn (comp (r/map vec) (r/filter second)))

感谢(def costlist #(into {} (r-fn %))) 使用into,您的列表元素只会被分配一次。

由于顺序与哈希映射无关,您也可以使用reduce conj。然后您的列表将被过滤,并且元素将并行转换为矢量(如果您的列表包含超过512个元素)。

r/fold

根据集合的大小,减速器可能有点太重。对于像你的例子那样的小尺寸,我建议你自己编写缩小功能:

(def constlist #(r/fold (r/monoid conj hash-map) (r-fn %)))