From 16fb04b4fa5399433ff8875062e43c15eb9251a8 Mon Sep 17 00:00:00 2001 From: satotake Date: Wed, 17 Nov 2021 15:18:45 +0000 Subject: [PATCH 1/3] Add builtin `List.intersperse` --- compiler/builtins/src/std.rs | 7 +++ compiler/can/src/builtins.rs | 77 ++++++++++++++++++++++++++++++ compiler/module/src/symbol.rs | 2 + compiler/solve/tests/solve_expr.rs | 11 +++++ compiler/test_gen/src/gen_list.rs | 23 +++++++++ 5 files changed, 120 insertions(+) diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 0f8d1fe154..289ae67bbe 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -1140,6 +1140,13 @@ pub fn types() -> MutMap { ) } + // 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 // len : Dict * * -> Nat diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 6e2342ca3e..2a247b9e61 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -111,6 +111,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option LIST_WALK_UNTIL => list_walk_until, LIST_SORT_WITH => list_sort_with, LIST_ANY => list_any, + LIST_INTERSPERSE => list_intersperse, LIST_FIND => list_find, DICT_LEN => dict_len, 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 fn list_drop(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh(); diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 44bf51012a..3783d24b90 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1072,6 +1072,8 @@ define_builtins! { 47 LIST_FIND: "find" 48 LIST_FIND_RESULT: "#find_result" // symbol used in the definition of List.find 49 LIST_SUBLIST: "sublist" + 50 LIST_INTERSPERSE: "intersperse" + 51 LIST_INTERSPERSE_CLOS: "#intersperseClos" } 5 RESULT: "Result" => { 0 RESULT_RESULT: "Result" imported // the Result.Result type alias diff --git a/compiler/solve/tests/solve_expr.rs b/compiler/solve/tests/solve_expr.rs index dcf74d79bb..c38a9b480d 100644 --- a/compiler/solve/tests/solve_expr.rs +++ b/compiler/solve/tests/solve_expr.rs @@ -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] fn function_that_captures_nothing_is_not_captured() { // we should make sure that a function that doesn't capture anything it not itself captured diff --git a/compiler/test_gen/src/gen_list.rs b/compiler/test_gen/src/gen_list.rs index 5e0f737e72..dc482918e3 100644 --- a/compiler/test_gen/src/gen_list.rs +++ b/compiler/test_gen/src/gen_list.rs @@ -277,6 +277,29 @@ fn list_drop_at() { assert_evals_to!("List.dropAt [0] 0", RocList::from_slice(&[]), RocList); } +#[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 + ); + assert_evals_to!( + indoc!( + r#" + List.intersperse [] 1 + "# + ), + RocList::from_slice(&[]), + RocList + ); +} + #[test] #[cfg(any(feature = "gen-llvm"))] fn list_drop_at_shared() { From 7ce9f1b3bd8ef03d495a67161dff5b254ca51d54 Mon Sep 17 00:00:00 2001 From: satotake Date: Thu, 18 Nov 2021 10:15:38 +0000 Subject: [PATCH 2/3] refactor after review --- compiler/can/src/builtins.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 2a247b9e61..2416ef3afc 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -2166,7 +2166,7 @@ fn list_intersperse(symbol: Symbol, var_store: &mut VarStore) -> Def { let int_var = var_store.fresh(); let zero = int(int_var, Variable::NATURAL, 0); - // \elem -> [sep, elem] + // \acc, elem -> acc |> List.append sep |> List.append elem let clos = Closure(ClosureData { function_type: clos_var, closure_type: var_store.fresh(), @@ -2180,19 +2180,21 @@ fn list_intersperse(symbol: Symbol, var_store: &mut VarStore) -> Def { (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))], + let append_sep = RunLowLevel { + op: LowLevel::ListAppend, + args: vec![(clos_acc_var, Var(clos_acc_sym)), (sep_var, Var(sep_sym))], + ret_var: clos_acc_var, }; + Box::new(no_region(RunLowLevel { - op: LowLevel::ListConcat, - args: vec![(clos_acc_var, Var(clos_acc_sym)), (clos_acc_var, pair)], + op: LowLevel::ListAppend, + args: vec![(clos_acc_var, append_sep), (sep_var, Var(clos_elem_sym))], ret_var: clos_acc_var, })) }, }); - // List.walk [] l (\acc, elem -> List.concat acc [sep, elem]) + // List.walk [] l (\acc, elem -> acc |> List.append sep |> List.append elem) let acc = RunLowLevel { op: LowLevel::ListWalk, args: vec![ From 9aabd0895309a58243dd76c684cf0e6988f15309 Mon Sep 17 00:00:00 2001 From: satotake Date: Thu, 18 Nov 2021 11:17:05 +0000 Subject: [PATCH 3/3] fmt --- compiler/can/src/builtins.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 4f4ef6643a..163a82fd92 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -2227,7 +2227,6 @@ fn list_intersperse(symbol: Symbol, var_store: &mut VarStore) -> Def { ) } - /// List.split : List elem, Nat -> { before: List elem, others: List elem } fn list_split(symbol: Symbol, var_store: &mut VarStore) -> Def { let list_var = var_store.fresh();