如何用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))))