Clojure新手实现flatten函数遇let问题,返回空向量求解答
问题分析与解决
嘿,我来帮你揪出问题所在~你遇到的核心问题是对Clojure的不可变性理解还没到位,这也是很多Clojure新手容易踩的坑!
为什么你的函数返回空向量?
你代码里的result是通过let绑定的不可变向量,而conj是一个纯函数——它不会修改原来的result,而是返回一个新的向量。你在doseq里调用(conj result element2)的时候,只是生成了新向量,但没有把这个新向量保存下来(毕竟result是不可变的,没法直接修改)。最后doseq执行完,你返回的还是最初绑定的空result,自然就得不到想要的结果了。
另外补充一点:doseq是用来执行副作用操作(比如打印日志、写入文件)的,它本身不会返回任何有意义的结果,不适合用来做这种结果累积的工作。
修正方案:用Clojure的惯用方式实现flatten
下面给你两种常见的实现思路,都是符合Clojure函数式风格的:
方法1:用loop/recur迭代累积
(defn flat [arr] (loop [remaining arr ; 待处理的剩余元素 result []] ; 累积的结果向量 (if (empty? remaining) result ; 没有剩余元素时返回结果 (let [current (first remaining)] (if (coll? current) ; 如果当前元素是集合,把它的元素和剩余元素拼接后继续处理 (recur (concat current (rest remaining)) result) ; 如果不是集合,把它加入结果,继续处理剩余元素 (recur (rest remaining) (conj result current)))))))
方法2:用reduce递归展开
这种写法更简洁,利用reduce做累积,遇到集合就递归展开:
(defn flat [arr] (reduce (fn [acc elem] (if (coll? elem) ; 递归展开子集合,用into把元素合并到累加器 (into acc (flat elem)) ; 非集合元素直接加入累加器 (conj acc elem))) [] ; 初始累加器为空向量 arr))
调用测试一下:
(flat ["a" ["b" "c"] "d"]) ; 输出:["a" "b" "c" "d"]
额外小提示
其实Clojure标准库已经自带了flatten函数,直接调用(flatten ["a" ["b" "c"] "d"])也能得到你想要的结果,但自己实现一遍确实是理解Clojure不可变性和递归的好练习!
内容的提问来源于stack exchange,提问作者Kevin Steen
相关产品推荐
相关产品推荐

