如果我有这样的话:
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))
答案 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