Clojure - 1 个函数的 2 个版本。哪个更惯用?

Posted

技术标签:

【中文标题】Clojure - 1 个函数的 2 个版本。哪个更惯用?【英文标题】:Clojure - 2 versions of 1 function. Which is more idiomatic? 【发布时间】:2012-02-24 19:07:24 【问题描述】:

在此处包含的两个函数中,哪一个更惯用?两者都不代表可以被认为是好的 Clojure 的东西吗?有没有更优雅的方式来实现这一点?寻找一些关于风格/方向的建设性批评。

(在github上:https://github.com/jtrim/clojure-sandbox/blob/master/bit-sandbox/src/bit_sandbox/core.clj#L25)

这个函数的两个版本都采用数字表示的字节向量,并且 将字节转换为数字。例如

(bytes-to-num [0 0 0 0])   ;=> number `0`
(bytes-to-num [0 0 0 255]) ;=> number `255`
(bytes-to-num [0 0 1 0])   ;=> number `256`
; etc...

v1:循环/重复

在每个递归级别,有问题的字节 左移一个对应于字节数的数字 给定的递归级别,然后添加到运行总和中 返回或传递到另一个级别。

(defn bytes-to-num-v1 [vec-bytes]
  (loop [sum 0, the-bytes vec-bytes]
    (if (empty? the-bytes)
      sum
      (recur
        (+ sum (shifted-byte (first the-bytes) (count (rest the-bytes))))
        (rest the-bytes)))))

v2:减少

v2 使用 [sum position] 的累加器减少字节向量,其中:

sum:移位字节的运行总和 位置:从零开始的索引(注意:从右侧开始,而不是从左侧开始) 向量中的当前字节。用于确定要左移多少位 有问题的字节。

(defn bytes-to-num-v2 [vec-bytes]
  (first (reduce
    (fn [acc, the-byte]
      [(+ (first acc) (shifted-byte the-byte (last acc))) (dec (last acc))])
    [0 (dec (count vec-bytes))]
    vec-bytes)))

为了完整性,shifted-byte 函数的来源:

(defn shifted-byte [num-byte-value, shift-by]
  (bit-shift-left
    (bit-and num-byte-value 0xFF)
    (* shift-by 8)))

【问题讨论】:

【参考方案1】:

您正在尝试将字节转换为无符号大整数,对吗?

在这种情况下,您可能想要这样的东西:

(defn bytes-to-num [bytes]
  (reduce (fn [acc x] (+ x (* 256 acc))) bytes))

一般cmets:

Reduce通常是比循环/递归更好、更惯用的选项 如果你能提供帮助,你真的不想拉一个位置索引

或者,您可以使用 Java 互操作直接使用接受字节数组的 BigInteger 构造函数。这里唯一的技巧是 Java 需要有符号字节,所以你需要先做一点转换:

(defn to-signed-byte [x] (.byteValue x))

(BigInteger. (byte-array (map to-signed-byte [ 0 0 0 255])))
=> 255

【讨论】:

非常好。加载更简单,更容易阅读。感谢您的反馈! to-signed-byte 也可以使用Byte/valueOf(defn t-s-b [x] (Byte/valueOf (byte x)))。它会为您完成转换。 @kotarak - 不确定是否有效,因为 (byte x) 失败,任何高于 127 的值......据我所知,对于未经检查的强制整数类型。 实际上从头开始。 (.byteValue x) 似乎确实有效......使用此编辑的答案 啊。哎呀。对不起。我的意思是.byteValue

以上是关于Clojure - 1 个函数的 2 个版本。哪个更惯用?的主要内容,如果未能解决你的问题,请参考以下文章

嵌套地图的Clojure Zipper压制TRIE

Clojure 性能,如何输入提示到 r/map

为什么Clojure区分符号和变量?

windows怎么安装2个版本python

Clojure - 宏中的 let 不起作用

SQL Server 2016有几个版本?哪个比较好些?