Reputation: 6442
I need to make a generic function that only stops when throwing an exception. In the example bellow, I need to create a positive number list: by creating a mutable
list then appending to it infinitely.
I'm required to use exception for breaking the loop, how can I stop using a mutable list to save the result but achieve the same functionality?
let many f =
let mutable list = []
let rec many' () =
list <- list @ f()
many'()
try many'() with Failure _ -> ()
list
let mutable n = Console.ReadLine() |> Int32.Parse
let positiveNumbers = many (fun () ->
n <- n - 1
if n < 0 then failwith ""
else n)
Upvotes: 2
Views: 62
Reputation: 11221
You can move the exception handling into the loop.
let many f =
let rec loop list =
try loop <| f() :: list
with Failure _ -> List.rev list
loop List.empty
let positiveNumbers =
many (fun () ->
let n = Console.ReadLine() |> Int32.Parse
if n > 0 then n
else failwith "")
Still, you shouldn't use exceptions for (expected) program flow. What you're after can be done by introducing a predicate
.
let many f predicate =
let rec loop list =
let n = f()
if predicate n then
loop <| n :: list
else
List.rev list
loop List.empty
let positiveNumbers =
many (fun () -> Console.ReadLine() |> Int32.Parse)
(fun n -> n > 0)
Wrapping things up --using the Option
type for (extended) validation.
let many f =
let rec loop list =
match f() with
| Some n
-> loop <| n :: list
| _ -> List.rev list
loop List.empty
let f() =
match Console.ReadLine() |> Int32.TryParse with
| true, i
-> if i > 0 then Some(i) else None
| _ -> None
let positiveNumbers = many f
Upvotes: 2