Add overload for iterator with lambdas

Hello all,

I want to achieve some kind of generic generator.

It should be in the form of
let gen = Generator::new(f)
f being a lambda.
I wanna to achieve Add overloading, like in
let gen = Generator::new(f1) + Generator::new(f2)
[gen should be a new Generator with f = f1.next + f2.next]

If I understand, I need to declare three lambda type differents, for the two ins, and the out.
I'm using a Iterator, and I'm stuck can't declare a new type for my output

type sound = f64;

struct Ugen<T>
    where T : Fn(f64) -> sound, 
{ 
    time: f64,
    handler: T
}
impl<T> Ugen<T>
    where T : Fn(f64) -> sound, 
{
    pub fn new(handler: T) -> Self { Ugen{time: 0.0, handler} }
}
impl<T> Iterator for Ugen<T>
    where T : Fn(f64) -> sound,
{
    type Item = sound;
    fn next(&mut self) -> Option<Self::Item> {
        self.time += 0.1;
        Some((self.handler)(self.time))
    }
}

impl<T, U> std::ops::Add<Ugen<U>> for Ugen<T> where
    T : Fn(f64) -> sound,
    U : Fn(f64) -> sound,
{
    type Output = Ugen<T>;

    fn add(self, rhs:Ugen<U>) -> Self::Output
    {
        Ugen::new(|time| { self.next().unwrap() + rhs.next().unwrap()})
    }
}

#[cfg(test)]
mod test {
    use super::Ugen;
    use super::sound;
fn sin(t: f64) -> sound { t.sin() }


#[test]
fn testIterator() {
        let i = Ugen::new(|time| -> sound { time.sin() });
        let mut ii = 0.0f64;
        for i in it {
            ii += 0.1;
            assert!(i == ii.sin(), format!("{} : {}", i, ii));
        }
    }

Any help would be greatly appreciated :slight_smile:
Thank you !

Hello, are you the one who posted this,

I'm Yato on internals and I posted a solution there by adding a new trait and type you can generalize over generators and introduce operator overloading.

playground

Does this not work for you?

1 Like

Yes, sorry the mistakes in the internals forum. Your solution is interesting, you don't bind the types in your struct, which result in clearer code, it's cool.
I will play with it and see if I can extend that easily by myself to every crazy DSP modular synths and all the stuff.
Thanks

1 Like

Ok, I'm confused with one thing in your code :

impl<F: Fn(f64) -> Sound> SoundGen for F {
    fn gen(&mut self, f: f64) -> Sound {
        self(f)
    }
}

I'm not sure if F is a type or just a Trait here. I imagine it is a type wich implement the trait Fn, but trying to redo the thing after studying your code, I was stucked here ==>

type Sound = f64;

struct MonoUgen<T>
{ 
    time: f64,
    handler: T
}
struct BinaryUgen<A, B>{a:A, b:B}
trait Ugen{}
impl<T> Ugen for MonoUgen<T>{}
impl<A, B> Ugen for BinaryUgen<A, B>{}

impl<T: FnMut(f64) -> Sound> MonoUgen<T>
{
    pub fn new(handler: T) -> Self { MonoUgen{time: 0.0, handler} }
}
impl<T: FnMut(f64) -> Sound> Iterator for MonoUgen<T>
{
    type Item = Sound;
    fn next(&mut self) -> Option<Self::Item> {
        self.time += 0.1;
        Some((self.handler)(self.time))
    }
}
impl<A:Iterator<Item=Sound> + Ugen, 
    B:Iterator<Item=Sound> + Ugen>
    Iterator for BinaryUgen<A, B> {
        type Item = Sound;

        fn next(&mut self) -> Option<Self::Item> {
            //self.time += 0.1;
            Some(self.a.next().unwrap() + self.b.next().unwrap())
        } 
}

//// HERE
///
///
impl<T:Ugen, U:Ugen> std::ops::Add<U> for T
{
    type Output = BinaryUgen<T, U>;

    fn add(self, rhs:U) -> Self::Output
    {
        BinaryUgen{a: self, b: rhs}
    }
}

Why Can't I do the same, implements add for any type T which implement the trait Ugen, which I defined empty at the beginning??
!!

This is it


The blanket impl doesn't work because any that could implement Ugen, not just ones that you define. and you aren't allowed to define Add for types you don't declare.