忽略函数的 F# 内联如何在副作用函数方面起作用

How F# inlining of ignore function works regarding side effect functions

我正在读这个 我想知道 ignore 函数是如何内联的:它的参数应该被丢弃但副作用仍然发生:

// See https://github.com/dotnet/fsharp/blob/main/src/fsharp/FSharp.Core/prim-types.fs
let inline (|>) x f = f x
let inline ignore _ = ()

// Side effect function returning a value to ignore
let ok () =
    printfn "ok"
    true

// Usage
let t1 = ok () |> ignore
//     = ignore (ok ()) // `|>` inlined
//     = ()             // `ignore` inlined
//     what happened for `printfn "ok"` inside the `ok` function?

控制台输出:

ok
val ok : unit -> bool
val t1 : unit = ()

在 FSI 中执行代码时,编译时会打印“ok”(与 val ok : unit -> bool 之前出现的一样)。

→ 执行 .fs 文件中的代码会发生什么?

首先,F# interactive 的输出有点令人困惑 - 它在编译时没有 运行 函数。它首先编译代码,然后 运行s 它然后打印结果类型和所有结果的值。它需要 运行 打印前的代码,因为它还会打印最终值。

至于发生了什么,让我们看看如果您刚刚发生了什么:

let ok () = printfn "ok"; true
  • 我们从let t1 = ok () |> ignore
  • 开始
  • 内联 |> 后,这变成 let t1 = ignore(ok())
  • 内联 ignore 后,这变成 let t1 = ok(); ()
  • 现在您有一个使用 ; 组成的表达式,因此 F# 计算第一个子表达式,即对 ok() 函数的调用。你得到 let t1 = (printf "ok"; true); ()
  • 表达式是从左到右计算的,所以这个 运行 打印(执行副作用)并且 printf 的结果是一个单位值 ()。所以我们现在有 let t1 = ((); true); ().
  • 现在,计算 ; 运算符并丢弃 ()。我们有 let t1 = true; ()
  • 现在,计算第二个 ; 运算符并丢弃 true。我们有 let t1 = ()。这就是最终结果!