Reputation: 1737
I am trying to find a functional correct way for the following piece of code:
let mutable u = initialize cities pms
for i in 0 .. 10 do
u <- randomIteration u pms distances
randomIteration is a simple function which takes an array with 2 more parameters and returns a modified array. This process has to be repeated n-times (10 here).
I came up with a solution, which uses fold, but I am creating a "dummy" sequence just to be able to fold on it, which does not seem right.
let result = Seq.init 10 (fun i -> i) |> Seq.fold (fun uNext i -> randomIteration uNext pms distances) u
I could also use recursion with a counter variable, but that as well seems ackward. Am I just missing a simple right solution?
Upvotes: 5
Views: 3806
Reputation: 7543
This is just a slight variation on Nikon-the-Third's answer. One could create a more general function that repeatedly applies another function:
let repeat n fn = List.init n (fun _ -> fn) |> List.reduce (>>)
This could then be used to create a named function that repeats the first 10 times:
let getNext10Times = repeat 10 (fun u -> randomIteration u pms distances)
getNext10Times u
or it could be used anonymously:
u |> repeat 10 (fun u -> randomIteration u pms distances)
Upvotes: 2
Reputation: 109005
I could also use recursion with a counter variable, but that as well seems ackward.
That would seem natural to me: allowing the result of one call to be passed to the next without mutable state. Something like:
let interateSelf func initial count =
let rec inner intermediate n =
if n = 1 then
func intermediate
else
inner (func intermediate) (n - 1)
inner initial count
Upvotes: 5
Reputation: 2831
Just trying to think outside the box here, but instead of folding over randomIteration
with different arguments each time, you could create a chain of N randomIteration
calls and call this chain once:
let repeat n =
Seq.init n (fun _ u -> randomIteration u pms distances)
|> Seq.reduce (>>)
initialize cities pms
|> repeat 10
|> printfn "Result: %A"
Upvotes: 6
Reputation: 19897
One easy change to make that less awkward is to use a sequence expression rather than Seq.init
.
let result = {1..10}
|> Seq.fold (fun uNext i -> randomIteration uNext pms distances) u
If you really want to keep the Seq.init
you could replace the identify function with the build-in one like this:
let result = Seq.init 10 id
|> Seq.fold (fun uNext i -> randomIteration uNext pms distances) u
An alternative would be to create a recursive function something like this:
let result = let rec loop x i =
match i with
| 0 -> x
| i -> loop (randomIteration x pms) (i-1)
loop u 10
Upvotes: 5