Skip to content

Commit 33e0dbb

Browse files
authored
Merge branch 'dev' into projector-html
2 parents ba6f6a2 + aeea780 commit 33e0dbb

File tree

4 files changed

+332
-4
lines changed

4 files changed

+332
-4
lines changed

src/haz3lcore/pretty/ExpToSegment.re

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,6 +1383,7 @@ let rec exp_to_pretty = (~settings: Settings.t, exp: Exp.t): pretty => {
13831383
let+ p = pat_to_pretty(~settings: Settings.t, p)
13841384
and+ thm = go(thm)
13851385
and+ e = go(e);
1386+
let e = settings.inline ? e : [Secondary(mk_newline(Id.mk()))] @ e;
13861387
wrap(exp, [mk_form(Theorem, id, [p, thm])] @ e);
13871388
| ProofObject(t) =>
13881389
let id = exp |> Exp.rep_id;
@@ -1767,7 +1768,7 @@ and typ_to_pretty = (~settings: Settings.t, typ: Typ.t): pretty => {
17671768
| Variant(c, ann, None) => {
17681769
let+ seg =
17691770
text_to_pretty(
1770-
Option.value(~default=Id.invalid, ListUtil.hd_opt(ann.ids)),
1771+
OptUtil.get(() => Id.mk(), ListUtil.hd_opt(ann.ids)),
17711772
Sort.Typ,
17721773
c,
17731774
);
@@ -1776,7 +1777,7 @@ and typ_to_pretty = (~settings: Settings.t, typ: Typ.t): pretty => {
17761777
| Variant(c, ann, Some(x)) => {
17771778
let+ constructor =
17781779
text_to_pretty(
1779-
Option.value(~default=Id.invalid, List.nth_opt(ann.ids, 1)),
1780+
OptUtil.get(() => Id.mk(), List.nth_opt(ann.ids, 1)),
17801781
Sort.Typ,
17811782
c,
17821783
);
@@ -1786,7 +1787,7 @@ and typ_to_pretty = (~settings: Settings.t, typ: Typ.t): pretty => {
17861787
@ [
17871788
mk_form(
17881789
ApTyp,
1789-
Option.value(~default=Id.invalid, ListUtil.hd_opt(ann.ids)),
1790+
OptUtil.get(() => Id.mk(), ListUtil.hd_opt(ann.ids)),
17901791
[go(x)],
17911792
),
17921793
],

src/language/builtins/BuiltinsList.re

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2880,6 +2880,302 @@ let go: ([?], [?], [?]) -> [?] =
28802880
Fresh.(Exp.(var("zip")));
28812881
},
28822882
},
2883+
{
2884+
str: {|fix unique -> fun xs ->
2885+
fold_left(xs, fun (seen, x) -> if mem(seen, x) then seen else seen @ [x], [])|},
2886+
name: "unique",
2887+
arg: List(unknown(Internal)),
2888+
ret: List(unknown(Internal)),
2889+
imp: {
2890+
Fresh.(
2891+
Exp.(
2892+
fix_f(
2893+
Pat.var("unique"),
2894+
fn(
2895+
Pat.var("xs"),
2896+
ap(
2897+
Forward,
2898+
var("fold_left"),
2899+
tuple([
2900+
var("xs"),
2901+
fn(
2902+
Pat.tuple([Pat.var("seen"), Pat.var("x")]),
2903+
if_(
2904+
ap(
2905+
Forward,
2906+
var("mem"),
2907+
tuple([var("seen"), var("x")]),
2908+
),
2909+
var("seen"),
2910+
ap(
2911+
Forward,
2912+
var("append"),
2913+
tuple([var("seen"), list_lit([var("x")])]),
2914+
),
2915+
),
2916+
None,
2917+
None,
2918+
),
2919+
list_lit([]),
2920+
]),
2921+
),
2922+
None,
2923+
None,
2924+
),
2925+
None,
2926+
)
2927+
)
2928+
);
2929+
},
2930+
},
2931+
{
2932+
str: {hazel|fix pivot_table -> fun (table, new_col, index, value) ->
2933+
let indices = map(table, index) |> unique in
2934+
let new_cols = map(table, new_col) |> unique in
2935+
2936+
map(indices, fun idx ->
2937+
(index=idx) ...
2938+
(map(new_cols, fun col ->
2939+
(label=col,
2940+
value=filter(table, fun r -> index(r) == idx && new_col(r) == col)
2941+
|>value)
2942+
) |> from_lvs))|hazel},
2943+
name: "pivot_table",
2944+
arg:
2945+
Prod([
2946+
list(unknown(Internal)),
2947+
arrow(unknown(Internal), unknown(Internal)),
2948+
arrow(unknown(Internal), unknown(Internal)),
2949+
arrow(unknown(Internal), unknown(Internal)),
2950+
]),
2951+
ret: List(unknown(Internal)),
2952+
imp: {
2953+
open Fresh;
2954+
open Exp;
2955+
let indices =
2956+
ap(
2957+
Reverse,
2958+
var("unique"),
2959+
ap(Forward, var("map"), tuple([var("table"), var("index")])),
2960+
);
2961+
let new_cols =
2962+
ap(
2963+
Reverse,
2964+
var("unique"),
2965+
ap(
2966+
Forward,
2967+
var("map"),
2968+
tuple([var("table"), var("new_col")]),
2969+
),
2970+
);
2971+
2972+
// filter(table, fun r -> index(r) == idx && new_col(r) == col)
2973+
let filtered_values =
2974+
ap(
2975+
Forward,
2976+
var("filter"),
2977+
tuple([
2978+
var("table"),
2979+
fn(
2980+
Pat.var("r"),
2981+
bin_op(
2982+
Bool(And),
2983+
bin_op(
2984+
Poly(Equals),
2985+
ap(Forward, var("index"), var("r")),
2986+
var("idx"),
2987+
),
2988+
bin_op(
2989+
Poly(Equals),
2990+
ap(Forward, var("new_col"), var("r")),
2991+
var("col"),
2992+
),
2993+
),
2994+
None,
2995+
None,
2996+
),
2997+
]),
2998+
);
2999+
/* (label=col,
3000+
value=filter(table, fun r -> index(r) == idx && new_col(r) == col)
3001+
|>value) */
3002+
let lvs =
3003+
tuple([
3004+
tup_label(label("label"), var("col")),
3005+
tup_label(
3006+
label("value"),
3007+
ap(Forward, var("value"), filtered_values),
3008+
),
3009+
]);
3010+
3011+
let from_lvs =
3012+
ap(
3013+
Reverse,
3014+
var("from_lvs"),
3015+
ap(
3016+
Forward,
3017+
var("map"),
3018+
tuple([
3019+
var("new_cols"),
3020+
fn(Pat.var("col"), lvs, None, None),
3021+
]),
3022+
),
3023+
);
3024+
3025+
let mapped =
3026+
ap(
3027+
Forward,
3028+
var("map"),
3029+
tuple([
3030+
var("indices"),
3031+
fn(
3032+
Pat.var("idx"),
3033+
tuple_extension(
3034+
tuple([tup_label(label("index"), var("idx"))]),
3035+
from_lvs,
3036+
),
3037+
None,
3038+
None,
3039+
),
3040+
]),
3041+
);
3042+
3043+
let fn =
3044+
fn(
3045+
Pat.tuple([
3046+
Pat.var("table"),
3047+
Pat.var("new_col"),
3048+
Pat.var("index"),
3049+
Pat.var("value"),
3050+
]),
3051+
let_(
3052+
Pat.var("indices"),
3053+
indices,
3054+
let_(Pat.var("new_cols"), new_cols, mapped),
3055+
),
3056+
None,
3057+
None,
3058+
);
3059+
fix_f(Pat.var("pivot_table"), fn, None);
3060+
},
3061+
},
3062+
{
3063+
str: {|fix group_on_key -> fun (xs, f) -> fold_left(xs, fun (acc, x) ->
3064+
let update_groups = fix update_groups -> fun (acc, key, x) ->
3065+
case acc
3066+
| [] => [(key, [x])]
3067+
| (k, g) :: acc => if k == key then (k, x :: g) :: acc else (k, g) :: update_groups(acc, key, x)
3068+
end in update_groups(acc, f(x), x), [])|},
3069+
name: "group_on_key",
3070+
arg:
3071+
Prod([
3072+
list(unknown(Internal)),
3073+
arrow(unknown(Internal), unknown(Internal)),
3074+
]),
3075+
ret: List(prod([unknown(Internal), list(unknown(Internal))])),
3076+
imp: {
3077+
Fresh.(
3078+
Exp.(
3079+
fix_f(
3080+
Pat.var("group_on_key"),
3081+
fn(
3082+
Pat.tuple([Pat.var("xs"), Pat.var("f")]),
3083+
ap(
3084+
Forward,
3085+
var("fold_left"),
3086+
tuple([
3087+
var("xs"),
3088+
let_(
3089+
Pat.var("update_groups"),
3090+
fix_f(
3091+
Pat.var("update_groups"),
3092+
fn(
3093+
Pat.tuple([
3094+
Pat.var("acc"),
3095+
Pat.var("key"),
3096+
Pat.var("x"),
3097+
]),
3098+
match(
3099+
var("acc"),
3100+
[
3101+
(
3102+
Pat.list_lit([]),
3103+
list_lit([
3104+
tuple([
3105+
var("key"),
3106+
list_lit([var("x")]),
3107+
]),
3108+
]),
3109+
),
3110+
(
3111+
Pat.cons(
3112+
Pat.tuple([Pat.var("k"), Pat.var("g")]),
3113+
Pat.var("acc_tail"),
3114+
),
3115+
if_(
3116+
bin_op(
3117+
Poly(Equals),
3118+
var("k"),
3119+
var("key"),
3120+
),
3121+
cons(
3122+
tuple([
3123+
var("k"),
3124+
list_concat(
3125+
var("g"),
3126+
list_lit([var("x")]),
3127+
),
3128+
]),
3129+
var("acc_tail"),
3130+
),
3131+
cons(
3132+
tuple([var("k"), var("g")]),
3133+
ap(
3134+
Forward,
3135+
var("update_groups"),
3136+
tuple([
3137+
var("acc_tail"),
3138+
var("key"),
3139+
var("x"),
3140+
]),
3141+
),
3142+
),
3143+
),
3144+
),
3145+
],
3146+
),
3147+
None,
3148+
Some("update_groups+"),
3149+
),
3150+
None,
3151+
),
3152+
fn(
3153+
Pat.tuple([Pat.var("acc"), Pat.var("x")]),
3154+
ap(
3155+
Forward,
3156+
var("update_groups"),
3157+
tuple([
3158+
var("acc"),
3159+
ap(Forward, var("f"), var("x")),
3160+
var("x"),
3161+
]),
3162+
),
3163+
None,
3164+
None,
3165+
),
3166+
),
3167+
list_lit([]),
3168+
]),
3169+
),
3170+
None,
3171+
Some("group_on_key+"),
3172+
),
3173+
None,
3174+
)
3175+
)
3176+
);
3177+
},
3178+
},
28833179
]
28843180
// De-alias all aliases
28853181
|> Util.ListUtil.map_with_history((prev, curr) =>

src/web/app/editors/result/StepperEditor.re

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ module View = {
155155
~selected_id,
156156
~_dynamics: Language.Dynamics.Map.t=Language.Dynamics.Map.empty,
157157
model: Model.t,
158-
) =>
158+
) => {
159159
CodeSelectable.View.view(
160160
~dynamics=Language.Dynamics.Map.empty,
161161
~signal=
@@ -176,4 +176,5 @@ module View = {
176176
),
177177
model.editor,
178178
);
179+
};
179180
};

test/evaluator/Test_Evaluator_Builtins_Lists.re

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,5 +446,35 @@ let tests = (
446446
);
447447
},
448448
),
449+
test_case("unique", `Quick, () =>
450+
parse_and_evaluate_test({|[1, 2, 3]|}, {|unique([1, 2, 2, 3, 1, 3])|})
451+
),
452+
test_case("group_on_key by parity", `Quick, () =>
453+
parse_and_evaluate_test(
454+
{|[(1, [1, 3]), (0, [2, 4])]|},
455+
{|group_on_key([1, 2, 3, 4], fun x -> int_mod(x, 2))|},
456+
)
457+
),
458+
test_case("pivot_table", `Quick, () =>
459+
parse_and_evaluate_test(
460+
{|
461+
[(index="x", `A`=2, `B`=1, `C`=0), (index="y", `A`=1, `B`=1, `C`=1)]
462+
|},
463+
{|pivot_table(
464+
[
465+
("A", "x"),
466+
("A", "y"),
467+
("B", "x"),
468+
("B", "y"),
469+
("A", "x"),
470+
("C", "y")
471+
],
472+
fun (r, _) -> r,
473+
fun (_, c) -> c,
474+
length
475+
)
476+
|},
477+
)
478+
),
449479
],
450480
);

0 commit comments

Comments
 (0)