在Clojure的条件表达式中保存重复计算?(Save repeated computation in conditional expression in Clojure?)

编程入门 行业动态 更新时间:2024-10-27 16:34:37
在Clojure的条件表达式中保存重复计算?(Save repeated computation in conditional expression in Clojure?)

在下面的代码中,我需要计算键盘中的一个元素和驱动器中的一个元素之和的最大值,但总和应小于或等于s 。

(def s 10) (def keyboards '(3 1)) (def drives '(5 2 8)) (let [k (sort (fn [x y] (> x y)) keyboards) ; sort into decreasing d (sort (fn [x y] (> x y)) drives) ; sort into decreasing ] (loop [k1 (first k) ks (rest k) d1 (first d) ds (rest d)] (cond (or (nil? k1) (nil? d1)) -1 ; when one of the list is empty (< (+ k1 d1) s) (+ k1 d1) ; whether (+ k1 d1) can be saved to compute once? (and (empty? ks) (empty? ds)) -1 (empty? ks) (if (< (+ k1 (first ds)) s) (+ k1 (first ds)) -1) ; whether (+ k1 (first ds)) can be saved once? (empty? ds) (if (< (+ d1 (first ks)) s) (+ d1 (first ks)) -1) ; whether (+ d1 (first ks)) can be saved once? :else (let [bs (take-while #(< % s) [ (+ k1 (first ds)) (+ (first ks) d1) ])] (if (empty? bs) (recur (first ks) (rest ks) (first ds) (rest ds)) (apply max bs))))))

如注释中所示,我想知道是否有任何方法可以进一步优化条件表达式中的重复添加操作。 在条件检查之前使用let绑定来计算它们可能不是最佳的,因为只有一个条件是真的,因此其他条件的计算将被浪费。

我想知道Clojure编译器是否足够聪明,可以为我优化重复计算,还是有一个巧妙的表达式,使得在检查和返回值中只执行一次操作?

任何建议,使代码更习惯性将不胜感激。

In the following code, I need to compute the maximum of the sum of one element from keyboards and one from drives, subject that the sum should be less or equal to s.

(def s 10) (def keyboards '(3 1)) (def drives '(5 2 8)) (let [k (sort (fn [x y] (> x y)) keyboards) ; sort into decreasing d (sort (fn [x y] (> x y)) drives) ; sort into decreasing ] (loop [k1 (first k) ks (rest k) d1 (first d) ds (rest d)] (cond (or (nil? k1) (nil? d1)) -1 ; when one of the list is empty (< (+ k1 d1) s) (+ k1 d1) ; whether (+ k1 d1) can be saved to compute once? (and (empty? ks) (empty? ds)) -1 (empty? ks) (if (< (+ k1 (first ds)) s) (+ k1 (first ds)) -1) ; whether (+ k1 (first ds)) can be saved once? (empty? ds) (if (< (+ d1 (first ks)) s) (+ d1 (first ks)) -1) ; whether (+ d1 (first ks)) can be saved once? :else (let [bs (take-while #(< % s) [ (+ k1 (first ds)) (+ (first ks) d1) ])] (if (empty? bs) (recur (first ks) (rest ks) (first ds) (rest ds)) (apply max bs))))))

As indicated in the comments, I wonder if there is any way to further optimize the repeated add operation in the conditional expressions. It may not be optimal to use let bindings to compute them all before the condition checkings, as only one of the condition would be true, thus the computations for the other conditions would be wasted.

I wonder if Clojure compiler would be smart enough to optimize the repeated computation for me, or there is a clever expression to make the operation to be performed only once in both the checking and return value?

Any suggestion to make the code more idiomatic would be appreciated.

最满意答案

如果您想保留当前代码的结构,可以使用Mark Engelberg的更好的cond库:

(require '[better-cond.core :as b]) (def s 10) (def keyboards '(3 1)) (def drives '(5 2 8)) (let [k (sort (fn [x y] (> x y)) keyboards) ; sort into decreasing d (sort (fn [x y] (> x y)) drives)] ; sort into decreasing (loop [k1 (first k) ks (rest k) d1 (first d) ds (rest d)] (b/cond (or (nil? k1) (nil? d1)) -1 ; when one of the list is empty :let [x (+ k1 d1)] (< x s) x (and (empty? ks) (empty? ds)) -1 :let [y (+ k1 (first ds))] (empty? ks) (if (< y s) (dec y)) :let [z (+ d1 (first ks))] (empty? ds) (if (< z s) (dec z)) :else (let [bs (take-while #(< % s) [(+ k1 (first ds)) (+ (first ks) d1)])] (if (empty? bs) (recur (first ks) (rest ks) (first ds) (rest ds)) (apply max bs))))))

If you want to keep the structure of your current code, you can use Mark Engelberg's better-cond library:

(require '[better-cond.core :as b]) (def s 10) (def keyboards '(3 1)) (def drives '(5 2 8)) (let [k (sort (fn [x y] (> x y)) keyboards) ; sort into decreasing d (sort (fn [x y] (> x y)) drives)] ; sort into decreasing (loop [k1 (first k) ks (rest k) d1 (first d) ds (rest d)] (b/cond (or (nil? k1) (nil? d1)) -1 ; when one of the list is empty :let [x (+ k1 d1)] (< x s) x (and (empty? ks) (empty? ds)) -1 :let [y (+ k1 (first ds))] (empty? ks) (if (< y s) (dec y)) :let [z (+ d1 (first ks))] (empty? ds) (if (< z s) (dec z)) :else (let [bs (take-while #(< % s) [(+ k1 (first ds)) (+ (first ks) d1)])] (if (empty? bs) (recur (first ks) (rest ks) (first ds) (rest ds)) (apply max bs))))))

更多推荐

本文发布于:2023-07-22 14:07:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1220597.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:表达式   条件   Save   Clojure   conditional

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!