|
| 1 | + |
| 2 | +fun nofibPrint(x) = globalThis.process.stdout.write(globalThis.JSON.stringify(x) + "\n") |
| 3 | +fun nofibError(e) = globalThis.eval("throw new Error('" + e + "')") |
| 4 | +fun nofibBigInt(i) = globalThis.BigInt(i) |
| 5 | + |
| 6 | +abstract class Option[out T]: Some[T] | None |
| 7 | +class Some[out T](x: T) extends Option[T] |
| 8 | +object None extends Option |
| 9 | + |
| 10 | +class Lazy[out A](init: () -> A) with |
| 11 | + mut val cached: Option[A] = None |
| 12 | + fun get() = |
| 13 | + if cached is |
| 14 | + Some(v) then v |
| 15 | + else |
| 16 | + let v = init() |
| 17 | + set cached = Some(v) |
| 18 | + v |
| 19 | +fun lazy(x) = Lazy(x) |
| 20 | +fun force(x) = if x is Lazy then x.get() |
| 21 | + |
| 22 | +abstract class List[out T]: Cons[T] | Nil |
| 23 | +class Cons[out T](head: T, tail: List[T]) extends List[T] with |
| 24 | + fun toString() = |
| 25 | + "[" + _internal_cons_to_str(Cons(head, tail)) + "]" |
| 26 | +object Nil extends List with |
| 27 | + fun toString() = "[]" |
| 28 | +fun (::) cons(x, xs) = Cons(x, xs) |
| 29 | +fun _internal_cons_to_str(ls) = if ls is |
| 30 | + Nil then "" |
| 31 | + Cons(h, Nil) then h.toString() |
| 32 | + Cons(h, t) then h.toString() + "," + _internal_cons_to_str(t) |
| 33 | +fun ltList(xs, ys, lt, gt) = if xs is |
| 34 | + Nil then true |
| 35 | + Cons(x, xs) and ys is |
| 36 | + Nil then false |
| 37 | + Cons(y, ys) and |
| 38 | + lt(x, y) then true |
| 39 | + gt(x, y) then false |
| 40 | + else ltList(xs, ys, lt, gt) |
| 41 | + |
| 42 | + |
| 43 | +type LazyList[out T] = Lazy[LzList[T]] |
| 44 | +abstract class LzList[out T]: LzCons[T] | LzNil |
| 45 | +class LzCons[out T](head: T, tail: LazyList[T]) extends LzList[T] |
| 46 | +object LzNil extends LzList |
| 47 | + |
| 48 | +class Tup2[out T1, T2](fst: T1, snd: T2) with |
| 49 | + fun toString() = "(" + fst.toString() + "," + snd.toString() + ")" |
| 50 | +fun ltTup2(t1, t2, lt1, gt1, lt2) = if t1 is Tup2(a, b) and t2 is Tup2(c, d) and |
| 51 | + lt1(a, c) then true |
| 52 | + gt1(a, c) then false |
| 53 | + else lt2(b, d) |
| 54 | +fun eqTup2(t1, t2) = if t1 is Tup2(a, b) and t2 is Tup2(c, d) then a == c and b == d |
| 55 | +class Tup3[out T1, T2, T3](fst: T1, snd: T2, thd: T3) with |
| 56 | + fun toString() = "(" + fst.toString() + "," + snd.toString() + "," + thd.toString() + ")" |
| 57 | +class Tup4[out T1, T2, T3, T4](fst: T1, snd: T2, thd: T3, fth: T4) |
| 58 | +class Tup5[out T1, T2, T3, T4, T5](fst: T1, snd: T2, thd: T3, fth: T4, ffth: T5) |
| 59 | +class Tup6[out T1, T2, T3, T4, T5, T6](fst: T1, snd: T2, thd: T3, fth: T4, ffth: T5, sxth: T6) |
| 60 | +class Tup7[out T1, T2, T3, T4, T5, T6, T7](fst: T1, snd: T2, thd: T3, fth: T4, ffth: T5, sxth: T6, svth: T7) |
| 61 | +class Tup8[out T1, T2, T3, T4, T5, T6, T7, T8](fst: T1, snd: T2, thd: T3, fth: T4, ffth: T5, sxth: T6, svth: T7, eghth: T8) |
| 62 | + |
| 63 | +fun compose(f, g) = x => f(g(x)) |
| 64 | + |
| 65 | +fun snd(x) = if x is Tup2(f, s) then s |
| 66 | +fun fst(x) = if x is Tup2(f, s) then f |
| 67 | + |
| 68 | +fun until(p, f, i) = if p(i) then i else until(p, f, f(i)) |
| 69 | + |
| 70 | +fun flip(f, x, y) = f(y)(x) |
| 71 | + |
| 72 | +fun not(x) = if x then false else true |
| 73 | + |
| 74 | +fun power(a, n) = globalThis.Math.pow(a, n) |
| 75 | + |
| 76 | +fun intDiv(a, b) = globalThis.Math.floor(a / b) |
| 77 | +fun intQuot(a, b) = globalThis.Math.trunc(a / b) |
| 78 | + |
| 79 | +fun intMod(a, b) = a - (b * intDiv(a, b)) |
| 80 | +fun intRem(a, b) = a - (b * intQuot(a, b)) |
| 81 | + |
| 82 | +fun quotRem(a, b) = Tup2(intQuot(a, b), intRem(a, b)) |
| 83 | +fun divMod(a, b) = Tup2(intDiv(a, b), intMod(a, b)) |
| 84 | + |
| 85 | +fun max(a, b) = globalThis.Math.max(a, b) |
| 86 | + |
| 87 | +fun abs(x) = globalThis.Math.abs(x) |
| 88 | + |
| 89 | +fun head(l) = if l is Cons(h, t) then h |
| 90 | +fun tail(l) = if l is Cons(h, t) then t |
| 91 | + |
| 92 | +fun reverse(l) = |
| 93 | + fun r(l', l) = if l is Cons(x, xs) then r(Cons(x, l'), xs) else l' |
| 94 | + r(Nil, l) |
| 95 | + |
| 96 | +fun map(f, xs) = if xs is |
| 97 | + Cons(x, xs) then Cons(f(x), map(f, xs)) |
| 98 | + Nil then Nil |
| 99 | + |
| 100 | +fun listLen(ls) = |
| 101 | + fun l(ls, a) = if ls is |
| 102 | + Nil then a |
| 103 | + Cons(h, t) then l(t, a + 1) |
| 104 | + l(ls, 0) |
| 105 | + |
| 106 | +fun listEq(xs, ys) = if |
| 107 | + xs is Nil and ys is Nil then true |
| 108 | + xs is Cons(hx, tx) and ys is Cons(hy, ty) and (hx == hy) then listEq(tx, ty) |
| 109 | + else false |
| 110 | + |
| 111 | +fun enumFromTo(a, b) = if a <= b then Cons(a, enumFromTo(a + 1, b)) else Nil |
| 112 | + |
| 113 | +fun enumFromThenTo(a, t, b) = if a <= b then Cons(a, enumFromThenTo(t, 2 * t - a, b)) else Nil |
| 114 | + |
| 115 | +fun drop(n, ls) = if ls is |
| 116 | + Nil then Nil |
| 117 | + Cons(h, t) and |
| 118 | + n <= 0 then ls |
| 119 | + else drop(n - 1, t) |
| 120 | + |
| 121 | +fun take(n, ls) = if ls is |
| 122 | + Nil then Nil |
| 123 | + Cons(h, t) and |
| 124 | + n <= 0 then Nil |
| 125 | + else Cons(h, take(n - 1, t)) |
| 126 | + |
| 127 | +fun splitAt(n, ls) = Tup2(take(n, ls), drop(n, ls)) |
| 128 | + |
| 129 | +fun zip(xs, ys) = if xs is |
| 130 | + Cons(x, xs) and ys is Cons(y, ys) then Cons(Tup2(x, y), zip(xs, ys)) |
| 131 | + else Nil |
| 132 | + |
| 133 | +fun inList(x, ls) = if ls is |
| 134 | + Cons(h, t) and |
| 135 | + x == h then true |
| 136 | + else inList(x, t) |
| 137 | + Nil then false |
| 138 | + |
| 139 | +fun notElem(x, ls) = not(inList(x, ls)) |
| 140 | + |
| 141 | +fun append(xs, ys) = if xs is |
| 142 | + Nil then ys |
| 143 | + Cons(x, xs) then Cons(x, append(xs, ys)) |
| 144 | + |
| 145 | +fun concat(ls) = if ls is |
| 146 | + Nil then Nil |
| 147 | + Cons(x, xs) then append(x, concat(xs)) |
| 148 | + |
| 149 | +fun filter(f, ls) = if ls is |
| 150 | + Nil then Nil |
| 151 | + Cons(h, t) and |
| 152 | + f(h) then h :: filter(f, t) |
| 153 | + else filter(f, t) |
| 154 | + |
| 155 | +fun all(p, ls) = if ls is |
| 156 | + Nil then true |
| 157 | + Cons(h, t) and |
| 158 | + p(h) then all(p, t) |
| 159 | + else false |
| 160 | + |
| 161 | +fun orList(ls) = if ls is |
| 162 | + Nil then false |
| 163 | + Cons(h, t) and |
| 164 | + h then true |
| 165 | + else orList(t) |
| 166 | + |
| 167 | +fun dropWhile(f, ls) = if ls is |
| 168 | + Nil then Nil |
| 169 | + Cons(h, t) and |
| 170 | + f(h) then dropWhile(f, t) |
| 171 | + else h :: t |
| 172 | + |
| 173 | +fun foldl(f, a, xs) = if xs is |
| 174 | + Nil then a |
| 175 | + Cons(h, t) then foldl(f, f(a, h), t) |
| 176 | + |
| 177 | +fun scanl(f, q, ls) = if ls is |
| 178 | + Nil then Cons(q, Nil) |
| 179 | + Cons(x, xs) then Cons(q, scanl(f, f(q, x), xs)) |
| 180 | + |
| 181 | +fun scanr(f, q, ls) = if ls is |
| 182 | + Nil then Cons(q, Nil) |
| 183 | + Cons(x, xs) and scanr(f, q, xs) is Cons(q, t) then Cons(f(x, q), Cons(q, t)) |
| 184 | + |
| 185 | +fun foldr(f, z, xs) = if xs is |
| 186 | + Nil then z |
| 187 | + Cons(h, t) then f(h, foldr(f, z, t)) |
| 188 | + |
| 189 | +fun foldl1(f, ls) = if |
| 190 | + ls is Cons(x, xs) then foldl(f, x, xs) |
| 191 | + |
| 192 | +fun foldr1(f, ls) = if ls is |
| 193 | + Cons(x, Nil) then x |
| 194 | + Cons(x, xs) then f(x, foldr1(f, xs)) |
| 195 | + |
| 196 | +fun maximum(xs) = foldl1((x, y) => if x > y then x else y, xs) |
| 197 | + |
| 198 | +fun nubBy(eq, ls) = if ls is |
| 199 | + Nil then Nil |
| 200 | + Cons(h, t) then h :: nubBy(eq, filter(y => not(eq(h, y)), t)) |
| 201 | + |
| 202 | +fun zipWith(f, xss, yss) = if |
| 203 | + xss is Cons(x, xs) and yss is Cons(y, ys) then Cons(f(x, y), zipWith(f, xs, ys)) |
| 204 | + else Nil |
| 205 | + |
| 206 | +fun deleteBy(eq, x, ys) = if ys is |
| 207 | + Nil then Nil |
| 208 | + Cons(y, ys) and |
| 209 | + eq(x, y) then ys |
| 210 | + else Cons(y, deleteBy(eq, x, ys)) |
| 211 | + |
| 212 | +fun unionBy(eq, xs, ys) = append(xs, foldl((acc, y) => deleteBy(eq, y, acc), nubBy(eq, ys), xs)) |
| 213 | + |
| 214 | +fun union(xs, ys) = unionBy((x, y) => x == y, xs, ys) |
| 215 | + |
| 216 | +fun atIndex(i, ls) = if ls is |
| 217 | + Cons(h, t) and |
| 218 | + i == 0 then h |
| 219 | + else atIndex(i - 1, t) |
| 220 | + |
| 221 | +fun sum(xs) = |
| 222 | + fun go(xs, a) = if xs is |
| 223 | + Nil then a |
| 224 | + Cons(h, t) then go(t, a + h) |
| 225 | + go(xs, 0) |
| 226 | + |
| 227 | +fun null_(ls) = if ls is |
| 228 | + Nil then true |
| 229 | + else false |
| 230 | + |
| 231 | +fun replicate(n, x) = if n == 0 then Nil else Cons(x, replicate(n - 1, x)) |
| 232 | + |
| 233 | +fun unzip(l) = |
| 234 | + fun f(l, a, b) = if l is |
| 235 | + Nil then Tup2(reverse(a), reverse(b)) |
| 236 | + Cons(Tup2(x, y), t) then f(t, Cons(x, a), Cons(y, b)) |
| 237 | + f(l, Nil, Nil) |
| 238 | + |
| 239 | +fun zip3(xs, ys, zs) = if |
| 240 | + xs is Cons(x, xs) and ys is Cons(y, ys) and zs is Cons(z, zs) then Cons(Tup3(x, y, z), zip3(xs, ys, zs)) |
| 241 | + else Nil |
| 242 | + |
| 243 | +fun transpose(xss) = |
| 244 | + fun lscomp(ls) = if ls is |
| 245 | + Nil then Nil |
| 246 | + Cons(h, t) and h is |
| 247 | + Cons(hd, tl) then Cons(Tup2(hd, tl), lscomp(t)) |
| 248 | + else lscomp(t) |
| 249 | + fun combine(y, h, ys, t) = Cons(Cons(y, h), transpose(Cons(ys, t))) |
| 250 | + if xss is |
| 251 | + Nil then Nil |
| 252 | + Cons(Nil, xss) then transpose(xss) |
| 253 | + Cons(Cons(x, xs), xss) and unzip(lscomp(xss)) is Tup2(hds, tls) then combine(x, hds, xs, tls) |
| 254 | + |
| 255 | + |
| 256 | +// ===================== |
| 257 | + |
| 258 | +fun map_lz(f, ls) = lazy of () => |
| 259 | + if force(ls) is |
| 260 | + LzNil then LzNil |
| 261 | + LzCons(h, t) then LzCons(f(h), map_lz(f, t)) |
| 262 | + |
| 263 | +fun filter_lz(p, ls) = Lazy of () => |
| 264 | + if force(ls) is |
| 265 | + LzNil then LzNil |
| 266 | + LzCons(h, t) and |
| 267 | + p(h) then LzCons(h, filter_lz(p, t)) |
| 268 | + else force(filter_lz(p, t)) |
| 269 | + |
| 270 | +fun nubBy_lz(eq, ls) = Lazy of () => |
| 271 | + if force(ls) is |
| 272 | + LzNil then LzNil |
| 273 | + LzCons(h, t) then LzCons(h, nubBy_lz(eq, filter_lz(y => not(eq(h, y)), t))) |
| 274 | + |
| 275 | +fun nub_lz(ls) = nubBy_lz((x, y) => x == y, ls) |
| 276 | + |
| 277 | +fun take_lz(n, ls) = if |
| 278 | + n > 0 and force(ls) is |
| 279 | + LzNil then Nil |
| 280 | + LzCons(h, t) then Cons(h, take_lz(n - 1, t)) |
| 281 | + else Nil |
| 282 | + |
| 283 | +fun take_lz_lz(n, ls) = lazy of () => |
| 284 | + if n > 0 and force(ls) is |
| 285 | + LzNil then LzNil |
| 286 | + LzCons(h, t) then LzCons(h, take_lz_lz(n - 1, t)) |
| 287 | + else LzNil |
| 288 | + |
| 289 | +fun drop_lz(n, ls) = if |
| 290 | + n <= 0 then ls |
| 291 | + force(ls) is |
| 292 | + LzNil then lazy of () => LzNil |
| 293 | + LzCons(h, t) then drop_lz(n - 1, t) |
| 294 | + |
| 295 | +fun splitAt_lz(n, ls) = Tup2(take_lz(n, ls), drop_lz(n, ls)) |
| 296 | + |
| 297 | +fun zipWith_lz_lz(f, xss, yss) = lazy of () => if |
| 298 | + force(xss) is LzCons(x, xs) and (force(yss)) is LzCons(y, ys) then LzCons(f(x, y), zipWith_lz_lz(f, xs, ys)) |
| 299 | + else LzNil |
| 300 | + |
| 301 | +fun zipWith_lz_nl(f, xss, yss) = if |
| 302 | + force(xss) is LzCons(x, xs) and yss is Cons(y, ys) then Cons(f(x, y), zipWith_lz_nl(f, xs, ys)) |
| 303 | + else Nil |
| 304 | + |
| 305 | +fun iterate(f, x) = lazy of () => LzCons(x, iterate(f, f(x))) |
| 306 | + |
| 307 | +fun append_nl_lz(xs, ys) = if xs is |
| 308 | + Nil then ys |
| 309 | + Cons(h, t) then lazy of () => LzCons(h, append_nl_lz(t, ys)) |
| 310 | + |
| 311 | +fun replicate_lz(n, x) = if n == 0 then lazy of () => LzNil else lazy of () => LzCons(x, replicate_lz(n - 1, x)) |
| 312 | + |
| 313 | +fun enumFrom(a) = lazy of () => LzCons(a, enumFrom(a + 1)) |
| 314 | + |
| 315 | +// ===================== |
| 316 | + |
| 317 | + |
| 318 | +fun stringOfFloat(x) = x + "" |
| 319 | +fun stringOfInt(x) = x + "" |
| 320 | +fun stringConcat(x, y) = x + y |
| 321 | +fun stringListConcat(ls) = if ls is |
| 322 | + Nil then "" |
| 323 | + Cons(h, t) then stringConcat(h, stringListConcat(t)) |
| 324 | +fun sqrt(x) = globalThis.Math.sqrt(x) |
| 325 | +fun tan(x) = globalThis.Math.tan(x) |
| 326 | +fun sin(x) = globalThis.Math.sin(x) |
| 327 | +fun cos(x) = globalThis.Math.cos(x) |
| 328 | +fun round(x) = globalThis.Math.round(x) |
| 329 | +fun int_of_char(x) = x.charCodeAt(0) |
| 330 | +fun nofibStringToList(s) = |
| 331 | + fun go(i) = if i < s.length then Cons(s.charAt(i), go(i + 1)) else Nil |
| 332 | + go(0) |
| 333 | +fun nofibListToString(ls) = if ls is |
| 334 | + Nil then "" |
| 335 | + Cons(h, t) then h + nofibListToString(t) |
0 commit comments