语义如何处理副作用?


19

在Anthony Aaby的语义学编程语言简介”部分中,他做了以下观察:

编程语言的语义方面的许多工作是由尝试构建和理解命令式程序(带有赋值命令的程序)时遇到的问题所激发的。由于赋值命令会将值重新分配给变量,因此赋值可能在程序的远处产生意外的影响。

这让我印象深刻,承认允许副作用会激发语义工作的大部分。

编程语言中副作用的存在如何影响将程序映射到计算模型的能力?是否有管理状态的方法可以改善此过程,同时仍然允许副作用?


是否应该将其标记为软问题?由于“语义上的许多工作都是[副作用]促成的”,因此您肯定不能指望简短而严格的回答。
Radu GRIGore

1
@Radu:在MO上,这可能会被标记为[big-picture],而这些标记大多不是[soft-question]或CW。
查尔斯·斯图尔特

标签大图甚至更好。我忘了
Radu GRIGore 2010年

好建议;我添加了标签。
Shane 2010年

Answers:


18

在查尔斯的答案的基础上,编程语言理论的主要困难在于,程序等效性的自然概念通常不是严格的相等性,无论是在您可以给出的最直接的数学语义上还是在底层的机器模型中。例如,考虑以下类似Java的代码:

Object x = new Object();
Object y = new Object();
... some more code ...

因此,该程序创建一个对象并将其命名为x,然后创建另一个名为y的对象,然后继续执行更多代码。现在,假设程序员决定翻转这两个对象的分配顺序:

Object y = new Object();
Object x = new Object();
... some more code ...

现在,问一个问题:重构会改变程序的行为吗?一方面,在底层计算机上,x和y将在程序的两次运行中分配在不同的位置。因此,从这个意义上说,程序的行为有所不同。

但是在类似Java的语言中,您只能测试引用是否相等,而不能测试顺序,因此这是“更多代码” 无法观察到的差异。结果,大多数程序员希望颠倒顺序不会对最终答案产生任何影响,并且大多数编译器作者希望能够在此基础上执行重新排序和优化。(在另一方面,在一个类似C语言,你可以比较指针排序,首先他们铸造整数,因此该重新排序也并非一定保留观察到的行为。)

语义学的中心问题之一是回答两个程序何时可观察到相等的问题。由于我们的观察概念取决于编程语言的功能,因此我们得出这样的定义:“当没有任何客户端程序可以基于接收这些程序作为输入来计算不同答案时,两个程序是等效的”。所有客户端程序的量化是使这个问题变得困难的原因-似乎您最终不得不对所有可能的客户端程序说一些话,对两个特定的代码说了些话。

指称语义的窍门是给出一种数学解释,以使您避免这种普遍的量化-您说一段代码的含义是一些数学值,然后通过检查它们是否在数学上相等或比较来对它们进行比较。不。这是局部的(即组成的),不涉及所有可能客户的量化。(当然,您确实需要证明指称语义意味着它在听起来上是对等的。当它完成时-当指称相等与上下文对等完全相同时,我们说语义是“完全抽象的”。)

但是,这意味着您需要确保指称语义验证这些等效性。因此,对于此示例,如果您想为这种类似于Java的语言提供一种指称语义,则不仅需要确保调用new会占用一个堆并使用新创建的对象还给您一个新的堆,还应确保其含义程序的输入在输入堆的所有排列下都是不变的。这可能涉及相当复杂的数学结构(例如,在这种情况下,以确保所有内容以适当的排列组为模的形式工作)。


“当没有任何客户端程序可以基于接收那些程序作为输入来计算不同答案时,两个程序是等效的。” 我对此感到困惑。如果您有一个程序X和一个客户端程序Y,那么我认为它是指Y“调用”X。但是然后您似乎说Y读取X的文本作为输入,在这种情况下,我几乎不会调用Y是X的“客户”。请您澄清一下吗?
Radu GRIGore 2010年

1
我所说的“ X的客户端”与“程序上下文”相同,后者只是“包含X作为子项的较大程序”。
Neel Krishnaswami

因此,您将“ X是Y的客户”与“ X将Y读作输入”互换使用是因为您认为X是应用于Y的lambda吗?这是有道理的,但是当您谈论Java时,它有点扭曲。:)
Radu GRIGore 2010年

1
@RaduGRIGore:程序上下文还具有其他含义。您正在正确阅读帖子,但是如果X读取Y的源代码作为输入(这就是我解释帖子的方式),则可以区分每两个语法不同的程序;相反,如果Y是X上的lambda函数,则可以区分的程序太少。Neel对“程序上下文”的评论是正确的定义:程序上下文Y是在AST中带有孔的程序,您可以在其中放置(有意义地)两个不同的程序片段X1和X2。
Blaisorblade 2012年

@NeelKrishnaswami:您能否阐明您在帖子中的意思?您可以继续使用示例并讨论一个程序,您可以在其中插入一个或另一个片段。
Blaisorblade

12

当然,有一些方法可以处理(表示式)语义中的效果。例如,我们可以使用Eugenio Moggi的想法,即计算效果是单子(在Haskell的设计中也曾使用过这种想法)。问题之一是单子难以组合。戈登·普洛特金Gordon Plotkin)约翰·鲍尔John Power)提出将莫吉的单子形式改进为Lawvere理论(也称为代数理论),其中包括代数效应(最常见的效应是代数,例如状态,I / O,非确定性,但延续是不)。有关全面的处理,请参阅Matija Pretnar的论文

