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:
- Is a recursive function in a
let
binding something of a code smell? - Is there a better way to refactor this?
- If not, could my
loop
function be generalized further, or somehow improved?
These questions are a bit subjective, but here are my answers:
- No
- I think what you've got is okay.
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 -> ...)
精彩评论