Skip to content

Commit 379a2c0

Browse files
committed
README
1 parent 4f31a02 commit 379a2c0

File tree

2 files changed

+40
-27
lines changed

2 files changed

+40
-27
lines changed

README.org

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,16 @@
2323
#+begin_quote
2424
Zig Chinese Community is dedicated to sharing and spreading the use of Zig language among Chinese users.
2525
#+end_quote
26+
27+
本网站使用 [[https://gohugo.io/][hugo]](extended 版本)与 [[https://www.docsy.dev/][docsy]] 主题进行构建, =hugo serve= 可进行本地预览。
28+
#+begin_src bash
29+
# For macOS
30+
brew install hugo
31+
# For Debian
32+
sudo apt install hugo
33+
# For Arch
34+
sudo pacman -S hugo
35+
36+
# Snap
37+
sudo snap install hugo
38+
#+end_src

content/post/2024-11-26-typed-fsm.md

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -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
317317
pub 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
341341
const Exmaple = enum {
342342
exit,
343343
s1,
@@ -359,7 +359,7 @@ const Exmaple = enum {
359359
360360
接下来是消息的定义和产生,
361361
362-
```c
362+
```zig
363363
// exit 状态下没有任何消息
364364
pub fn exitMsg(_: Exmaple) void {
365365
return {};
@@ -406,7 +406,7 @@ pub fn s2Msg(end: Exmaple) type {
406406
407407
这些对于代码的编写,修改,重构都有巨大的帮助。
408408
409-
```c
409+
```zig
410410
fn 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

449449
const 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
529529
pub fn readyHandler(comptime w: AtmSt.EWitness(.ready), ist: *InternalState) void {
530530
switch (w.getMsg()()) {
531531
.ExitAtm => |witness| {

0 commit comments

Comments
 (0)