如何用Clojure编写这段代码

如何用Clojure编写这段代码,clojure,Clojure,如果我有这样的东西: int foo() { if(somecondition) { // some code if(cond2) return -1; // some code again } if(cond3){ // something again } return bar(); } (defn foo [] (if somecondition (do ; som

如果我有这样的东西:

int foo() {
    if(somecondition) {
       // some code
       if(cond2) return -1;
       // some code again
    }
    if(cond3){
       // something again
    }
    return bar();
 }
(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))))
我如何用Clojure来表达它

它不应该写得像_elseif一样,因为somecondition和cond3可能都是true,也可能都是execute

从下面的建议中,我提出了另一个解决方案。请让我知道这是否正确:

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

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

我认为它看起来像这样:

int foo() {
    if(somecondition) {
       // some code
       if(cond2) return -1;
       // some code again
    }
    if(cond3){
       // something again
    }
    return bar();
 }
(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))))
多难看啊——别这么做:)


据我所知,缺乏控制是故意的。这个函数是完全由副作用驱动的,这是一个危险信号,可能潜在的问题可以用另一种方式更好地表示出来,但是很难给出任何真正的建议,因为这个例子是完全抽象的。“因为所有Lisp表达式,包括循环和条件等控件构造,计算结果都是一个值”。Clojure没有回报。

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

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)))))
 }
我们必须对其进行调整,使其成为“所有一个大的长返回语句”中所描述的内容,或者成为真正研究函数编程的人所称的“函数”


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

您可以通过将部分代码重构为单独的函数来撤销控制流中的节点;这在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
);真值表(这对我的思考有点帮助,但没有直接进入设计)

Clojure的工作方式没有“回报”。Clojure函数始终返回要计算的最后一个表达式。如果我们想产生与C/Java代码相同的副作用(从“某些代码”、“再次出现某些代码”和“再次出现某些代码”)和结果,我们需要使代码以这样一种方式运行,即结果实际上是最后执行的

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

以下是我的代码到伪代码的翻译:

职能2:

if c3 then
   "something again"
endif
bar()
功能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
如果是c1,则
“一些代码”
如果是c2,那么

-1该代码示例已准备就绪


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

首先,我定义了一些助手函数,以验证何时调用这些函数

(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语言中,在一个函数中有多个返回语句通常是不好的风格。转换为函数式风格的另一个好处是,代码中的路径变得更加清晰

编辑:我用

(for [somecondition [true false] cond2 [true false] cond3 [true false] ]  
    (do 
        (println "========") 
        (println "round" somecondition cond2 cond3) 
        (println "result:" (foo somecondition cond2 cond3))))

忽略出现的nil,它们是因为
println
返回nil

啊,我很高兴看到我的版本看起来很像亚瑟的。我使用了一个“let fn”(不使用letfn,因为我没有记住它的语法),以便将helper函数保留在使用它的地方。when宏是一种更可读的方法。因为海报代码没有真正的else,所以如果内置的是overkill,我相信您忽略了
return-1
,它极大地改变了执行流程。正如您在上面的伪代码中所看到的,我的翻译需要两个带有
else
分支的
if
s。当
达到良好效果时,我看不到任何使用
的机会。我们达成类似的解决方案可能是巧合,但我要说,它指向了Clojure(和Python)的哲学,即应该有一种明显的最佳方法来做大多数事情。到现在为止,一直都还不错。但我有一个附加问题(在下一篇评论中),我们在(更重要的是,在)(somecondition)和“somecode”之外定义helper函数。是否仍然存在故障漏洞,因为我们可能会错过前面代码中的副作用或闭包?我看不到,尽管任何人都可以编写没有bug的代码:)@Carl,为什么要调用helper函数两次?在我的C代码中,有两条路径可以调用helper函数,但我们不能避免调用,因为这条规则:(defn foo[](foo1)(foo2))在这种情况下,我们确保(foo2)总是被调用。所以,我认为在你的代码中,如果你把最后一个对helper函数的调用移到if块之外,那么它就会自动被调用。@Arthur:对我来说,这是个好主意。谢谢请参阅我的示例,了解一种更简洁的方法来完成他所描述的内容。
((一些代码)(如果(cond2)-1(再次出现一些代码))
不起作用。Clojure中的Parens总是意味着进行函数调用。当
(for [somecondition [true false] cond2 [true false] cond3 [true false] ]  
    (do 
        (println "========") 
        (println "round" somecondition cond2 cond3) 
        (println "result:" (foo somecondition cond2 cond3))))