Add builtin List.intersperse

This commit is contained in:
satotake 2021-11-17 15:18:45 +00:00 committed by GitHub
parent 8f25106b2c
commit 16fb04b4fa
5 changed files with 120 additions and 0 deletions

View file

@ -1140,6 +1140,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
) )
} }
// intersperse : List elem, elem -> List elem
add_top_level_function_type!(
Symbol::LIST_INTERSPERSE,
vec![list_type(flex(TVAR1)), flex(TVAR1)],
Box::new(list_type(flex(TVAR1))),
);
// Dict module // Dict module
// len : Dict * * -> Nat // len : Dict * * -> Nat

View file

@ -111,6 +111,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
LIST_WALK_UNTIL => list_walk_until, LIST_WALK_UNTIL => list_walk_until,
LIST_SORT_WITH => list_sort_with, LIST_SORT_WITH => list_sort_with,
LIST_ANY => list_any, LIST_ANY => list_any,
LIST_INTERSPERSE => list_intersperse,
LIST_FIND => list_find, LIST_FIND => list_find,
DICT_LEN => dict_len, DICT_LEN => dict_len,
DICT_EMPTY => dict_empty, DICT_EMPTY => dict_empty,
@ -2147,6 +2148,82 @@ fn list_sublist(symbol: Symbol, var_store: &mut VarStore) -> Def {
) )
} }
/// List.intersperse : List elem, elem -> List elem
fn list_intersperse(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list_var = var_store.fresh();
let sep_var = var_store.fresh();
let list_sym = Symbol::ARG_1;
let sep_sym = Symbol::ARG_2;
let clos_var = var_store.fresh();
let clos_acc_var = var_store.fresh();
let clos_sym = Symbol::LIST_INTERSPERSE_CLOS;
let clos_acc_sym = Symbol::ARG_3;
let clos_elem_sym = Symbol::ARG_4;
let int_var = var_store.fresh();
let zero = int(int_var, Variable::NATURAL, 0);
// \elem -> [sep, elem]
let clos = Closure(ClosureData {
function_type: clos_var,
closure_type: var_store.fresh(),
closure_ext_var: var_store.fresh(),
return_type: clos_acc_var,
name: clos_sym,
recursive: Recursive::NotRecursive,
captured_symbols: vec![(sep_sym, sep_var)],
arguments: vec![
(clos_acc_var, no_region(Pattern::Identifier(clos_acc_sym))),
(sep_var, no_region(Pattern::Identifier(clos_elem_sym))),
],
loc_body: {
let pair = List {
elem_var: sep_var,
loc_elems: vec![no_region(Var(sep_sym)), no_region(Var(clos_elem_sym))],
};
Box::new(no_region(RunLowLevel {
op: LowLevel::ListConcat,
args: vec![(clos_acc_var, Var(clos_acc_sym)), (clos_acc_var, pair)],
ret_var: clos_acc_var,
}))
},
});
// List.walk [] l (\acc, elem -> List.concat acc [sep, elem])
let acc = RunLowLevel {
op: LowLevel::ListWalk,
args: vec![
(list_var, Var(list_sym)),
(
clos_acc_var,
List {
elem_var: sep_var,
loc_elems: vec![],
},
),
(clos_var, clos),
],
ret_var: clos_acc_var,
};
let body = RunLowLevel {
op: LowLevel::ListDropAt,
args: vec![(clos_acc_var, acc), (int_var, zero)],
ret_var: clos_acc_var,
};
defn(
symbol,
vec![(list_var, list_sym), (sep_var, sep_sym)],
var_store,
body,
clos_acc_var,
)
}
/// List.drop : List elem, Nat -> List elem /// List.drop : List elem, Nat -> List elem
fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def { fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list_var = var_store.fresh(); let list_var = var_store.fresh();

View file

@ -1072,6 +1072,8 @@ define_builtins! {
47 LIST_FIND: "find" 47 LIST_FIND: "find"
48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find 48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find
49 LIST_SUBLIST: "sublist" 49 LIST_SUBLIST: "sublist"
50 LIST_INTERSPERSE: "intersperse"
51 LIST_INTERSPERSE_CLOS: "#intersperseClos"
} }
5 RESULT: "Result" => { 5 RESULT: "Result" => {
0 RESULT_RESULT: "Result" imported // the Result.Result type alias 0 RESULT_RESULT: "Result" imported // the Result.Result type alias

View file

@ -3805,6 +3805,17 @@ mod solve_expr {
); );
} }
#[test]
fn list_intersperse() {
infer_eq_without_problem(
indoc!(
r#"
List.intersperse
"#
),
"List a, a -> List a",
);
}
#[test] #[test]
fn function_that_captures_nothing_is_not_captured() { fn function_that_captures_nothing_is_not_captured() {
// we should make sure that a function that doesn't capture anything it not itself captured // we should make sure that a function that doesn't capture anything it not itself captured

View file

@ -277,6 +277,29 @@ fn list_drop_at() {
assert_evals_to!("List.dropAt [0] 0", RocList::from_slice(&[]), RocList<i64>); assert_evals_to!("List.dropAt [0] 0", RocList::from_slice(&[]), RocList<i64>);
} }
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn list_intersperse() {
assert_evals_to!(
indoc!(
r#"
List.intersperse [0, 0, 0] 1
"#
),
RocList::from_slice(&[0, 1, 0, 1, 0]),
RocList<i64>
);
assert_evals_to!(
indoc!(
r#"
List.intersperse [] 1
"#
),
RocList::from_slice(&[]),
RocList<i64>
);
}
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn list_drop_at_shared() { fn list_drop_at_shared() {