F#创建一个包含多个函数的循环

时间:2010-09-15 18:49:22

标签: loops f#

我刚开始深入研究一些编程并决定使用F#。作为练习,我试图将我在.bat中创建的脚本转换为F#。我在创建一个不止一件事的循环函数时遇到了麻烦。以下是此循环的旧脚本的代码。

: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

到目前为止,我试图在F#中为相同的函数创建的代码如下所示:

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

我知道如果它到达最后一个“其他”,我会遗漏一些让它再次运行的东西;我收到了这些错误:

表达式的类型应为'unit',但类型为'string'。使用'ignore'丢弃表达式的结果,或'let'将结果绑定到名称。

错误1此表达式的类型为int,但此处的类型为字符串19 21

错误2此表达式的类型为int,但此处的类型为字符串20 23

错误3此表达式的类型为int,但此处的类型为字符串21 23

错误4此表达式应具有类型字符串,但此处具有类型单元22 17

警告5此表达式应为“unit”类型,但类型为“string”。使用'ignore'丢弃表达式的结果,或'let'将结果绑定到名称。 19 5

我更喜欢使用这样的方法(非常不完整):

let rec getGame() =
    match Int32.Parse(stdin.ReadLine()) with
    | 1 -> "Assassin's Creed"
    | 2 -> "Crysis"
    | 3 -> "Mass Effect"
    | _ -> printf "Temp"

但我得到了:

错误1此表达式应具有类型字符串,但此处具有类型单元36 19

而且我不确定如何将其循环并将其设为'printf'和'Console.Clear'

如果有一种我不了解的功能性方法,我当然希望学习: - )

提前致谢!

2 个答案:

答案 0 :(得分:7)

您第一次尝试的最大问题是您正在将string的输入解析为int,但之后您尝试对字符串进行模式匹配。使用123代替"1""2""3"将解决该问题,但之后您将成为与你的第二次尝试大致相同。

你的第二次尝试几乎可以解决,但是F#告诉你你没有在所有分支中使用一致的返回类型:在前三种情况下你返回一个字符串,但在最后一种情况下你不是回来什么。在这种情况下,你需要做的只是循环,编译器会很高兴:

let rec getGame() =
    match Int32.Parse(stdin.ReadLine()) with
    | 1 -> "Assassin's Creed"
    | 2 -> "Crysis"
    | 3 -> "Mass Effect"
    | _ -> printf "Temp"; getGame()

我会做更多这样的事情:

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

答案 1 :(得分:0)

感谢非常及时的回复!我从昨天开始就一直在努力克服这个障碍xD

当前的代码实现:

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

我拿出了:

Type Game = Creed | Crysis | Mass

因为它干扰了getGame()

结果的'printf'

这些笔记适用于任何对细节感兴趣的新人。