【问题标题】:Help translating this Java codeblock to Clojure?帮助将此 Java 代码块翻译成 Clojure?
【发布时间】:2009-11-16 20:14:01
【问题描述】:

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);

}

【问题讨论】:

  • 什么是 url.length()?应该是str吗?
  • url 变量是什么,toHex8 是做什么的?
  • 我不知道Clojure,所以我不会写答案,但是你想要reduce函数:clojure.org/api#reduce
  • 我认为“key>>>(8&255)”的括号不正确。

标签: java functional-programming clojure


【解决方案1】:

我们刚刚过了万圣节,这是... 活着的 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 位十六进制数。只是为了编译该死的东西。

我没有使用索引从hashstrn 中提取字符,而是将它们都视为字符序列,并且在每次迭代中只处理它们的头部元素。 hash 无限长,感谢(cycle)

位操作的名称以“bit-”开头。

由于在 Clojure 中整数可以变得任意大,因此由于&lt;&lt; 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 工作,我必须将它们压缩成一个列表;见 cmets。

我们仍然有一个问题,即原始算法不适用于无限大小的整数,以及最后一行中可能存在的括号问题。您可能想要构建自己的截断位旋转函数。

【讨论】:

  • 努力+1,但是哇!如果这真的是我们在 Clojure 中可以做的最好的事情,我想知道我们是否发现了 Clojure 比 Java不如简洁的一个领域(有点麻烦)。我不反对提议的解决方案。 (我当然不能做得更好。)但是与我们提出的相比,Java 版本读起来像丝绸一样流畅。
  • 好吧,Clojure 在 Java 具有简洁运算符的情况下需要冗长的函数名称,这有点丢了。而且我很确定真正的 Clojurians 可以做得比我做得更好。一方面,我错过了在 next-key 中解构的机会。
【解决方案2】:

Clojure 不公开 >>> 运算符,因此无法直接翻译。

【讨论】:

  • 好的,我承认我在这方面马虎了,做了一个简单的右移。让我们看看我能不能解决这个问题......
  • 啊,太好了...因为我们从一个正数开始,并且因为它不断增长并变成一个 BigInt,所以它永远不是正数。所以 >> 产生与 >>> 相同的结果。呸!
  • :) 你仍然可以在 Clojure 中创建一个数学上等价的函数,这是肯定的 :)
猜你喜欢
  • 1970-01-01
  • 2020-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-25
  • 1970-01-01
  • 2018-05-13
  • 2016-08-04
相关资源
最近更新 更多