@@ -20,20 +20,20 @@ typed-fsm-zig 是一个利用 zig 类型系统加一些编程规范实现的一
2020
2121它具有以下两点优势:
2222
23- 1 . 类型安全,极大方便代码的编写,修改和重构
24- 手写状态机在实际代码中有很大的心智负担,对于它的修改和重构更是如噩梦一样。
23+ 1 . 类型安全,极大方便代码的编写,修改和重构
24+ 手写状态机在实际代码中有很大的心智负担,对于它的修改和重构更是如噩梦一样。
2525
26- typed-fsm-zig 在类型上跟踪状态机的变化,使消息的定义,产生,处理都和状态相关联,从而让类型系统帮我们检查这个过程中是否存在状态错误。
26+ typed-fsm-zig 在类型上跟踪状态机的变化,使消息的定义,产生,处理都和状态相关联,从而让类型系统帮我们检查这个过程中是否存在状态错误。
2727
28- 在编写,修改和重构的时候,任何状态的错误都会产生编译错误,而这些编译错误能帮助我们快速找到问题,解决问题。
28+ 在编写,修改和重构的时候,任何状态的错误都会产生编译错误,而这些编译错误能帮助我们快速找到问题,解决问题。
2929
30- > PS:推荐在 zls 中打开保存时检查,这样你几乎能得到一个交互式的状态机开发环境。
30+ > PS:推荐在 zls 中打开保存时检查,这样你几乎能得到一个交互式的状态机开发环境。
3131
32- 2 . 简单高效,无任何代码生成,能方便与现有逻辑整合
32+ 2 . 简单高效,无任何代码生成,能方便与现有逻辑整合
3333
34- typed-fsm-zig 是一种编程的思想,掌握这种思想就能方便的使用它。
34+ typed-fsm-zig 是一种编程的思想,掌握这种思想就能方便的使用它。
3535
36- 在实际的使用中没有任何的代码生成,除了一处隐式的约束要求之外,没有任何其它的控制,开发者完全掌握状态机,因此你可以方便的将它和你现有的代码结合起来。
36+ 在实际的使用中没有任何的代码生成,除了一处隐式的约束要求之外,没有任何其它的控制,开发者完全掌握状态机,因此你可以方便的将它和你现有的代码结合起来。
3737
3838# 2. 例子:修改 ATM 状态机的状态
3939
@@ -76,7 +76,7 @@ ATM 代表自动取款机,因此它的代码的逻辑就是模拟自动取款
7676
7777实际的消息 Update 定义代码如下
7878
79- ``` c
79+ ``` zig
8080 pub fn changePinMsg(end: AtmSt) type {
8181 return union(enum) {
8282 Update: struct { v: [4]u8, wit: WitFn(end, .ready) = .{} },
@@ -124,8 +124,8 @@ referenced by:
124124
125125修改之后的代码如下:
126126
127- ``` c
128- @call(.always_tail, cardInsertedHandler, .{ val.wit, ist });
127+ ` ` ` zig
128+ @call(.always_tail, cardInsertedHandler, .{ val.wit, ist });
129129` ` `
130130
131131在这里类型系统精确的告诉了我们需要修改的地方,以及原因。修改完成后程序即能正确运行。
@@ -313,7 +313,7 @@ fn s2Handler(val: Witness(Exmaple, .exit, .s2), ref: *i32) void {
313313
314314当 end == start 时表示当前处于终止状态,因此 Witness 只能使用 terminal 函数,当 end ! = start 时表示当前不处于终止状态,应该继续从外部获取消息,因此 Witness 只能使用 getMsg 函数。
315315
316- ` ` ` c
316+ ` ` ` zig
317317pub fn Witness(T: type, end: T, start: T) type {
318318 return struct {
319319 pub fn getMsg(self: @This ()) @TypeOf(start.STM(end).getMsg) {
@@ -337,7 +337,7 @@ pub fn Witness(T: type, end: T, start: T) type {
337337
338338实际代码中会将消息集合整合在 enum 的内部,使用特殊的命名规范将状态与消息集合对应。目前的隐式规范是在状态后面加上 Msg。
339339
340- ` ` ` c
340+ ` ` ` zig
341341const Exmaple = enum {
342342 exit,
343343 s1,
@@ -359,7 +359,7 @@ const Exmaple = enum {
359359
360360接下来是消息的定义和产生,
361361
362- ` ` ` c
362+ ` ` ` zig
363363// exit 状态下没有任何消息
364364pub fn exitMsg(_: Exmaple) void {
365365 return {};
@@ -406,7 +406,7 @@ pub fn s2Msg(end: Exmaple) type {
406406
407407这些对于代码的编写,修改,重构都有巨大的帮助。
408408
409- ` ` ` c
409+ ` ` ` zig
410410fn s1Handler(val: Witness(Exmaple, .exit, .s1), ref: * i32) void {
411411 std.debug.print(" val: {d}\n" , .{ref.* });
412412 switch (val.getMsg()(ref)) {
@@ -432,19 +432,19 @@ fn s2Handler(val: Witness(Exmaple, .exit, .s2), ref: *i32) void {
432432
433433# 4. typed-fsm-zig 需要哪些编程规范
434434
435- # # 1. 状态和消息集合之间需要满足的隐式命名规范
435+ 1. 状态和消息集合之间需要满足的隐式命名规范
436436
437- 以 ATM 为例:
437+ 以 ATM 为例:
438438
439- exit -- exitMsg
439+ exit -- exitMsg
440440
441- ready -- readyMsg
441+ ready -- readyMsg
442442
443- cardInserted -- cardInsertedMsg
443+ cardInserted -- cardInsertedMsg
444444
445- session -- sessionMsg
445+ session -- sessionMsg
446446
447- ` ` ` c
447+ ` ` ` zig
448448
449449const AtmSt = enum {
450450 exit,
@@ -492,15 +492,15 @@ const AtmSt = enum {
492492};
493493` ` `
494494
495- # # 2. 除了 exit 状态外,其它消息需要包含 genMsg 函数用于产生消息,任何消息都必须带有 Witness
495+ 2. 除了 exit 状态外,其它消息需要包含 genMsg 函数用于产生消息,任何消息都必须带有 Witness
496496
497- # # 3. 状态机都需要定义退出状态,尽管你可能永远也不会退出状态机,但退出状态作用于类型上,是不可缺少的
497+ 3. 状态机都需要定义退出状态,尽管你可能永远也不会退出状态机,但退出状态作用于类型上,是不可缺少的
498498
499- # # 4. 在互相调用其它 handler 的时候使用尾递归的语法,并且在必须在语句块最后处理消息附带的 Witness
499+ 4. 在互相调用其它 handler 的时候使用尾递归的语法,并且在必须在语句块最后处理消息附带的 Witness
500500
501501由于 zig 的实现缺少 Mcbride Indexed Monad 语义的支持,因此类型系统不能阻止你进行下面的操作:
502502
503- ` ` ` c
503+ ` ` ` zig
504504
505505// 使用上面 Example 的处理函数 s1Handler, 将它修改成下面的样子。
506506// 这里的 s1Handler 不应该被多次调用,在 haskell 版本的 typed-fsm 中,类型系统能检查出这里类型错误,但是在 zig 实现中无法做到,
@@ -525,7 +525,7 @@ fn s2Handler(val: Witness(Exmaple, .exit, .s2), ref: *i32) void {
525525
526526在实际的 ATM 例子中他们的调用方式是:
527527
528- ` ` ` c
528+ ` ` ` zig
529529pub fn readyHandler(comptime w: AtmSt.EWitness(.ready), ist: * InternalState) void {
530530 switch (w.getMsg()()) {
531531 .ExitAtm => | witness| {
0 commit comments