繁体   English   中英

F# 模块对加载的影响

[英]F# module effects upon loading

我怀疑这种行为可能不是 F# 独有的,但我会选择它,因为这是我用于工作的。

假设我有一个模块

open System

module Bar =
    let bar =
        Console.WriteLine("BAR!")
        "bar"

我在 fsx 中有以下内容:

// this is a standard library function (Operators.defaultArg or Option.defaultValue)
let getValueOr v = function
| Some x -> x
| None -> v

let opt = Some "foo"

Console.WriteLine( opt |> getValueOr Bar.bar )

当我运行它时,我看到以下打印

BAR!
foo

这是预期的,因为参数通常在函数体之前评估,所以我希望Bar.bar的效果发生在getValueOr部分应用它之前(甚至在读取模块时)。

但是,当我将Bar模块编译成 DLL 并#r它时,我只看到

foo

换句话说, Bar.bar没有得到评估......为什么? 是因为#r吗?

对于我正在尝试创建的东西,这种行为实际上是可取的,但它有点违反直觉,我想更好地理解它。

这是因为优化。

当您在 FSI 中运行时,优化被关闭,所以一切都按照您期望的方式工作。

但是当您在 Release 中编译(即使用优化)时,F# 编译器能够做更多的事情,因为它知道您的代码的结构。 在这种情况下,函数getValueOr在调用站点被内联,最后一行大致变成以下内容:

// C# syntax
Console.WriteLine( foo == null ? Bar.bar : foo.Value )

这是另一个有趣的实验:如果将Bar模块的定义移动到引用Bar.bar的同一位置,效果将(可能)重新出现,因为bar本身的定义将被内联,大致如下所示:

// C# syntax:
Console.WriteLine( "BAR!" )
var bar = "bar"
var foo = new Some("foo")
Console.WriteLine( foo == null ? bar : foo.Value )

底线是:不受控制的影响是不好的。 它们使您的程序变得不可预测。 尽量避免它们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM