F#奇怪的printfn问题

Shd*_*dNx 7 f#

我正在玩F#(Visual Studio 2010 beta 1),我写了一个小的控制台脚本,要求用户输入2个数字和一个操作符,然后执行它.它工作正常,除了一个微小但令人烦恼的事情:有时我的printfn指令被忽略.我在代码中放置了断点,以确定情况确实如此.

代码段:

let convert (source : string) =
    try System.Int32.Parse(source)
    with :? System.FormatException ->
        printfn "'%s' is not a number!" source;
        waitForExitKey();
        exit 1

let read =
    printfn "Please enter a number.";
    System.Console.ReadLine

let num1 : int = read() |> convert // the printfn in the read function is run...
let num2 : int = read() |> convert // ... but here is ignored
Run Code Online (Sandbox Code Playgroud)

这当然不是完整的来源,但我认为这就足够了.如果您需要完整的来源,请告诉我.

所以我的问题很简单:printfn导致这个问题的原因是什么?难道我做错了什么?

提前谢谢,ShdNx

Jul*_*iet 16

这个页面部分解释了发生了什么,但简短而甜蜜的版本是F#如果不接受参数,将在声明上执行任何值.

let read =
    printfn "Please enter a number."
    System.Console.ReadLine
Run Code Online (Sandbox Code Playgroud)

由于read不带任何参数,它会在声明时立即执行,并将函数的返回值绑定到标识符read.

顺便提一下,您的返回值恰好是类型的函数(unit -> string).这是因为如果没有传递所有参数,F#会自动调整函数.ReadLine期望一个单位参数,但由于它没有传递,你实际上绑定readReadLine函数本身.

解决方案如下:

let read() = // read takes one unit parameter
    printfn "Please enter a number."
    System.Console.ReadLine() // pass paramter to ReadLine method
Run Code Online (Sandbox Code Playgroud)

由于read接受一个参数,每次调用时都会重新评估.另外,我们传递一个参数ReadLine,否则我们只是将ReadLine函数作为值返回.


Ray*_*gus 8

我知道这可能令人困惑.在您的示例中,printfn运行时间比您想象的要早.即使没有调用它也会实际执行read(),即注释掉最后两行,你仍然会看到正在打印的消息.

我认为你的意图是这样的:

let read() =
    printfn "Please enter a number.";
    System.Console.ReadLine()
Run Code Online (Sandbox Code Playgroud)

这将创建一个"可重用"函数,而不是像在原始示例中那样将函数绑定到标识符.

作为旁注,这里使用分号是可选的,所以你可以写:

let read() =
    printfn "Please enter a number."
    System.Console.ReadLine()
Run Code Online (Sandbox Code Playgroud)