// Example 8: closures, (bounded) polymorphism

fn twice_i32<F>(x0: i32, f: &F) -> i32 where F: Fn(i32) -> i32
{   //                                             ^       ^
//    closure named `f`, which                 |       |
//  is a (generic type) `F` where              ^~~     |
//  `F` is an Fn (i.e. closure) that takes an `i32`    ^~~
//                                 ... and returns an `i32`.

let x1 = f(x0); // (work-around weakness in current borrow-checker)

f(x1)
}

pub fn main() {
println!("twice_i32(0, add_1): {}", twice_i32(0, &|y| y+1));
let w = 3;
println!("twice_i32(0, add_w): {}", twice_i32(0, &|z| z+w));

println!("twice(0, add_1): {}", twice(0i32, &|y| y+1));

// println!("twice_peano(0): {}", twice_peano(0i32)); // XXX (see exercise below)
}

pub fn twice<X, F>(x: X, f: &F) -> X where F: Fn(X) -> X {
let x1 = f(x);
f(x1)
}

pub trait Peano {
fn succ(self) -> Self;
}

impl Peano for i32 {

}

pub fn twice_peano<X:Peano>(x: X) -> X {
#![allow(unused_variables)]
unimplemented!()

// Hint: review ex4.rs
}

// EXERCISE: finish implementing Peano for `i32`; uncomment line marked XXX above.

// EXERCISE: The first two calls to `twice_i32` in `main` illustrate
// closures closed over their environment.  Try to make the classic
// `make_adder` example of a higher-order function, i.e. defined
// analogously to `make_adder ≡ λw.λz.z+w`
//
// Discuss.