3个版本 (破坏性更新)
使用旧的Rust 2015
0.3.0 | 2018年5月24日 |
---|---|
0.2.0 | 2018年5月24日 |
0.1.0 | 2018年5月6日 |
#2060 在 游戏开发
34KB
594 行
卢普 ("循环")
为Rust提供的自定义索引循环宏库。
此库提供了一种基于索引循环的迭代器模式之外的不同模式。索引循环在游戏编程和科学计算中非常常见。库中包含的循环反映了在Dyon中使用的循环。
您可以通过实现Lup
特质来创建自己的自定义循环。
动机
- 比迭代器模式更接近数学符号
- 在解决复杂问题时,减少了逻辑错误的机会
- 支持在循环内使用
continue
、break
或return
- 嵌套循环的紧凑表示法,
i in 0..3, j in 0..3 =>
- 带有安全范围的缩写表示法,
i, j by list =>
- 自动推断秘密的证据类型
- 可用于数值暴力定理证明
- 当与最多4维度的向量一起工作时,更符合人体工程学
用法
循环Any
、All
、Max
和Min
使用Secret
结构。此类型包含证明值的证据。
以下是一个使用Any
循环和by
语法的简单示例
#[macro_use]
extern crate lup;
use lup::Any;
fn main() {
let words = vec!["mary", "had", "a", "little", "lamb"];
println!("Words:");
println!("{:?}\n", words);
// Find the word "lamb".
let lamb = lup!(Any<_>: i by words => {words[i] == "lamb"});
println!("Is there any word `lamb`?");
println!("{}\n", lamb.value); // Prints `true`.
println!("What is the evidence?");
println!("{:?}\n", lamb.evidence); // Prints `Some(4)`.
println!("Using the evidence to find the word:");
println!("{}\n", words[lamb.evidence.unwrap()]); // Prints `lamb`.
}
by
语法使用列表的范围。在上面的例子中,这等同于
lup!(Any<_>: i in 0..words.len() => {words[i] == "lamb"})
以下是一个稍微复杂一些的例子
#[macro_use]
extern crate lup;
use lup::Any;
fn main() {
// Create a 2D array.
let arr = [[1, 2], [3, 4]];
// Look for a number greater than 2.
let b = lup!(Any<_>: i, j by arr => {arr[i][j] > 2});
println!("{:?}", b.evidence); // Prints `Some((1, 0))`.
// Get the number that is greater than 2.
let ev = b.evidence.unwrap();
println!("{}", arr[ev.0][ev.1]); // Prints `3`.
}
在上面的例子中,有两个循环,一个索引为i
,一个索引为j
。
内部循环j
的结果类型为Secret<(usize), bool>
。
外层循环 i
的结果是 Secret<<(usize, usize), bool>
类型。
使用 Secret
类型可以将循环的结果组合起来,以给出有意义的答案。
使用 Max
循环的另一个示例
#[macro_use]
extern crate lup;
use lup::Max;
fn main() {
let data = vec![
(1, 1),
(2, 2),
(3, 4),
(4, 4)
];
let a = lup!(Max<_, _>: i by data => {data[i].0 as f32});
let b = lup!(Max<_, _>: i by data => {data[i].1 as f32});
println!("{} vs {}", a.value, b.value); // Prints `4 vs 4`.
println!("{:?} vs {:?}", a.evidence, b.evidence); // Prints `Some(3) vs Some(2)`.
}
由于 Max
仅对 f32
和 f64
实现,我们将数据转换为 f32
。
证据指向第一个达到最大值的项。
以下是一个演示秘密强大功能的示例
#[macro_use]
extern crate lup;
use lup::{Any, Max};
fn main() {
let data = vec![
vec![1, 2, 6, 4, 5, 3],
vec![4, 6, 9, 3, 2, 1],
];
// Find out whether any list has a maximum value less than 7.
let search = lup!(Any<_>: i by data => {
lup!(Max<_, _>: j by data[i] => {data[i][j] as f32}).le(&7.0)
});
println!("{}", search.value); // Prints `true`.
println!("{:?}", search.evidence); // Prints `Some((0, 2))`.
let ev = search.evidence.unwrap();
println!("{}", data[ev.0][ev.1]); // Prints `6`.
}
我们如何知道一个列表的最大值小于7?我们知道,因为第一个列表的最大值是6!
秘密为我们提供了为什么某事为真的有意义的理由。
在上面的示例中,Max
循环的秘密传播到 Any
循环。
示例调用 .le
而不是使用 <=
,因为 Rust 不允许覆盖比较运算符的返回值。