Clojure 如何在if-let中使用嵌套let编写一次函数调用?
我有以下职能:Clojure 如何在if-let中使用嵌套let编写一次函数调用?,clojure,Clojure,我有以下职能: (def i (atom {})) ;incremented/calculated file stats (defn updatei [n fic fos] (swap! i conj {(keyword n)[fic fos]})) (defn calcfo [fo fi fis] (if-let [n (get @i fo)] ;find a previous record? (let [fic (inc (first n)), fos (+ fis (s
(def i (atom {})) ;incremented/calculated file stats
(defn updatei [n fic fos]
(swap! i conj {(keyword n)[fic fos]}))
(defn calcfo [fo fi fis]
(if-let [n (get @i fo)] ;find a previous record?
(let [fic (inc (first n)), fos (+ fis (second n))] ;increment the stats
(updatei fo fic fos))
(let [fic 1, fos fis] ;if not then: first calc recorded
(updatei fo fic fos))))
如何编写(updatei fo fos)一次,而不是在函数中列出两次?有什么秘密或让我不知道的吗
-假想代码-
(defn calcfo [fo fi fis]
(if-let [n (get @i fo)] ;find a previous record?
(let [fic (inc (first n)), fos (+ fis (second n))] ;increment the stats
(or-let [fic 1, fos fis] ;if not then: first calc recorded
(updatei fo fic fos)))))
还是我认为这过于强制性而不是功能性
编辑:
我认为这对我来说是最有意义的:
(defn calcfo [fo fis]
(apply updatei fo
(if-let [[rfc rfos] (get @i fo)] ;find a previous record?
[(inc rfc) (+ rfos fis)] ;increment the stats
[1 fis]) ;if not then: first calc recorded
))
谢谢你的回答 如果使用
if
然后进行解构怎么样?以下是一种方法:
(defn calcfo [fo fi fis]
(let [n (get @i fo) ;find a previous record?
[fic fos] (if n
[(-> n first inc) (-> n second (+ fis))] ;increment the stats
[1 fis])] ;if not then: first calc recorded
(updatei fo fic fos)))
参数fi
似乎未被使用,因此您可以将其从参数列表中删除
(defn calcfo [fo fis] ,,,)
通过在let
表单中绑定n
时使用解构,也可以避免使用first
和second
:
(defn calcfo [fo fis]
(let [[x y & _] (get @i fo)
[fic fos] (if x [(inc x) (+ fis y)] [1 fis])]
(updatei fo fic fos)))
我认为如果您重新编写
updatei
,您会避开整个问题,使代码变得更好,比如:
(defn- safe+ [a b]
(if a (if b (+ a b) a) b))
(defn updatei [n fic fos]
(swap! i update-in [(keyword n)] #(vector (safe+ fic (first %)) (safe+ fos (second %)))))
可能有更好的方法来编写代码,但基本思想是使用
中的update
来存储新值(如果之前没有为该键存储任何值),或者将它们与已有值组合起来。重新排列可能会有所帮助
(defn calcfo [fo fi fis]
(apply updatei fo
(if-let [n (get @i fo)]
[(inc (first n)), (+ fis (second n))]
[1, fis] )))
这是个好主意,让我试试看,你是用
(或(和x res1)res2)
而不是(如果x res1 res2)
?我的意思是,你正在代码中重新实现if
。我很好奇为什么需要“and x”,我不明白。我试过了,但不知道怎么读。我这样编写了我的函数,所以用rfc(记录的文件计数)替换x:(定义calcfo[fo-fis](让[[rfc-rfos](get@I-fo);查找以前的记录?[fic-fos](或(和rfc[(inc-rfc)(+rfos-fis)];增加统计数据[1-fis]);如果没有,则:记录的第一个calc(更新fic-fos)))@scape和
检查其所有参数是否都是false(false
或nil
),如果都是,则返回最后一个参数,或者返回第一个为false的参数。正如Leonid指出的,在这种情况下,使用和和或就像重新实现如果,因为实际上只有两个可能的结果依赖于单个值,x
。您可以通过使用mapv
和部分,而不是(
宏:(部分mapv-safe+[fic-fos])
。有趣的想法,我喜欢hashset;让我看看这是如何工作的,因为我刚刚意识到mapv
无法处理键的初始nil
值。但是fnil
解决了这个问题:(fnil(部分mapv-safe+[fic-fos])[0])
。在这种情况下,您也不需要safe+
。@LeonidBeschastny,为什么不继续编辑代码使其更好呢?我只是想在
中演示更新的用法。这可能是我的最爱。非常容易阅读,而且似乎是最惯用的方法。如果let:(如果let[[x y](get@i fo)][(incx)(+fis y)][1 fis]
。是的,我这样做了:(defn-calcfo[fo-fis](apply-updatei-fo)(如果let[[rfc-rfos](get@i fo)];查找以前的记录?[(inc-rfc)(+rfos-fis)];增加统计数据[1个金融机构];如果不是,则:记录的第一次计算)