Помогите перевести этот код Java в Clojure? - PullRequest
4 голосов
/ 16 ноября 2009

Я мокну от Clojure и пытаюсь привыкнуть к функциональному программированию.

Я переводил различные императивные функции из других языков в их эквиваленты Clojure - и до сих пор все шло хорошо. Однако теперь я столкнулся с проблемой, и не знаю, как перевести этот метод Java в идиоматический Clojure.

Сначала "карта" казалась подходящим инструментом, но, немного поиграв с ним, я не совсем уверен. Может кто-нибудь показать мне, как написать эту функцию в Clojure?

Спасибо!

public String calculateChecksum(String str)
{
    String hash = "bjytk3lfj%3jklDskj";
    int key = 1690912;

    for(int i=0; i < str.length(); i++) {

        key = key ^ (int)(hash.charAt(i%hash.length()))^(int)(str.charAt(i));
        key = key>>>23|key<<9;

    }return "8"+toHex8(key>>>(8&255))+toHex8(key&255);

}

Ответы [ 2 ]

7 голосов
/ 17 ноября 2009

Мы только что прошли Hallow'een, и сейчас ... ночь живых n00bs!

У меня всего несколько дней программирования на Clojure. Это усилие ближе к «настоящему» Clojure, и, по крайней мере, оно компилируется. Это также дает результат, но, вероятно, не правильный. Еще после этого:

(ns erikcw)

(defn toHex8 [n] (format "%08x" n))        ; Just a guess!

                                           ; can't use str, that's predefined.
(defn calculateChecksum [url]               ; I renamed the arg to url so I can use strn later.
  (loop [strn url                          ; this will loop over chars in strn.
         hash (cycle "bjytk3lfj%3jklDskj") ; now hash repeats for as long as you need it.
         key 1690912]                      ; modifying key along the way.
    (prn strn key)                           ; debug print.
    (let [k2 (bit-xor (bit-xor key (int (first hash))) (int (first strn)))
          k3 (bit-or (bit-shift-right k2 23) (bit-shift-left k2 9))]
      (if (empty? (rest strn))
        (str "8" (toHex8 (bit-shift-right k3 8)) (toHex8 (bit-and k3 255)))
        (recur (rest strn) (rest hash) k3)))))

(prn (calculateChecksum "HowNowBrownCow"))

Я не знаю, что делает функция toHex8, поэтому я написал функцию, которая печатает свой аргумент в виде 8-значного шестнадцатеричного числа. Просто чтобы получить чертову вещь для компиляции.

Вместо того, чтобы использовать индекс для извлечения символов из hash и strn, я рассматриваю оба как последовательности символов и работаю только с их элементами заголовка в каждой итерации. hash бесконечно долго, благодаря (cycle).

Битовые операции имеют имена, начинающиеся с "bit-".

Поскольку целые числа могут стать сколь угодно большими в Clojure, результирующее число становится больше с каждым символом благодаря << 9. Это, вероятно, не предназначено.

Во всяком случае, какой-то спойлспорт только что опубликовал, что, вероятно, будет правильным ответом. Тем не менее, это было весело, надеюсь, мне удалось поделиться с вами некоторыми усилиями.

Редактировать: Поскольку Дейв Рэй настаивает на использовании (reduce), я принял другое решение:

(defn next-key [key str-hash]
  (let [str1 (first str-hash)
        hash1 (second str-hash)
        k2 (bit-xor (bit-xor key hash1) str1)]
        (bit-or (bit-shift-right k2 23) (bit-shift-left k2 9))))

(defn calculateChecksum2 [url]
  (let [kk
    (reduce next-key 1690912
      (partition 2                ; (72 98) (111 106) (119 121) ...
        (map int                  ; 72 98 111 106 119 121
          (interleave url (cycle "bjytk3lfj%3jklDskj"))))) ; "HbojwyNt..."
  ]
  (str "8" (toHex8 (bit-shift-right kk 8)) (toHex8 (bit-and kk 255)))))

(prn (calculateChecksum2 "HowNowBrownCow"))

Этот немного легче читать и не нуждается в цикле. next-key можно было бы перетащить в основную функцию, но мне кажется, что такие вещи проще понять.

У нас есть список значений хеш-функции и одно из строковых значений. Чтобы заставить reduce работать, мне пришлось разбить их на один список; см. комментарии.

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

1 голос
/ 17 ноября 2009

Clojure не предоставляет оператора >>>, поэтому прямой перевод невозможен.

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