欢迎光临
我们一直在努力

DeepSeek解读用TypeScript的类型求解数独的代码

在网上看到一个用TypeScript的类型求解数独的代码。 但是我按照TypeScript的编译执行过程,没有任何输出。而执行app.ts编译后的js文件是有输出的。

export PATH=$PATH:/mnt/c/d/node-v24.4.1-linux-x64/bin

npm config set registry https://registry.npmmirror.com
npm install -g typescript

added 1 package in 17s
tsc -v
Version 5.9.3
cd ../..
tsc app.ts
node app.js
Hello World

tsc sudoku2.ts

于是询问DeepSeek:

怎么执行typescript程序,我对附件执行tsc sudoku2.ts得到一个sudoku2.js,但里面只有一行注释//type Answer3 = Solve;

他的解答如下:

这是因为你的 TypeScript 代码完全是在类型层面(type level)运行的,而不是在值层面。你使用的是 TypeScript 的类型系统本身来“计算”数独的解,而不是编写运行时的 JavaScript 代码。

让我们来解释一下:

你的代码做了以下事情:

  • 定义了 Digit、Problem 等类型
  • 使用 ToRow、ToColumn、ToSquare 等类型将数独问题转换为类型约束
  • 通过 Solve 类型进行递归类型计算来求解数独
  • 最后定义了 Answer1、Answer2、Answer3 等类型(不是值)
  • 如何看到结果?

    由于这是类型计算,你需要通过 TypeScript 编译器来查看类型推断的结果。有几种方法:

    方法1:使用编辑器/IDE

    在 VSCode 或其他支持 TypeScript 的编辑器中,将鼠标悬停在 Answer1 或 Answer2 上,你会看到类型推导的结果。

    方法2:创建类型检查文件

    创建一个测试文件来查看结果:

    // test.ts
    import type { Answer1, Answer2 } from './sudoku2';

    // 创建一个错误来查看类型
    type ShowAnswer1 = Answer1; // 将鼠标悬停在这里看结果
    type ShowAnswer2 = Answer2;

    // 或者故意制造类型错误来查看
    const a1: Answer1 = [];
    // 错误信息会显示 Answer1 的实际类型

    方法3:使用 tsc –showConfig 或创建接口

    // 在你的 sudoku2.ts 文件末尾添加
    interface Answers {
    answer1: Answer1;
    answer2: Answer2;
    // answer3: Answer3; // 取消注释这个试试
    }

    方法4:使用 TypeScript Playground

    将你的代码复制到 TypeScript Playground 中,然后将鼠标悬停在类型上查看。

    注意:

    • 这种类型层面的计算在编译时完成,不会生成任何 JavaScript 代码
    • Answer3 被注释掉可能是因为这个数独太难,类型递归深度超过了 TypeScript 的限制(默认约 1000 层)
    • 如果你想要一个运行时求解器,你需要编写真正的 JavaScript/TypeScript 函数,而不是使用类型系统

    创建运行时求解器:

    如果你想要一个实际的数独求解器程序,你需要编写类似这样的代码:

    // runtime-solver.ts
    function solveSudoku(board: number[][]): boolean {
    // 实际的回溯算法实现
    // …
    }

    const problem1 = [
    [0, 2, 4, 0, 8, 7, 5, 0, 9],
    // … 其他行
    ];

    solveSudoku(problem1);
    console.log(problem1);

    你当前的代码是一个类型体操(type gymnastics)的练习,展示了 TypeScript 类型系统的强大,但不是用来实际运行的。

    我将代码复制到 TypeScript Playground,果真点击执行后,把鼠标移动到相应类型上,它就显示了求出的数独解。如下所示

    type Answer1 = [3, 2, 4, 1, 8, 7, 5, 6, 9, 8, 9, 1, 4, 5, 6, 3, 7, 2, 5, 6, 7, 2, 9, 3, 8, 4, 1, 7, 8, 6, 5, 2, 9, 1, 3, 4, 2, 5, 9, 3, 1, 4, 7, 8, 6, 1, 4, 3, 6, 7, 8, 2, 9, 5, 4, 7, 2, 9, 3, 1, 6, 5, 8, 6, 3, 5, 8, 4, 2, 9, 1, 7, 9, 1, 8, 7, 6, 5, 4, 2, 3]

    type Answer2 = [6, 9, 4, 8, 5, 7, 1, 2, 3, 3, 8, 7, 1, 4, 2, 6, 5, 9, 1, 5, 2, 6, 3, 9, 7, 8, 4, 2, 3, 5, 4, 8, 1, 9, 6, 7, 4, 1, 8, 9, 7, 6, 5, 3, 2, 7, 6, 9, 3, 2, 5, 8, 4, 1, 8, 7, 6, 2, 9, 3, 4, 1, 5, 9, 2, 1, 5, 6, 4, 3, 7, 8, 5, 4, 3, 7, 1, 8, 2, 9, 6] | [6, 9, 7, 8, 4, 2, 1, 5, 3, 3, 8, 4, 1, 5, 7, 6, 2, 9, 1, 5, 2, 6, 3, 9, 7, 8, 4, 2, 3, 5, 4, 8, 1, 9, 6, 7, 4, 1, 8, 9, 7, 6, 5, 3, 2, 7, 6, 9, 3, 2, 5, 8, 4, 1, 8, 7, 6, 2, 9, 3, 4, 1, 5, 9, 2, 1, 5, 6, 4, 3, 7, 8, 5, 4, 3, 7, 1, 8, 2, 9, 6]

    type Answer3 = [4, 5, 8, 3, 2, 6, 7, 1, 9, 6, 7, 2, 9, 1, 4, 3, 8, 5, 9, 1, 3, 8, 5, 7, 4, 2, 6, 3, 4, 1, 5, 7, 9, 2, 6, 8, 8, 9, 6, 2, 3, 1, 5, 7, 4, 7, 2, 5, 4, 6, 8, 1, 9, 3, 1, 3, 7, 6, 8, 5, 9, 4, 2, 5, 8, 4, 7, 9, 2, 6, 3, 1, 2, 6, 9, 1, 4, 3, 8, 5, 7]

    虽然没什么实用性,也算增长了typescript方面的见识。

    翻译了注释的代码如下

    // 可用的数字是从1到9
    type Digit = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
    // 空白格子用0表示
    type Empty = 0;

    // 长度为9的元组类型
    type Tuple9<T> = [T, T, T, T, T, T, T, T, T];

    // 长度为81的元组类型
    type Tuple81<T> = [
    Tuple9<T>,
    Tuple9<T>,
    Tuple9<T>,
    Tuple9<T>,
    Tuple9<T>,
    Tuple9<T>,
    Tuple9<T>,
    Tuple9<T>,
    Tuple9<T>
    ];

    // 表示数独问题的类型
    type Problem = Tuple81<Digit | Empty>;

    // 问题示例
    type Problem1 = [
    0, 2, 4, 0, 8, 7, 5, 0, 9,
    8, 9, 1, 4, 5, 6, 3, 7, 2,
    5, 6, 7, 0, 9, 3, 0, 0, 1,
    7, 8, 6, 5, 2, 9, 0, 3, 4,
    2, 0, 0, 3, 1, 0, 0, 0, 0,
    1, 4, 0, 6, 7, 8, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 6, 0, 0,
    0, 3, 0, 0, 0, 0, 0, 1, 0,
    9, 0, 0, 0, 0, 5, 0, 0, 0,
    ];

    // 将元组的索引转换为行号的类型
    type ToRow = [
    0, 0, 0, 0, 0, 0, 0, 0, 0,
    1, 1, 1, 1, 1, 1, 1, 1, 1,
    2, 2, 2, 2, 2, 2, 2, 2, 2,
    3, 3, 3, 3, 3, 3, 3, 3, 3,
    4, 4, 4, 4, 4, 4, 4, 4, 4,
    5, 5, 5, 5, 5, 5, 5, 5, 5,
    6, 6, 6, 6, 6, 6, 6, 6, 6,
    7, 7, 7, 7, 7, 7, 7, 7, 7,
    8, 8, 8, 8, 8, 8, 8, 8, 8
    ];

    // 将元组的索引转换为列号的类型
    type ToColumn = [
    0, 1, 2, 3, 4, 5, 6, 7, 8,
    0, 1, 2, 3, 4, 5, 6, 7, 8,
    0, 1, 2, 3, 4, 5, 6, 7, 8,
    0, 1, 2, 3, 4, 5, 6, 7, 8,
    0, 1, 2, 3, 4, 5, 6, 7, 8,
    0, 1, 2, 3, 4, 5, 6, 7, 8,
    0, 1, 2, 3, 4, 5, 6, 7, 8,
    0, 1, 2, 3, 4, 5, 6, 7, 8,
    0, 1, 2, 3, 4, 5, 6, 7, 8
    ];

    // 将元组的索引转换为3*3分组号的类型
    type ToSquare = [
    0, 0, 0, 1, 1, 1, 2, 2, 2,
    0, 0, 0, 1, 1, 1, 2, 2, 2,
    0, 0, 0, 1, 1, 1, 2, 2, 2,
    3, 3, 3, 4, 4, 4, 5, 5, 5,
    3, 3, 3, 4, 4, 4, 5, 5, 5,
    3, 3, 3, 4, 4, 4, 5, 5, 5,
    6, 6, 6, 7, 7, 7, 8, 8, 8,
    6, 6, 6, 7, 7, 7, 8, 8, 8,
    6, 6, 6, 7, 7, 7, 8, 8, 8
    ];

    type PopValue<T extends Digit[], K extends number, V extends Digit | Empty> = {
    [key in keyof T]: key extends `${K}` ? Exclude<T[key], V> : T[key];
    };

    type RowLimit<
    Board extends Problem,
    Ret extends Tuple9<Digit> = Tuple9<Digit>,
    I extends unknown[] = []
    >
    = I["length"] extends 81
    ? Ret
    : RowLimit<
    Board,
    PopValue<Ret, ToRow[I["length"]], Board[I["length"]]>,
    [I, unknown]
    >;

    type ColumnLimit<
    Board extends Problem,
    Ret extends Tuple9<Digit> = Tuple9<Digit>,
    I extends unknown[] = []
    >
    = I["length"] extends 81
    ? Ret
    : ColumnLimit<
    Board,
    PopValue<Ret, ToColumn[I["length"]], Board[I["length"]]>,
    [I, unknown]
    >;

    type SquareLimit<
    Board extends Problem,
    Ret extends Tuple9<Digit> = Tuple9<Digit>,
    I extends unknown[] = []
    >
    = I["length"] extends 81
    ? Ret
    : SquareLimit<
    Board,
    PopValue<Ret, ToSquare[I["length"]], Board[I["length"]]>,
    [I, unknown]
    >;

    type Solve<
    Board extends Problem,
    Row extends Tuple9<Digit> = RowLimit<Board>,
    Column extends Tuple9<Digit> = ColumnLimit<Board>,
    Square extends Tuple9<Digit> = SquareLimit<Board>,
    Answer extends Digit[] = [],
    L extends number = Answer["length"],
    T = Board[L] extends Empty
    ? Row[ToRow[L]] & Column[ToColumn[L]] & Square[ToSquare[L]]
    : Board[L]
    >
    = L extends 81
    ? Answer
    : T extends Digit
    ? Solve<
    Board,
    PopValue<Row, ToRow[L], T>,
    PopValue<Column, ToColumn[L], T>,
    PopValue<Square, ToSquare[L], T>,
    [Answer, T]
    >
    : never;

    type Answer1 = Solve<Problem1>;

    type Problem2 = [
    0, 0, 0, 0, 0, 0, 0, 0, 3,
    0, 0, 0, 0, 0, 0, 6, 0, 9,
    1, 5, 2, 0, 0, 0, 0, 0, 0,
    2, 3, 0, 4, 8, 0, 0, 0, 0,
    4, 1, 8, 0, 0, 6, 5, 0, 0,
    7, 0, 9, 3, 2, 5, 0, 0, 0,
    8, 0, 6, 0, 9, 3, 4, 1, 0,
    9, 2, 1, 5, 0, 0, 3, 0, 0,
    5, 0, 0, 0, 1, 8, 2, 9, 6
    ];

    type Answer2 = Solve<Problem2>;

    type Problem3 = [
    0, 0, 0, 3, 0, 0, 0, 1, 9,
    6, 7, 0, 0, 0, 4, 0, 0, 0,
    0, 0, 0, 8, 0, 0, 0, 2, 0,
    3, 4, 0, 0, 7, 0, 2, 0, 0,
    0, 0, 6, 0, 3, 1, 5, 0, 0,
    0, 0, 0, 0, 6, 0, 0, 9, 0,
    1, 3, 0, 6, 0, 0, 0, 0, 2,
    0, 0, 4, 7, 0, 0, 6, 0, 0,
    2, 0, 9, 0, 4, 0, 0, 0, 0
    ];

    //type Answer3 = Solve<Problem3>;

    赞(0)
    未经允许不得转载:171主机测评 » DeepSeek解读用TypeScript的类型求解数独的代码
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址