2个版本
0.1.1 | 2023年5月12日 |
---|---|
0.1.0 | 2023年5月11日 |
#36 in #meta-programming
24 每月下载量
用于 junglefowl
8KB
77 行
Junglefowl
一次证明就残酷地谋杀Rust的类型系统。
Junglefowl在Rust类型上运行Peano算术,编译时验证。
为什么?
因此我们可以做理论上很难的事情,比如这些const泛型切片
use junglefowl::*;
// Accept only `u8` arrays with exactly 3 elements:
fn picky<T: Nest<Element = u8, Length = peano!(3)>>(_: &T) {}
// Create an array with 5 elements:
let n12345 = nest![1, 2, 3, 4, 5];
// Split it after its second element without changing anything in memory:
let (left, right) = split!(n12345, 2);
// And we can prove that the second segment will have exactly two elements:
picky(&right);
// picky(&left); // won't compile!
// And know exactly what its elements are:
assert_eq!(nest![3, 4, 5], right);
怎么做?
这是我们Peano编码
0 <--> ()
1 <--> ((), ())
2 <--> ((), ((), ()))
3 <--> ((), ((), ((), ())))
注意,多亏了Rust语法的巧妙滥用,这些既是类型也是值。
接下来有一个宏,让你忘记你刚才读到的内容
peano!(0);
--> ()
peano!(42);
--> ((), ((), ((), ((), ((), ((), ((), ((), ((), ...)))))))))
注意,这个宏展开为类型,所以你会这样使用它
let x: peano!(42) = todo!();
而不是这样
let x = peano!(42); // bad!
接下来还有一大堆其他的东西,但为了不解释所有这些,请看这个编译过程
static_assert_eq!(peano!(39), sub!(peano!(42), peano!(3)));
展开为
enum False {} // uninstantiable type
// this part vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv evaluates to zero when the two sides are equal
const _: [False; (peano!(39) != sub!(peano!(42), peano!(3))) as usize] = [];
// ... which makes the list length zero, which matches the right-hand side (and couldn't be nonzero since its members are uninstantiable)
// learned the list length trick from the `static_assertions` crate, so all credit there!
展开上面的有趣部分(并反转,以便将!=变成
==
)
peano!(39) == < peano!(42) as peano::Sub< peano!(3) >>::Difference;
peano!(39) == <((), ((), ((), peano!(39)))) as peano::Sub<((), ((), ((), ())))>::Difference;
这是peano::Sub
的定义,在这个包中的大多数操作中都有代表性
pub trait Sub<R: peano::N>: peano::N { type Difference: peano::N; } // sealed trait
impl<T: peano::N> Sub<()> for T { type Difference = Self; } // subtracting zero is our super-simple base case
impl<L: peano::N + Sub<R>, R: peano::N> Sub<((), R)> for ((), L) { type Difference = sub!(L, R); } // otherwise, reduce the problem until it's dividing by zero
开始简化!
peano!(39) == <((), ((), ((), peano!(39)))) as peano::Sub<((), ((), ((), ())))>::Difference;
peano!(39) == < ((), ((), peano!(39))) as peano::Sub< ((), ((), ())) >::Difference;
peano!(39) == < ((), peano!(39)) as peano::Sub< ((), ()) >::Difference;
peano!(39) == < peano!(39) as peano::Sub< () >::Difference;
peano!(39) == peano!(39) ;
et voila!
为什么叫这个名字?
某个知名的定理证明器是以法语单词“公鸡”(coq)命名的,所以我谷歌了一下“公鸡”,发现(令我惊讶的是!)它们属于junglefowl物种。这个名字听起来很酷。
依赖关系
~250–700KB
~17K SLoC