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个金融机构];如果不是,则:记录的第一次计算)