是否有一种允许使用堆栈语义的功能语言-作用域末尾的自动确定性销毁?
是否有一种允许使用堆栈语义的功能语言-作用域末尾的自动确定性销毁?
Answers:
虽然我不是函数式编程专家,但我不知道。
原则上似乎很困难,因为从函数返回的值可能包含对在同一函数内(在堆栈上)创建的其他值的引用,或者可能像参数一样容易地被传入,或被传入的东西引用作为参数。在C语言中,此问题的解决方法是:如果程序员未正确处理,则可能会发生悬空指针(或更准确地说,未定义的行为)。那不是功能语言设计师认可的那种解决方案。
但是,有潜在的解决方案。一种想法是使值的生存期与值的引用一起成为值的类型的一部分,并定义基于类型的规则,以防止堆栈分配的值从a的返回或引用。功能。我还没有解决所有的隐患,但是我怀疑那将是可怕的。
对于单子代码,还有(实际上或几乎)单子的另一种解决方案,它可以提供一种自动确定性破坏的IORef。原理是定义“嵌套”动作。组合在一起时(使用关联运算符),它们定义了一个嵌套控制流-我认为是“ XML元素”,其中最左边的值提供了外部的开始和结束标记对。这些“ XML标记”只是在另一抽象级别上定义单子动作的顺序。
在某个点上(在关联组合链的右侧),您需要某种终止符来结束嵌套-需要一些终止符来填充中间的孔。需要终止符可能意味着嵌套合成运算符不是一元运算符,尽管同样,我不确定我是否还没有研究细节。正如所有应用终止符的操作一样,它实际上是将嵌套动作有效地转换为组合的正常单子动作-不一定会影响嵌套合成运算符。
这些特殊操作中有许多将具有无效的“结束标记”步骤,并将“开始标记”步骤等同于一些简单的单调操作。但是有些将代表变量声明。它们将用begin-tag表示构造函数,并用end-tag表示析构函数。所以你得到类似...
act = terminate ((def-var "hello" ) >>>= \h ->
(def-var " world") >>>= \w ->
(use-val ((get h) ++ (get w)))
)
按照以下执行顺序转换为Monadic合成,每个标记(而非元素)成为正常的Monadic动作...
<def-var val="hello"> -- construction
<def-var val=" world> -- construction
<use-val ...>
<terminator/>
</use-val> -- do nothing
</def-val> -- destruction
</def-val> -- destruction
这样的规则可以允许实现C ++风格的RAII。类似于IORef的引用无法逃脱其范围,原因与普通IORef不能逃脱monad的原因类似-关联组合的规则无法为引用提供逃脱途径。
编辑 -我差点忘了说-我不确定这里有一定范围。重要的是要确保外部变量基本上不能引用内部变量,因此必须有一个限制才能使用这些类似于IORef的引用。同样,我还没有完成所有细节。
因此,构建可以例如打开一个销毁关闭的文件。施工可以打开一个插座,销毁将关闭。基本上,就像在C ++中一样,变量成为资源管理器。但是与C ++不同,没有没有不能自动销毁的堆分配对象。
尽管此结构支持RAII,但仍然需要垃圾回收器。尽管嵌套动作可以分配和释放内存(将其视为资源),但在该内存块和其他内存中仍然存在对(可能共享的)功能值的所有引用。鉴于可以简单地在堆栈上分配内存,从而避免了释放堆的需要,所以真正的意义(如果有的话)是针对其他类型的资源管理。
因此,至少在RAII基于简单嵌套范围的情况下,这样做可以将RAII样式的资源管理与内存管理分开。您仍然需要一个垃圾回收器来进行内存管理,但是您可以安全,及时地自动确定性清除其他资源。
shared_ptr<>
)来说没有问题,但您仍然要保持确定性销毁。RAII棘手的一件事是循环引用。如果所有权图是有向无环图,则RAII可以正常工作。
如果您认为C ++是一种功能语言(它具有lambda),那么它就是不使用垃圾收集的语言的示例。
我不得不说这个问题定义不明确,因为它假定存在“功能语言”的标准集合。几乎每种编程语言都支持一定数量的功能编程。而且,几乎每种编程语言都支持一定数量的命令式编程。除了文化偏见和流行教条的指导外,有人在哪里划清界限,说哪一种是功能性语言和哪一种命令性语言?
解决这个问题的更好方法是“是否有可能在堆栈分配的内存中支持功能编程”。正如已经提到的,答案是非常困难的。函数式编程风格可随意促进递归数据结构的分配,这需要堆内存(无论是收集垃圾还是对引用计数)。但是,有一种相当复杂的编译器分析技术,称为基于区域的内存分析,利用该技术,编译器可以将堆分成大块,然后可以像堆栈分配那样自动分配和释放。Wikipedia页面列出了该技术的各种实现,适用于“功能”和“命令式”语言。