【问题标题】:Converting the Java concept into Clojure将 Java 概念转换为 Clojure
【发布时间】:2014-06-11 23:38:12
【问题描述】:

我对 Clojure 很陌生。我有一个包含布尔变量的 Java 方法,我想重写此方法以在 Clojure 中使用相同的功能。但是我找不到如何在 Clojure 的运行时设置布尔值 true 和 false。

下面的sn-p基本上只强调布尔部分,我很难想到用函数的方式写这个。

int calculate(...){
  int y = 0;
  boolean flag = false;
  foreach(...){
     if(!flag){
        y = 1;
        flag = true;
     }
     else{
        y = -1;
        flag = false;
     }
  }
  return y;
} 

这是我在 Clojure 中的第一次尝试:

(defn calculate [...]
    ( ??flag?? -> I do not know which macro I should use over here
      (doseq [x ...]
        (if (false? flag) (do 1 (set the flag true)) 
           (do -1 (set the flag false)))))

如何在 Clojure 中实现相同的概念?

【问题讨论】:

  • 从概念上讲,使用辅助函数和递归函数可能更简洁 - (defn calculate [y flag] ..)
  • 这个程序毫无意义……你循环遍历集合的元素,翻转 y 的值——“标志”是否意味着代表集合中每个元素的某些功能?如果没有,则返回 1 或 -1,具体取决于集合的元素数是奇数还是偶数
  • 您问“如何在 Clojure 中实现相同的概念?”。 为什么您希望这样做?将 Java 逐点翻译成 Clojure,即使在可能的情况下,通常也是徒劳的。在你的 Java 程序有意义之前,很难看到如何在惯用的 Clojure 中呈现它的函数。如果您想解决 Clojure 中定义明确的小问题,请查看 4Clojure。如果您想将 Clojure 解决方案与 Java 和其他语言的解决方案进行比较,Rosetta Code 是一个很好的来源。我发现两者都非常有帮助。万事如意!

标签: java clojure


【解决方案1】:

对于您拥有的 Java 代码,将其转换为 Clojure 的最简单方法似乎是跳过所有迭代并仅返回最终值:

(defn calculate [coll]
  (odd? (count coll)))

如果你想要更精致的东西,我想你可以做类似的事情

(defn calc [coll flag]
  (if (empty? coll)
    flag
    (recur (rest coll) (not flag))))

并调用它

(defn calculate [coll]
  (calc coll false))     

这种递归不是最惯用的风格,而且对于这个问题有点疯狂,但它演示了如何代替变异变量编写一个表达式,该表达式在计算时会产生传递给下一次迭代的值(参见上例中的重复调用)。

这样改写会更好

(defn calculate
  ([coll flag]
    (if (empty? coll)
      flag
      (recur (rest coll) (not flag))))
  ([coll]
    (calculate coll false)))

所以只有一个函数名需要处理。 (我认为对于 Clojure 的新手来说阅读起来可能会更清晰。)

我赞同建议您查看4clojure 的评论。这是一种获得实践的好方法,一旦你有了解决方案,你就可以从其他用户的做法中学习。

【讨论】:

    【解决方案2】:

    使用 loop/recur 在 Clojure 中模拟迭代语句:

    (defn calculate [...]
      (loop [...
             y    0
             flag false]
        ...
        (if (false? flag)
          (recur ...  1 true)   ;; "loop with x = ..., y = 1 and flag = true"
          (recur ... -1 false)) ;; "loop with x = ..., y = -1 and flag = false"
        ... )
    

    编辑:让我详细说明。我从您的问题中了解到,您在将基于可变性(Java)的代码转换为 Clojure 时遇到了麻烦。这是很自然的。 Clojure 非常注重不变性。

    在 Clojure 程序中实现可变性的一种方法是使用引用类型,尤其是 atoms。在 Clojure 中,您的代码可以这样编写:

    (defn calculate [...]
      (let [y    (atom 0)
            flag (atom false)]
        (doseq [x ...]
          (if (false? @flag)
            (do (reset! y 1)
                (reset! flag true))
            (do (reset! y -1)
                (reset! flag false))))
        (... return some function of y and flag ...)))
    

    它有效。但是在 Clojure 中大量使用原子和副作用并不是惯用的。有时很有用,是的,但与功能性、惯用的 Clojure 相比,它不是必需且麻烦的。

    在迭代上下文中对可变性建模的更好方法是将其转换为递归,就像我在上面对loop/recur 所做的那样。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-25
      • 1970-01-01
      • 1970-01-01
      • 2015-06-14
      • 1970-01-01
      • 2017-01-13
      • 1970-01-01
      • 2021-01-12
      相关资源
      最近更新 更多