Clojure as cond in F #

I recently made a crawl in clojure from F # and came across a macro called cond. Here is a usage example:

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

This means the following in pseudo code:

 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 

This is just a binary search example if you were wondering what was left to the right and in the middle, but not very important.

I tried to find something similar in F #, but I couldn’t, so I decided to try and write it for myself. I got something like this:

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

The problem is that I want to use it in a recursive function and because recSrch left (mid-1) is evaluated immediately, so I end an infinite loop. I want this to be evaluated only on condition of fulfillment. In addition, the form is still not as clean as in Clojure.

Any ideas how I can improve this?

+7
clojure f #
source share
3 answers

You need a way for organs of state to evaluate lazily. Here is one way to do this by making the body function when you repeat a sequence of conditions:

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

Note that it makes sense to use something like this if your list of conditions should be dynamic.

For static conditions, you have pattern matching with when clauses. This gives you a nice idiomatic syntax and usually checks the exhaustibility of your matches at compile time, so it's worth it.

 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" 

It turns out better if you wrap it as an active template.

+4
source share

Here is a sketch using match , which in my opinion is close to clojure.

It defines Cond as a partial active template that takes a test function as an argument

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

using it is pretty easy

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

In F #, there is a language construct for this expression:

 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 

... or, generally speaking, I see the Clojure cond macro as the equivalent of matching a pattern or if/elif/else . They are clearly not quite the same, because Clojure is interpreted and dynamically typed, while F # is compiled and statically typed.

+4
source share

All Articles