Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >没有通过追加或尾调用更新TLA+序列

没有通过追加或尾调用更新TLA+序列
EN

Stack Overflow用户
提问于 2019-01-06 16:26:51
回答 1查看 304关注 0票数 1

问题

我正在玩弄TLA+,并认为我应该用PlusCal编写以下明显错误的规范:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
---- MODULE transfer ----
EXTENDS Naturals, TLC, Sequences

(* --algorithm transfer

\* Simple algorithm:
\*  1. Start with a shared-memory list with one element.
\*  2. A process adds arbitrary numbers of elements to the list.
\*  3. Another process removes arbitrary numbers of elements from the list, 
\*     but only if the list has more than one item in it. This check is 
\*     applied just before trying to removing an element. 
\* Is it true that the list will always have a length of 1? 
\* You would expect this to be false, since the adder process can add more elements 
\* than the remover process can consume.

variables stack = <<0>>

process Adder = 0
  begin
      AddElement:
        stack := Append(stack, Len(stack));
        either goto AddElement
        or skip
        end either;
end process;

process Remover = 1
  begin
      RemoveElement:
        \* Pop from the front of the stack
        if Len(stack) > 1 then
            stack := Tail(stack);
        end if;
        either goto RemoveElement
        or skip
        end either;
end process;

end algorithm *)

IsStackAlwaysUnitLength == Len(stack) = 1

====

在将IsStackAlwaysUnitLength检查为要报告的时间属性之一之后,我希望TLA+将此属性标记为失败。

然而,所有的州都通过了!为什么不失败呢?

调试尝试

在使用print语句进行调试时,我注意到以下奇怪的行为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
process Adder = 0
  begin
      AddElement:
        print stack;
        print "Adder applied!";
        stack := Append(stack, Len(stack));
        print stack;
        print "Adder task complete!";
        \* Force 
        either goto AddElement
        or skip
        end either;
end process;

process Remover = 1
  begin
      RemoveElement:
        \* Pop from the front of the stack
        print stack;
        print "Remover applied!";
        if Len(stack) > 1 then
            stack := Tail(stack);
            print stack;
            print "Remover task complete!";
        else
            print "Remover task complete!";
        end if;
        either goto RemoveElement
        or skip
        end either;
end process;

在调试面板中产生

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<<0>>
"Adder applied!"
<<0>>
"Adder task complete!"
<<0>>
<<0>>
"Remover applied!"
"Remover applied!"
"Remover task complete!"
"Remover task complete!"
<<0>>
"Adder applied!"
<<0>>
"Adder task complete!"

我不知道为什么stack := Append(stack, Len(stack));stack := Tail(stack);不更新全局stack变量。

生成完整的TLA规范

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
---- MODULE transfer ----
EXTENDS Naturals, TLC, Sequences

(* --algorithm transfer

variables stack = <<0>>

process Adder = 0
  begin
      AddElement:
        stack := Append(stack, Len(stack));
        either goto AddElement
        or skip
        end either;
end process;

process Remover = 1
  begin
      RemoveElement:
        \* Pop from the front of the stack
        if Len(stack) > 1 then
            stack := Tail(stack);
        end if;
        either goto RemoveElement
        or skip
        end either;
end process;

end algorithm *)
\* BEGIN TRANSLATION
VARIABLES stack, pc

vars == << stack, pc >>

ProcSet == {0} \cup {1}

Init == (* Global variables *)
        /\ stack = <<0>>
        /\ pc = [self \in ProcSet |-> CASE self = 0 -> "AddElement"
                                        [] self = 1 -> "RemoveElement"]

AddElement == /\ pc[0] = "AddElement"
              /\ stack' = [stack EXCEPT ![0] = Append(stack, Len(stack))]
              /\ \/ /\ pc' = [pc EXCEPT ![0] = "AddElement"]
                 \/ /\ TRUE
                    /\ pc' = [pc EXCEPT ![0] = "Done"]

Adder == AddElement

RemoveElement == /\ pc[1] = "RemoveElement"
                 /\ IF Len(stack) > 1
                       THEN /\ stack' = [stack EXCEPT ![1] = Tail(stack)]
                       ELSE /\ TRUE
                            /\ stack' = stack
                 /\ \/ /\ pc' = [pc EXCEPT ![1] = "RemoveElement"]
                    \/ /\ TRUE
                       /\ pc' = [pc EXCEPT ![1] = "Done"]

