F#模块在加载时的效果

dxh

我怀疑这种行为可能不是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吗?

实际上,对于我要创建的东西来说,这种行为是理想的,但这有点违反直觉,我想更好地理解它。

费奥多·索金(Fyodor Soikin)

发生这种情况是由于优化。

在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 )

底线是:不受控制的效果不好。它们使您的程序变幻莫测。尽量避免它们。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章