August Feng

Implementing flip in rust

About

I challenged myself to implement the flip function on functions that can be partially applied.

Code

FnOnce -> FnOnce

This flip implementation returns a function that can only be used once.

  fn flip<'a, A, B, C, F, G>(func: F) -> impl FnOnce(B) -> Box<dyn FnOnce(A) -> C + 'a>
  where
      F: Fn(A) -> G + 'a,
      G: FnOnce(B) -> C,
      B: 'a,
  {
      move |b: B| Box::new(move |a: A| func(a)(b))
  }

  fn join(a: String) -> impl FnOnce(String) -> String {
      move |b| format!("{}{}", a, b)
  }

  pub fn main() {
      let join_flipped = flip(join);

      let hello = "hello".to_string();
      let world = "world".to_string();

      let world_suffix = join_flipped(world);

      let helloworld = world_suffix(hello);

      println!("{}", helloworld);
  }

FnOnce -> FnOnce on a function that mutates its arguments

This flip implementation will flip a function that mutates.

  fn flip<'a, A, B, C, F, G>(mut func: F) -> impl FnOnce(B) -> Box<dyn FnOnce(A) -> C + 'a>
  where
      F: FnMut(A) -> G + 'a,
      G: FnOnce(B) -> C,
      B: 'a,
  {
      move |b: B| Box::new(move |a: A| func(a)(b))
  }

  fn push(data: &mut Vec<String>) -> impl FnOnce(String) {
      |s| data.push(s)
  }

  pub fn main() {
      let mut data: Vec<String> = vec![];

      let push_flipped = flip(push);

      let helloworld = "helloworld".to_string();

      push_flipped(helloworld)(&mut data);

      println!("{:?}", data);
  }

Fn -> FnOnce (not really working)

This last implementation didn't really work because the closure call doesn't seem to let go of a mutable borrow. I'm leaving it in here in case I ever want to revisit the challenge in the future:

  fn flip<'a, A, B, C, F, G>(mut func: F) -> impl Fn(B) -> Box<dyn FnOnce(A) -> C + 'a>
  where
      F: FnMut(A) -> G + 'a + Copy,
      G: FnOnce(B) -> C,
      B: 'a,
  {
      move |b: B| Box::new(move |a: A| func(a)(b))
  }

  fn push(data: &mut Vec<String>) -> impl FnOnce(String) {
      |s| data.push(s)
  }

  pub fn main() {
      let mut data: Vec<String> = vec![];
      let push_flipped = flip(push);

      let helloworld = "helloworld".to_string();

      let push_helloworld = push_flipped(helloworld);

      push_helloworld(&mut data);
      push_helloworld(&mut data); // cannot borrow `data` as mutable more than once at a time [E0499]

      drop(push_flipped);

      println!("{:?}", data);
  }