From a35d6584b3cdd2497887dfb5cd518205e6dc1328 Mon Sep 17 00:00:00 2001 From: ultraman <1394466835@qq.com> Date: Thu, 22 Aug 2024 16:52:05 +0800 Subject: [PATCH] update --- 2024/08/ts_type_system_rule110.md | 201 ++++++++++++++++++++++++++++++ README.md | 1 + 2 files changed, 202 insertions(+) create mode 100644 2024/08/ts_type_system_rule110.md diff --git a/2024/08/ts_type_system_rule110.md b/2024/08/ts_type_system_rule110.md new file mode 100644 index 0000000..0ff5190 --- /dev/null +++ b/2024/08/ts_type_system_rule110.md @@ -0,0 +1,201 @@ + +#typescript + +## TS Conditional Types 介绍 + +去了解[ts中的conditional types](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html) +会发现extend,infer语法,很好理解extend用于判断类型是什么,然后结合`? :`做逻辑 +例如, + +```ts +type Test = T extends any[] ? 1 : 2; + +// 如果T是数组类型,则返回1,否则返回2; + +let x: Test = 1; // x的类型是1 +let y: Test = 2; // y的类型是2 + +``` + +那么如果T是数组怎么获得T里的元素类型?是string还是number + +```ts +type Test = T extends any[] ? T[number] : never; + +// ERROR: x类型应该是string +// Type 'number' is not assignable to type 'string'. +// let x: Test = 1; + +let x: Test = "1"; + + + +``` + +还可以使用infer语法 + +```ts +type Test = T extends Array ? E : never; + +let x: Test = "1"; + +``` + +有什么用?对于数组可能有`T[number]`访问元素的方法,但是如果是别的复杂类型呢? + +好了简单介绍完,来看几个典型函数式编程中的函数实现。 + +### Tail + +对一个数组,取排除第一个元素后的元素集合。 + +```ts +type Tail> = Lst extends [infer head, ...infer Rest] + ? Rest + : never; + +var x: Tail<[1, 2, 3]> = [2, 3]; +``` + +### Head + +取数组每一个元素。 + +```ts +type Head> = Lst extends [infer head, ...infer Rest] + ? head + : never; + +var y: Head<["a", "b", "c"]> = "a"; + +``` + +### Cons + +向数组头部添加元素。 + +```ts +type Cons> = [E, ...Lst]; + +var z: Cons<1, [1, 1]> = [1, 1, 1]; + +``` + +### Reverse + +```ts +type Reverse< + Lst extends Array, + Acc extends Array = [] +> = Lst extends [] ? Acc : Reverse, Cons>; + +var a: Reverse<[1, 2, 3]> = [3, 2, 1]; +``` + +## Rule110 + +[Wiki](https://en.wikipedia.org/wiki/Rule_110) + +### 什么是Rule110? + +Rule 110 是一种著名的一维元胞自动机规则,由数学家斯蒂芬·沃尔夫拉姆(Stephen Wolfram)在他的研究中提出。元胞自动机是一种离散数学模型,规则110属于其中的一维元胞自动机类别。 + +在一维元胞自动机中,每个单元(称为元胞)处于有限数量的状态之一(通常是0或1),并且根据与相邻元胞的状态及一个预定的规则进行状态更新。Rule 110具体规定了在一维数组中,每个元胞在下一时刻的状态是由它当前的状态以及其左邻和右邻元胞的状态共同决定的。 + +具体来说,Rule 110的更新规则如下表所示(当前状态表示当前元胞和它左右两个邻居的状态,下一状态表示该元胞下一时刻的状态): + +| 当前状态 (左邻, 自身, 右邻) | 下一状态 | +| --------------------------- | -------- | +| 111 | 0 | +| 110 | 1 | +| 101 | 1 | +| 100 | 0 | +| 011 | 1 | +| 010 | 1 | +| 001 | 1 | +| 000 | 0 | + +Rule 110因其复杂性和行为特性而广受关注。尽管规则本身看似简单,但它展示了复杂的演化行为,并且已经被证明是图灵完备的(即它可以模拟任何计算机的计算过程)。 + +### 实现 + +用TS类型系统实现,很方便的在编译时刻计算出结果,不是。 + +```ts +// 建立Rul110表 +type Cell = 0 | 1; +type Rule110 = { + "000": 0; + "001": 1; + "010": 1; + "011": 1; + "100": 0; + "101": 1; + "110": 1; + "111": 0; +}[`${X}${Y}${Z}`]; + +// 根据State生成下一个State,第一个元素不变 +type NextState> = State extends [ + infer X extends Cell, + ...infer Reset extends Array +] + ? [X, ...Next] + : []; + +type Next> = Lst extends [ + infer Y extends Cell, + infer Z extends Cell, + ...infer Rest extends Array +] + ? [Rule110, ...Next] + : Lst extends [infer Y extends Cell] + ? [Y] + : []; + +// 执行N次,返回包含N个State的数组 +type GenNTime, State extends Array> = N extends [] + ? [] + : [State, ...GenNTime, NextState>]; + +type N = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; +type InitState = [0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0]; + +let k: GenNTime = 69; + +``` + +### 运行 + +```sh +$ make run +npm install + +up to date, audited 3 packages in 716ms + +found 0 vulnerabilities +./node_modules/typescript/bin/tsc -noErrorTruncation rule110.ts | sed 's/\[/\n[/g' +rule110.ts(63,5): error TS2322: Type 'number' is not assignable to type ' +[InitState, +[0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0], +[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0], +[0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0], +[0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0], +[0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0], +[0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0], +[0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0], +[0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0], +[0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0], +[0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0], +[0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0], +[0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0], +[0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0]]'. +``` + +[Full Code](https://github.com/Ysoding/ts-type-system) + +## References + +[I Wrote Superhuman Code By Hands - YouTube](https://www.youtube.com/watch?v=6DEr82sj4zM&t=2623s) +[🌳 A tiny language interpreter implemented purely in TypeScript's type-system](https://github.com/ronami/typelang) +[rule110.ts](https://gist.github.com/rexim/7c966737e9a2737c7e17bdfc97ebc43a) diff --git a/README.md b/README.md index ad16e3b..515c53e 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ The best thing to do is have fun. - [Hobby Projects](/hobby_projects.md) - **2024-08** + - [用ts类型系统,实现Rule110(在编译时生成)](/2024/08/ts_type_system_rule110.md) - [Raylib CGo Demo](/2024/08/raylib_cgo_demo.md) - [Vscode/ssh配置远程服务器图形化](/2024/08/vscode_ssh_graph_configure.md) - [Ros2环境搭建](/2024/08/ros2_dev_environment.md)