2009-12-10 69 views
2

如果我有這樣的事情怎麼寫這段代碼中的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

'((一些代碼)(如果(COND2)-1(some-代碼 - 再次)))'不起作用。Clojure的Parens總是意味着做一個函數調用。使用'when'並擺脫外面的parens。或者使用'do'。 – 2009-12-10 19:11:48

+0

@ajay:我的答案按照承諾更新。 – 2009-12-10 20:08:17

回答

3

你可以說,這是不好的風格,因爲它很難理解控制流當然,除非這種模式被用於返回錯誤條件(這是常見於C)。 Clojure支持異常。如果你真的想在其他地方發送控制使用它們。

+1

關於錯誤的有趣想法,+1!當然有些人使用例外控制流程,但我*真的*真的不推薦! – 2009-12-10 23:05:58

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沒有返回。

+0

請參閱我的示例,以更簡潔的方式執行他所描述的操作。 – 2009-12-10 18:25:11

+1

除了它不完全相同的東西... – 2009-12-10 22:55:36

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))))) 
} 

我們不得不調整這使它什麼可以在「都是一個大長return語句」或人描述真的挖功能性編程稱它爲「一項功能」。

(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)必須被調用兩次,因爲有兩個代碼路徑使用它。

+0

我們到達類似的解決方案可能是巧合,但我會說它指向Clojure(和Python)的哲學,應該有一個明顯的最好的方式來做大多數事情。到現在爲止還挺好。但是我有一個括號問題(在下一個評論中)。 – 2009-12-10 08:40:45

+0

我們在外面(更重要的是,之前)(somecondition)和「一些代碼」定義了輔助函數。是否仍然存在漏洞,因爲我們可能錯過了前面代碼的副作用或關閉? – 2009-12-10 08:43:54

+0

不是我所看到的,儘管任何人都可以編寫沒有錯誤的代碼,他們可以看到:) – 2009-12-10 17:30:27

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)))) 

UPDATE一些解釋。

因爲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分支之一中調用以下代碼。事實上,它出現在兩個分支。因此,爲了不必重複代碼,我將其拉入了自己的功能。

這裏是我的代碼的翻譯僞代碼:

功能foo2的:

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 

末1是你的棘手 「return -1」。結尾2包括「some code again」,結束3沒有。結束2和結束3測試C3,也許做「something again」,然後return bar()

+0

啊,我很高興看到我的版本看起來很像亞瑟的。我使用了「let fn」(因爲我沒有記憶的語法),所以爲了保持輔助函數本地到使用它的地方。 – 2009-12-10 08:37:42

+0

當宏是一個更可讀的方式來做到這一點。由於海報代碼沒有真正的其他塊,所以如果內置的是過度殺傷性的cond。 – 2009-12-10 18:28:20

+0

我相信你忽略了'return -1',這大大改變了執行流程。正如你在上面的僞代碼中看到的那樣,我的翻譯需要兩個帶有else分支的if。我沒有看到任何機會使用'when'來取得良好效果。 – 2009-12-10 20:05:31

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)) 

使代碼清晰可讀的,簡潔的,你指定什麼呢。

+0

我不同意。我的代碼中沒有任何地方可以看到'return -1'的等價物。你未能捕捉到問題邏輯最重要的部分。 – 2009-12-10 19:51:16

+0

你是完全正確的。我錯過了他的例子的迴歸-1部分。我撤回我的例子。 – 2009-12-10 19:59:00

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中,在函數中有多個返回語句通常是不好的風格。轉換爲功能風格的另一個好處是強制通過代碼的路徑變得更加清晰。

編輯:我驗證了這個代碼

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

忽略該showup近等基因系,他們是因爲println返回nil

相關問題