如何在Clojure中编写这段代码

时间:2009-12-10 06:55:54

标签: clojure

如果我有这样的话:

int foo() {
    if(somecondition) {
       // some code
       if(cond2) return -1;
       // some code again
    }
    if(cond3){
       // something again
    }
    return bar();
 }

我如何在Clojure中表达它?

它不应该写成if_elseif,因为somecondition和cond3都可能为true且两者都可以执行。

根据以下建议,我建议再提一个解决方案。如果这是对的,请告诉我:

(defn foo []
    (if (somecondition)
        ( (some-code) (if (cond2) -1 (some-code-again)) )
        1 ; empty statement
    )
    (if (cond3) (something-again) 1)
    (bar))

6 个答案:

答案 0 :(得分:3)

你可能会认为这是一种糟糕的风格,因为很难理解控制流,除非这种模式当然用于返回错误条件(这在C中很常见)。 Clojure支持异常。如果你真的想在别处发送控件,请使用它们。

答案 1 :(得分:3)

您可以通过将一些代码重构为单独的函数来撤消控制流中的结。这也适用于C和Clojure。

这是我对它的刺痛。手工翻译,未经测试,因此可能是错误的。

(defn foo []
  (let [foo2 (fn [] 
    (if cond3 "something again")
    (bar))]
    (if somecondition
      (do
        "some code"
        (if cond2
          -1
          (do
            "some code again"
            (foo2))))
      (foo2))))

更新并提供一些解释。

因为ajay问道,我想揭露一些让我进入上述解决方案的想法。

快捷键

c1 = somecondition
c2 = cond2
c3 = cond3

真值表(这对我的想法有点帮助,但没有直接进入设计)

c1 c2 c3 results
----------------
T  T  .  "some code" -1
T  F  T  "some code" "some code again" "something again" bar()
T  F  F  "some code" "some code again" bar()
F  .  T  "something again" bar()
F  .  F  bar()

Clojure的工作方式,没有“回归”。 Clojure函数始终返回要计算的最后一个表达式。如果我们想要产生相同的副作用(来自“一些代码”,“一些代码再次”和“某些东西”)并作为C / Java代码产生,我们需要使代码以这样的方式运行实际上是最后一件事。

能够返回-1的唯一方法是重新编写代码,以便从一开始就有一个分支 - 真正结束 - 在“-1”。这意味着必须从其他IF分支中调用以下代码。事实上,它出现在两个分支中。为了不必重复代码,我把它拉成了自己的函数。

这是我的代码到伪代码的翻译:

function foo2:

if c3 then
   "something again"
endif
bar()

function foo:

if c1 then
   "some code"
   if c2 then
     -1            <-- end 1
   else
     "some code again"
     foo2          <-- end 2
   endif
else
   foo2            <-- end 3
endif

结束1是你棘手的“return -1”。结束2包括“some code again”,结束3不包括“something again”。结束2和结束3都测试c3,可能是“return bar()”然后是{{1}}。

答案 2 :(得分:1)

我认为它看起来像这样:

(defn foo
  []
  (if somecondition
    (do
      ; some code
      (if cond2
        -1
        (do
          ; somecode again
          (if cond3
            (do
              ; something again))
          (bar))))
    (do
      (if cond3
        (do
          ; something again))
      (bar))))

多么丑陋 - 不要那样做:)

据我所知,缺乏控制跳跃是设计的。这个函数完全是副作用驱动的,这是一个红旗,也许底层问题可以用另一种方式更好地表示,但很难给出任何真正的建议,因为这个例子完全是抽象的。 CL has a return-from which is rarely used“因为所有Lisp表达式,包括循环和条件等控制结构,都计算为值”。 Clojure没有回复。

答案 3 :(得分:1)

让我们从一些字面翻译开始,以建立一个共同点:

int foo() {
(defn foo []

    if(somecondition) {
    (if somecondition 

       // some code
       (some-code 1 2 3)

       if(cond2) return -1;
       (if cond2 
          -1
          // some code again
          (some-code 1 2 3)

        }
              if(cond3){
              // something again
              }
              (if cond3
                  (something :again)

                  return bar();
                  (bar)))))
 }

我们必须对此进行调整,以使其能够在“所有一个很长的返回语句”中进行描述,或者将真正挖掘函数式编程的人称之为“函数”。

(defn helper-function []
   (if cond3
      (something again))
   bar))

(defn foo []
    (if somecondition 
      (some-code 1 2 3)
      (if cond2 
          -1
          (helper-function)
     (helper-function)

该函数有两个确定返回点的位置。在clojure中,这只是函数的结尾。 clojure函数返回在函数结束之前计算的最后一个表达式的结果,否则我们将在任何地方写回。 (helper-function)必须被调用两次,因为有两个代码路径使用它。

答案 4 :(得分:0)

该代码示例已准备好用于when

(defn foo []
  (when somecondition
    ; code goes here
    (do-somecondition-code)
    (when cond2
       ; more code goes here
       (do-cond2-code)))
  (when cond3
      ; even more code here
      (do-cond3-code))
  (bar))

代码清晰可读,简洁明了,完全符合您的要求。

答案 5 :(得分:0)

首先,我定义了一些辅助函数来验证函数的调用时间。

(defn some-code [] (println "some code"))
(defn some-code-again [] (println "some code again"))
(defn something-again [] (println "something again"))
(defn bar [] "bar")

然后我定义foo就像这样接受三个条件因此我可以测试它:

(defn foo [somecondition cond2 cond3]
  (if (and  somecondition cond2)
    (do (when somecondition (some-code)) -1)
    (do
      (when somecondition (some-code))
      (when cond3 (something-again))
      (bar))))
我采取了几个自由。首先,C代码可能允许在some code中设置cond2,这也可以使用let语句进行处理。另外,我通常不会有do子句,但由于我不知道代码到底是做什么的,所以不可能创建有意义的函数名。

另一种风格注释:在C语言中,在函数中包含多个return语句通常是不好的风格。转换为功能样式的另一个好处是使代码中的路径变得更加清晰。

编辑:我用

验证了这段代码
(for [somecondition [true false] cond2 [true false] cond3 [true false] ]  
    (do 
        (println "========") 
        (println "round" somecondition cond2 cond3) 
        (println "result:" (foo somecondition cond2 cond3))))

忽略显示的nils,因为println返回nil