2016-05-29 23 views
7

我最近在F#的clojure中繞道而過,碰到一個叫做cond的宏。 下面是使用的例子:在F中像cond那樣的clojure#

(cond 
(= target (nth arr mid)) mid 
(< target (nth arr mid)) (search left (- mid 1)) 
(> target (nth arr mid)) (search (+ mid 1) right) 
(= left right) -1) 

這意味着在僞代碼如下:

if target == arr.[mid] then return mid 
if target < arr.[mid] then return (call search(left, mid-1)) 
if target > arr.[mid] then return (call search(mid+1, right)) 
if left == right then return -1 

這僅僅是從的情況下,二進制搜索你想知道什麼是左右和示例中期,但並不重要。

我試圖在F#中找到類似的東西,但是我不能,所以我決定嘗試爲自己寫。 我結束了這樣的事情:

type condition = bool * int 

let cond (conds: condition seq) = 
    conds |> Seq.pick(fun c -> if fst c then Some (snd c) else None) 

cond [| ((=) target arr.[mid], mid) 
     ((=) left right, -1) 
     ((<) target arr.[mid], recSrch left (mid-1)) 
     ((>) target arr.[mid], recSrch (mid+1) right) 
     |] 

這裏的問題是,我想在一個遞歸函數來使用它,因爲recSrch左(中1)目前正在評估的時候了,所以我在最後一個無限循環。我希望只有在條件成立的情況下才能評估它。另外,這個表格還沒有Clojure那麼幹淨。

任何想法我怎麼能改善這一點?

+0

對於我們這些誰不知道你的Clojure你的問題是非常不透明的。 – ildjarn

+0

對不起,我添加了一些僞代碼來清楚說明clojure代碼的行爲。 –

+0

你可以發佈完整的代碼,包括''target'',''left'',''right''。 – Gustavo

回答

4

你需要一種讓條件機構懶惰地評估的方法。下面是做這件事,通過使機體的功能,你通過條件的順序重複調用一個方法:

type condition = bool * (unit -> int) 

let cond (conds: condition seq) = 
    conds 
    |> Seq.pick(fun c -> 
     let pred, func = c 
     if pred then Some (func()) else None) 

cond [| ((=) target arr.[mid], fun() -> mid) 
     ((=) left right, fun() -> -1) 
     ((<) target arr.[mid], fun() -> recSrch left (mid-1)) 
     ((>) target arr.[mid], fun() -> recSrch (mid+1) right) 
     |] 

注意,它纔有意義,如果你的條件清單應該使用這樣的事情充滿活力。

對於靜態條件,您可以使用與when子句匹配的模式。這給你很好的慣用語法,並且通常在編譯時檢查你的匹配窮舉,所以它非常值得。

let result = 
    match target with 
    | _ when target = arr.[mid] -> mid 
    | _ when left = right -> -1 
    | _ when target < arr.[mid] -> recSrch left (mid-1)  
    | _ when target > arr.[mid] -> recSrch (mid+1) right 
    | _ -> failwith "you need this case if the compiler can't figure if your matches are exhaustive" 

,如果你把它包裝成一個活躍的格局轉好。

4

在F#,有一個爲那種表達的一個語言結構:

if target = arr.[mid] then mid 
elif target < arr.[mid] then call (search(left, mid-1)) 
elif target > arr.[mid] then call (search(mid+1, right)) 
else -1 

...或者,一般來說:我認爲Clojure的cond宏作爲圖案匹配或if/elif/else塊的等價物。它們顯然不完全相同,因爲Clojure是被解釋和動態輸入的,而F#是編譯和靜態類型的。

+0

匹配表達和匹配的主要區別是在一個條件下進行評估,而使用cond則可以測試不同的條件。 –

+0

@PeterV是的,這就是我在這裏提供'if/elif/else'示例的原因,而不是模式匹配。 –

+0

沒錯,解決了這個問題。我真正想要的是在clojure中爲cond宏創建一個類似的構造,主要是因爲我喜歡它是多麼緊湊。你可以爭論是否有意義。它主要是代碼乒乓球。我有點像這些,但我認爲我可以學到很多關於語言的知識。 –

7

這是一個使用match的草圖,我認爲它非常接近clojure。

Cond定義爲局部活躍模式使用它這需要測試函數作爲參數

let (|Cond|_|) f arg = 
    if f arg then Some() else None;; 

是很容易

match 1 with 
|Cond ((=) 5) _ -> printfn "unlikely" 
| _ -> printfn "likely";; 
+0

這是一個非常酷的方法。 – scrwtp

相關問題