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.
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 was reading up on functional languages and i wondered how i would implement 'tries' in a pure functional language. So i decided to try to do it in F#
But i couldnt get half of the basics. I couldnt figure out how to use a random number, how to use return/continue (at first i thought i was doing a multi statement if wrong but it seems like i was doing it right) and i couldnt figure out how to print a number in F# so i did it in the C# way.
Harder problems is the out param in tryparse and i still unsure how i'll do implement tries without using a mutable variable. Maybe some of you guys can tell me how i might correctly implement this
C# code i had to do last week
using System;
namespace CS_Test
{
class Program
{
static void Main(string[] args)
{
var tries = 0;
var answer = new Random().Next(1, 100);
Console.WriteLine("Guess the number between 1 and 100");
while (true)
{
var v = Console.ReadLine();
if (v == "q")
{
Console.WriteLine("you have quit");
return;
}
int n;
var b = Int32.TryParse(v, out n);
if (b == false)
{
Console.WriteLine("This is not a number");
continue;
}
tries++;
if (n == answer)
{
Console.WriteLine("Correct! You win!");
break;
}
else if (n < answer)
Console.WriteLine("Guess higher");
else if (n > answer)
Console.WriteLine("Guess lower");
}
Console.WriteLine("You guess {0} times", tries);
Console.WriteLine("Press enter to exist");
Console.ReadLine();
}
}
}
The very broken and wrong F# code
open System;
let main() =
let tries = 0;
let answer = (new Random()).Next 1, 100
printfn "Guess the number between 1 and 100"
let dummyWhileTrue() =
let v = Console.ReadLine()
if v = "q" then
printfn ("you have quit")
//return
printfn "blah"
//let b = Int32.TryParse(v, out n)
let b = true;
let n = 3
if b = false then
printfn ("This is not a number")
//continue;
//tries++
(*
if n = answer then
printfn ("Correct! You win!")
//break;
elif n < answer then
printfn ("Guess higher")
elif n>answer then
printfn ("Guess lower")
*)
dummyWhileTrue()
(Console.WriteLine("You guess {0} times", tries))
printfn ("Press enter to exist")
Console.ReadLine()
main()
Welcome to F#!
Here's a working program; explanation follows below.
open System
let main() =
let answer = (new Random()).Next(1, 100)
printfn "Guess the number between 1 and 100"
let rec dummyWhileTrue(tries) =
let v = Console.ReadLine()
if v = "q" then
printfn "you have quit"
0
else
printfn "blah"
let mutable n = 0
let b = Int32.TryParse(v, &n)
if b = false then
printfn "This is not a number"
dummyWhileTrue(tries)
elif n = answer then
printfn "Correct! You win!"
tries
elif n < answer then
printfn "Guess higher"
dummyWhileTrue(tries+1)
else // n>answer
printfn "Guess lower"
dummyWhileTrue(tries+1)
let tries = dummyWhileTrue(1)
printfn "You guess %d times" tries
printfn "Press enter to exit"
Console.ReadLine() |> ignore
main()
A number of things...
If you're calling methods with multiple arguments (like Random.Next), use parens around the args (.Next(1,100)).
You seemed to be working on a recursive function (dummyWhileTrue) rather than a while loop; a while loop would work too, but I kept it your way. Note that there is no break or continue in F#, so you have to be a little more structured with the if stuff inside there.
I changed your Console.WriteLine to a printfn to show off how to call it with an argument.
I showed the way to call TryParse that is most like C#. Declare your variable first (make it mutable, since TryParse will be writing to that location), and then use &n as the argument (in this context, &n is like ref n or out n in C#). Alternatively, in F# you can do like so:
let b, n = Int32.TryParse(v)
where F# lets you omit trailing-out-parameters and instead returns their value at the end of a tuple; this is just a syntactic convenience.
Console.ReadLine returns a string, which you don't care about at the end of the program, so pipe it to the ignore function to discard the value (and get rid of the warning about the unused string value).
Here's my take, just for the fun:
open System
let main() =
let answer = (new Random()).Next(1, 100)
printfn "Guess the number between 1 and 100"
let rec TryLoop(tries) =
let doneWith(t) = t
let notDoneWith(s, t) = printfn s; TryLoop(t)
match Console.ReadLine() with
| "q" -> doneWith 0
| s ->
match Int32.TryParse(s) with
| true, v when v = answer -> doneWith(tries)
| true, v when v < answer -> notDoneWith("Guess higher", tries + 1)
| true, v when v > answer -> notDoneWith("Guess lower", tries + 1)
| _ -> notDoneWith("This is not a number", tries)
match TryLoop(1) with
| 0 -> printfn "You quit, loser!"
| tries -> printfn "Correct! You win!\nYou guessed %d times" tries
printfn "Hit enter to exit"
Console.ReadLine() |> ignore
main()
Things to note:
Pattern matching is prettier, more concise, and - I believe - more idiomatic than nested ifs
Used the tuple-return-style TryParse suggested by Brian
Renamed dummyWhileTrue to TryLoop, seemed more descriptive
Created two inner functions doneWith and notDoneWith, (for purely aesthetic reasons)
I lifted the main pattern match from Evaluate in #Huusom's solution but opted for a recursive loop and accumulator instead of #Hussom's (very cool) discriminate union and application of Seq.unfold for a very compact solution.
open System
let guessLoop answer =
let rec loop tries =
let guess = Console.ReadLine()
match Int32.TryParse(guess) with
| true, v when v < answer -> printfn "Guess higher." ; loop (tries+1)
| true, v when v > answer -> printfn "Guess lower." ; loop (tries+1)
| true, v -> printfn "You won." ; tries+1
| false, _ when guess = "q" -> printfn "You quit." ; tries
| false, _ -> printfn "Not a number." ; loop tries
loop 0
let main() =
printfn "Guess a number between 1 and 100."
printfn "You guessed %i times" (guessLoop ((Random()).Next(1, 100)))
Also for the fun of if:
open System
type Result =
| Match
| Higher
| Lower
| Quit
| NaN
let Evaluate answer guess =
match Int32.TryParse(guess) with
| true, v when v < answer -> Higher
| true, v when v > answer -> Lower
| true, v -> Match
| false, _ when guess = "q" -> Quit
| false, _ -> NaN
let Ask answer =
match Evaluate answer (Console.ReadLine()) with
| Match ->
printfn "You won."
None
| Higher ->
printfn "Guess higher."
Some (Higher, answer)
| Lower ->
printfn "Guess lower."
Some (Lower, answer)
| Quit ->
printfn "You quit."
None
| NaN ->
printfn "This is not a number."
Some (NaN, answer)
let main () =
printfn "Guess a number between 1 and 100."
let guesses = Seq.unfold Ask ((Random()).Next(1, 100))
printfn "You guessed %i times" (Seq.length guesses)
let _ = main()
I use an enumeration for state and Seq.unfold over input to find the result.
F# allows to use checked arithmetics by opening Checked module, which redefines standard operators to be checked operators, for example:
open Checked
let x = 1 + System.Int32.MaxValue // overflow
will result arithmetic overflow exception.
But what if I want to use checked arithmetics in some small scope, like C# allows with keyword checked:
int x = 1 + int.MaxValue; // ok
int y = checked { 1 + int.MaxValue }; // overflow
How can I control the scope of operators redefinition by opening Checked module or make it smaller as possible?
You can always define a separate operator, or use shadowing, or use parens to create an inner scope for temporary shadowing:
let f() =
// define a separate operator
let (+.) x y = Checked.(+) x y
try
let x = 1 +. System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
// shadow (+)
let (+) x y = Checked.(+) x y
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
// shadow it back again
let (+) x y = Operators.(+) x y
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
// use parens to create a scope
(
// shadow inside
let (+) x y = Checked.(+) x y
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
)
// shadowing scope expires
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
f()
// output:
// exception
// ran ok
// exception
// ran ok
// exception
// ran ok
Finally, see also the --checked+ compiler option:
http://msdn.microsoft.com/en-us/library/dd233171(VS.100).aspx
Here is a complicated (but maybe interesting) alternative. If you're writing something serious then you should probably use one of the Brians suggestions, but just out of curiosity, I was wondering if it was possible to write F# computation expression to do this. You can declare a type that represents int which should be used only with checked operations:
type CheckedInt = Ch of int with
static member (+) (Ch a, Ch b) = Checked.(+) a b
static member (*) (Ch a, Ch b) = Checked.(*) a b
static member (+) (Ch a, b) = Checked.(+) a b
static member (*) (Ch a, b) = Checked.(*) a b
Then you can define a computation expression builder (this isn't really a monad at all, because the types of operations are completely non-standard):
type CheckedBuilder() =
member x.Bind(v, f) = f (Ch v)
member x.Return(Ch v) = v
let checked = new CheckedBuilder()
When you call 'bind' it will automatically wrap the given integer value into an integer that should be used with checked operations, so the rest of the code will use checked + and * operators declared as members. You end up with something like this:
checked { let! a = 10000
let! b = a * 10000
let! c = b * 21
let! d = c + 47483648 // !
return d }
This throws an exception because it overflows on the marked line. If you change the number, it will return an int value (because the Return member unwraps the numeric value from the Checked type). This is a bit crazy technique :-) but I thought it may be interesting!
(Note checked is a keyword reserved for future use, so you may prefer choosing another name)
I'd like to create a builder that builds expressions that returns something like a continuation after each step.
Something like this:
module TwoSteps =
let x = stepwise {
let! y = "foo"
printfn "got: %A" y
let! z = y + "bar"
printfn "got: %A" z
return z
}
printfn "two steps"
let a = x()
printfn "something inbetween"
let b = a()
Where the 'let a' line returns something containing the rest of the expressions to be evaluated later on.
Doing this with a separate type for each number of steps is straightforward but of course not particularly useful:
type Stepwise() =
let bnd (v: 'a) rest = fun () -> rest v
let rtn v = fun () -> Some v
member x.Bind(v, rest) =
bnd v rest
member x.Return v = rtn v
let stepwise = Stepwise()
module TwoSteps =
let x = stepwise {
let! y = "foo"
printfn "got: %A" y
let! z = y + "bar"
printfn "got: %A" z
return z
}
printfn "two steps"
let a = x()
printfn "something inbetween"
let b = a()
module ThreeSteps =
let x = stepwise {
let! y = "foo"
printfn "got: %A" y
let! z = y + "bar"
printfn "got: %A" z
let! z' = z + "third"
printfn "got: %A" z'
return z
}
printfn "three steps"
let a = x()
printfn "something inbetween"
let b = a()
printfn "something inbetween"
let c = b()
And the results are what I'm looking for:
two steps
got: "foo"
something inbetween
got: "foobar"
three steps
got: "foo"
something inbetween
got: "foobar"
something inbetween
got: "foobarthird"
But I can't figure out what the general case of this would be.
What I'd like is to be able to feed events into this workflow, so you could write something like:
let someHandler = Stepwise<someMergedEventStream>() {
let! touchLocation = swallowEverythingUntilYouGetATouch()
startSomeSound()
let! nextTouchLocation = swallowEverythingUntilYouGetATouch()
stopSomeSound()
}
And have events trigger a move to the next step in the workflow. (In particular, I want to play with this sort of thing in MonoTouch - F# on the iPhone. Passing around objc selectors drives me insane.)
the problem with your implementation is that it returns "unit -> 'a" for each call to Bind, so you'll get a different type of result for different number of steps (in general, this is a suspicious definition of monad/computation expression).
A correct solution should be to use some other type, which can represent a computation with arbitrary number of steps. You'll also need to distinguish between two types of steps - some steps just evaluate next step of the computation and some steps return a result (via the return keyword). I'll use a type seq<option<'a>>. This is a lazy sequence, so reading the next element will evaluate the next step of the computation. The sequence will contain None values with the exception of the last value, which will be Some(value), representing the result returned using return.
Another suspicious thing in your implementation is a non-standard type of Bind member. The fact that your bind takes a value as the first parameter means that your code looks a bit simpler (you can write let! a = 1) however, you cannot compose stepwise computation. You may want to be able to write:
let foo() = stepwise {
return 1; }
let bar() = stepwise {
let! a = foo()
return a + 10 }
The type I described above will allow you to write this as well. Once you have the type, you just need to follow the type signature of Bind and Return in the implementation and you'll get this:
type Stepwise() =
member x.Bind(v:seq<option<_>>, rest:(_ -> seq<option<_>>)) = seq {
let en = v.GetEnumerator()
let nextVal() =
if en.MoveNext() then en.Current
else failwith "Unexpected end!"
let last = ref (nextVal())
while Option.isNone !last do
// yield None for each step of the source 'stepwise' computation
yield None
last := next()
// yield one more None for this step
yield None
// run the rest of the computation
yield! rest (Option.get !last) }
member x.Return v = seq {
// single-step computation that yields the result
yield Some(v) }
let stepwise = Stepwise()
// simple function for creating single-step computations
let one v = stepwise.Return(v)
Now, let's look at using the type:
let oneStep = stepwise {
// NOTE: we need to explicitly create single-step
// computations when we call the let! binder
let! y = one( "foo" )
printfn "got: %A" y
return y + "bar" }
let threeSteps = stepwise {
let! x = oneStep // compose computations :-)
printfn "got: %A" x
let! y = one( x + "third" )
printfn "got: %A" y
return "returning " + y }
If you want to run the computation step-by-step, you can simply iterate over the returned sequence, for example using the F# for keyword. The following also prints the index of the step:
for step, idx in Seq.zip threeSteps [ 1 .. 10] do
printf "STEP %d: " idx
match step with
| None _ -> ()
| Some(v) -> printfn "Final result: %s" v
Hope this helps!
PS: I found this problem very interesting! Would you mind if I addapted my answer into a blog post for my blog (http://tomasp.net/blog)? Thanks!
Monads and computation builders confuse the hell out of me, but I've adapted something I've made in an earlier SO post. Maybe some bits and pieces can be of use.
The code below contains an action queue, and a form where the Click event listens to the next action available in the action queue. The code below is an example with 4 actions in succession. Execute it in FSI and start clicking the form.
open System.Collections.Generic
open System.Windows.Forms
type ActionQueue(actions: (System.EventArgs -> unit) list) =
let actions = new Queue<System.EventArgs -> unit>(actions) //'a contains event properties
with
member hq.Add(action: System.EventArgs -> unit) =
actions.Enqueue(action)
member hq.NextAction =
if actions.Count=0
then fun _ -> ()
else actions.Dequeue()
//test code
let frm = new System.Windows.Forms.Form()
let myActions = [
fun (e:System.EventArgs) -> printfn "You clicked with %A" (e :?> MouseEventArgs).Button
fun _ -> printfn "Stop clicking me!!"
fun _ -> printfn "I mean it!"
fun _ -> printfn "I'll stop talking to you now."
]
let aq = new ActionQueue(myActions)
frm.Click.Add(fun e -> aq.NextAction e)
//frm.Click now executes the 4 actions in myActions in order and then does nothing on further clicks
frm.Show()
You can click the form 4 times and then nothing happens with further clicks.
Now execute the following code, and the form will respond two more times:
let moreActions = [
fun _ -> printfn "Ok, I'll talk to you again. Just don't click anymore, ever!"
fun _ -> printfn "That's it. I'm done with you."
]
moreActions |> List.iter (aq.Add)
I'm using F# v 1.9.6.2, and I've defined a very simple computation expression:
type MaybeBuilder() =
member this.Let(x, f) =
printfn "this.Let: %A" x
this.Bind(Some x, f)
member this.Bind(x, f) =
printfn "this.Bind: %A" x
match x with
| Some(x) when x >= 0 && x <= 100 -> f(x)
| _ -> None
member this.Delay(f) = f()
member this.Return(x) = Some x
let maybe = MaybeBuilder()
I've sprinkled some print statements in the code to tell me which methods are being called in a computation expression. When I execute the following statement:
maybe {
let x = 12
let! y = Some 11
let! z = Some 30
return x + y + z
}
I expect the console to print out the following:
this.Let 12
this.Bind Some 12
this.Bind Some 11
this.Bind Some 30
But my actual results are as follows:
this.Bind: Some 11
this.Bind: Some 30
In other words, F# doesn't appear to be executing the Let member. When I re-write Let to throw an exception, the code run without an exception. Additionally, when I comment out the Let member entirely, I do not get an error message stating The field, constructor or member 'Let' is not defined, and the code executes as expected.
(I've tried investigating the code with Reflector, but as is usually the case, decompiled F# is mangled beyond readability.)
It looks like the spec for computation expressions has changed. Are let bindings no longer treated as syntax sugar, and is the Let members no longer required in computation workflows?
You had the answer yourself. From the F# spec that describes how computation expressions are translated:
{| let binds in cexpr |}C = let binds in {| cexpr |}C)
So no, you don't need to define let explicitly anymore, it's translated by the compiler.
Update: this change is mentioned in the detailed release notes of the September CTP.
Correct -- you can no longer provide a binding for let :(.
See also
http://cs.hubfs.net/forums/thread/6950.aspx