Sudoku Checker in Rust Type System!🦀

181 points saqulium 19 comments

NOTE: This post is Re-Re-Post, I missed title (Changed "Solver" -> "Checker").
Sorry........................

Hi, I'm a beginner Rustacean who recently started learning Rust after coming from Python!

I've been truly impressed by how enjoyable writing Rust is. It's genuinely reignited my passion for programming.

Speaking of powerful type systems, I think many of us know TypeScript's type system is famous for its (sometimes quirky but) impressive expressiveness. I recently stumbled upon an experimental project called typescript-sudoku, which implements a Sudoku Checker using only its type system.

it got me thinking: Could I do something similar to leverage Rust's Types for Sudoku?🦀

And I'm excited to share that I managed to implement a Sudoku checker using Rust's type system!

My Repositry is here: https://github.com/S4QuLa/sudoku-type-rs

trait IsDiffType<T, U> {}
impl IsDiffType<_1, _2> for () {}
impl IsDiffType<_1, _3> for () {}
impl IsDiffType<_1, _4> for () {}
/* ... */
impl IsDiffType<__, _7> for () {}
impl IsDiffType<__, _8> for () {}
impl IsDiffType<__, _9> for () {}

trait AreDiffTypeParams<T1, T2, T3, T4, T5, T6, T7, T8, T9> {}
impl<T1, T2, T3, T4, T5, T6, T7, T8, T9> AreDiffTypeParams<T1, T2, T3, T4, T5, T6, T7, T8, T9> for ()
where
    (): IsDiffType<T1, T2> + IsDiffType<T1, T3> + IsDiffType<T1, T4> + IsDiffType<T1, T5> + IsDiffType<T1, T6> + IsDiffType<T1, T7> + IsDiffType<T1, T8> + IsDiffType<T1, T9>,
    (): IsDiffType<T2, T3> + IsDiffType<T2, T4> + IsDiffType<T2, T5> + IsDiffType<T2, T6> + IsDiffType<T2, T7> + IsDiffType<T2, T8> + IsDiffType<T2, T9>,
    (): IsDiffType<T3, T4> + IsDiffType<T3, T5> + IsDiffType<T3, T6> + IsDiffType<T3, T7> + IsDiffType<T3, T8> + IsDiffType<T3, T9>,
    (): IsDiffType<T4, T5> + IsDiffType<T4, T6> + IsDiffType<T4, T7> + IsDiffType<T4, T8> + IsDiffType<T4, T9>,
    (): IsDiffType<T5, T6> + IsDiffType<T5, T7> + IsDiffType<T5, T8> + IsDiffType<T5, T9>,
    (): IsDiffType<T6, T7> + IsDiffType<T6, T8> + IsDiffType<T6, T9>,
    (): IsDiffType<T7, T8> + IsDiffType<T7, T9>,
    (): IsDiffType<T8, T9>,
{}

The version written using stable Rust defines structs for numbers 1-9 and an empty cell. Then, I implemented an IsDiffType trait for all differing pairs of these types. After that, it's basically a brute-force check of all the rules across the board. :)

"the trair `IsDiffType<_9, _9>` is not implemented"

The compiler flagging errors when rules are violated is a given, but it's amazing how helpful the Rust compiler's error messages are, even for something like a type-level Sudoku checker!

I've also created a couple of other versions using unstable features:

  • One uses const generics to support primitive integer types.
  • Another uses specialization for a more elegant implementation of the IsDiffType trait.

I hope this demonstrates that Rust's type system isn't just about safety, but also offers remarkable expressiveness for tasks like validation!

Next: DOOM by Rust Type?