the next generation of the in-browser educational proof assistant
1let newline = "\n"
2let mapMapValues = (m: Map.t<'a, 'b>, f: 'b => 'c) => {
3 let nu = Map.make()
4 m->Map.forEachWithKey((v, k) => {
5 nu->Map.set(k, f(v))
6 })
7 nu
8}
9
10@send external toString: 'a => string = "toString"
11let showArray: array<'a> => string = a => `[${Array.toString(a)}]`
12let showTuple: (('a, 'b)) => string = ((a, b)) => `(${toString(a)} ${toString(b)})`
13
14let prettyPrintMap = (
15 m: Map.t<'k, 'v>,
16 ~showK: 'k => string=toString,
17 ~showV: 'v => string=toString,
18) => {
19 m
20 ->Map.entries
21 ->Iterator.toArray
22 ->Array.map(((k, v)) => {
23 (showK(k), showV(v))
24 })
25 ->showArray
26}
27
28let prettyPrintIntMap = (m: Belt.Map.Int.t<'v>, ~showV: 'v => string=toString) => {
29 m
30 ->Belt.Map.Int.toArray
31 ->Array.map(((k, v)) => {
32 (Int.toString(k), showV(v))
33 })
34 ->showArray
35}
36
37let prettyPrintVar = (idx: int, scope: array<string>) =>
38 "$" ++
39 switch scope[idx] {
40 | Some(n) if Array.indexOf(scope, n) == idx => n
41 | _ => "\\"->String.concat(String.make(idx))
42 }
43let prettyPrintSchematic = (schematic: int, allowed: array<int>, scope: array<string>) => {
44 let allowedStr =
45 allowed
46 ->Array.map(idx => prettyPrintVar(idx, scope))
47 ->Array.join(" ")
48 `?${Int.toString(schematic)}(${allowedStr})`
49}
50
51let mapIntersectionWith = (m1: Map.t<'k, 'a>, m2: Map.t<'k, 'b>, f: ('a, 'b) => 'c) => {
52 let go = (m1, m2) => {
53 let nu: Map.t<'k, 'c> = Map.make()
54 m1->Map.forEachWithKey((v1, k) => {
55 switch m2->Map.get(k) {
56 | Some(v2) => nu->Map.set(k, f(v1, v2))
57 | None => ()
58 }
59 })
60 nu
61 }
62 if Map.size(m1) < Map.size(m2) {
63 go(m1, m2)
64 } else {
65 go(m2, m1)
66 }
67}
68
69let mapUnionWith = (m1: Map.t<'k, 'a>, m2: Map.t<'k, 'a>, f: ('a, 'a) => 'a) => {
70 let nu = Map.make()
71 m1->Map.forEachWithKey((v1, k) => {
72 switch m2->Map.get(k) {
73 | Some(v2) => nu->Map.set(k, f(v1, v2))
74 | None => nu->Map.set(k, v1)
75 }
76 })
77 m2->Map.forEachWithKey((v, k) => {
78 switch nu->Map.get(k) {
79 | Some(_) => ()
80 | None => nu->Map.set(k, v)
81 }
82 })
83 nu
84}
85
86// left biased
87let mapUnion = (m1, m2) => mapUnionWith(m1, m2, (v1, _v2) => v1)
88
89let mapIntersection = (m1: Map.t<'k, 'a>, m2: Map.t<'k, 'b>): Map.t<'k, ('a, 'b)> =>
90 mapIntersectionWith(m1, m2, (b, c) => (b, c))
91
92let withKey: ('props, int) => 'props = %raw(`(props, key) => ({...props, key})`)
93
94let mapEqual = (m1, m2) => {
95 Map.size(m1) == Map.size(m1) &&
96 mapIntersection(m1, m2)
97 ->Map.values
98 ->Iterator.toArray
99 ->Array.filter(((a, b)) => a == b)
100 ->Array.length == Map.size(m2)
101}
102
103module Map = {
104 type t<'k, 'v> = Map.t<'k, 'v>
105 let filterMap = (m: t<'k, 'v1>, f: ('k, 'v1) => option<'v2>): t<'k, 'v2> =>
106 m
107 ->Map.entries
108 ->Iterator.toArrayWithMapper(((i, v)) => f(i, v)->Option.map(v => (i, v)))
109 ->Array.keepSome
110 ->Map.fromArray
111}
112
113let arrayWithIndex = (arr: array<React.element>) => {
114 React.array(arr->Array.mapWithIndex((m, i) => <span key={String.make(i)}> m </span>))
115}
116let execRe = (re, str) => {
117 re
118 ->RegExp.exec(str)
119 ->Option.map(result => {
120 open RegExp.Result
121 (matches(result), fullMatch(result)->String.length)
122 })
123}
124
125let identRegexStr = `([a-zA-Z][a-zA-Z\\d]*)`
126
127let intersperse = (a: array<'a>, ~with: 'a) =>
128 a->Array.flatMapWithIndex((e, i) =>
129 if i == 0 {
130 [e]
131 } else {
132 [with, e]
133 }
134 )
135
136exception Unreachable(string)
137exception Err(string)
138let mustFindIndex = (arr, f) => {
139 switch Array.findIndex(arr, f) {
140 | -1 => throw(Unreachable("Element not found"))
141 | i => i
142 }
143}
144
145module Result = {
146 include Result
147 type t<'a, 'b> = result<'a, 'b>
148 let ok = (r: t<'a, 'b>): option<'a> =>
149 switch r {
150 | Ok(a) => Some(a)
151 | Error(_) => None
152 }
153 let or = (r1: t<'a, 'b>, r2: unit => t<'a, 'b>): t<'a, 'b> =>
154 switch r1 {
155 | Ok(_) => r1
156 | Error(_) => r2()
157 }
158}
159
160module Option = {
161 include Option
162 let getOrElse = (t, f): 'a =>
163 switch t {
164 | Some(a) => a
165 | None => f()
166 }
167}