在有健忘症的情况下用 Rust 写快速排序

一觉醒来,我忘记了 Rust 中的绝大部分关键字

一觉醒来,我忘记了 Rust 中的绝大部分关键字。我忘记了所有的整数类型,忘记了它们之间的大小关系,忘记了数组,忘记了布尔类型,忘记了 if,忘记了循环…我还能写出快速排序算法吗?

首先定义自然数:

1#[derive(Debug, Clone)]
2enum Nat {
3    Zero,
4    Succ(Box<Nat>)
5}

接着定义自然数列表:

1#[derive(Debug, Clone)]
2enum List {
3    Nil,
4    Cons(Nat, Box<List>)
5}

排序需要知道自然数之间的大小关系。定义布尔类型:

1#[derive(Debug)]
2enum Bool {
3    True,
4    False
5}

从而可以定义自然数上的序:

 1fn le(a: &Nat, b:&Nat) -> Bool {
 2    match (a, b) {
 3        (Nat::Zero, _) => Bool::True,
 4        (_, Nat::Zero) => Bool::False,
 5        (Nat::Succ(a), Nat::Succ(b)) => le(a, b)
 6    }
 7}
 8
 9fn gt(a: &Nat, b:&Nat) -> Bool {
10    match (a, b) {
11        (Nat::Zero, Nat::Zero) => Bool::False,
12        (Nat::Zero, _) => Bool::False,
13        (_, Nat::Zero) => Bool::True,
14        (Nat::Succ(a), Nat::Succ(b)) => gt(a, b)
15    }
16}

接着定义列表上的常用操作。由于模式匹配,我甚至不需要 carcdr

 1fn append(a: &List, b: &List) -> List {
 2    match a {
 3        List::Nil => b.clone(),
 4        List::Cons(n, l) => List::Cons(n.clone(), Box::new(append(l, b)))
 5    }
 6}
 7
 8fn filter(a: &List, f: &dyn Fn(&Nat) -> Bool) -> List {
 9    match a {
10        List::Nil => List::Nil,
11        List::Cons(n, l) => {
12            match f(n) {
13                Bool::True => List::Cons(n.clone(), Box::new(filter(l, f))),
14                Bool::False => filter(l, f)
15            }
16        }
17    }
18}

终于,我能写出快速排序了:

 1fn quick_sort(a: &List) -> List {
 2    match a {
 3        List::Nil => List::Nil,
 4        List::Cons(pivot, lst) => {
 5            let f = |x: &Nat| le(x, pivot);
 6            let g = |x: &Nat| gt(x, pivot);
 7            let l = filter(lst, &f);
 8            let r = filter(lst, &g);
 9            let sorted_l = quick_sort(&l);
10            let sorted_r = quick_sort(&r);
11            append(&sorted_l, &List::Cons(pivot.clone(), Box::new(sorted_r)))
12        }
13    }
14}

这时候,我突然想起了什么是 u32,什么是 Vec。写一段互相转换的代码:

 1fn u32_to_nat(n: u32) -> Nat {
 2    match n {
 3        0 => Nat::Zero,
 4        _ => Nat::Succ(Box::new(u32_to_nat(n - 1)))
 5    }
 6}
 7
 8fn nat_to_32(n: Nat) -> u32 {
 9    match n {
10        Nat::Zero => 0,
11        Nat::Succ(prev) => nat_to_32(*prev) + 1
12    }
13}
14
15fn array_to_list(a: &[u32]) -> List {
16    match a {
17        [] => List::Nil,
18        [x, xs @ ..] => List::Cons(u32_to_nat(*x), Box::new(array_to_list(xs)))
19    }
20}
21
22fn list_to_array(l: &List) -> Vec<u32> {
23    match l {
24        List::Nil => vec![],
25        List::Cons(n, l) => {
26            let mut v = list_to_array(l);
27            v.insert(0, nat_to_32(n.clone()));
28            v
29        }
30    }
31}

测试一下我们的快速排序吧!

1fn main() {
2    let l = vec![5, 4, 3, 2, 1, 0, 1, 2, 3];
3    let sorted = quick_sort(&array_to_list(&l));
4    println!("{:?}", list_to_array(&sorted));
5}
    Running `target/debug/forgot`
[0, 1, 1, 2, 2, 3, 3, 4, 5]