I'm porting QuickCheck to Rust, and I've written everything except for_all as I'm not sure what the type signature should be.
I know that in general, for_all will accept a property lambda and a collection of generator lambdas. It will evaluate the generators in order to create a random test case to give the property as input.
It should print +++ OK, passed 100 tests. if the property returns true, otherwise, it should print *** Failed! and print the offending test case values.
In Rust, all functions take a fixed number of parameters, so there's no such thing as an equivalent to Lisp's apply in the general case, but macros can provide you with the abstraction you desire. You can write:
macro_rules! for_all {
( $tester:expr, $( $generator:expr ),* ) => {
$tester( $($generator() ),* )
}
}
Then, for_all!(|a, b| a + b, || 4, || 7) produces 11.
Good luck with your project!
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.
If all you need is a way to define apply, try Rust's macro-by-example syntax extensions:
fn main() {
#macro[[#apply[f, [x, ...]], f(x, ...)]];
fn add(a: int, b: int) -> int { a + b }
assert (#apply[add, [1, 15]] == 16);
}
The above code is from the Rust test suite.
Sadly, the documentation on syntax extensions is a bit sparse at the moment. The Rust reference manual is probably your best bet--although the example it gives (of apply, no less!) is outdated, so I'm not sure how much of its information can be trusted.
Update:
All that's left is figuring out how to wrap add ... assert in a function with the right type signature that accepts arbitrary generators.
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 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));
}
However, working with numbers in Rust is sort of a pain at the moment, and if you want to generalize assert_even to any numeric type you'll have to define interfaces/implementations and then declare assert_even with a bounded generic type:
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));
}
Side note: if you're interested in testing, you should check out Rust's typestate facilities. See the Rust manual here 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 design by contract.
Update 2:
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.
This complete source file should fully demonstrate the behavior that you're looking for, hopefully (the definition of for_all is near the very bottom):
use std;
import std::rand;
import std::io::println;
iface is_even { fn is_even() -> bool; }
impl of is_even for int { fn is_even() -> 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<T: is_even>(num_gen: fn() -> T) -> 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() -> float,
num_gen2: fn() -> float) -> 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 < 100 && 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]];
}
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 #for_all will have to appear in the file in which it is invoked.
Can you describe precisely what you want? I think what you're asking for is something like this:
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);
}
Related
I would like to refactor this Rust code for calculating the largest series product and make it as efficient and elegant as possible. I feel that
lsp(string_digits: &str, span: usize) -> Result<u64, Error>
could be done in a way to make it much more elegant than it is right now. Could lsp be implemented with only one series of chained iterator methods?
#[derive(Debug, PartialEq)]
pub enum Error {
SpanTooLong,
InvalidDigit(char),
}
fn sp(w: &[u8]) -> u64 {
w.iter().fold(1u64, |acc, &d| acc * u64::from(d))
}
pub fn lsp(string_digits: &str, span: usize) -> Result<u64, Error> {
let invalid_chars = string_digits
.chars()
.filter(|ch| !ch.is_numeric())
.collect::<Vec<_>>();
if span > string_digits.len() {
return Err(Error::SpanTooLong);
} else if !invalid_chars.is_empty() {
return Err(Error::InvalidDigit(invalid_chars[0]));
} else if span == 0 || string_digits.is_empty() {
return Ok(1);
}
let vec_of_u8_digits = string_digits
.chars()
.map(|ch| ch.to_digit(10).unwrap() as u8)
.collect::<Vec<_>>();
let lsp = vec_of_u8_digits
.windows(span)
.max_by(|&w1, &w2| sp(w1).cmp(&sp(w2)))
.unwrap();
Ok(sp(lsp))
}
Not sure if this is the most elegant way, but I've given it a try, hope the new version is equivalent to the given program.
Two things will be needed in this case: First, we need a data structure that provides the sliding window "on the fly" and second a function that ends the iteration early if the conversion yields an error.
For the former I've chosen a VecDeque since span is dynamic. For the latter there is a function called process_results in the itertools crate. It converts an iterator over results to an iterator over the unwrapped type and stops iteration if an error is encountered.
I've also slightly changed the signature of sp to accept any iterator over u8.
This is the code:
use std::collections::VecDeque;
use itertools::process_results;
#[derive(Debug, PartialEq)]
pub enum Error {
SpanTooLong,
InvalidDigit(char),
}
fn sp(w: impl Iterator<Item=u8>) -> u64 {
w.fold(1u64, |acc, d| acc * u64::from(d))
}
pub fn lsp(string_digits: &str, span: usize) -> Result<u64, Error> {
if span > string_digits.len() {
return Err(Error::SpanTooLong);
} else if span == 0 || string_digits.is_empty() {
return Ok(1);
}
let mut init_state = VecDeque::new();
init_state.resize(span, 0);
process_results(string_digits.chars()
.map(|ch| ch.to_digit(10)
.map(|d| d as u8)
.ok_or(Error::InvalidDigit(ch))),
|digits|
digits.scan(init_state, |state, digit| {
state.pop_back();
state.push_front(digit);
Some(sp(state.iter().cloned()))
})
.max()
.unwrap()
)
}
I have written a trait that specifies some methods similar to those of Vec:
pub trait Buffer {
type Item;
fn with_capacity(c: usize) -> Self;
fn push(&mut self, item: Self::Item);
}
I would like to implement FromIterator for all types that implement Buffer, as follows:
impl<T> iter::FromIterator<T::Item> for T
where T: Buffer
{
fn from_iter<I>(iter: I) -> Self
where I: IntoIterator<Item = T>
{
let mut iter = iter.into_iter();
let (lower, _) = iter.size_hint();
let ans = Self::with_capacity(lower);
while let Some(x) = iter.next() {
ans.push(x);
}
ans
}
}
The compiler won't let me:
error[E0210]: type parameter `T` must be used as the type parameter
for some local type (e.g. `MyStruct<T>`); only traits defined in the
current crate can be implemented for a type parameter
I think I understand the error message; it is preventing me from writing code that is incompatible with possible future changes to the standard library.
The only way around this error appears to be to implement FromIterator separately for every type for which I implement Buffer. This will involve copying out exactly the same code many times. Is there a a way to share the same implementation between all Buffer types?
You can't implement a trait from another crate for an arbitrary type, only for a type from your crate. However, you can move the implementation to a function and reduce amount of duplicated code:
fn buffer_from_iter<I, B>(iter: I) -> B
where I: IntoIterator<Item = B::Item>,
B: Buffer
{
let mut iter = iter.into_iter();
let (lower, _) = iter.size_hint();
let mut ans = B::with_capacity(lower);
while let Some(x) = iter.next() {
ans.push(x);
}
ans
}
struct S1;
impl Buffer for S1 {
type Item = i32;
fn with_capacity(c: usize) -> Self { unimplemented!() }
fn push(&mut self, item: Self::Item) { unimplemented!() }
}
impl std::iter::FromIterator<<S1 as Buffer>::Item> for S1 {
fn from_iter<I>(iter: I) -> Self
where I: IntoIterator<Item = <S1 as Buffer>::Item>
{
buffer_from_iter(iter)
}
}
This implementation of FromIterator can be wrapped into a macro to further reduce code duplication.
I want to implement the IntoIterator trait for a struct containing a String. The iterator is based on the chars() iterator, is supposed to count the '1' chars and accumulate the result. This is a simplified version of what I got so far:
use std::iter::Map;
use std::str::Chars;
fn main() {
let str_struct = StringStruct { system_string: String::from("1101") };
for a in str_struct {
println!("{}", a);
}
}
struct StringStruct {
system_string: String
}
impl IntoIterator for StringStruct {
type Item = u32;
type IntoIter = Map<Chars, Fn(char) -> u32>;
fn into_iter(self) -> Self::IntoIter {
let count = 0;
return self.system_string.chars().map(|c| match c {
Some('1') => {
count += 1;
return Some(count);
},
Some(chr) => return Some(count),
None => return None
});
}
}
Expected output: 1, 2, 2, 3
This fails with:
error[E0107]: wrong number of lifetime parameters: expected 1, found 0
--> src/main.rs:17:25
|
17 | type IntoIter = Map<Chars, Fn(char) -> u32>;
| ^^^^^ expected 1 lifetime parameter
The chars iterator should have the same lifetime as the StringStruct::system_string, but I have no idea how to express this or if this approach is viable at all.
To answer the question you asked, I'd recommend to impl IntoIterator for &StringStruct (a reference to a StringStruct instead of the struct directly). The code would look like this:
impl<'a> IntoIterator for &'a StringStruct {
type Item = u32;
type IntoIter = Map<Chars<'a>, Fn(char) -> u32>;
// ...
}
However, you will notice many more errors that have a different origin afterwards. The next error that pops up is that Fn(char) -> u32 does not have a constant size at compile time.
The problem is that you try to name the type of your closure by writing Fn(char) -> u32. But this is not the type of your closure, but merely a trait which is implemented by the closure. The type of a closure can't be named (sometimes called "Voldemort type").
This means that, right now, you can't specify the type of a Map<_, _> object. This is a known issue; the recently accepted impl Trait-RFC might offer a workaround for cases like this. But right now, it's not possible, sorry.
So how to solve it then? You need to create your own type that implements Iterator and use it instead of Map<_, _>. Note that you can still use the Chars iterator. Here is the full solution:
struct StringStructIter<'a> {
chars: Chars<'a>,
count: u32,
}
impl<'a> Iterator for StringStructIter<'a> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.chars.next().map(|c| {
if c == '1' {
self.count += 1;
}
self.count
})
}
}
impl<'a> IntoIterator for &'a StringStruct {
type Item = u32;
type IntoIter = StringStructIter<'a>;
fn into_iter(self) -> Self::IntoIter {
StringStructIter {
chars: self.system_string.chars(),
count: 0,
}
}
}
fn main() {
let str_struct = StringStruct { system_string: String::from("1101") };
for a in &str_struct {
println!("{}", a);
}
}
And just a small note: an explicit return when not necessary is considered bad style in Rust. Better stick to rule and write idiomatic code by removing return whenever possible ;-)
This question already has answers here:
How to implement Iterator and IntoIterator for a simple struct?
(2 answers)
Closed 4 years ago.
Editor's note: This code example is from a version of Rust prior to 1.0 and is not valid Rust 1.0 code. Updated versions of this code no longer produce an error due to changes how for loops are implemented.
I'm writing a Vector struct in Rust.
pub struct Vector {
pub x: f32,
pub y: f32,
pub z: f32,
curr: uint
}
And I'd like to write a simple iterator for it, so that I can iterate over the elements of the vector. It's occasionally useful, plus I know next to nothing about iterators in Rust.
Here's what I've got at the moment.
impl Iterator<f32> for Vector {
fn next(&mut self) -> Option<f32> {
let new_next : Option<f32> = match self.curr {
0 => Some(self.x),
1 => Some(self.y),
2 => Some(self.z),
_ => None
};
let new_curr = (self.curr + 1) % 4;
mem::replace(&mut self.curr, new_curr);
new_next
}
}
Now ideally I'd like to be able to use this like:
let u = Vector::new(0.0f32, 0.0f32, 0.0f32);
for element in u {
///
}
However, I get the following compiler error:
error: cannot borrow immutable local variable `u` as mutable
So I'm stumped. After a couple hours of Googling, I couldn't come up with anything. I feel like I'm missing something huge.
Are you sure you really want the Vector itself to be an iterator? Usually structures and iterators into them are separate. Consider something like this:
pub struct Vector {
pub x: f32,
pub y: f32,
pub z: f32,
}
pub struct VectorIter<'a> {
vector: &'a Vector,
cur: usize,
}
impl<'a> Iterator for VectorIter<'a> {
type Item = f32;
fn next(&mut self) -> Option<f32> {
let r = match self.cur {
0 => self.vector.x,
1 => self.vector.y,
2 => self.vector.z,
_ => return None,
};
self.cur += 1;
Some(r)
}
}
impl Vector {
fn iter(&self) -> VectorIter {
VectorIter {
vector: self,
cur: 0,
}
}
}
fn main() {
let v = Vector { x: 1.0, y: 2.0, z: 3.0 };
for c in v.iter() {
println!("{}", c);
}
}
Because Vector is very simple, it can derive Copy, and its iterator can take it by value:
#[derive(Copy, Clone)]
pub struct Vector {
pub x: f32,
pub y: f32,
pub z: f32,
}
pub struct VectorIter {
vector: Vector,
cur: usize,
}
impl Iterator for VectorIter {
type Item = f32;
fn next(&mut self) -> Option<f32> {
let r = match self.cur {
0 => self.vector.x,
1 => self.vector.y,
2 => self.vector.z,
_ => return None,
};
self.cur += 1;
Some(r)
}
}
impl Vector {
fn iter(&self) -> VectorIter {
VectorIter {
vector: *self,
cur: 0,
}
}
}
fn main() {
let v = Vector { x: 1.0, y: 2.0, z: 3.0 };
for c in v.iter() {
println!("{}", c);
}
}
This variant is probably better unless your Vector contains something other than coordinates. This variant is more flexible because it does not tie the iterator with the iterable, but on the other hand, exactly because of the same reason it may be undesirable (with Copy you can change the original value, and the iterator won't reflect it; without Copy and with references you won't be able to change the original value at all). The semantics you would want to use heavily depends on your use cases.
Editor's note: This answer is no longer useful as of Rust 1.0 due to changes how the for loop works.
Vladimir Matveev's answer is correct and explains what you should do. I'd like to add on by explaining your error a bit more.
error: cannot borrow immutable local variable u as mutable
When you are iterating over something, you need to mutate something that tracks where you are. In your code, that's done by:
mem::replace(&mut self.curr, new_curr);
And Rust knows which thing you want to mutate because the method signature for next indicates it:
fn next(&mut self) -> Option<f32>
The problem is that your object is not mutable:
let u = Vector::new(0.0f32, 0.0f32, 0.0f32);
If you change your code to
let mut u = Vector::new(0.0f32, 0.0f32, 0.0f32);
I'd expect your code to work as-is. All that being said, a separate iterator is probably the right way to go. However, you'll know more than we do about your code!
I have the following code in a repo:
impl<Id> IdAllocator<Id> where
Id : Clone + Default + Add<u32, Id>,
{
pub fn new() -> IdAllocator<Id> {
IdAllocator {
next: Default::default()
}
}
// Produce an Id that hasn't been produced yet by this object.
pub fn allocate(&mut self) -> Id {
let ret = self.next.clone();
self.next = self.next + 1;
ret
}
}
But it seems a little clumsy, especially since the Add instance is only used as a succ function (generating the next value in sequence). Is there some Succ class I can use? And if so, is there already some Iterator construction somewhere in the standard library that already does this Default+Succ pattern?
Thanks!
No, unfortunately, there is no Succ-like thing in the standard library. The closest thing you can find is range() family of iterators, however, it uses Add and One numeric traits to generate items. You can do it this way (the idea is basically the same as yours, but this version is slightly more generic due to One trait usage):
use std::num::One;
use std::default::Default;
struct IdAllocator<T> {
current: T
}
impl<T: Default> IdAllocator<T> {
#[inline]
pub fn new() -> IdAllocator<T> {
IdAllocator {
current: Default::default()
}
}
}
impl<T: Add<T, T>+One+Clone> Iterator<T> for IdAllocator<T> {
fn next(&mut self) -> Option<T> {
let next = self.current + One::one();
self.current = next.clone();
Some(next)
}
}
fn main() {
let a = IdAllocator::<uint>::new();
for i in a.take(10) {
println!("{}", i);
}
}
(try it here)