mirror of
https://github.com/tweag/nickel.git
synced 2024-09-20 08:05:15 +03:00
Add a generate primitive operator
This commit is contained in:
parent
922b950231
commit
e57bb043fe
@ -324,6 +324,7 @@ UOp: UnaryOp = {
|
||||
"wrap" => UnaryOp::Wrap(),
|
||||
"embed" <Ident> => UnaryOp::Embed(<>),
|
||||
"map" => UnaryOp::ListMap(),
|
||||
"generate" => UnaryOp::ListGen(),
|
||||
"recordMap" => UnaryOp::RecordMap(),
|
||||
"seq" => UnaryOp::Seq(),
|
||||
"deepSeq" => UnaryOp::DeepSeq(),
|
||||
@ -626,6 +627,7 @@ extern {
|
||||
|
||||
"hasField" => Token::Normal(NormalToken::HasField),
|
||||
"map" => Token::Normal(NormalToken::Map),
|
||||
"generate" => Token::Normal(NormalToken::ListGen),
|
||||
"elemAt" => Token::Normal(NormalToken::ElemAt),
|
||||
"merge" => Token::Normal(NormalToken::Merge),
|
||||
"default" => Token::Normal(NormalToken::Default),
|
||||
|
@ -477,6 +477,43 @@ fn process_unary_operation(
|
||||
))
|
||||
}
|
||||
}
|
||||
UnaryOp::ListGen() => {
|
||||
let (f, _) = stack
|
||||
.pop_arg()
|
||||
.ok_or_else(|| EvalError::NotEnoughArgs(2, String::from("generate"), pos_op.clone()))?;
|
||||
|
||||
if let Term::Num(n) = *t {
|
||||
let n_int = n as usize;
|
||||
if n < 0.0 || n.fract() != 0.0 {
|
||||
Err(EvalError::Other(format!("generate: expected the 1st agument to be a positive integer, got {}", n), pos_op))
|
||||
} else {
|
||||
let mut shared_env = Environment::new();
|
||||
let f_as_var = f.body.closurize(&mut env, f.env);
|
||||
|
||||
// List elements are closurized to preserve lazyness of data structures. It
|
||||
// maintains the invariant that any data structure only contain thunks (that is,
|
||||
// currently, variables).
|
||||
let ts = (0..n_int)
|
||||
.map(|n| {
|
||||
mk_app!(f_as_var.clone(), Term::Num(n as f64))
|
||||
.closurize(&mut shared_env, env.clone())
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Closure {
|
||||
body: Term::List(ts).into(),
|
||||
env: shared_env,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Err(EvalError::TypeError(
|
||||
String::from("Num"),
|
||||
String::from("generate, 1st argument"),
|
||||
arg_pos,
|
||||
RichTerm { term: t, pos },
|
||||
))
|
||||
}
|
||||
}
|
||||
UnaryOp::RecordMap() => {
|
||||
let (f, ..) = stack
|
||||
.pop_arg()
|
||||
|
@ -198,6 +198,8 @@ pub enum NormalToken<'input> {
|
||||
Map,
|
||||
#[token("%elemAt%")]
|
||||
ElemAt,
|
||||
#[token("%generate%")]
|
||||
ListGen,
|
||||
#[token("merge")]
|
||||
Merge,
|
||||
#[token("default")]
|
||||
|
@ -592,6 +592,8 @@ pub enum UnaryOp {
|
||||
ListTail(),
|
||||
/// Return the length of a list.
|
||||
ListLength(),
|
||||
/// Generate a list of a given length by mapping a `Num -> Num` function onto `[1,..,n]`.
|
||||
ListGen(),
|
||||
|
||||
/// Generated by the evaluation of a string with interpolated expressions. `ChunksConcat`
|
||||
/// applied to the current chunk to evaluate. As additional state, it uses a string
|
||||
|
@ -1565,6 +1565,13 @@ pub fn get_uop_type(state: &mut State, op: &UnaryOp) -> Result<TypeWrapper, Type
|
||||
let f_type = mk_tyw_arrow!(a.clone(), b.clone());
|
||||
mk_tyw_arrow!(mk_typewrapper::list(a), f_type, mk_typewrapper::list(b))
|
||||
}
|
||||
// forall a. Num -> (Num -> a) -> List a
|
||||
UnaryOp::ListGen() => {
|
||||
let a = TypeWrapper::Ptr(new_var(state.table));
|
||||
|
||||
let f_type = mk_tyw_arrow!(AbsType::Num(), a.clone());
|
||||
mk_tyw_arrow!(AbsType::Num(), f_type, mk_typewrapper::list(a))
|
||||
}
|
||||
// forall a b. { _ : a} -> (Str -> a -> b) -> { _ : b }
|
||||
UnaryOp::RecordMap() => {
|
||||
// Assuming f has type Str -> a -> b,
|
||||
|
@ -60,11 +60,7 @@
|
||||
foldl aux {right = []; wrong = []} l,
|
||||
|
||||
generate : forall a. (Num -> a) -> Num -> List a =
|
||||
fun gen n =>
|
||||
if n <= 0 then
|
||||
[]
|
||||
else
|
||||
generate gen (n-1) @ [gen n],
|
||||
fun f n => generate% n f,
|
||||
|
||||
sort : forall a. (a -> a -> <Less, Equal, Greater>) -> List a -> List a =
|
||||
fun cmp l =>
|
||||
|
Loading…
Reference in New Issue
Block a user