Remover == RemoveElement

Next == Adder \/ Remover
           \/ (* Disjunct to prevent deadlock on termination *)
              ((\A self \in ProcSet: pc[self] = "Done") /\ UNCHANGED vars)

Spec == Init /\ [][Next]_vars

Termination == <>(\A self \in ProcSet: pc[self] = "Done")

\* END TRANSLATION

IsStackAlwaysUnitLength == Len(stack) = 1

====
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-01-06 18:56:48

恭喜你,你碰到了一个PlusCal错误!这也是一种边缘情况,它不是一个bug,但仍然是不直观的。让我们从窃听器开始。

有时,当使用PlusCal时,我们希望有多个进程共享标签。我们使用一个过程来完成这个任务。为了使其全部工作,PlusCal转换器添加了一个额外的簿记变量,名为stack。通常,如果用户定义一个与生成的变量foo冲突的变量foo,则转换将一个重命名为foo_。在这种情况下,由于没有冲突,所以没有任何改名。*错误在于,翻译人员混淆并翻译了变量,就好像它应该是簿记stack。您可以看到这一点,因为它将附件转换为

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
stack' = [stack EXCEPT ![0] = Append(stack, Len(stack))]

当它应该是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
stack' = Append(stack, Len(stack))

您可以通过将stack mystack**.重命名为mystack**.来修复这个问题,这将使规范运行正常。但是它还是会过去的:这是因为您将IsStackAlwaysUnitLength作为一个属性而不是一个不变变量。作为一个时态属性,如果IsStackAlwaysUnitLength在初始状态为true,则它是true。作为一个不变量,如果在所有状态中都是正确的,则IsStackAlwaysUnitLength是正确的。** YOu可以通过将**YOu属性中的**更改为“什么是模型”页面中的不变来使规范正确失败。

*实际上,在这种情况下,如果添加一个过程,翻译器不会重命名stack,它只是抛出一个错误。但这仍然是不安全的。

**这是因为TLC (模型检查器)将不变的P视为时态属性[]P。基本上是语法糖。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54067207

