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 ] => { ... };
}
Expand description
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 Fn
s 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);