Reputation: 47904
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 it'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:
let
binding something of a code smell?loop
function be generalized further, or somehow improved?Upvotes: 2
Views: 209
Reputation: 243061
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 -> ...)
Upvotes: 0
Reputation: 55184
These questions are a bit subjective, but here are my answers:
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)
Upvotes: 4