I cannot find any simple (compared to the try catch method, which is rather straightforward) way to do this:
try
Some (line.Split delimiter |> Array.map Int32.Parse)
with
|_ -> None
A bad (call Parse twice) approach is like this:
let array = line.Split delimiter
let parseSucceed =
array |> Array.exist (Int32.TryParse >> fst >> not)
|> not
if parseSucceed then Some (array |> Array.map Int32.Parse) else None
Is there any standard way of doing such tasks? Do I have to write up a recursive function to handle this?
What if the input is not an array but a stream/sequence?
Update:
@Daniel’s method is great.
module Seq =
let tryCatch myFun (x: seq<_>) =
let rec loop acc (e: IEnumerator<_>) =
if e.MoveNext() then
match myFun e.Current with
| Some v -> loop (v::acc) e
| None -> (false, acc |> List.rev |> List.toSeq)
else
(true, acc |> List.rev |> List.toSeq)
use e = x.GetEnumerator()
loop [] e
let parse x =
printf "%d " x // log when the function is called.
if x > 3 then None else Some x
let tt myFun x =
let y = Seq.tryCatch myFun x
if fst y then
printfn "yes %A" (y |> snd |> Seq.toArray)
else
printfn "no %A" (y |> snd |> Seq.toArray)
tt parse [| 0;2;1;2;4;1;2 |]
tt parse [| 0;2;1;2 |]
>
0 2 1 2 4 no [|0; 2; 1; 2|] // parse is called minimum number of times
0 2 1 2 yes [|0; 2; 1; 2|]
You could do:
Or, if you want something a bit more reusable: