Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么F#中允许可变项?什么时候是必要的?_F# - Fatal编程技术网

为什么F#中允许可变项?什么时候是必要的?

为什么F#中允许可变项?什么时候是必要的?,f#,F#,从C#来,试着了解语言 据我所知,F#的一个主要好处是你抛弃了国家的概念,在很多情况下,国家应该让事情变得更加稳健 如果是这种情况(如果不是,请纠正我),为什么允许我们用可变项打破这个原则?对我来说,他们似乎不属于这种语言。我知道你不必使用它们,但它为你提供了工具,让你偏离正轨,以面向对象的方式思考 任何人都可以提供一个例子来说明可变值在哪里是必不可少的吗?目前用于声明性(无状态)代码的编译器不是很聪明。这会导致大量的内存分配和复制操作,这是相当昂贵的。通过改变对象的某些属性,可以在新状态下重新

从C#来,试着了解语言

据我所知,F#的一个主要好处是你抛弃了国家的概念,在很多情况下,国家应该让事情变得更加稳健

如果是这种情况(如果不是,请纠正我),为什么允许我们用可变项打破这个原则?对我来说,他们似乎不属于这种语言。我知道你不必使用它们,但它为你提供了工具,让你偏离正轨,以面向对象的方式思考


任何人都可以提供一个例子来说明可变值在哪里是必不可少的吗?

目前用于声明性(无状态)代码的编译器不是很聪明。这会导致大量的内存分配和复制操作,这是相当昂贵的。通过改变对象的某些属性,可以在新状态下重新使用对象,这要快得多

想象你做了一个游戏,10000个单位以每秒60次的速度移动。您可以在F#中执行此操作,包括在单个CPU内核上与可变四叉树或八叉树发生冲突

现在假设单位和四叉树是不可变的。编译器最好的办法就是每秒分配和构造600000个单元,每秒创建60棵新树。这不包括其他管理结构的任何变化。在具有复杂单元的实际用例中,这种解决方案将过于缓慢


F#是一种多范式语言,它使程序员能够编写功能性的、面向对象的,并且在一定程度上是命令式的程序。目前,每个变体都有其有效的用途。也许,在将来的某个时候,更好的编译器将允许更好地优化声明性程序,但现在,当性能成为问题时,我们必须退回到命令式编程。

出于性能原因和其他原因,能够使用可变状态通常很重要

考虑实现API
List.take:count:int->List:'a List->'一个列表
,它返回一个只包含输入列表中第一个
count
元素的列表

如果您受到不变性的约束,那么列表只能从头开始构建。实现
take
然后归结为

  • 使用输入的第一个
    count
    guys:O(count)从头到尾建立结果列表
  • 反转该结果并返回O(计数)
出于性能原因,F#运行时具有在需要时前后构建列表的神奇特殊能力(即,将最后一个家伙的尾部变异为指向新的尾部元素)。
列表的基本算法是:

  • 使用输入的第一个
    count
    guys:O(count)建立前后结果列表
  • 返回结果
同样的渐近性能,但实际上,在这种情况下使用变异的速度是使用变异的两倍

无处不在的可变状态可能是一场噩梦,因为代码很难推理。但是,如果您考虑代码,使可变状态被紧密封装(例如,在
List.take
的实现细节中),那么您可以在有意义的地方享受它的好处。因此,使不变性成为默认值,但仍然允许可变性,是该语言非常实用和有用的特性。

首先,在我看来,使F#强大的不仅仅是默认的不变性,而是一整套特性,如:默认不变性、类型推断、轻量级语法、sum(DU)和产品类型(元组),模式匹配和默认的咖喱。可能更多

这使得F#在默认情况下非常实用,并且让您以某种方式编程。特别是当您使用可变状态时,它们让您感到不舒服,因为它需要
mutable
关键字。从这个意义上讲,不舒服意味着更加小心。这正是您应该做的

可变状态本身不是禁止的或邪恶的,但它应该被控制。明确使用
可变状态的需要就像一个警告标志,让你意识到危险。控制它的好方法是在函数内部使用它。这样你就可以拥有自己的内部可变状态,并且仍然l是完全线程安全的,因为您没有共享可变状态。事实上,您的函数仍然可以是引用透明的,即使它在内部使用可变状态

至于为什么F#允许可变状态,在没有这种可能性的情况下编写通常的真实代码是非常困难的。例如,在Haskell中,像随机数这样的事情不能像在F#中那样以相同的方式完成,而是需要显式地遍历状态


当我编写应用程序时,我倾向于以一种非常实用的风格拥有大约95%的代码库,可以说Haskell几乎是1:1的可移植性,没有任何问题。但是在系统边界或某些性能关键的内部循环中,使用了可变状态。这样你就可以充分利用这两个方面。

与C#和其他.NET进行互操作代码、优化等。它们不是必需的。它们是有用的。F#的设计并没有考虑到极简主义。许多问题用可变变量(尤其是复杂的折叠)更清楚地表达。它们是F#有用的必要条件。如果没有这些功能,将很难在生产代码中使用F#。