复制
相关文章
尾调用
尾调用(Tail Call)是函数式编程的一个重要概念,本身非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。
Karl Du
2023/10/20
1760
尾调用和尾递归
尾调用是函数式编程中一个很重要的概念,当一个函数执行时的最后一个步骤是返回另一个函数的调用,这就叫做尾调用。
leocoder
2018/10/31
1.1K0
尾调用优化
[参考链接]((https://www.ruanyifeng.com/blog/2015/04/tail-call.html)
ACK
2020/01/14
3490
尾调用优化
尾调用(Tail Call)是函数式编程的一个重要概念,本文介绍它的含义和用法。 一、什么是尾调用? 尾调用的概念非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。 functio
ruanyf
2018/04/12
8030
尾调用优化
如何优化尾调用
经常看到关于尾递归这三个词,递归很多时候,都离不开我们,废话不多说,这次我们梳理一遍关于递归那些事。
前端进击者
2021/07/27
9090
递归尾调用优化
尾调用(Tail Call)是函数式编程的一个重要概念,就是指某个函数的最后一步是return调用另一个函数。
wade
2020/04/24
6950
图解尾调用优化
函数在调用的时候会在调用栈中 push 一个调用帧,每次执行完函数都会逐一弹出调用帧知道所有函数执行完毕,调用栈被清空:
JS菌
2019/04/10
4720
图解尾调用优化
学习Javascript之尾调用
总括: 本文介绍了尾调用,尾递归的概念,结合实例解释了什么是尾调用优化,并阐述了尾调用优化如今的现状。
Damonare
2020/02/23
1.2K0
学习Javascript之尾调用
springboot中通过main方法调用service或dao
大多数情况下,我们使用springboot是创建一个web项目,然后通过接口访问,但是也有特殊情况,比如线上跑着的web项目,有一些特殊的数据,需要经过计算导入到数据库,这个时候,我们可能需要原来的web项目中的一些service,dao才辅助操作,但是又不能在服务端新开接口。我们通过springboot的main方法执行这些操作。 此时,service和到需要通过上下文获得。
tongyao
2022/06/09
1.1K0
java中复制对象通过反射或序列化
在使用缓存读取数据后修改发现缓存被修改。于是找了下复制对象的方法。 关于对象克隆 ---- 按我的理解,对象是包含引用+数据。通常变量复制都是将引用传递过去。比如: 1 Person p1 = new Person(); 2 Person p2 = p1; 这两句话,创建两个引用p1,p2,但指向共同的内存大堆数据。修改任何一个,另一个的数据也将修改。 直接引用传递测试用例: 1.实体类: 1 package com.test.java; 2 3 import java.io.Serializ
Ryan-Miao
2018/03/13
1.4K0
java中复制对象通过反射或序列化
JavaScript 中的尾调用和优化
本文由 IMWeb 社区授权转载自 css88.com。点击阅读原文查看 IMWeb 社区更多精彩文章。 尾调用(Tail Call) 尾调用是函数式编程里比较重要的一个概念,它的意思是在函数的执行过程中,如果最后一个动作是一个函数的调用,即这个调用的返回值被当前函数直接返回,则称为尾调用,如下所示: function f(x) {  return g(x)} 在 f 函数中,最后一步操作是调用 g 函数,并且调用 g 函数的返回值被 f 函数直接返回,这就是尾调用。而下面这个栗子就不是尾调用: funct
用户1097444
2022/06/29
1.1K0
JavaScript 中的尾调用和优化
【C 语言】文件操作 ( 配置文件读写 | 写出或更新配置文件 | 追加键值对数据 | 更新键值对数据 )
在上一篇博客 【C 语言】文件操作 ( 配置文件读写 | 写出或更新配置文件 | 逐行遍历文件文本数据 | 获取文件中的文本行 | 查询文本行数据 | 追加文件数据 | 使用占位符方式拼接字符串 ) 中 , 介绍了 逐行 遍历查询 文本文件中的键值对信息 ;
韩曙亮
2023/03/30
7260
[译] ES6中的尾调用优化
原文:http://exploringjs.com/es6/ch_tail-calls.html
江米小枣
2020/06/16
9490
[译] ES6中的尾调用优化
JS 调用栈机制与 ES6 尾调用优化介绍
调用栈的英文名叫做Call Stack,大家或多或少是有听过的,但是对于js调用栈的工作方式以及如何在工作中利用这一特性,大部分人可能没有进行过更深入的研究,这块内容可以说对我们前端来说就是所谓的基础知识,咋一看好像用处并没有很大,但掌握好这个知识点,就可以让我们在以后可以走的更远,走的更快!
OBKoro1
2019/05/21
8900
js 调用栈机制与ES6尾调用优化介绍
本文中提到的链接,因为微信的限制,没有显示出来,查看文中链接,需要点击最下方的阅读原文链接
OBKoro1
2020/10/27
7030
js 调用栈机制与ES6尾调用优化介绍
一个尾调用相关的诡异报错信息
看上去这就是一道送分题啊:无非就是 test 函数的第一个参数类型应该是 string,实际传递的却是 userdata。就当我觉得可以轻而易举解决问题的时候,突然发现 test 函数定义就没有参数,调用的时候也没传参数,真是太诡异了。
LA0WAN9
2021/12/14
8460
Python追加Excel追加数据
前面我分享了 Excel 的读写:Python 实现 Excel 的读写操作:https://bornforthis.cn/column/pyauto/auto_base05.html
AI悦创
2022/07/17
2.9K0
python twisted callLater 调用序列
from twisted.internet import reactor import time
用户5760343
2022/05/14
2830
python twisted callLater 调用序列
python写文件追加 按行追加_python 追加写入
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
全栈程序员站长
2022/11/07
3.6K0
Thinking Above Code:TLA+ 思维概述
本文是《Thinking Above Code:TLA+ 从入门到实践》系列文章第一篇。
深度学习与Python
2021/12/10
6380
Thinking Above Code:TLA+ 思维概述

相似问题

UCanAccess调用保存的追加、更新或删除查询

10

TLA+中序列元素和集合元素的比较

10

尾递归调用尾递归

24

Kotlin -A函数被标记为尾递归,但没有发现尾调用。

27

如何实现尾递归列表追加?

31
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文