我还应该提到由弗兰克·奥莱斯(Frank Oles)和约翰·雷诺兹John Reynolds)开发的局部状态的可能世界语义(抱歉,找不到更好的链接,这是1982年的文字),它早于Moggi的单子。他们使用预滑轮的类别来提供类似于algol的语言的语义,该语言正确地对局部状态的许多方面进行了建模(但并非所有模型都可以建模,但我认为该模型允许回弹,但也许我的记忆对我有误)。


1
是的,函子类别语义不能验证所有的Meyer-Sieber等价物。彼得·奥海恩(Peter O'Hearn)和罗伯特·特南特(Robert Tennant)在90年代中期开发了函子类别语义的参数化版本,该版本(IIRC)获得了所有Meyer-Sieber示例,但我不知道它是否完全抽象。
Neel Krishnaswami 2010年

O'Hearn和Tennent模型不是完全抽象的。在文件本身中对此进行了讨论。但是O'Hearn和Reynolds使用线性lambda演算的精炼完全抽象到了二阶。它打破了三阶,例如艾哈迈德(Ahmed),德雷尔(Dreyer),伯克达尔(Birkedal)等人研究的等价物。
Uday Reddy

12

马蒂亚斯·费莱森(Matthias Felleisen)在“控制与状态的句法理论”系列中提出了一种令人信服的语义学副作用解决方案。

该工作产生了CESK机器,这是一个简单的抽象机器框架,能够对功能,面向对象,命令式甚至逻辑语言进行简洁地建模。CESK框架不仅可以处理副作用,还可以处理“复杂”的控制结构,例如异常,连续性,惰性以及甚至线程。

大约二十年来,CESK机器以及更广泛的小步操作语义已经成为编程语言理论的事实上的标准。

简而言之,CESK机器是一台小步机器,具有四个组件来描述每个机器状态:控制字符串(程序计数器的概括),环境,存储(也称为堆)和当前延续。

环境将变量映射到地址。商店将地址映射到值。

这使对可变变量建模变得简单:只需更改其地址处的值即可。

它还使指针建模和动态分配变得容易:只需使存储地址成为一流的值即可。

以类似的方式,一流的延续来自于使它们成为可寻址的值。


6

编程语言中副作用的存在如何影响将程序映射到计算模型的能力?

它不一定使它变得困难,但是它确实限制了可以从较小的表达式构造较大表达式的语义的方式。例如,如果要为一种语言提供一种Scott风格的指称语义,以便允许将高阶函数分配给全局引用,它可能会与某些其他编程结构发生非常恶劣的交互。

造成问题的原因不只是状态之类的副作用。简单的命令式语言(例如Dijkstra的受保护的命令语言)具有这些副作用,并且具有良好的语义。即使在没有副作用的情况下,lambda微积分的扩展也会带来编程语言所期望的操作语义的麻烦:最早,Plotkin的PCF相对较早地获得了指称模型,但语义并不完全抽象,这意味着指称语义过于笼统,与其操作语义不完全对应。PCF最终在1980年代后期获得了带有游戏语义的完全抽象的指称语义,这与Scott的顺序理论语义完全不同。并发仍未得到充分充分的指称治疗。

许多人质疑这种语义的重要性。我们始终可以提供某种操作语义,即使“语义”只是程序源以及已经编译并运行该程序的某些计算机的名称:出于这个原因,Strachey谴责了操作语义。但是Plotkin的结构化操作语义学表明了如何将操作语义学与机器模型分开,而Pitt的工作表明了这种语义学如何能够支持关于程序语言和编程语言的类似推理。因此,操作语义是指代语义的可行替代方法,并且已成功应用于大量编程语言(例如Standard ML)。

是否有管理状态的方法可以改善此过程,同时仍然允许副作用?

在某种程度上,提供语义的困难与提供功能强大的编程语言以人们期望的方式表现的困难相对应。务实的设计决策(例如,通常通过消息传递并发避免使用全局状态和并发)使提供语义更加容易。


斯科特的PCF没有状态,也不是斯科特的,是不是看到了吗?en.wikipedia.org/wiki/...
安德烈·鲍尔

@Andrej:嗯,很不错,因为Luke Ong监督了我的D.Phil,所以我不应该犯这个错误。我发布了Milner的PCF和Scott的LCF的预告摘要,作为LtU故事, 它比WP更为简洁:lambda-the-ultimate.org/node/2196在我看来,您可能可以使用缺少的Scott (1969年)手稿...
查尔斯·斯图尔特

我想这就是Plotkin的PCF :-)我可以尝试掌握手稿,但实际上我没有。
安德烈·鲍尔

但是问题仍然在于PCF没有状态。您说Strachey谴责操作语义是什么“理由”?这对我来说并不明显。最后一段与您之前所说的相反,即受保护的命令具有很好的语义,但PCF却没有!
Uday Reddy 2012年

@Andrej,乌代:不到三年后,我已经修正了我的职位。
查尔斯·斯图尔特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.