I have the following piece of code in hand:
match intersection with
| None ->
printfn "Please provide an empty intersection for ring placement"
gameState
| Some x ->
match x.Status with
| Empty ->
let piece = { Color = gameState.Active.Color; Type = Ring }
putPieceOnIntersection gameState.Board pos piece
printfn "%s ring placed at %A" (colorStr gameState.Active.Color) pos
// Decide if we ended this phase
let updatedPhase = if ringsPlaced = 10 then Main else Start(ringsPlaced + 1)
let newActivePlayer = gameState.Players |> Array.find (fun p -> p.Color = invertColor gameState.Active.Color)
let updatedGameState = { gameState with Active = newActivePlayer; CurrentPhase = updatedPhase }
updatedGameState
| _ ->
printfn "Please provide an empty intersection for ring placement"
gameState
As you may see, if the variable intersection is either None or its Status is different than empty, I should do exactly the same branch of printing some text and return. However I don't know how to do that kind of condition expression in F# so that I can share the same branch. In imperative programming I would do this easily, but in F# how can I do it?
Thank you
If Status is a record field then you can do:
match intersection with
| Some { Status = Empty } ->
// Code for empty...
| _ ->
printfn "Please provide an empty intersection for ring placement"
gameState
Otherwise, you can use a guard:
match intersection with
| Some x when x.Status = Empty ->
// Code for empty...
| _ ->
printfn "Please provide an empty intersection for ring placement"
gameState
Related
When should I use a function within a function versus a separate private function?
I observed that a function that I wrote was fairly long:
let optionsFor piece (positions:Space list) =
let yDirection = match piece with
| Black _ -> -1
| Red _ -> 1
let sourceX , sourceY =
match piece with
| Black (checker , pos) -> pos
| Red (checker , pos) -> pos
let optionsForPiece =
(fun pos -> pos = ((sourceX - 1) , (sourceY + yDirection)) ||
pos = ((sourceX + 1) , (sourceY + yDirection)))
let availableSelection =
(fun space -> match space with
| Available pos -> Some pos
| Allocated _ -> None)
let availablePositions =
positions |> List.filter toAvailable
|> List.choose availableSelection
availablePositions |> List.filter optionsForPiece
Thus, I considered refactoring the function above into several small functions.
However, I am not sure if this is necessary in functional programming.
What is the current recommendation on inner functions versus extracting them out to private functions?
Appendix:
open NUnit.Framework
open FsUnit
(* Types *)
type Black = BlackKing | BlackSoldier
type Red = RedKing | RedSoldier
type Coordinate = int * int
type Piece =
| Black of Black * Coordinate
| Red of Red * Coordinate
type Space =
| Allocated of Piece
| Available of Coordinate
type Status =
| BlacksTurn | RedsTurn
| BlackWins | RedWins
(* Functions *)
let black coordinate = Allocated (Black (BlackSoldier , coordinate))
let red coordinate = Allocated (Red (RedSoldier , coordinate))
let startGame () =
[ red (0,0); red (2,0); red (4,0); red (6,0)
red (1,1); red (3,1); red (5,1); red (7,1)
red (0,2); red (2,2); red (4,2); red (6,2)
Available (1,3); Available (3,3); Available (5,3); Available (7,3)
Available (0,4); Available (2,4); Available (4,4); Available (6,4)
black (1,5); black (3,5); black (5,5); black (7,5)
black (0,6); black (2,6); black (4,6); black (6,6)
black (1,7); black (3,7); black (5,7); black (7,7) ] , BlacksTurn
let private toAvailable =
(fun space -> match space with
| Available pos -> true
| _ -> false)
let available (positions:Space list) = positions |> List.filter toAvailable
let optionsFor piece (positions:Space list) =
let yDirection = match piece with
| Black _ -> -1
| Red _ -> 1
let sourceX , sourceY =
match piece with
| Black (checker , pos) -> pos
| Red (checker , pos) -> pos
let optionsForPiece =
(fun pos -> pos = ((sourceX - 1) , (sourceY + yDirection)) ||
pos = ((sourceX + 1) , (sourceY + yDirection)))
let availableSelection =
(fun space -> match space with
| Available pos -> Some pos
| Allocated _ -> None)
let availablePositions =
positions |> List.filter toAvailable
|> List.choose availableSelection
availablePositions |> List.filter optionsForPiece
This is more opinion-based, but I'll offer my opinion.
My rule of thumb would be that if the "helper" function is tighly associated with the "main" function, I'd write it as a nested function. If they're not tightly associated, I'd write the helper function as a separate function -- and I might not even make it private, because you never know when it might come in handy for other code in a different module.
An example of a tightly associated inner function would be the kind of loop-with-accumulator function that you often end up writing in recursive functional programming. For example, here's some code I wrote for an F# programming exercise:
module BinarySearchTree
type Node<'T> =
{ left: Node<'T> option
value: 'T
right: Node<'T> option }
let singleton v = { left = None; value = v; right = None }
let rec insert v t =
if v <= t.value
then match t.left with
| None -> { t with left = singleton v |> Some }
| Some n -> { t with left = insert v n |> Some }
else match t.right with
| None -> { t with right = singleton v |> Some }
| Some n -> { t with right = insert v n |> Some }
let fromList l =
match l with
| [] -> failwith "Can't create a tree from an empty list"
| hd::tl ->
tl |> List.fold (fun t v -> insert v t) (singleton hd)
let toList t =
let rec loop acc = function
| None -> acc
| Some node ->
(loop [] node.left) # (node.value :: (loop [] node.right))
loop [] (Some t)
Take a look at that last toList function. It has an inner function that I called loop, which would make no sense as a standalone function. It is so tightly associated to the toList function that it just makes sense to keep it as an inner function, not accessible from outside toList.
However, when I wrote the fromList function, I did not define insert inside it as an inner function. The insert function is useful on its own, quite apart from the functionality of fromList. So I wrote insert as a separate function. Even though fromList is the only function in my code that actually uses insert, that might not necessarily be true in the future. I might write a fromArray function, where I don't want to reuse fromList for efficiency's sake. (I could write fromArray as let fromArray a = a |> List.ofArray |> fromList, but that creates an unnecessary list that I'm just going to throw away when I'm done; it makes more sense, efficiency-wise, to directly iterate over the array and call insert as appropriate.)
So there's an example of when it's wise to use nested inner functions vs. separate functions in the same module. Now let's look at your code.
yDirection - This is a variable, but could be turned into a function taking piece as a parameter. As a function, it looks like it could be useful in many different functions. My judgment: separate.
sourceX and sourceY - These are variables, not functions, but you could turn that match into a function called source that returns a tuple, and then call it in your optionsFor function to set the values of sourceX and sourceY. In my opinion, that source function makes most sense as a separate function.
optionsForPiece - This function looks tightly associated with the optionsFor function, such that you probably wouldn't want to call it from elsewhere. My judgment: nested.
availableSelection - This could be quite useful in several situations, not just optionsFor. My judgment: separate.
availablePositions - This is a variable, but could easily be turned into a function that takes positions as a parameter and returns which ones are available. Again, that could be useful in several situations. My judgment: separate.
So by splitting out all the functions that seem like they could be re-used, we've gotten your optionsFor function down to the following:
// Functions yDirection, source, availableSelection,
// and availablePositions are all defined "outside"
let optionsFor piece (positions:Space list) =
let yDir = yDirection piece
let sourceX , sourceY = source piece
let optionsForPiece pos =
pos = ((sourceX - 1) , (sourceY + yDir)) ||
pos = ((sourceX + 1) , (sourceY + yDir))
positions |> availablePositions |> List.filter optionsForPiece
That's a lot more readable when you revisit the code later, plus you get the benefit of having more reusable functions (like availableSelections) around for when you write the next bit of your code.
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 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.
Here is the full code so far:
module clean
#light
open System
open System.IO
let pause() = Console.ReadLine()
let drive = System.IO.Directory.GetDirectoryRoot(System.IO.Directory.GetCurrentDirectory())
printfn "You're using the %s drive.\n\n" drive
let game1 = "Assassin's Creed"
let game2 = "Crysis"
let game3 = "Mass Effect"
let local1 = "\%APPDATA\%\\Ubisoft\\Assassin's Creed\\Saved Games\\"
let local2 = "\%USERPROFILE\%\\Documents\\My Games\\Crysis\\SaveGames\\"
let local3 = "\%USERPROFILE\%\\Documents\\BioWare\\Mass Effect\\Save\\"
let roam1 = drive + "Saves\\Abraxas\\" + game1 + "\\"
let roam2 = drive + "Saves\\Abraxas\\" + game2 + "\\"
let roam3 = drive + "Saves\\Abraxas\\" + game3 + "\\"
let rec getGame() =
printfn "Which Game?\n\n 1.%s\n 2.%s\n 3.%s\n\n" game1 game2 game3
match Int32.TryParse(stdin.ReadLine()) with
| true,1 -> game1
| true,2 -> game2
| true,3 -> game3
| _ ->
printfn "You did not enter a valid choice."
let _ = pause()
Console.Clear()
getGame()
let mutable gameprint = getGame()
printf "You have chosen %s\n\n" gameprint
let roaming =
match gameprint with
| game1 -> roam1
| game2 -> roam2
| game3 -> roam3
| _ -> "test"
printf "Roaming set to %s\n\n" roaming
let local =
match gameprint with
| game1 -> local1
| game2 -> local2
| game3 -> local3
| _ -> "test"
printf "Local set to %s\n\n" local
printf "Check gameprint %s" gameprint
In the section that sets the roaming and local objects, it is telling me that it will never match with anything other than 'game1'.
I did the 'printf' to check before and after matching with the local and roaming objects... The gameprint shows correctly in both of the printf commands, but doesn't match to anything other than game1... I'm not sure where I made the mistake.
Two things.
In F#, bindings can be shadowed. In particular, within your match, when you use game1, game2, and game3 in patterns, you are actually declaring new bindings with these names. Therefore, the first pattern will always match, and will just assign whatever value you are trying to match against it to the new binding game1 before evaluating the right hand side.
One way to work around this is to declare your gameN bindings with the [<Literal>] attribute (but note that they must also start with capital letters to work as constants):
[<Literal>]
let Game1 = "Assassin's Creed"
Now you can use Game1 in a pattern match and it will work as you expect.
You may be aware of this, but you're not actually updating the gameprint binding anywhere anyway, so it's going to be set to the same value throughout your program and there is no point to its being mutable.
See F# matching with two values for an explanation.
When comparing against a few non-literal values, I'd just use an if-then-else
if gameprint = game1 then ...
elif gameprint = game2 then ...
...
Maybe something a little more like this would allow you to make it more extensible (if you populate the list of games at runtime) ... sorry the codes a little rushed I'm trying to get ready for work:
open System
type Game = {Title:string; local:string; roam:string}
let game1 = {
Title= "Assassin's Creed";
local = "\%APPDATA\%\\Ubisoft\\Assassin's Creed\\Saved Games\\";
roam = "Saves\\Abraxas\\\Assassin's Creed\\"
}
let game2 = {
Title= "Crysis";
local = "\%USERPROFILE\%\\Documents\\My Games\\Crysis\\SaveGames\\";
roam = "Saves\\Abraxas\\\Crysis\\"
}
let games = [game1; game2]
let printGamelListItem i g = printfn "%i: %s" i g.Title
let printChoice() =
printfn "Which Game?\n"
games |> List.fold (fun acc g ->
printGamelListItem acc g
acc+1) 1
|> ignore
let rec getGame() =
printChoice()
match Int32.TryParse(Console.ReadLine()) with
|true, x when x <= games.Length -> games.[x-1]
| _ ->
printfn "You did not enter a valid choice."
let _ = Console.ReadLine()
Console.Clear()
getGame()
let selection = getGame()
printfn "Roaming set to: %s" (selection.roam)
printfn "Local set to: %s" (selection.local)
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.