Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Creating a single loop with multiple functions

Tags:

loops

f#

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!

like image 224
Abraxas000 Avatar asked Apr 20 '26 02:04

Abraxas000


1 Answers

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()
like image 181
kvb Avatar answered Apr 21 '26 23:04

kvb



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!