tags:

views:

95

answers:

2

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!

+7  A: 

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()
kvb
@Abraxas000: I see this is your first question here. Welcome! It is good etiquette to accept an answer if you feel that it does answer your question. This can be done by clicking on the check box outline to the left of the answer.
Muhammad Alkarouri
A: 

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.

Abraxas000
Note that you can use `"%A"` in a printf format string to print values of any arbitrary type (instead of `"%s"`, which just prints strings).
kvb