F# 范围是在编译时或运行时评估的

发布于 2024-09-24 05:09:05 字数 101 浏览 2 评论 0原文

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

请帮我爱他 2024-10-01 05:09:05

我认为kvb的回复解答了大部分的疑虑。但是,我认为更准确的答案是范围在运行时延迟评估。以下是范围如何工作的更多详细信息...

当您在代码中的某处使用例如 1 .. 10 时,它会简单地转换为某些方法调用。该调用取决于上下文和使用的数字类型。

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

  • 当你有类似 obj.[ 1 .. ]obj 是支持切片的对象(例如矩阵类型)时,它将被转换为 < code>obj.GetSlice(Some(1), None) (请注意,在这种情况下,上/下限可能会丢失)。

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

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

序列表达式将转换为对 RangeInt32 的调用。这将仅返回一个延迟评估的 seq类型的值。对 take 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 and for loop, the compiler will generate something like RangeInt32(1, 1, 10) (the additional parameter is the step).

  • When you have something like obj.[ 1 .. ] and obj is some object that supports slicing (e.g. matrix type), then it will be translated to obj.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:

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

The sequence expression will be translated to a call to RangeInt32. This will just return a value of type seq<int> which is evaluated lazily. The call to take 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 method GetSlice, which is in more detail discussed here.

≈。彩虹 2024-10-01 05:09:05

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

let f n = [1 .. n]

在编译时甚至不知道上限。当然,作为实现细节,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:

let f n = [1 .. n]

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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文