简体   繁体   English

F# 模块对加载的影响

[英]F# module effects upon loading

I suspect that this behavior may not be unique to F#, but I'll pick on it since that's what I'm using for work.我怀疑这种行为可能不是 F# 独有的,但我会选择它,因为这是我用于工作的。

suppose I have a module假设我有一个模块

open System

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

and I have the following in an fsx:我在 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 )

When I run this, I see the following printed当我运行它时,我看到以下打印

BAR!
foo

which is expected, since arguments are usually evaluated before the function body so I expect the effects in Bar.bar to be happen before getValueOr partially applies it (or even when the module is read).这是预期的,因为参数通常在函数体之前评估,所以我希望Bar.bar的效果发生在getValueOr部分应用它之前(甚至在读取模块时)。

However, when I compile the Bar module into a DLL and #r it, I see just但是,当我将Bar模块编译成 DLL 并#r它时,我只看到

foo

In other words, Bar.bar doesn't get evaluated... why?换句话说, Bar.bar没有得到评估......为什么? Is it because of #r ?是因为#r吗?

This behavior is actually desirable for something I'm trying to create, but it's a little counterintuitive and I'd like to understand it better.对于我正在尝试创建的东西,这种行为实际上是可取的,但它有点违反直觉,我想更好地理解它。

This happens because of optimizations.这是因为优化。

When you run in FSI, optimizations are turned off, so everything works the way you expect it to work.当您在 FSI 中运行时,优化被关闭,所以一切都按照您期望的方式工作。

But when you compile in Release (ie with optimizations), F# compiler is able to do a lot more because it knows the structure of your code.但是当您在 Release 中编译(即使用优化)时,F# 编译器能够做更多的事情,因为它知道您的代码的结构。 In this case, the function getValueOr gets inlined at call site, and your last line turns into roughly the following:在这种情况下,函数getValueOr在调用站点被内联,最后一行大致变成以下内容:

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

Here's another interesting experiment: if you move the definition of the Bar module to the same place where Bar.bar is referenced, the effect will (probably) reappear, because the definition of bar itself will be inlined, roughly like this:这是另一个有趣的实验:如果将Bar模块的定义移动到引用Bar.bar的同一位置,效果将(可能)重新出现,因为bar本身的定义将被内联,大致如下所示:

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

The bottom line is this: uncontrolled effects are bad.底线是:不受控制的影响是不好的。 They make your program unpredictable.它们使您的程序变得不可预测。 Try to avoid them.尽量避免它们。

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

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