为什么我看不到主要入口点之外的printfn结果(F#)

时间:2015-06-25 13:25:26

标签: f#

我有一个F#控制台应用程序,它调用其他模块中的函数来从主函数入口点执行其工作。我在这些其他函数中有一系列printfn来向我提供有关程序运行的信息。

在DEBUG模式下编译时,所有语句都会打印到控制台。但是,在RELEASE模式下编译时,打印到控制台的唯一语句是直接位于主入口点函数内的语句。

如何在这些其他模块中打印信息语句?

下面提供了一个代码示例:

Program.fs

[<EntryPoint>]
let main argv = 
  printfn "%s" "start"   // prints in RELEASE and DEBUG mode

  File1.Run

  printfn "%s" "end"     // prints in RELEASE and DEBUG mode
  System.Console.ReadLine() |> ignore
  0 // return an integer exit code

File1.fs

module File1

let Run = 
  let x = 1
  printfn "%d" x  // this won't print in RELEASE mode

1 个答案:

答案 0 :(得分:5)

是的,你是(对)正确 - 它不会打印,因为Run是一个表达式,似乎编译器正在发布模式中优化它。

为什么不呢?在一个完美的(纯/参考透明)世界中,你有一个unit类型的表达式,只能有一个值() ...而你甚至不使用或记住这个值!

说实话,我不知道这是一个错误还是一个功能;)

无论如何,这个简单的技巧会帮助你,实际上你不应该像你一样使用带有效果的表达式:

let Run () = 
  let x = 1
  printfn "%d" x

...

File1.Run ()

看 - 现在它是一个函数,并在正确的时间调用,输出又回来了;)

顺便说一句:如果你对这种东西感兴趣,你可以使用像Reflector这样的工具(我目前还没有这个)或者只使用 IL DASM (一个工具VS应该无论如何安装) - 如果你看看编译好的调试/发布程序集,你会注意到这样的事情:

IL_001f:  call       class [FSharp.Core]Microsoft.FSharp.Core.Unit File1::get_Run()
如果您使用表达式,则可以在发行版中找到

我玩了一下,你必须有创意让编译器做这件事:

例如

let reallyNeed v =
    if v = ()

[<EntryPoint>]
let main argv = 
  printfn "%s" "start"   // prints in RELEASE and DEBUG mode

  File1.Run |> reallyNeed


  printfn "%s" "end"     // prints in RELEASE and DEBUG mode
  System.Console.ReadLine () |> ignore
  0 // return an integer exit code

有效(打印您的1) - 而

ignore File1.Run

let reallyNeed v = ignore v

don`t;) - 似乎你必须实际在某处使用该值:D