Haskell GHC何时在内部变异不可变值?

Haskell GHC何时在内部变异不可变值?,haskell,optimization,real-time,immutability,ghc,Haskell,Optimization,Real Time,Immutability,Ghc,我希望将Haskell用于由不断变化的重状态组成的实时应用程序 当然,状态是不可变的,因此在每个状态步骤中,我都会重新创建一个稍微更改的新状态,并丢弃旧状态。在这种情况下,效率会非常低,因为我不需要以前的状态 我经常遇到有人说GHC可以优化这些东西,并在内部改变不可变的值,我想确保它会 可能吗?有没有办法确定GHC是否会通过内部变异值来优化它?有没有办法强制执行/确保执行 另外,这种优化有正式名称吗?GHC本身不这么做。各种容器库使用了一种称为流融合的技巧,这意味着一些纯功能代码所建议的拷贝实际

我希望将Haskell用于由不断变化的重状态组成的实时应用程序

当然,状态是不可变的,因此在每个状态步骤中,我都会重新创建一个稍微更改的新状态,并丢弃旧状态。在这种情况下,效率会非常低,因为我不需要以前的状态

我经常遇到有人说GHC可以优化这些东西,并在内部改变不可变的值,我想确保它会

可能吗?有没有办法确定GHC是否会通过内部变异值来优化它?有没有办法强制执行/确保执行


另外,这种优化有正式名称吗?

GHC本身不这么做。各种容器库使用了一种称为流融合的技巧,这意味着一些纯功能代码所建议的拷贝实际上从未制作过——但这仍然不是真正的“内部变异”,而是将多个操作组合在一起,每个操作都涉及到一个拷贝到一个大操作,并且仍然只有一个拷贝

我不认为以全自动的方式实现真正的“变异优化”是切实可行的;有些语言有点像声称他们做到了,但我真的不知道它的效果如何

然而,像Haskell这样的纯函数式语言非常能够显式地处理可变状态:通过单子。这可以是“万能的”
IO
monad(有些人不喜欢它,因为你失去了所有的ref-transp.保证,但对于实时应用程序来说,这可能是正确的),也可以是专门的,其目的是专门允许您使用真正的可变状态,同时保持程序的外部行为完全正常。

如果采用这种方法,您不仅可以确保不会制作成本高昂的副本,还可以得到更好的代码。因为有时候突变是思考问题的正确方式;如果您“假装”使用可变状态,即使是真正纯函数的代码有时也会变得更好,因为在一般情况下,.

AFAIK
ghc
不会执行这种优化。这可能需要时间

但它的运行时针对这种“状态略有变化”的情况进行了优化。通常情况下,您的状态(或可以表示为)类似于一棵树,并且大多数经理实际上重用了大多数现有树。所以修改只操作了很少的指针,而且非常有效。考虑这个例子:

data State = State
  { theA :: A
  , theB :: B
  }

data A = A Int
data B = B String

modifyTheA :: (A -> A) -> State -> State
modifyTheA f s = s {theA = f (theA s)}

这里的
modifyTheA
函数创建新的
状态
,但它只是两个指针。整个
b
字符串被重用

GHC在一个条件下进行此优化:如果一个对象在声明它的函数中使用一次,并且没有创建对它的附加引用。除非源函数是内联的,否则如果对象是在单独的函数中创建和使用的,则不会应用该函数


GHC做得更可靠的还有另一个相关优化。如果函数的最后一个操作是使用几乎相同的参数调用自己,那么它甚至不会触及未更改的参数。

您刚才提到的
IO
monad可能是实时的正确选择。您是否排除了
ST
,或者它可能也会为我服务?@MasterMastic:
ST
应该可以。@MasterMastic:
IO
ST
实际上就可变状态而言是相同的;区别在于
ST
不允许您执行文件读取、随机数访问等操作。。因此,它的端到端性能是参考透明的;因此,您可以将可变的
ST
算法安全地嵌入纯功能程序(使用
runST
;当使用
IO
时,这需要
unsafePerformIO
,我们不希望这样)。但是,如果您使用的是
IO
monad,那么您也可以将其用于可变状态。GHC实际上偶尔会执行此优化(它有一个名称,我正试图记住),但它在检测何时适用方面一点也不彻底。您可能希望在“重新创建一个新的略微更改的状态”。我想您可能会询问共享,或者GHC如何表示堆上的数据。手动通知编译器可以进行这种优化需要唯一的类型,但在一些情况下GHC会自行执行此操作(例如,当对象的声明和上次使用在同一函数中时)