2010-09-21 94 views
1

F#中的(..)和(.. ..)运算符在某个时间点展开,是编译时操作还是运行时操作?是在编译时或运行时评估的F#范围

无论哪种情况,这是什么表现?即是否可以构建一个自定义函数来更快地完成这些操作?

+0

编写它,编译它,并用反射器检查出来。如果你看到它展开......这是编译时间。如果没有,它是运行时(我会尝试它,但我目前没有工具)。 – 2010-09-21 17:40:14

+0

如果您问是否可以构建自定义函数来比语言内置的功能更快地评估理解 - 也许。像软件开发中的大多数事情一样,答案将取决于上下文。 – 2010-09-21 20:57:18

回答

3

我认为的回复kvb回答了大部分问题。但是,我认为更准确的答案是,在运行时间处懒惰地评估范围。这里有一些更详细的信息如何范围工作...

当你使用例如1 .. 10在你的代码中的某个地方,它只是转换为一些方法调用。调用取决于使用的上下文和数字类型。

  • 对于[ 1 .. 10 ]或其它序列表达式和for循环,编译器会生成类似RangeInt32(1, 1, 10)(附加参数是步骤)。

  • 当您有类似obj.[ 1 .. ]obj是一些对象,它支持分片(例如矩阵型),那么它会被转换为obj.GetSlice(Some(1), None)(注意,在这种情况下,上/下限可能丢失)。

现在很容易回答你的问题 - 这是一个方法调用,将在运行时进行评估。然而,重要的是要注意整个范围可能不需要评估!例如:

let nums = seq { 1 .. 10 } |> Seq.take 1 

序列表达将被转换为到RangeInt32的呼叫。这只会返回延迟评估的seq<int>类型的值。拨打take 1只需要第一个元素,因此只需要范围中的第一个数字并进行评估。

我不认为你自己的范围实现可能与标准实现不同,但是你可以提供你的实现作为对象的成员。然后你可以写myObj.[1 .. 10](并且结果可以是你想要的任何类型)。为此,您需要一个实例方法GetSlice,详细信息请参见discussed here

3

运行时间。作为编译的一部分,F#将很少运行您的代码 - 我能想到的唯一情况是NumericLiteralX模块中的代码。此外,在这样的代码:

let f n = [1 .. n] 

上编译甚至不知道在编译时。当然,作为实现细节,F#编译器显式展开定义,其中两个边界都是已知类型的静态已知值(例如int),但在语义上应该始终与运行时完成的定义相同。

关于你的第二个问题,比什么快?