Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

a way to compose functions #28226

Closed
johnynek opened this Issue Sep 4, 2015 · 7 comments

Comments

Projects
None yet
5 participants
@johnynek
Copy link

johnynek commented Sep 4, 2015

Here is a way (I was pointed to this by mbrubeck on the rust IRC channel) to compose two functions.

#![feature(unboxed_closures, core)]

fn succ(x: i32) -> i32 { x + 1 }
fn sq(x: i32) -> i32 { x * x }

struct Compose<F, G>(F, G); 
impl<R, M, A, F: FnOnce(M) -> R, G: FnOnce<A, Output=M>> FnOnce<A> for Compose<F, G> {
    type Output = R;
    extern "rust-call" fn call_once(self, args: A) -> R {
        let Compose(f, g) = self;
        f(g.call_once(args))
    }
}
impl<R, M, A, F: FnMut(M) -> R, G: FnMut<A, Output=M>> FnMut<A> for Compose<F, G> {
    extern "rust-call" fn call_mut(&mut self, args: A) -> R {
        self.0(self.1.call_mut(args))
    }
}
impl<R, M, A, F: Fn(M) -> R, G: Fn<A, Output=M>> Fn<A> for Compose<F, G> {
    extern "rust-call" fn call(&self, args: A) -> R {
        self.0(self.1.call(args))
    }
}

fn main() {
    let f = Compose(succ, sq);
    println!("{} {}", f(5), f(6));
}

This seems like something it would be worth adding to the standard library.

Should I just open a pull request or is there another process for this kind of proposal?

@jroesch

This comment has been minimized.

Copy link
Member

jroesch commented Sep 4, 2015

This is a question for the libs team, I'm not 100% what granularity of change necessitates an RFC in the libs world. cc @rust-lang/libs

@BurntSushi

This comment has been minimized.

Copy link
Member

BurntSushi commented Sep 4, 2015

My suggestion would be to post this as a Pre-RFC on https://internals.rust-lang.org/ so that you can solicit feedback. It is a brand new API though, so I would expect something like this to ultimately require an RFC though.

@steveklabnik steveklabnik added the A-libs label Sep 4, 2015

@geofft

This comment has been minimized.

Copy link
Contributor

geofft commented Sep 8, 2015

Dumb question: what prevents |x| succ(sq(x)) from being used where you'd want to use Compose(succ, sq)? It works on current, stable Rust and is even fewer characters.

(Or in other words, what would adding struct Compose<F, G> to the standard library enable?)

@johnynek

This comment has been minimized.

Copy link
Author

johnynek commented Sep 8, 2015

This is a good question. The main here was just to demonstrate that the direct thing works. In reality, you want something like:

struct Mapped<I, F> {
  iter: I,
  func: F
}

struct Compose<F, G>(F, G);

fn map<I, T, U, F, F2, U2>(m: Mapped<I, F>, func: F2) -> Mapped<I, Compose<F, F2>>
  where I: Iterator<Item=T>,
            F: Fn(T) -> U,
            F2: Fn(U) -> U2 {
  Mapped { iter: m.iter, func: Compose(m.func, func) }
}

You could do this by continuing to return Box<Fn> I guess, but you keep creating dynamic calls (I think) for a function that has lots of composition.

This is useful for data flow programming systems (similar to spark) where you might want to build up a large computation description, but not run it right away (in fact, you might only run part of it on a given node).

@johnynek

This comment has been minimized.

Copy link
Author

johnynek commented Sep 8, 2015

added a discussion here: https://internals.rust-lang.org/t/function-composition-in-the-standard-library/2615

Not sure where we should discuss.

@geofft

This comment has been minimized.

Copy link
Contributor

geofft commented Sep 8, 2015

I see, so an unboxed Compose<F, F2> could be used as (part of a) return type because you can monomorphize your map function for some concrete <F, F2>, whereas if you wanted to return a closure, you'd have to box it since there's no way to specify in the type how big the closure object is. Thanks, I'll say that on the internals thread in case anyone else is confused like me.

@steveklabnik

This comment has been minimized.

Copy link
Member

steveklabnik commented Mar 1, 2017

Triage: small API additions just need a PR; larger ones need an RFC. Please pursue one of those two avenues, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.