F# 范围是在编译时或运行时评估的
F# 中的 (..) 和 (.. ..) 运算符在某个时刻展开,这是编译时操作还是运行时操作?
无论哪种情况,其性能如何?即是否可以构建一个自定义函数来更快地执行这些操作?
the (..) and (.. ..) operators in F# are unrolled at some point, is that a compile time operation or a run time operation?
in either case, what are the performance of this? i.e. is it possible to build a custom function that does those operations faster?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为kvb的回复解答了大部分的疑虑。但是,我认为更准确的答案是范围在运行时延迟评估。以下是范围如何工作的更多详细信息...
当您在代码中的某处使用例如
1 .. 10
时,它会简单地转换为某些方法调用。该调用取决于上下文和使用的数字类型。对于
[ 1 .. 10 ]
或其他序列表达式和for
循环,编译器将生成类似RangeInt32(1, 1, 10)< /code> (附加参数是步骤)。
当你有类似
obj.[ 1 .. ]
且obj
是支持切片的对象(例如矩阵类型)时,它将被转换为 < code>obj.GetSlice(Some(1), None) (请注意,在这种情况下,上/下限可能会丢失)。现在很容易回答您的问题 - 这是一个将在运行时评估的方法调用。但值得注意的是,可能不需要评估整个范围!例如:
序列表达式将转换为对类型的值。对
RangeInt32
的调用。这将仅返回一个延迟评估的 seqtake 1
的调用仅采用第一个元素,因此仅需要并评估该范围中的第一个数字。我认为您自己的范围实现可能与标准范围没有任何不同,但是您可以将您的实现作为对象的成员提供。然后您可以编写
myObj.[1 .. 10]
(结果可以是您想要的任何类型)。为此,您需要一个实例方法GetSlice
,该方法更详细此处讨论。I think that the reply from kvb answers most of the concerns. However, I think that a more precise answer is that ranges are evaluated lazily at runtime. Here are some more details how ranges work...
When you use for example
1 .. 10
somewhere in your code, it is simply translated to some method call. The call depends on the context and numeric types used.For
[ 1 .. 10 ]
or other sequence expressions andfor
loop, the compiler will generate something likeRangeInt32(1, 1, 10)
(the additional parameter is the step).When you have something like
obj.[ 1 .. ]
andobj
is some object that supports slicing (e.g. matrix type), then it will be translated toobj.GetSlice(Some(1), None)
(note that in this case the upper/lower bound may be missing).Now it is quite easy to answer your question - it is a method call that will be evaluated at runtime. However it is important to note that the whole range may not need to be evaluated! For example:
The sequence expression will be translated to a call to
RangeInt32
. This will just return a value of typeseq<int>
which is evaluated lazily. The call totake 1
takes only first element, so only the first number from the range will be needed and evaluated.I don't think your own implementation of ranges could be any different than the standard one, however you can provide your implementation as a member of an object. Then you could write
myObj.[1 .. 10]
(and the result could be any type you want). To do that, you'll need an instance methodGetSlice
, which is in more detail discussed here.运行时间。 F# 很少会在编译过程中运行您的代码 - 我能想到的唯一情况是 NumericLiteralX 模块中的代码。此外,在这样的代码中:
在编译时甚至不知道上限。当然,作为实现细节,F# 编译器可能会显式展开定义,其中两个边界都是已知类型的静态已知值(例如
int
),但从语义上讲,它应该始终与它的定义相同。在运行时完成。关于你的第二个问题,比什么更快?
Run time. F# will only very rarely run your code as part of compilation - the only case I can think of is code in
NumericLiteralX
modules. Besides, in code like this:the upper bound isn't even known at compile time. Of course it's possible that as an implementation detail the F# compiler explicitly unrolls definitions where both bounds are statically known values of a known type (such as
int
), but semantically it should always be the same as if it's done at run time.Regarding your second question, faster than what?