A little coding challenge. The task is to state a generic memoizing fixed-point combinator. As an application, calculate the Fibonacci numbers with it, i.e.
def fix(m,f):
def g(x):
if x not in m: m[x] = f(g,x)
return m[x]
return g
fib = fix({0: 1, 1: 1}, lambda f,n: f(n-1) + f(n-2))
a = [fib(n) for n in range(0,10)]
print(a)
Spoiler: Ugly solution
use std::collections::HashMap;
use std::hash::Hash;
use std::cell::RefCell;
macro_rules! hashmap {
( $( $key:expr => $value:expr ),* ) => {{
let mut _m = HashMap::new();
$(_m.insert($key,$value);)*
_m
}}
}
struct Fun<X,Y> {
m: RefCell<HashMap<X,Y>>,
f: Box<dyn Fn(&Fun<X,Y>, X) -> Y>
}
impl<X,Y> Fun<X,Y> where X: Clone+Eq+Hash, Y: Clone {
fn call(&self, x: X) -> Y {
if let Some(value) = self.m.borrow().get(&x) {
return value.clone();
}
let value = (self.f)(&self,x.clone());
self.m.borrow_mut().insert(x,value.clone());
value.clone()
}
}
fn fix<X: Copy+Eq+Hash, Y: Clone>(
m: HashMap<X,Y>,
f: impl Fn(&Fun<X,Y>,X) -> Y + 'static
) -> impl Fn(X) -> Y
{
let f = Fun{m: RefCell::new(m), f: Box::new(f)};
return move |x| f.call(x);
}
fn main() {
let fib = fix(hashmap!{0 => 1, 1 => 1},
|f, n| f.call(n-1) + f.call(n-2));
let a: Vec<u32> = (0..10).map(fib).collect();
println!("{:?}", a);
}