Initialize function with standard input - f#

I am facing a problem that leave me disoriented, since it should be a pretty basic procedure. I am learning how to build simple console applications with F#, but I cannot figure out how to pass an integer as standard input to the program. Please consider:
open System
let square x = x * x
[<EntryPoint>]
let main (argv :string[]) =
printfn "The function will take an input and square it"
printfn "%d squared is %d" 12 (square 12)
Console.ReadLine() |> ignore
0
How can I pass the value to printfn and square the way I can do in C with:
int main(){
int i;
scanf("%d", &i);
printf("\nThe value of variable i is %d.\n", i);
return 0;
}
I tried to adapt let x = Console.ReadLine() to get integers, but no appreciable results. The documentation I consulted, mainly consider string inputs. I am afraid I am missing something important for properly comprehend the basic of F#. Any suggestion, in this sense, would be highly appreciated.

ReadLine () will return a string. As mentioned by #JohnPalmer, it needs to be parsed to an int. The following program should give you the basic idea:
let rec input () =
printf "Input: "
match Core.int.TryParse (stdin.ReadLine ()) with
| true, i -> i
| _ ->
printfn "Invalid input, try again"
input ()
let square x = x * x
[<EntryPoint>]
let main _ =
printfn "The function will take an input and square it"
let i = input ()
printfn "%d squared is %d" i (square i)
0

Related

F# - Ask for 3 numbers and then find the minimum?

I am new to programming so this should be an easy one.
I want to write a code that asks for 3 numbers and then finds the minimum. Something like that:
let main(): Unit =
putline ("Please enter 3 numbers:")
putline ("First number: ")
let a = getline ()
putline ("Second number: ")
let b = getline ()
putline("Third number: ")
let c = getline ()
if (a<b && a<c) then putline ("Minimum:" + a)
elif (b<c && b<a) then putline ("Minimum:" + b)
else putline ("Minimum:" + c)
I am sorry if this is terrible but I am still new to this. Also I am not allowed to use the dictionary. Any advice?
You can use the F# function min, which gives you the minimum of two values.
min 1 2 // 1
To get the minimum of three values you can use it twice:
min (min a b) c
A cleaner way to write this with F# piping is:
a |> min b |> min c
Alternatively, put the items in a list and use List.min:
[ a; b; c ] |> List.min
If, for some reason, you decide to expand beyond three numbers, you could consider using Seq.reduce
let xs = [0;-5;3;4]
xs
|> Seq.reduce min
|> printfn "%d"
// prints -5 to stdout
You can use min as the reducer because it accepts 2 arguments, which is exactly what Seq.reduce expects
Firstly your putline function. I'm assuming that this is supposed to take a value and print it to the console with a newline, so the built in F# command to do this is printfn and you would use it something like this:
let a = 1
printfn "Minimum: %d" a
The %d gets replaced with the value of a as, in this case, a is an integer. You would use %f for a float, %s for a string... the details will all be in the documentation.
So we could write your putline function like this:
let putline s = printfn "%s" s
This function has the following signature, val putline : s:string -> unit, it accepts a string and return nothing. This brings us onto your next problem, you try and say putline ("Minimum:" + a). This won't work as adding a number and a string isn't allowed, so what you could do is convert a to a string and you have several ways to do this:
putline (sprintf "Minimum: %d" a)
putline ("Minimum:" + a.ToString())
sprintf is related to printfn but gives you back a string rather than printing to the console, a.ToString() converts a to a string allowing it to be concatenated with the preceding string. However just using printfn instead of putline will work here!
You also have a logic problem, you don't consider the cases where a == b == c, what's the minimum of 1,1,3? Your code would say 3. Try using <= rather than <
For reading data from the console, there is already an answer on the site for this Read from Console in F# that you can look at.

Try Finally statement in F#

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()

How do i write the classic high/low game in F#?

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.

Block following this 'let' is unfinished. Expect an expression

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.

How do you create an F# workflow that enables something like single-stepping?

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)

Resources