Macro adapton::thunk [] [src]

macro_rules! thunk {
    ([ $nmop:expr ] ? $fun:expr ; $( $lab:ident :$arg:expr ),* ) => { ... };
    ([ $nmop:expr ] ? $fun:expr ; $( $lab:ident :$arg:expr ),* ;; $( $lab2:ident :$arg2:expr ),* ) => { ... };
    ( [ $name:ident ] $fun:expr ; $( $lab:ident :$arg:expr ),* ) => { ... };
    ( $nm:expr =>> $fun:expr , $( $lab:ident : $arg:expr ),* ) => { ... };
    ( $nm:expr =>> $fun:expr , $( $lab:ident : $arg:expr ),* ;; $( $lab2:ident : $arg2:expr ),* ) => { ... };
    [ [ $nmop:expr ] ? $body:expr ] => { ... };
    [ [ $name:ident ] $body:expr ] => { ... };
    [ $body:expr ] => { ... };
}

Wrappers for engine::thunk.

Thunks

The following form is preferred:

thunk!( [ optional_name ]? fnexpr ; lab1 : arg1, ..., labk : argk )

It accepts an optional name, of type Option<Name>, and a function fnexpr, of type Fn(A1,...,Ak) -> B.

The arguments arg1,...,argk have types A1,...,Ak. Like the other thunk and memoization forms, this form requires that the programmer provide a label labi for each argument argi.

Example 1

The programmer specifies the optional name opnm, function expression max, and two labeled arguments x and y:

fn max(a:usize,b:usize) -> usize { 
  if a > b { a } else { b } 
};
let opnm : Option<Name> = Some(name_unit());
let t : Art<usize> = thunk!([opnm]? max ; x:10, y:20 );
assert_eq!(get!(t), 20);

Example 2

The function expression need not be pre-declared:

let opnm : Option<Name> = Some(name_unit());
let t : Art<usize> = thunk!([opnm]? 
                            |x,y| if x > y { x } else { y }; 
                            x:10, y:20 );
assert_eq!(get!(t), 20);

Example 3

Sometimes thunks just consist of a body expression, without separated arguments:

let x : Art<usize> = cell!([x] 10);
let y : Art<usize> = cell!([y] 20);
let t : Art<usize> = thunk![[Some(name_unit())]? 
                            if get!(x) > get!(y) { get!(x) } else { get!(y) } ];
assert_eq!(get!(t), 20);

Convenience forms, for examples

Example 4:

We can use the Rust symbol t as the name to repeat Example 2 above, as follows:

let t : Art<usize> = thunk!([t]
                            |x,y| if x > y { x } else { y }; 
                            x:10, y:20 );
assert_eq!(get!(t), 20);

Example 5

We can use the Rust symbol t as the name to repeat Example 3 above, as follows:

let x : Art<usize> = cell!([x] 10);
let y : Art<usize> = cell!([y] 20);
let t : Art<usize> = thunk![[t] if get!(x) > get!(y) { get!(x) } else { get!(y) } ];
assert_eq!(get!(t), 20);

Example 6

Implicit name-counter version (not suitable for archivist role):

let x : Art<usize> = cell!(10);
let y : Art<usize> = cell!(20);
let t : Art<usize> = thunk![ if get!(x) > get!(y) { get!(x) } else { get!(y) } ];
assert_eq!(get!(t), 20);

Spurious arguments

Sometimes, we need to pass arguments that do not admit the traits required by Adapton thunks Eq + Hash + Debug + Clone.

For instance, suppose that we want to pass Fns around, which are not Debug, Eq or Hash. Though generally unsound, we can use the ;; syntax below to append arguments to thunks that do not admit these traits. For soundness, it is critical that the name and/or other arguments (before the ;;) functionally determine the arguments that follow the ;;, which are stored and never updated, nor tested for changes.

let t : Art<usize> = thunk!(
  [Some(name_unit())]?
    |x:usize,y:usize,
      choose:Rc<Fn(usize,usize)->bool>|{ 
        if choose(x,y) { x } else { y }
    };
    x:10, y:20 ;; 
    f:Rc::new(|x,y| if x > y { true } else { false })
  );

assert_eq!(get!(t), 20);