2009-11-16 56 views
4

我正在用Clojure弄湿我的脚,并试图习惯功能性编程。帮助将此Java代码块转换为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); 

} 
+0

什么是url.length()?它应该是str? – 2009-11-16 20:19:03

+0

什么是url变量和hx8做什么? – jitter 2009-11-16 20:19:34

+1

我不知道Clojure,所以我不会写一个答案,但你想reduce函数:http://clojure.org/api#reduce – 2009-11-16 20:49:16

回答

7

我们刚刚通过万圣节,它是... 生活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位十六进制数字参数的函数。只是为了让dang的东西编译。

我不是使用索引从hashstrn中提取字符,而是将它们当作字符序列处理,并且仅在每次迭代中处理其头元素。 hash是无限长的,由于(cycle)

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

由于整数在Clojure中可以变得任意大,因此由于<< 9,每个字符的结果数量会变得更大。这可能不是有意的。

无论如何,一些spoilsport只是发布了什么可能是正确答案。尽管如此,这很有趣,我希望我能与你分享一些努力。

编辑:因为戴夫射线使用(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工作,我不得不把它们压缩成一个单一的列表;看评论。

我们仍然有一个问题,即原始算法不适用于无限大小的整数,再加上最后一行中可能的括号问题。你可能想要构建你自己的截断比特旋转函数。

+0

+1的努力,但哇!如果这真的是我们可以在Clojure中做的最好的事情,那么我想知道我们是否发现了一个Clojure比Java更简洁的地方(有点纠结)。我不是在敲敲解决方案。 (我当然无法做得更好。)但是与我们所提出的相比,Java版本看起来像丝绸般光滑。 – clartaq 2009-11-19 19:44:05

+0

那么,Clojure会因为Java简洁的操作符而需要冗长的函数名称。我很确定真正的Clojurians可以做得比我做得更好。首先,我错过了下一个关键解构的机会。 – 2009-11-20 06:04:40

1

Clojure没有公开>>>运算符,所以直接转换是不可能的。

+0

好吧,我承认我对此嗤之以鼻,做了一个简单的右移。让我们看看我是否可以解决这个问题... – 2009-11-16 22:22:07

+0

啊,优秀...因为我们从一个正数开始,并且因为它不断增长并且变成一个BigInt,所以它永远不会是积极的。所以>>得到与>>>相同的结果。唷! – 2009-11-16 22:25:11

+0

:)你仍然可以在Clojure中创建一个数学上等价的函数,这是肯定的:) – 2009-11-16 23:41:30