将这段Java代码块翻译为Clojure,有什么帮助吗?

4
我正在尝试使用Clojure并逐渐适应函数式编程。我一直在将其他语言的命令式函数翻译成它们对应的Clojure函数,到目前为止一切都很顺利。然而,我现在遇到了一个难题,不知道如何将这个Java方法翻译成惯用的Clojure。起初,“map”似乎是正确的工具,但经过一些尝试后,我不太确定。有人能向我展示如何在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);

}

url.length()是什么?它应该是str吗? - Jeff Foster
什么是url变量,toHex8有什么作用? - jitter
1
我不熟悉 Clojure,所以无法回答您的问题,但您需要使用 reduce 函数:http://clojure.org/api#reduce - Dave Ray
1
我认为 "key>>>(8&255)" 的括号使用不正确。 - Carl Smotricz
2个回答

7
我们刚度过万圣节,现在是...新手们的夜晚! 我只学了几天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位十六进制数打印出来,只是为了让它编译通过。

与其使用索引从hashstrn中获取字符,我将它们都视为字符序列,并在每次迭代中仅处理它们的头元素。 hash由于使用了(cycle)而具有无限长度。

位操作名称以"bit-"开头。

由于Clojure中的整数可以变得任意大,所以由于<< 9,结果数字随着每个字符而变得更大。这可能不是预期的。

无论如何,一些破坏者刚刚发布了一个可能是正确答案。 不过,这很有趣,我希望我能与您分享一点努力。

编辑:因为Dave Ray坚持使用(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分鼓励你的努力,但哇!如果这确实是Clojure在位操作方面比Java更冗长的最佳实践,我不禁想知道我们是否发现了Clojure不如Java的领域。我不是贬低提出的解决方案。(我自己也做不得更好。)但与我们想出的内容相比,Java版本读起来非常流畅。 - clartaq
嗯,Clojure 在需要冗长的函数名称方面稍微逊色于 Java 的简洁运算符。而且我相信真正的 Clojurians 肯定比我做得更好。首先,在 next-key 中我错过了解构的机会。 - Carl Smotricz

1

Clojure没有暴露>>>运算符,因此无法直接翻译。


好的,我承认我在那里马虎了,只做了一个简单的右移动。让我们看看我能不能改正一下... - Carl Smotricz
啊,太棒了......因为我们从一个正数开始并且它不断增长并变成了一个 BigInt,所以它永远不会是正的。所以>>产生的结果与>>>相同。幸好! - Carl Smotricz
你仍然可以在Clojure中创建一个数学上等价的函数,这是肯定的 :) - Timothy Pratley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接