Reputation: 57
I'm just starting to dig into some programming and decided to go with F#. As practice, I was trying to convert a script I made in .bat into F#. I'm having trouble creating a looping function that does more than one thing. Here is the code from the old script for this loop.
:Select
cls
echo.
echo Which Game?
echo.
echo 1. Assassin's Creed
echo 2. Crysis
echo 3. Mass Effect
echo.
echo.
set/p "game=>"
if /I %game%==1 goto Creed
if /I %game%==2 goto Crysis
if /I %game%==3 goto Mass
echo.
echo Invalid selection!
echo.
echo.
pause
goto Select
The code I've tried to make for the same function in F# looks like this so far:
let rec gameprint gameselect =
printfn "Which Game?\n\n 1.%s\n 2.%s\n 3.%s\n\n\n" game1 game2 game3
let mutable gameselect = Int32.Parse(stdin.ReadLine())
if gameselect = "1" then game1
elif gameselect = "2" then game2
elif gameselect = "3" then game3
else printf "temp"
Console.Clear
I know I'm missing something that tells it to run again if it reaches the last "else"; and I'm getting these errors:
The expression should have type 'unit' but has type 'string'. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name.
Error 1 This expression was expected to have type int but here has type string 19 21
Error 2 This expression was expected to have type int but here has type string 20 23
Error 3 This expression was expected to have type int but here has type string 21 23
Error 4 This expression was expected to have type string but here has type unit 22 17
Warning 5 This expression should have type 'unit', but has type 'string'. Use 'ignore' to discard the result of the expression, or 'let' to bind the result to a name. 19 5
I'd prefer to use an approach like this (Very incomplete):
let rec getGame() =
match Int32.Parse(stdin.ReadLine()) with
| 1 -> "Assassin's Creed"
| 2 -> "Crysis"
| 3 -> "Mass Effect"
| _ -> printf "Temp"
But I'm getting:
Error 1 This expression was expected to have type string but here has type unit 36 19
And I'm not sure how I would loop it and make it 'printf' and 'Console.Clear'
If there is a more functional approach that I don't know about, I would certainly love to learn :-)
Thanks in advance!
Upvotes: 3
Views: 625
Reputation: 57
Thanks for the VERY prompt response! I've been working on this hurdle since yesterday xD
Current code implementation:
#light
open System
open System.IO
//Simplify pausing
let pause() = Console.ReadLine()
//Identify the durrent drive letter associated with the flash drive for use
//when saving/deleting Save Data
let drive = System.IO.Directory.GetDirectoryRoot(System.IO.Directory.GetCurrentDirectory())
printfn "You're using the %s drive.\n\n" drive
//Identify the games to save
let game1 = "Assassin's Creed"
let game2 = "Crysis"
let game3 = "Mass Effect"
//Identify which game to Save/Load the data for
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."
//The '_' is to ignore the result of Console.Readline() without binding it to anything
//that way you can re-use the same line as many times as you like
let _ = pause()
Console.Clear()
getGame()
//Print the selected game
let gameprint = getGame()
printf "You have chosen %s\n\n" gameprint
let _ = pause()
I took out:
Type Game = Creed | Crysis | Mass
because it was interfering with 'printf' of the result of getGame()
The notes are for any new people that are interested in details.
Upvotes: 0
Reputation: 55184
The biggest problem with your first attempt is that you're parsing the input from a string
into an int
, but then you try to pattern match against strings. Using 1
, 2
, and 3
instead of "1"
, "2"
, and "3"
will fix that problem, but then you'll be at roughly the same point as your second attempt.
Your second attempt nearly works, but F# is telling you that you aren't using a consistent return type across all of your branches: in the first three cases you're returning a string but in the last case you're not returning anything. All you need to do is loop in that case, and the compiler will be happy:
let rec getGame() =
match Int32.Parse(stdin.ReadLine()) with
| 1 -> "Assassin's Creed"
| 2 -> "Crysis"
| 3 -> "Mass Effect"
| _ -> printf "Temp"; getGame()
I'd do something more like this:
type Game = Creed | Crysis | Mass
let rec getGame() =
printfn "Which Game?\n\n 1.%A\n 2.%A\n 3.%A\n\n" Creed Crysis Mass
match stdin.ReadLine() |> Int32.TryParse with
| true,1 -> Creed
| true,2 -> Crysis
| true,3 -> Mass
| _ ->
printfn "You did not enter a valid choice."
// put any other actions you want into here
getGame()
Upvotes: 7