Hi everbody I am doing a project with F# but I get this error when ı use let num= line for the following code . I'm new at F# so I can not solve the problem. My code should do this things. User enter a number and calculate the fibonacci but if user enter not a number throw exception
open System
let rec fib n =
match n with
|0->0
|1->1
|2->1
|n->fib(n-1)+fib(n-2);;
let printFibonacci list =
for i=0 to (List.length list)-1 do
printf "%d " (list.Item(i));;
let control = true
while control do
try
printfn "Enter a Number:"
let num:int = Convert.ToInt32(stdin.ReadLine())
with
| :? System.FormatException->printfn "Number Format Exception";
let listFibonacci = [for i in 0 .. num-1->fib(i)]
printFibonacci(listFibonacci)
printfn "\n%A"(listFibonacci)
control<-false
Console.ReadKey(true)
exit 0;;
I'm not an F# expert but I can see 3 problems with the code you posted.
1) As Lasse V Karlsen commented - f# uses the 'offside' rule so your 'fib' expression needs the body indented in. If you are running this in the Visual Studio Shell it should warn you of this by putting a blue squiggly line under the appropriate code.
2) Both 'control' and 'num' are mutable values so need to be declared explicitly as such.
f# is a functional language so by default any expressions are immutable i.e they are not allowed to change state after they have been declared.
In f#, saying 'let n = expr' does not mean 'assign the value of expr to n' like you would in say c# or c++. Instead it means 'n fundamentally is expr' and will be forever much like a mathematical equation.
So if you want to update the value of a variable you use the special '<-' notation which is the equivalent of 'assign the value on rhs to the lhs' and you need to declare that variable as mutable i.e 'this value can be changed later'
So I think both num and control need to be declared at the top of the loop as
let mutable control = false
let mutable num = 0 // or whatever you want the initial value of num to be
As a side note you don't have to explicitly declare num as an int ( you can if you want ) but f# will infer the type for you
If I understand your code correctly, you want to keep asking for input number n until a valid number is given and print fibonacci numbers up to n. In this case, you'd better move the calculation and printing inside the try block. Here's an updated version with formatting.
open System
let rec fib n =
match n with
|0->0
|1->1
|2->1
|n->fib(n-1)+fib(n-2);;
let printFibonacci list =
for i=0 to (List.length list)-1 do
printf "%d " (list.Item(i))
let mutable control = true //you forgot to add the 'mutable' keyword
while control do
try
printfn "Enter a Number:"
let num:int = Convert.ToInt32(stdin.ReadLine())
let listFibonacci = [for i in 0 .. num-1 -> fib(i)]
printFibonacci(listFibonacci)
printfn "\n%A"(listFibonacci)
control <- false
with
| :? System.FormatException -> printfn "Number Format Exception"
//add the ignore statement to drop the resulting ConsoleKeyInfo struct
//or the compiler will complain about an unused value floating around.
Console.ReadKey(true) |> ignore
// exit 0 (* Exit isn't necessary *)
Instead of using an imperative style number entry routine and relying on exceptions for control flow, here's a recursive getNumberFromConsole function you could use as well:
open System
let rec fib n =
match n with
| 0 -> 0
| 1 | 2 -> 1
| n -> fib(n-1) + fib(n-2);;
let printFibonacci list =
for i=0 to (List.length list)-1 do
printf "%d " (list.Item(i))
//alternative number input, using recursion
let rec getNumberFromConsole() =
match Int32.TryParse(stdin.ReadLine()) with
| (true, value) -> value
| (false, _) -> printfn "Please enter a valid number"
getNumberFromConsole()
printfn "Enter a Number:"
let num = getNumberFromConsole()
let listFibonacci = [for i in 0 .. num-1 -> fib(i)]
printFibonacci(listFibonacci)
printfn "\n%A"(listFibonacci)
Console.ReadKey(true) |> ignore
P.S. Thanks for showing me stdin. I never knew it existed. Now I can write some interactive scripts.
Related
I'm reading through an F# tutorial, and ran into an example of syntax that I don't understand. The link to the page I'm reading is at the bottom. Here's the example from that page:
let rec quicksort2 = function
| [] -> []
| first::rest ->
let smaller,larger = List.partition ((>=) first) rest
List.concat [quicksort2 smaller; [first]; quicksort2 larger]
// test code
printfn "%A" (quicksort2 [1;5;23;18;9;1;3])
The part I don't understand is this: ((>=) first). What exactly is this? For contrast, this is an example from the MSDN documentation for List.partition:
let list1 = [ 1 .. 10 ]
let listEven, listOdd = List.partition (fun elem -> elem % 2 = 0) list1
printfn "Evens: %A\nOdds: %A" listEven listOdd
The first parameter (is this the right terminology?) to List.partition is obviously an anonymous function. I rewrote the line in question as this:
let smaller,larger = List.partition (fun e -> first >= e) rest
and it works the same as the example above. I just don't understand how this construct accomplishes the same thing: ((>=) first)
http://fsharpforfunandprofit.com/posts/fvsc-quicksort/
That's roughly the same thing as infix notation vs prefix notation
Operator are functions too and follow the same rule (ie. they can be partially applied)
So here (>=) first is the operator >= with first already applied as "first" operand, and gives back a function waiting for the second operand of the operator as you noticed when rewriting that line.
This construct combines two features: operator call with prefix notation and partial function application.
First, let's look at calling operators with prefix notation.
let x = a + b
The above code calls operator + with two arguments, a and b. Since this is a functional language, everything is a function, including operators, including operator +. It's just that operators have this funny call syntax, where you put the function between the arguments instead of in front of them. But you can still treat the operator just as any other normal function. To do that, you need to enclose it on parentheses:
let x = (+) a b // same thing as a + b.
And when I say "as any other function", I totally mean it:
let f = (+)
let x = f a b // still same thing.
Next, let's look at partial function application. Consider this function:
let f x y = x + y
We can call it and get a number in return:
let a = f 5 6 // a = 11
But we can also "almost" call it by supplying only one of two arguments:
let a = f 5 // a is a function
let b = a 6 // b = 11
The result of such "almost call" (technically called "partial application") is another function that still expects the remaining arguments.
And now, let's combine the two:
let a = (+) 5 // a is a function
let b = a 6 // b = 11
In general, one can write the following equivalency:
(+) x === fun y -> x + y
Or, similarly, for your specific case:
(>=) first === fun y -> first >= y
I am new to learning F# and writing a simple console application, where the user enters a value for distance, and I want some validation to make sure that the input is a number. It also needs to make sure that it is a number, and if it isn't, tell the user and they start again. This is what I have so far:
let distance = 0
while distance = 0 do
System.Console.WriteLine("How far do you want to travel?")
let answer = System.Console.ReadLine()
try
let distance = System.Int32.Parse(answer)
if distance < 0 then
let distance = 0
printfn "Can't use negative numbers"
elif distance = 0 then
printfn "Can't travel a distance of 0"
else
printfn "You are about to travel %A" distance
finally
let distance = 0
printfn "Invalid distance format"
And this is what comes up:
In this example, what I want to happen is for the "Invalid distance format" to not appear, and it moves on to the next part of the app.
How would I make it so that "Invalid distance format" only appears if distance can't be converted to an int via System.Int32.Parse(answer)
Even if try-finally is the complete wrong way to go about doing this, how else would it be done?
Thanks in advance
What you want is try...with
try
let distance = System.Int32.Parse(answer)
. . . . .
with
| _ as ex -> printfn "Invalid Distance Format"
http://fsharpforfunandprofit.com/posts/exceptions/
You could also do something like
...
let attemptedConvert = Int32.TryParse(answer)
let success,convertValue = attemptedConvert
if success then
//other stuff here
else
printfn "Invalid Number Format"
This way there is no exception thrown, and you still have validation if the entry was converted successfully.
As noted below, exceptions can be a more expensive operation than other alternatives, and should be evaluated to see if that is causing unnecessary overhead. Like any process though, this should be evaluated on a case by case basis.
TryParse Method
As you are learning, I would approach this problem by doing something like this.
It makes use of the option type which is useful for handling the 'null' case (i.e. no input). It also uses F#s pattern matching, which is a very powerful alternative to using if, else, elif etc.
//see here - http://fsharpforfunandprofit.com/posts/the-option-type/
let tryParseOption intStr =
try
let i = System.Int32.Parse intStr
Some i
with _ -> None
type Ask =
static member Askdistance (?text)=
let text = defaultArg text ""
printfn "%s" text
System.Console.WriteLine("How far do you want to travel?")
let distance = tryParseOption (System.Console.ReadLine())
match distance with
|None -> Ask.Askdistance("Invalid format distance provided")
|Some(a) when a <0 -> Ask.Askdistance("Can't use negative numbers")
|Some(a) when a =0 -> Ask.Askdistance("Can't travel a distance of 0")
|_ -> printfn "You are about to travel %A" distance.Value
ignore()
//this will keep asking you to input a distance until you put in a correct value (i.e. a positive integer value. Note it will reject a floating point input).
Ask.Askdistance()
While the other answers are correct, here is another way of doing it:
open System
let rec travel() =
printfn "How far do you want to travel?"
let d = Console.ReadLine()
match Int32.TryParse d with
| false, _ ->
printfn "Invalid distance format '%s'" d
travel()
| _, 0 ->
printfn "Can't travel a distance of 0"
travel()
| _, d when d < 0 ->
printfn "Can't use negative number %i" d
travel()
| _, d ->
printfn "You are about to travel %i" d
travel()
In my opinion, this has the following advantages:
does not use exceptions
does not use different concepts for the same thing (printfn vs Console.WriteLine)
does not introduce unnecessary constructs (types, helper functions for already existing functionality)
does not mix responsibilities (print error of this invocation in the next one)
I agree, that learning a new language you should explore the solution space. But then choose a concise, elegant way.
Some other aspects of my answer may be opinionated though. You might want to
use explicit trues instead of _.
choose a different name for the matched, parsed distance. I use shadowing because I think of the parsed value as just being a different representation.
reorder the cases, e.g. having the 'happy path' first resembles a try...catch:
open System
let rec travel() =
printfn "How far do you want to travel?"
let d = Console.ReadLine()
match Int32.TryParse d with
| true, d when d > 0 ->
printfn "You are about to travel %i" d
| true, 0 ->
printfn "Can't travel a distance of 0"
travel()
| true, _ ->
printfn "Can't use negative number %i" d
travel()
| _ ->
printfn "Invalid distance format '%s'" d
travel()
travel()
Another approach would be to separate reading from the console and traveling:
using a reading function which always returns an int:
open System
let rec readInt() =
let d = Console.ReadLine()
match Int32.TryParse d with
| true, d ->
d
| _ ->
printfn "Invalid distance format '%s'" d
readInt()
let rec travel() =
printfn "How far do you want to travel?"
let d = readInt()
if d > 0 then
printfn "You are about to travel %i" d
elif d = 0 then
printfn "Can't travel a distance of 0"
travel()
else
printfn "Can't use negative number %i" d
travel()
travel()
using a reading function that might fail:
open System
let rec readInt() =
let d = Console.ReadLine()
match Int32.TryParse d with
| true, d -> Some d
| _ -> None
let rec travel() =
printfn "How far do you want to travel?"
match readInt() with
| Some d when d > 0 ->
printfn "You are about to travel %i" d
| Some d when d = 0 ->
printfn "Can't travel a distance of 0"
travel()
| Some d ->
printfn "Can't use negative number %i" d
travel()
| None ->
printfn "Invalid distance format '%s'" d
travel()
travel()
I have a sequence of strings like this (lines in a file)
[20150101] error a
details 1
details 2
[20150101] error b
details
[20150101] error c
I am trying to map this to a sequence of strings like this (log entries)
[20150101] error a details 1 details 2
[20150101] error b details
[20150101] error c
I can do this in an imperative way (by translating the code I would write in C#) - this works but it reads like pseudo-code because I have omitted the referenced functions:
let getLogEntries logFilePath =
seq {
let logEntryLines = new ResizeArray<string>()
for lineOfText in getLinesOfText logFilePath do
if isStartOfNewLogEntry lineOfText && logEntryLines.Any() then
yield joinLines logEntryLines
logEntryLines.Clear()
logEntryLines.Add(lineOfText)
if logEntryLines.Any() then
yield joinLines logEntryLines
}
Is there a more functional way of doing this?
I can't use Seq.map since it's not a one to one mapping, and Seq.fold doesn't seem right because I suspect it will process the entire input sequence before returning the results (not great if I have very large log files). I assume my code above isn't the ideal way to do this in F# because it's using ResizeArray<string>.
In general, when there is no built-in function that you can use, the functional way to solve things is to use recursion. Here, you can recursively walk over the input, remember the items of the last chunk (since the last [xyz] Info line) and produce new results when you reach a new starting block. In F#, you can write this nicely with sequence expressions:
let rec joinDetails (lines:string list) lastChunk = seq {
match lines with
| [] ->
// We are at the end - if there are any records left, produce a new item!
if lastChunk <> [] then yield String.concat " " (List.rev lastChunk)
| line::lines when line.StartsWith("[") ->
// New block starting. Produce a new item and then start a new chunk
if lastChunk <> [] then yield String.concat " " (List.rev lastChunk)
yield! joinDetails lines [line]
| line::lines ->
// Ordinary line - just add it to the last chunk that we're collection
yield! joinDetails lines (line::lastChunk) }
Here is an example showing the code in action:
let lines =
[ "[20150101] error a"
"details 1"
"details 2"
"[20150101] error b"
"details"
"[20150101] error c" ]
joinDetails lines []
There is not much in-built in Seq that is going to help you, so you have to roll your own solution. Ultimately, parsing a file like this involves iterating and maintaining state, but what F# does is encapsulate that iteration and state by means of computation expressions (hence your use of the seq computation expression).
What you've done isn't bad but you could extract your code into a generic function that computes the chunks (i.e. sequences of strings) in an input sequence without knowledge of the format. The rest, i.e. parsing an actual log file, can be made purely functional.
I have written this function in the past to help with this.
let chunkBy chunkIdentifier source =
seq {
let chunk = ref []
for sourceItem in source do
let isNewChunk = chunkIdentifier sourceItem
if isNewChunk && !chunk <> [] then
yield !chunk
chunk := [ sourceItem ]
else chunk := !chunk # [ sourceItem ]
yield !chunk
}
It takes a chunkIdentifier function which returns true if the input is the start of a new chunk.
Parsing a log file is simply a case of extracting the lines, computing the chunks and joining each chunk:
logEntryLines |> chunkBy (fun line -> line.[0] = '[')
|> Seq.map (fun s -> String.Join (" ", s))
By encapsulating the iteration and mutation as much as possible, while creating a reusable function, it's more in the spirit of functional programming.
Alternatively, another two variants:
let lst = ["[20150101] error a";
"details 1";
"details 2";
"[20150101] error b";
"details";
"[20150101] error c";]
let fun1 (xs:string list) =
let sb = new System.Text.StringBuilder(xs.Head)
xs.Tail
|> Seq.iter(fun x -> match x.[0] with
| '[' -> sb.Append("\n" + x)
| _ -> sb.Append(" " + x)
|> ignore)
sb.ToString()
lst |> fun1 |> printfn "%s"
printfn "";
let fun2 (xs:string list) =
List.fold(fun acc (x:string) -> acc +
match x.[0] with| '[' -> "\n" | _ -> " "
+ x) xs.Head xs.Tail
lst |> fun2 |> printfn "%s"
Print:
[20150101] error a details 1 details 2
[20150101] error b details
[20150101] error c
[20150101] error a details 1 details 2
[20150101] error b details
[20150101] error c
Link:
https://dotnetfiddle.net/3KcIwv
Myello! So I am looking for a concise, efficient an idiomatic way in F# to parse a file or a string. I have a strong preference to treat the input as a sequence of char (char seq). The idea is that every function is responsible to parse a piece of the input, return the converted text tupled with the unused input and be called by a higher level function that chains the unused input to the following functions and use the results to build a compound type. Every parsing function should therefore have a signature similar to this one: char seq -> char seq * 'a . If, for example, the function's responsibility is simply to extract the first word, then, one approach would be the following:
let parseFirstWord (text: char seq) =
let rec forTailRecursion t acc =
let c = Seq.head t
if c = '\n' then
(t, acc)
else
forTailRecursion (Seq.skip 1 t) (c::acc)
let rest, reversedWord = forTailRecursion text []
(rest, List.reverse reversedWord)
Now, of course the main problem with this approach is that it extracts the word in reverse order and so you have to reverse it. Its main advantages however are that is uses strictly functional features and proper tail recursion. One could avoid the reversing of the extracted value while losing tail recursion:
let rec parseFirstWord (text: char seq) =
let c = Seq.head t
if c = '\n' then
(t, [])
else
let rest, tail = parseFirstWord (Seq.skip 1 t)
(rest, (c::tail))
Or use a fast mutable data structure underneath instead of using purely functional features, such as:
let parseFirstWord (text: char seq) =
let rec forTailRecursion t queue =
let c = Seq.head t
if c = '\n' then
(t, queue)
else
forTailRecursion (Seq.skip 1 t) (queue.Enqueu(c))
forTailRecursion text (new Queue<char>())
I have no idea how to use OO concepts in F# mind you so corrections to the above code are welcome.
Being new to this language, I would like to be guided in terms of the usual compromises that an F# developer makes. Among the suggested approaches and your own, which should I consider more idiomatic and why? Also, in that particular case, how would you encapsulate the return value: char seq * char seq, char seq * char list or evenchar seq * Queue<char>? Or would you even consider char seq * String following a proper conversion?
I would definitely have a look at FSLex. FSYacc, FParsec. However if you just want to tokenize a seq<char> you can use a sequence expression to generate tokens in the right order. Reusing your idea of a recursive inner function, and combinining with a sequence expression, we can stay tail recursive like shown below, and avoid non-idiomatic tools like mutable data structures.
I changed the separator char for easy debugging and the signature of the function. This version produces a seq<string> (your tokens) as result, which is probably easier to consume than a tuple with the current token and the rest of the text. If you just want the first token, you can just take the head. Note that the sequence is generated 'on demand', i.e. the input is parsed only as tokens are consumed through the sequence. Should you need the remainder of the input text next to each token, you can yield a pair in loop instead, but I'm guessing the downstream consumer most likely wouldn't (furthermore, if the input text is itself a lazy sequence, possibly linked to a stream, we don't want to expose it as it should be iterated through only in one place).
let parse (text : char seq) =
let rec loop t acc =
seq {
if Seq.isEmpty t then yield acc
else
let c, rest = Seq.head t, Seq.skip 1 t
if c = ' ' then
yield acc
yield! loop rest ""
else yield! loop rest (acc + string c)
}
loop text ""
parse "The FOX is mine"
val it : seq<string> = seq ["The"; "FOX"; "is"; "mine"]
This is not the only 'idiomatic' way of doing this in F#. Every time we need to process a sequence, we can look at the functions made available in the Seq module. The most general of these is fold which iterates through a sequence once, accumulating a state at each element by running a given function. In the example below accumulate is such a function, that progressively builds the resulting sequence of tokens. Since Seq.fold doesn't run the accumulator function on an empty sequence, we need the last two lines to extract the last token from the function's internal accumulator.
This second implementation keeps the nice characteriestics of the first, i.e. tail recursion (inside the fold implementation, if I'm not mistaken) and processing of the input sequence on demand. It also happens to be shorter, albeit a bit less readable probably.
let parse2 (text : char seq) =
let accumulate (res, acc) c =
if c = ' ' then (Seq.append res (Seq.singleton acc), "")
else (res, acc + string c)
let (acc, last) = text |> Seq.fold accumulate (Seq.empty, "")
Seq.append acc (Seq.singleton last)
parse2 "The FOX is mine"
val it : seq<string> = seq ["The"; "FOX"; "is"; "mine"]
One way of lexing/parsing in a way truly unique to F# is by using active patterns. The following simplified example shows the general idea. It can process a calculation string of arbitrary length without producing a stack overflow.
let rec (|CharOf|_|) set = function
| c :: rest when Set.contains c set -> Some(c, rest)
| ' ' :: CharOf set (c, rest) -> Some(c, rest)
| _ -> None
let rec (|CharsOf|) set = function
| CharOf set (c, CharsOf set (cs, rest)) -> c::cs, rest
| rest -> [], rest
let (|StringOf|_|) set = function
| CharsOf set (_::_ as cs, rest) -> Some(System.String(Array.ofList cs), rest)
| _ -> None
type Token =
| Int of int
| Add | Sub | Mul | Div | Mod
| Unknown
let lex: string -> _ =
let digits = set ['0'..'9']
let ops = Set.ofSeq "+-*/%"
let rec lex chars =
seq { match chars with
| StringOf digits (s, rest) -> yield Int(int s); yield! lex rest
| CharOf ops (c, rest) ->
let op =
match c with
| '+' -> Add | '-' -> Sub | '*' -> Mul | '/' -> Div | '%' -> Mod
| _ -> failwith "invalid operator char"
yield op; yield! lex rest
| [] -> ()
| _ -> yield Unknown }
List.ofSeq >> lex
lex "1234 + 514 / 500"
// seq [Int 1234; Add; Int 514; Div; Int 500]
I want to be able to write a computation expression in F# that will be able to retry an operation if it throws an exception. Right now my code looks like:
let x = retry (fun() -> GetResourceX())
let y = retry (fun() -> GetResourceY())
let z = retry (fun() -> DoThis(x, y))
etc. (this is obviously an astract representation of the actual code)
I need to be able to retry each of the functions a set number of times, which I have defined elswhere.
I was thinking a computation expression could help me here, but I don't see how it could help me remove explicitly wrapping each right hand side to a Retryable<'T>
I could see the computation expression looking something like:
let! x = Retryable( fun() -> GetResourceX())
etc.
I understand that Monads, in a crude fashion, are wrapper types, but I was hoping a way around this. I know I can overload an operator and have a very succinct syntax for converting an operation into a Retryable<'T>, but to me that's just making the repetition/wrapping more succinct; it's still there. I could wrap each function to be a Retryable<'T>, but once again, I don't see the value over doing what's done at the top of the post (calling retry on each operation. At least it's very explicit).
Maybe computation expressions are the wrong abstraction here, I'm not sure. Any ideas on what could be done here?
Computation expressions have a few extensions (in addition to the standard monadic features), that give you a nice way to do this.
As you said, the monads are essentially wrappers (creating e.g. Retryable<'T>) that have some additional behavior. However, F# computation expression can also define Run member which automatically unwraps the value, so the result of retry { return 1 } can have just a type int.
Here is an example (the builder is below):
let rnd = new System.Random()
// The right-hand side evaluates to 'int' and automatically
// retries the specified number of times
let n = retry {
let n = rnd.Next(10)
printfn "got %d" n
if n < 5 then failwith "!" // Throw exception in some cases
else return n }
// Your original examples would look like this:
let x = retry { return GetResourceX() }
let y = retry { return GetResourceY() }
let z = retry { return DoThis(x, y) }
Here is the definition of the retry builder. It is not really a monad, because it doesn't define let! (when you use computation created using retry in another retry block, it will just retry the inner one X-times and the outer one Y-times as needed).
type RetryBuilder(max) =
member x.Return(a) = a // Enable 'return'
member x.Delay(f) = f // Gets wrapped body and returns it (as it is)
// so that the body is passed to 'Run'
member x.Zero() = failwith "Zero" // Support if .. then
member x.Run(f) = // Gets function created by 'Delay'
let rec loop(n) =
if n = 0 then failwith "Failed" // Number of retries exceeded
else try f() with _ -> loop(n-1)
loop max
let retry = RetryBuilder(4)
A simple function could work.
let rec retry times fn =
if times > 1 then
try
fn()
with
| _ -> retry (times - 1) fn
else
fn()
Test code.
let rnd = System.Random()
let GetResourceX() =
if rnd.Next 40 > 1 then
"x greater than 1"
else
failwith "x never greater than 1"
let GetResourceY() =
if rnd.Next 40 > 1 then
"y greater than 1"
else
failwith "y never greater than 1"
let DoThis(x, y) =
if rnd.Next 40 > 1 then
x + y
else
failwith "DoThis fails"
let x = retry 3 (fun() -> GetResourceX())
let y = retry 4 (fun() -> GetResourceY())
let z = retry 1 (fun() -> DoThis(x, y))
Here is a first try at doing this in a single computation expression. But beware that it's only a first try; I have not thoroughly tested it. Also, it's a little bit ugly when re-setting the number of tries within the computation expression. I think the syntax could be cleaned-up a good bit within this basic framework.
let rand = System.Random()
let tryIt tag =
printfn "Trying: %s" tag
match rand.Next(2)>rand.Next(2) with
| true -> failwith tag
| _ -> printfn "Success: %s" tag
type Tries = Tries of int
type Retry (tries) =
let rec tryLoop n f =
match n<=0 with
| true ->
printfn "Epic fail."
false
| _ ->
try f()
with | _ -> tryLoop (n-1) f
member this.Bind (_:unit,f) = tryLoop tries f
member this.Bind (Tries(t):Tries,f) = tryLoop t f
member this.Return (_) = true
let result = Retry(1) {
do! Tries 8
do! tryIt "A"
do! Tries 5
do! tryIt "B"
do! tryIt "C" // Implied: do! Tries 1
do! Tries 2
do! tryIt "D"
do! Tries 2
do! tryIt "E"
}
printfn "Your breakpoint here."
p.s. But I like both Tomas's and gradbot's versions better. I just wanted to see what this type of solution might look like.