为什么我看不到在主入口点 (F#) 外部调用的 printfn 的结果

Why don't I see results of printfn called outside the main entrypoint (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

是的,你是(某种)正确的 - 它不会打印,因为 Run 是这里的一个表达式,而且编译器似乎正在发布模式下优化它。

为什么不呢?在一个完美的(pure/referential 透明)世界中,您有一个 unit 类型的表达式,它只能有一个值 () ...而且您甚至不使用或记住该值!

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

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

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

...

File1.Run ()

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


顺便说一句:如果你对这类东西感兴趣,你要么使用像 Reflector 这样的工具(我现在手边没有),要么只使用 IL DASM (无论如何都应该安装一个工具 VS)——如果你查看编译的 debug/release 程序集,你会注意到没有像这样的东西:

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

不要 ;) - 似乎你必须 实际上 在某处使用该值 :D