0

Is there any way of binding (instead of defining) possibly recursive functions? For example:

type F = fn(i32) -> i32;

// equivalent to |x| (x+1)*2
fn f: F = composite(add_by(1), mult_by(2));

// equivalent to |x| if x > 100 then {x} else {g(x*2)}
// note the recursion
fn g: F = branch(greater_than(100), identity, composite(mult_by(2), g));

The recursion I am trying to achieve is NOT of closure in general (asked here), which is impossible without hacks, but simply of a normal function with nicer syntax (both type signature and definition).

This could be helpful when type F is complicated and supposed to be used abstractly, e.g.

type Parser<T> = fn(&str) -> Option<(T, &str)>
exprosic
  • 630
  • 5
  • 17

1 Answers1

1

I don't see how add_by, mult_by or composite can return anything other than a closure, given that the returned "thing" must remember (eg. "capture") the parameters…

That being said, you can make it work if you make add_by and co. into macros instead of functions:

macro_rules! add_by {
   ($y:expr) => { { fn f (x: i32) -> i32 { x + $y } f } }
}

macro_rules! less_than {
   ($y:expr) => { { fn f (x: i32) -> bool { x < $y } f } }
}

macro_rules! compose {
   ($f:expr, $g:expr) => { { fn c (x: i32) -> i32 { $f ($g (x)) } c } }
}

macro_rules! branch {
   ($rec:ident, $test:expr, $if_true:expr, $if_false:expr) => { 
      {
         fn $rec (x: i32) -> i32 {
            if $test (x) { $if_true (x) } else { $if_false (x) }
         }
         $rec
      }
   }
}

fn main() {
    let g = branch!(g, less_than!(10), add_by!(1), compose!(add_by!(1), g));
    println!("Test: {}", g(4));
}

playground

The salient point here is that you need to give the name of the recursive function as a parameter to the branch macro (parameter $rec), at which point you can access it from the sub-expressions.

Jmb
  • 18,893
  • 2
  • 28
  • 55