我最近在F#中绕道而行,并遇到了一个叫做cond的宏.以下是用法示例:
(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)
Run Code Online (Sandbox Code Playgroud)
这意味着以下伪代码:
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
Run Code Online (Sandbox Code Playgroud)
这只是二进制搜索的一个例子,以防你想知道左边和右边是什么,但不是很重要.
我试图在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 )
|]
Run Code Online (Sandbox Code Playgroud)
这里的问题是我想在递归函数中使用它,并且因为recSrch left(mid-1)正在被立即评估,所以我最终处于无限循环中.我希望它只在条件成立时进行评估.此外,表格仍然不像Clojure那样干净.
任何想法我怎么能改善这个?
这是一个草图match
,我认为它非常接近clojure.
它定义Cond
为将测试函数作为参数的部分活动模式
let (|Cond|_|) f arg =
if f arg then Some () else None;;
Run Code Online (Sandbox Code Playgroud)
使用它很容易
match 1 with
|Cond ( (=) 5) _ -> printfn "unlikely"
| _ -> printfn "likely";;
Run Code Online (Sandbox Code Playgroud)
您需要一种使条件体延迟评估的方法。这是一种实现方法,将主体设置为在迭代条件序列时调用的函数:
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 )
|]
Run Code Online (Sandbox Code Playgroud)
请注意,只有当您的条件列表应该是动态的时,才有意义使用这样的东西。
对于静态条件,您可以使用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"
Run Code Online (Sandbox Code Playgroud)
如果将其包装为活动模式,效果会更好。