开发者

Abstracting a loop

I find myself writing loops (recursive functions) occasionally within assignments. It makes for awkward code like this:

let value =
  let rec loop a =
    if ... then a
    else loop a.B
  loop a

I know I could move the loop outside the let binding, but 开发者_如何学Cit's only purpose is to compute the bound value.

So I thought I might abstract the loop into a separate function:

let loop f a =
  let rec aux a =
    match f a with
    | Some b -> aux b
    | None -> a
  aux a

then I could do:

let value = a |> loop (fun a -> if ... then None else Some a.B)

Maybe that's better--at least it looks like more like assignment than a function definition. Here are my questions:

  1. Is a recursive function in a let binding something of a code smell?
  2. Is there a better way to refactor this?
  3. If not, could my loop function be generalized further, or somehow improved?


These questions are a bit subjective, but here are my answers:

  1. No
  2. I think what you've got is okay.
  3. Here's how I'd do it:

    let rec loop guard step init =
        if guard init then init
        else loop guard step (step init)
    
    let value = a |> loop (fun a -> ...) (fun a -> a.B)
    


I think that your or kvb's solutions are perfectly fine.

I don't know what is the data structure that you're iterating over in the loop. It looks like a data structure though, so it may make sense to implement the IEnuemerable<'T> interface or write a function that turns it into IEnumerable<'T>:

let rec asSeq a = seq {
  yield a 
  yield! asSeq a.B }

Then you could just use Seq.find and give it the condition you need:

// Using explicit conversion function
let value = a |> asSeq |> Seq.find (fun a -> ...)

// If 'a' actually implements 'seq<'T>', it is even nicer:
let value = a |> Seq.find (fun a -> ...)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