Testing 如何在Rust中模仿Lisp(应用)或(curry)?

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:

我正在移植到Rust,我已经为所有人编写了除
之外的所有东西,因为我不确定类型签名应该是什么

我知道,通常,
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);
}
以上代码来自

遗憾的是,目前关于语法扩展的文档有点少。这可能是你最好的选择——尽管它给出的示例(of
apply
,同样如此!)已经过时,所以我不确定它的信息有多少是可信的

更新:

剩下的就是要弄清楚如何包装添加。。。在具有接受任意生成器的正确类型签名的函数中断言

我仍然不确定您是如何将这一切放在一起的,但这里有一个函数,它接受任何生成
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() ),* )
    }
}