Clojure - 2 варианта 1 функции. Что более идиоматично? - PullRequest
3 голосов
/ 02 февраля 2012

Из двух включенных здесь функций, что является более идиоматическим из двух?Не представляют ли что-то, что можно считать хорошим 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: loop / recur

На каждом уровне рекурсии рассматриваемый байт смещается влево на число, соответствующее количеству байтов на данном данном уровнерекурсия, затем добавляется к текущей сумме и либо возвращается, либо переходит на другой уровень.

(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 сокращает вектор байтов с помощью аккумулятора [sumposition] где:

  • sum: текущая сумма сдвинутых байтов
  • position: индекс на основе нуля (примечание: справа, а не слева) текущего байта ввектор. Используется для определения количества битов для сдвига влево рассматриваемого байта.

:

(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 Ответ

7 голосов
/ 02 февраля 2012

Вы пытаетесь преобразовать байты в большое целое число без знака, верно?

В этом случае вам, вероятно, нужно что-то вроде:

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

Общие комментарии:

  • Уменьшение - обычно лучший и более идиоматический вариант, чем loop / recur
  • Вы действительно не хотите тянуть индекс позиции, если можете помочь

В качестве альтернативы вы можете использовать взаимодействие Java для непосредственного использования конструктора BigInteger, который принимает массив байтов.Единственная хитрость здесь в том, что Java ожидает подписанные байты, поэтому сначала нужно выполнить небольшое преобразование:

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

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