本文已参与「新人创作礼」活动,一起开启掘金创作之路。
范例一:三位二进制转十进制
代码:
-- 将布尔结果转换为数值,true为1,false为0
function ToBit(b: bool) returns (n: int) ;
let
n = if b then 1 else 0 ;
tel
-- 主函数,将输入的布尔值转换为数值
-- 输入参数:b2代表第三位,b1代表第二位,b0代表第一位
-- 输出参数:n表示转换的结果
node ToInt(b2, b1, b0: bool) returns (n: int) ;
let
n = 4 * ToBit(b2) + 2 * ToBit(b1) + ToBit(b0) ;
tel
Simulate执行结果:
范例二:递减计数器
----------------------------------------------------------------------
-- 如果输入的Restart的值为true,则返回输入的Time的值
-- 否则判断前一时刻返回值Ctr是否大于0
-- 如果Ctr大于0,则返回上一时刻返回值-1后的值
-- 否则返回上一时刻返回值
----------------------------------------------------------------------
node DownCounter( Time : int; Restart : bool ) returns ( Ctr : int );
let
Ctr = Time -> if Restart then Time
else if (pre Ctr) > 0 then (pre Ctr) - 1
else pre Ctr;
tel
Simulate执行结果:
范例三:两个互不影响的递减计数器
代码:
node DownCounter( Time : int; Restart : bool ) returns ( Ctr : int );
let
Ctr = Time -> if Restart then Time
else if (pre Ctr) > 0 then (pre Ctr) - 1
else pre Ctr;
tel
node DownCounters( Time1,Time2 : int; Restart : bool )
returns ( Ctr1,Ctr2 : int );
let
Ctr1 = DownCounter(Time1,Restart);
Ctr2 = DownCounter(Time2,Restart);
tel
Simulate执行结果:
范例四:按递增顺序,依次在每个时刻输出,大于初始时刻输入值的偶数
代码:
node Even(N: int) returns (B: bool);
let
B = (N mod 2 = 0);
tel
node EvensFrom (X: int) returns (E: int);
let
-- 这里注意一下,初始时刻,执行E = if Even(X) then X + 2 else X + 1,以后的时刻,执行的都是E = (pre E) + 2
E = (if Even(X) then X + 2 else X + 1) -> (pre E) + 2;
tel
Simulate执行结果:
EvensFrom的输出结果E只与上一时刻的E有关,而初始时刻的E只与初始时刻的输入X有关,因此,任意时刻的E都由初始时刻的X决定,而与以后时刻的X无关
范例五:从0开始计算每一个数的阶乘
代码:
node fact(_ : bool) returns (F: int);
var N: int;
let
-- 数字从0开始进行阶乘,后面逐一加一
N = 0 -> (pre N) + 1;
-- 0的阶乘为0,因此阶乘结果从1开始,以后逐一乘前一时刻的数值
F = 1 -> N * (pre F);
tel
Simulate执行结果:
当我们不需要结点的输入值时,我们用_ : bool来表示一个没有意义的输入,哪怕我们在Simulate的运行面板里面填写了true或false,对结点的运行也不会有任何影响
范例六:斐波纳契
node Fibonacci(_:bool) returns(Fib: int);
let
Fib = 1 -> pre (1 -> Fib + pre Fib);
tel
Simulate执行结果:
因为用到了较多的pre和->,不易理解,下面对语句进行拆分解释
- Fib在时间轴上的序列为:1,1,2,3,5,8,13,21,...
- pre Fib在时间轴上的序列为:0,1,1,2,3,5,8,13,21,...
- Fib + pre Fib在时间轴上的序列为:1,2,3,5,8,13,21,...
- 1 -> Fib + pre Fib表示初始时刻的值为1,以后时刻的值为Fib + pre Fib,在时间轴上的序列为:1,2,3,5,8,13,21,...
- pre (1 -> Fib + pre Fib)表示当前时刻的1 -> Fib + pre Fib的值的前一个值,如果是初始时刻,则为0或false,在时间轴上的序列为:0,1,2,3,5,8,13,21,...
- Fib = 1 -> pre (1 -> Fib + pre Fib)表示初始时刻的值为1,以后时刻的值为pre (1 -> Fib + pre Fib),在时间轴上的序列为:1,1,2,3,5,8,13,21,...
范例七:开关按钮
问题描述:Set为ture表示开,Reset为ture表示关,Init只在初始时刻起作用
代码
node Switch( Set, Reset, Init : bool ) returns ( X : bool );
let
X = if Set then true
else if Reset then false
else (Init -> pre X);
tel
Simulate执行结果:
这里解释一下else (Init -> pre X)这段代码:Init -> pre X表示Time=0的时候,如果执行这段代码,结果为Init的值,其余时刻,执行这段代码,结果为pre X的值。重点注意,时TIme=0,而不是第一次执行,就是Time=0的时候如果没有执行到else (Init -> pre X),那么,以后执行到这里时,都是执行pre X,不再执行Init。
范例八:验证开关按钮代码
node Switch( Set, Reset, Init : bool ) returns ( X : bool );
let
X = if Set then true
else if Reset then false
else (Init -> pre X);
tel
node SwitchReq( Set, Reset, Reset2, Init : bool )
returns ( R1, R2, R3, R4 : bool ) ;
var X : bool;
let
-- 调用开关按钮,将结果赋值给X
-- X中文表示为开关是否打开,ture为开,false为关
X = Switch( Set, Reset, Init ) ;
-- 验证在任一时刻,如果Set的值为true,那么X的值也为true
-- 如果 Set => X的结果为true,表示式子有效,--%PROPERTY R1的结果为valid
-- 如果 Set => X的结果为false,表示式子无效,--%PROPERTY R1的结果为falsevalid
-- R1的式子应该是有效的,因为当我们按下打开按钮时,开关会被打开
R1 = Set => X ;
-- 验证在任一时刻,如果Set的值不为true且Reset的值为true,那么X的值也不为true
R2 = (not Set and Reset) => not X ;
-- 验证在任一时刻,如果Set的值不为true且Reset的值不为true,那么X的值等于上一时刻的X的值
R3 = true -> ((not Set and not Reset) => X = pre X) ;
-- 验证在任一时刻,如果Set的值为true,那么Switch(Set, Reset, Init)和Switch(Set, Reset2, Init)相同
R4 = Set => Switch(Set, Reset, Init) = Switch(Set, Reset2, Init) ;
--%MAIN;
--%PROPERTY R1;
--%PROPERTY R2;
--%PROPERTY R3;
--%PROPERTY R4;
tel
Check验证结果:
范例九:交通灯
问题描述:
- 按钮规则:初始状态,绿色信号灯亮起(Green的值为true);按下按钮(Button的值为true),当前时刻,黄色信号灯亮起(Yellow的值为true),下一时刻,红色信号灯亮起(Red的值为true),十个时刻之后,绿色信号灯一直保持亮起状态。
- 行人是否可以通行规则:
- 当绿色或黄色的信号灯亮起的所有时刻,行人不可以通行(DontWalk的值为true)
- 当绿色的信号灯在下一时刻将要亮起时,当前时刻,行人不可以通行(DontWalk的值为true)
- 当红色的信号灯刚刚亮起时,当前时刻,行人不可以通行(DontWalk的值为true)
- 当红色的信号灯刚刚亮起时,下一时刻,行人可以通行(Walk的值为true)
代码:
node TrafficLight( Button: bool )
returns ( Red, Yellow, Green, Walk, DontWalk: bool );
var Phase, prePhase: int;
let
prePhase = 0 -> pre Phase;
Phase = if Button then
1
else if 0 < prePhase and prePhase < 10 then
prePhase + 1
else
0;
Green = Phase = 0;
Yellow = Phase = 1;
Red = Phase > 1;
Walk = Phase > 2 and Phase < 10;
DontWalk = not Walk;
tel
Simulate执行结果:
- 我们可以看到,在Time=3的时刻,输入的Button的值为true,此时信号灯Yellow的值变为true,然后下一时刻,信号灯Red的值变为true,直到Time=13的时刻,信号灯Green的值变为true
- 回到题目中的四个时刻:
- Time = 0-3和13-29:当绿色或黄色的信号灯亮起的所有时刻,行人不可以通行(DontWalk的值为true)
- Time = 12:当绿色的信号灯在下一时刻将要亮起时,当前时刻,行人不可以通行(DontWalk的值为true)
- Time = 4:当红色的信号灯刚刚亮起时,当前时刻,行人不可以通行(DontWalk的值为true)
- Time = 4:当红色的信号灯刚刚亮起时,下一时刻,行人可以通行(Walk的值为true)
范例十:验证交通灯代码
代码:
node TrafficLight( Button: bool )
returns ( Red, Yellow, Green, Walk, DontWalk: bool );
var Phase, prePhase: int;
let
prePhase = 0 -> pre Phase;
Phase = if Button then
1
else if 0 < prePhase and prePhase < 10 then
prePhase + 1
else
0;
Green = Phase = 0;
Yellow = Phase = 1;
Red = Phase > 1;
Walk = Phase > 2 and Phase < 10;
DontWalk = not Walk;
tel
node ReqTrafficLight( Button : bool )
returns (R1, R2, R3, R4, R5, R6, R7, R8, R9, R10: bool);
var CarsAllowed, Red, Yellow, Green, Walk, DontWalk : bool;
let
-- 根据按钮Button是否被按下,获取信号灯和能否通行的值
(Red, Yellow, Green, Walk, DontWalk) = TrafficLight(Button);
-- CarsAllowed表示车辆是否可以通行
CarsAllowed = Green or Yellow;
-- Walk是根据Phase的值获取的,表示行人是否可以通行
-- CarsAllowed是根据信号灯的值获取的,表示车辆是否可以通行
-- 因为按照规则,在任一时刻,行人和车辆不允许同时通行的
-- 所以我们用R1来验证代码是否符合这一规则
-- 如果验证结果为valid,则表示代码符合这一规则
R1 = not (CarsAllowed and Walk);
-- R2验证在任一时刻,红灯和绿灯不可能会同时出现
-- 只要R2的结果为ture,那就表示没有同时出现
-- 按照规则他们是不可以同时出现的
-- 如果验证结果为valid,则表示代码符合这一规则
R2 = not (Red and Green);
-- R3验证在任一时刻,至少一个信号灯会一直显示
-- 如果验证结果为valid,则表示代码符合这一规则
-- 要注意,R3并不能证明只有一个信号灯会一直显示,多个信号灯同时显示的话,R3也为true
R3 = Red or Yellow or Green;
-- R4验证在任一时刻,当行人可以通行时,红色信号灯一定是亮的
-- 验证结果应该为valid
R4 = Walk => Red;
-- R5验证在任一时刻,行人可以通行和不可以通行的情况是否没有可能同时出现
-- 验证结果应该为valid
R5 = Walk xor DontWalk;
-- R6验证在任一时刻,都不满足,当前时刻红灯亮且前一时刻绿灯亮
-- 验证结果应该为valid
R6 = true -> not (Red and pre Green);
-- R7验证在任一时刻,都不满足,当前时刻行人可以通行且前一时刻车辆可以通行
-- 验证结果应该为valid
R7 = true -> not (Walk and pre CarsAllowed);
-- R8验证在任一时刻,都不满足,当前时刻车辆可以通行且前一时刻行人可以通行
-- 验证结果应该为falsifiable
-- 因为在行人可以通行的一个时刻,是车辆和行人均不可通行的时刻
R8 = true -> not (CarsAllowed and pre Walk);
-- R9验证在任一时刻,都不满足,当前时刻和前一时刻黄色信号灯都在亮
-- 验证结果应该为falsifiable
-- 因为如果连续两个时刻按下按钮(Button的值为true),则此时当前时刻和前一时刻黄色信号灯都在亮
R9 = true -> not (Yellow and pre Yellow);
-- R10验证在任一时刻,都满足,只要前一时刻红色信号灯在亮且当前时刻红色信号灯不亮
-- 则当前时刻绿色信号灯就会亮
-- 验证结果应该为falsifiable
-- 因为前一时刻红色信号灯在亮,当前时刻红色信号灯不亮
-- 如果当前时刻按下按钮,亮的也可能是黄色信号灯
R10 = true -> (pre Red and not Red) => Green;
--%MAIN;
--%PROPERTY R1;
--%PROPERTY R2;
--%PROPERTY R3;
--%PROPERTY R4;
--%PROPERTY R5;
--%PROPERTY R6;
--%PROPERTY R7;
--%PROPERTY R8;
--%PROPERTY R9;
--%PROPERTY R10;
tel
Check验证结果: