我如何在F#中编写经典的高/低游戏?

7 f#

我正在阅读函数式语言,我想知道如何用函数式语言实现"尝试" .所以我决定尝试在F#中做到这一点

但我无法获得一半的基础知识.我无法弄清楚如何使用随机数,如何使用返回/继续(起初我以为我做了一个多语句如果错了但似乎我做得对)我无法弄清楚如何打印一个数字在F#所以我用C#方式做到了.

更难的问题是tryparse中的外部参数,我仍然不确定如何在tries不使用可变变量的情况下实现.也许你们中的一些人可以告诉我如何正确实现这一点

我上周要做的C#代码

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

非常破碎和错误的F#代码

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()
Run Code Online (Sandbox Code Playgroud)

Bri*_*ian 6

欢迎来到F#!

这是一个工作计划; 解释如下.

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() 
Run Code Online (Sandbox Code Playgroud)

很多事情......

如果您正在调用具有多个参数的方法(例如Random.Next),请使用args(.Next(1,100))周围的parens .

您似乎正在处理递归函数(dummyWhileTrue)而不是while循环; 一个while循环也可以,但我保持你的方式.请注意,没有breakcontinue在F#中,所以你必须更加结构化if内部的东西.

我改变你Console.WriteLine的方式printfn来展示如何用一个参数调用它.

我展示了调用TryParse最像C#的方式.首先要声明的变量(使它变的,因为TryParse将被写入到该位置),然后使用&n作为参数(在这种情况下,&n就像ref nout n在C#).或者,在F#中你可以这样做:

let b, n = Int32.TryParse(v)
Run Code Online (Sandbox Code Playgroud)

其中F#允许你省略trailing-out-parameters,而是在元组结束时返回它们的值; 这只是一种语法上的便利.

Console.ReadLine返回一个字符串,在程序结束时你不关心它,所以将它传递给ignore函数以丢弃该值(并删除有关未使用的字符串值的警告).


Ben*_*jol 6

这是我的看法,只是为了好玩:

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() 
Run Code Online (Sandbox Code Playgroud)

注意事项:

  • 模式匹配更漂亮,更简洁,而且 - 我相信 - 比嵌套ifs更惯用
  • 使用TryParseBrian建议的元组返回样式
  • 改名dummyWhileTrueTryLoop,似乎更具描述性
  • 创建了两个内部函数doneWithnotDoneWith,(对于纯美学的原因)


Ste*_*sen 5

我从Evaluate@ Huusom的解决方案中解除了主要模式匹配,但选择了递归循环和累加器而不是@Hussom(非常酷)区分联合和Seq.unfold的应用程序,以获得非常紧凑的解决方案.

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)))
Run Code Online (Sandbox Code Playgroud)