Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <blockquote> <p>Editor's note: This answer is from a version of Rust prior to 1.0 and contains code that is not syntactically valid in Rust 1.0.</p> </blockquote> <p>If all you need is a way to define <code>apply</code>, try Rust's macro-by-example syntax extensions:</p> <pre><code>fn main() { #macro[[#apply[f, [x, ...]], f(x, ...)]]; fn add(a: int, b: int) -&gt; int { a + b } assert (#apply[add, [1, 15]] == 16); } </code></pre> <p>The above code is from <a href="https://github.com/mozilla/rust/blob/master/src/test/run-pass/macro-by-example-1.rs" rel="nofollow noreferrer">the Rust test suite</a>.</p> <p>Sadly, the documentation on syntax extensions is a bit sparse at the moment. The <a href="http://doc.rust-lang.org/doc/rust.html#syntax-extension-expressions" rel="nofollow noreferrer">Rust reference manual</a> is probably your best bet--although the example it gives (of <code>apply</code>, no less!) is outdated, so I'm not sure how much of its information can be trusted.</p> <p><strong>Update:</strong></p> <blockquote> <p>All that's left is figuring out how to wrap add ... assert in a function with the right type signature that accepts arbitrary generators.</p> </blockquote> <p>I'm still not sure exactly how you're putting this all together, but here's a function that accepts any function that produces an <code>int</code>:</p> <pre><code>use std; import std::rand; fn assert_even(num_gen: fn() -&gt; int) -&gt; (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)); } </code></pre> <p>However, working with numbers in Rust is sort of a pain at the moment, and if you want to generalize <code>assert_even</code> to any numeric type you'll have to define interfaces/implementations and then declare <code>assert_even</code> with a bounded generic type:</p> <pre><code>use std; import std::rand; iface is_even { fn is_even() -&gt; bool; } impl of is_even for int { fn is_even() -&gt; bool { self % 2 == 0 } } impl of is_even for u32 { fn is_even() -&gt; bool { self % 2u == 0u } } fn assert_even&lt;T: is_even&gt;(num_gen: fn() -&gt; T) -&gt; (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)); } </code></pre> <p>Side note: if you're interested in testing, you should check out Rust's typestate facilities. See <a href="http://doc.rust-lang.org/doc/rust.html#typestate-system" rel="nofollow noreferrer">the Rust manual here</a> for an example of what typestate does and the ways in which it is capable of enforcing program correctness. The way I understand it, it's basically a more powerful version of Eiffel's <a href="http://en.wikipedia.org/wiki/Design_by_contract" rel="nofollow noreferrer">design by contract</a>.</p> <p><strong>Update 2:</strong></p> <blockquote> <p>for_all accepts a single property (e.g. is_even or divisible_by) and a collection of generator functions. The generators are lambdas which return random values to pass as input to the property, e.g. [gen_int] for is_even or [gen_int, gen_int] for divisible_by. for_all will call the property using the generated values as a test case, printing +++ OK, passed 100 tests if the property returns true for 100 random test cases, or *** Failed! {test_case} if one of the test cases fails.</p> </blockquote> <p>This complete source file should fully demonstrate the behavior that you're looking for, hopefully (the definition of <code>for_all</code> is near the very bottom):</p> <pre><code>use std; import std::rand; import std::io::println; iface is_even { fn is_even() -&gt; bool; } impl of is_even for int { fn is_even() -&gt; bool { self % 2 == 0 } } fn main() { let rng = rand::mk_rng(); // Cast to int here because u32 is lame let gen_even = {|| (rng.next() as int) * 2}; let gen_float = {|| rng.next_float()}; // Accepts generators that produce types that implement the is_even iface fn assert_even&lt;T: is_even&gt;(num_gen: fn() -&gt; T) -&gt; bool { let num = num_gen(); let prop_holds = num.is_even(); if !prop_holds { println(#fmt("Failure: %? is not even", num)); } ret prop_holds; } fn assert_divisible(num_gen1: fn() -&gt; float, num_gen2: fn() -&gt; float) -&gt; bool { let dividend = num_gen1(), divisor = num_gen2(); let prop_holds = dividend / divisor == 0f; if !prop_holds { println(#fmt("Failure: %? are not divisible", (dividend, divisor))); } ret prop_holds; } // Begin anonymous closure here #macro[[#for_all[prop, [gen, ...]], {|| let passed_tests = 0; let prop_holds = true; // Nice iterators and break/continue are still being implemented, // so this loop is a bit crude. while passed_tests &lt; 100 &amp;&amp; prop_holds { prop_holds = prop(gen, ...); if prop_holds { passed_tests += 1; } } println(#fmt("Tests passed: %d", passed_tests)); ret 0; // Necessary to infer type of #for_all, might be a compiler bug }()]]; // Close anonymous closure and self-execute, then close #macro #for_all[assert_even, [gen_even]]; #for_all[assert_divisible, [gen_float, gen_float]]; } </code></pre> <p>One more thing: the syntax extension mechanism is still fairly unpolished, so it's not possible to import macros from different crates. Until then, the definition of <code>#for_all</code> will have to appear in the file in which it is invoked.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload