Testing 如何在Rust中模仿Lisp(应用)或(curry)?
我正在移植到Rust,我已经为所有人编写了除Testing 如何在Rust中模仿Lisp(应用)或(curry)?,testing,quickcheck,rust,Testing,Quickcheck,Rust,我正在移植到Rust,我已经为所有人编写了除之外的所有东西,因为我不确定类型签名应该是什么 我知道,通常,for_all将接受一个属性lambda和一组生成器lambda。它将评估生成器,以创建一个随机测试用例,将属性作为输入 它应该打印+++OK,通过100个测试。如果属性返回true,否则,它应该打印***失败并打印有问题的测试用例值。您能准确描述您想要的吗?我想你要求的是这样的: fn for_all<A>(test: fn(A) -> bool, generators:
之外的所有东西,因为我不确定类型签名应该是什么
我知道,通常,for_all
将接受一个属性lambda和一组生成器lambda。它将评估生成器,以创建一个随机测试用例,将属性作为输入
它应该打印+++OK,通过100个测试。
如果属性返回true,否则,它应该打印***失败编码>并打印有问题的测试用例值。您能准确描述您想要的吗?我想你要求的是这样的:
fn for_all<A>(test: fn(A) -> bool, generators: &[fn() -> A]) -> bool {
generators.iter().all(|gen| test(gen()))
}
fn main() {
let generators: Vec<fn() -> (i32, i32)> = vec![
|| (1, 2),
|| (2, 3),
|| (3, 4),
];
for_all(|(a, b)| a < b, &generators);
}
fn for_all(测试:fn(A)->bool,生成器:&[fn()->A])->bool{
发电机.iter().all(| gen | test(gen()))
}
fn main(){
让生成器:Vec(i32,i32)>=Vec[
|| (1, 2),
|| (2, 3),
|| (3, 4),
];
对于所有(|(a,b)| a
编者按:此答案来自Rust 1.0之前的版本,包含Rust 1.0中语法无效的代码
如果您只需要一种定义apply
的方法,请通过示例语法扩展尝试Rust的宏:
fn main() {
#macro[[#apply[f, [x, ...]], f(x, ...)]];
fn add(a: int, b: int) -> int { a + b }
assert (#apply[add, [1, 15]] == 16);
}
以上代码来自
遗憾的是,目前关于语法扩展的文档有点少。这可能是你最好的选择——尽管它给出的示例(ofapply
,同样如此!)已经过时,所以我不确定它的信息有多少是可信的
更新:
剩下的就是要弄清楚如何包装添加。。。在具有接受任意生成器的正确类型签名的函数中断言
我仍然不确定您是如何将这一切放在一起的,但这里有一个函数,它接受任何生成int
的函数:
use std;
import std::rand;
fn assert_even(num_gen: fn() -> int) -> (bool, int) {
let num = num_gen();
ret (num % 2 == 0, num);
}
fn main() {
let rng = rand::mk_rng();
let gen_even = {|| (rng.next() as int) * 2};
log(error, assert_even(gen_even));
}
然而,在Rust中使用数字目前是一种痛苦,如果您想将assert\u偶
推广到任何数字类型,您必须定义接口/实现,然后使用有界泛型类型声明assert\u偶
:
use std;
import std::rand;
iface is_even { fn is_even() -> bool; }
impl of is_even for int { fn is_even() -> bool { self % 2 == 0 } }
impl of is_even for u32 { fn is_even() -> bool { self % 2u == 0u } }
fn assert_even<T: is_even>(num_gen: fn() -> T) -> (bool, T) {
let num = num_gen();
ret (num.is_even(), num);
}
fn main() {
let rng = rand::mk_rng();
let gen_even_int = {|| (rng.next() as int) * 2};
let gen_even_u32 = {|| rng.next() * 2u};
log(error, assert_even(gen_even_int));
log(error, assert_even(gen_even_u32));
}
还有一件事:语法扩展机制还相当不完善,因此不可能从不同的板条箱导入宏。在此之前,#for_all
的定义必须出现在调用它的文件中。在Rust中,所有函数都采用固定数量的参数,因此在一般情况下没有与Lisp的apply
等价的东西,但宏可以为您提供所需的抽象。你可以写:
macro_rules! for_all {
( $tester:expr, $( $generator:expr ),* ) => {
$tester( $($generator() ),* )
}
}
然后,为所有人!(|a,b | a+b,| 4,| 7)
产生11
祝你的项目好运 不完全是。我很难解释这一点。做得更好。如果你能在Rust中复制Lisp的(apply)
,我就可以完成其余的工作。这非常有帮助!剩下的就是如何包装add。。。在具有接受任意生成器的正确类型签名的函数中断言
。不是1
和15
,而是生成随机数(或任何类型)的函数。@mcandre您能否给出一个for_all
调用的示例,以及您希望传递的函数的签名?访问并查找或滚动到“for all”@mcandre你上次发表评论时,我正在编辑这篇文章,这是否回答了你的问题?现在就检查你的链接。酷。您能否重写该示例,以便for_all
接受任意返回类型的生成器?不仅仅是int,不仅仅是数字,还有字符串,向量等等。不仅仅是一元属性,还有n元属性。谢谢你的代码!我需要的最后一件事是1)在某种集合中临时存储生成的值2)将tester函数应用于集合中的每个测试用例3)如果任何测试用例失败,打印“FAIL!”并打印该测试用例中的值4)循环步骤1-3,以便针对测试仪运行100个测试用例,如果任何测试用例失败,则停止。如果100个测试用例中没有一个失败,打印“Ok”。帮助我欧比-万-卡诺比,你是我唯一的希望。
macro_rules! for_all {
( $tester:expr, $( $generator:expr ),* ) => {
$tester( $($generator() ),* )
}
}