3

我似乎对 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。

4

3 回答 3

4

问题是snds惰性序列,因此(snds lst)会引发错误。filter总是返回一个惰性序列。

你的功能也太复杂了。尝试使其更简单:

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

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

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

我使用list是因为quote阻止了对表达式的评估(请参阅 ToBeReplaced 的答案):

=> '( '("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)))

也会起作用。

于 2013-08-06T14:08:23.300 回答
1

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

以上等价于:

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

我认为您想要更多类似的东西:

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

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

于 2013-08-06T13:58:57.127 回答
0

不要'在里面使用'()。你不想quote '得到quote. 假设您将列表写为:

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

最优雅的可能是:

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

如同

(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您的列表元素将只分配一次。

由于哈希映射的顺序无关紧要,因此您也可以 user r/fold。然后您的列表将被过滤并将元素并行转换为向量(如果您的列表有超过 512 个元素)。

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

根据集合的大小,reducer 可能有点太重了。对于像你的例子这样的小尺寸,我建议编写你自己的归约函数:

(def costlist #(reduce (fn [acc [k v]]
                         (if v
                           (assoc acc k v)
                           acc)) {} %)
于 2013-08-06T19:17:31.320 回答