diff --git a/packages/squiggle-lang/bsconfig.json b/packages/squiggle-lang/bsconfig.json index 4c27a48a..e98b3822 100644 --- a/packages/squiggle-lang/bsconfig.json +++ b/packages/squiggle-lang/bsconfig.json @@ -20,7 +20,7 @@ ], "suffix": ".bs.js", "namespace": true, - "bs-dependencies": ["@glennsl/rescript-jest", "rationale", "bisect_ppx"], + "bs-dependencies": ["@glennsl/rescript-jest", "bisect_ppx"], "gentypeconfig": { "language": "typescript", "module": "commonjs", diff --git a/packages/squiggle-lang/package.json b/packages/squiggle-lang/package.json index 0dca9ea6..75583bfc 100644 --- a/packages/squiggle-lang/package.json +++ b/packages/squiggle-lang/package.json @@ -35,30 +35,22 @@ "bisect_ppx": "^2.7.1", "jstat": "^1.9.5", "lodash": "4.17.21", - "mathjs": "10.5.0", - "pdfast": "^0.2.0", - "rationale": "0.2.0", "rescript": "^9.1.4", "rescript-fast-check": "^1.1.1", "@glennsl/rescript-jest": "^0.9.0", "@istanbuljs/nyc-config-typescript": "^1.0.2", "@types/jest": "^27.4.0", "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", - "bisect_ppx": "^2.7.1", "chalk": "^5.0.1", "codecov": "3.8.3", "fast-check": "2.25.0", "gentype": "^4.3.0", "jest": "^27.5.1", - "jstat": "^1.9.5", - "lodash": "4.17.21", "mathjs": "10.5.0", "moduleserve": "0.9.1", "nyc": "^15.1.0", "pdfast": "^0.2.0", - "rationale": "0.2.0", "reanalyze": "^2.19.0", - "rescript": "^9.1.4", "ts-jest": "^27.1.4", "ts-loader": "^9.2.8", "ts-node": "^10.7.0", diff --git a/packages/squiggle-lang/src/rescript/Utility/E.res b/packages/squiggle-lang/src/rescript/Utility/E.res index 1f218194..a110f1b7 100644 --- a/packages/squiggle-lang/src/rescript/Utility/E.res +++ b/packages/squiggle-lang/src/rescript/Utility/E.res @@ -1,4 +1,7 @@ -open Rationale.Function.Infix +/* +Some functions from modules `L`, `O`, and `R` below were copied directly from +running `rescript convert -all` on Rationale https://github.com/jonlaing/rationale +*/ module FloatFloatMap = { module Id = Belt.Id.MakeComparable({ type t = float @@ -55,17 +58,59 @@ module O = { | None => rFn() } () - let fmap = Rationale.Option.fmap - let bind = Rationale.Option.bind - let default = Rationale.Option.default - let isSome = Rationale.Option.isSome - let isNone = Rationale.Option.isNone - let toExn = Rationale.Option.toExn - let some = Rationale.Option.some - let firstSome = Rationale.Option.firstSome - let toExt = Rationale.Option.toExn // wanna flag this-- looks like a typo but `Rationale.OptiontoExt` doesn't exist. - let flatApply = (fn, b) => Rationale.Option.apply(fn, Some(b)) |> Rationale.Option.flatten - let flatten = Rationale.Option.flatten + let fmap = (f: 'a => 'b, x: option<'a>): option<'b> => { + switch x { + | None => None + | Some(x') => Some(f(x')) + } + } + let bind = (o, f) => + switch o { + | None => None + | Some(a) => f(a) + } + let default = (d, o) => + switch o { + | None => d + | Some(a) => a + } + let isSome = o => + switch o { + | Some(_) => true + | _ => false + } + let isNone = o => + switch o { + | None => true + | _ => false + } + let toExn = (err, o) => + switch o { + | None => raise(Failure(err)) + | Some(a) => a + } + + let some = a => Some(a) + let firstSome = (a, b) => + switch a { + | None => b + | _ => a + } + + let toExt = toExn + + let flatten = o => + switch o { + | None => None + | Some(x) => x + } + + let apply = (o, a) => + switch o { + | Some(f) => bind(a, b => some(f(b))) + | _ => None + } + let flatApply = (fn, b) => apply(fn, Some(b)) |> flatten let toBool = opt => switch opt { @@ -113,6 +158,11 @@ module O2 = { /* Functions */ module F = { + let pipe = (f, g, x) => g(f(x)) + let compose = (f, g, x) => f(g(x)) + let flip = (f, a, b) => f(b, a) + let always = (x, _y) => x + let apply = (a, e) => a |> e let flatten2Callbacks = (fn1, fn2, fnlast) => @@ -160,10 +210,25 @@ exception Assertion(string) /* R for Result */ module R = { - let result = Rationale.Result.result + open Belt.Result + let result = (okF, errF, r) => + switch r { + | Ok(a) => okF(a) + | Error(err) => errF(err) + } let id = e => e |> result(U.id, U.id) - let fmap = Rationale.Result.fmap - let bind = Rationale.Result.bind + let fmap = (f: 'a => 'b, r: result<'a, 'c>): result<'b, 'c> => { + switch r { + | Ok(r') => Ok(f(r')) + | Error(err) => Error(err) + } + } + let bind = (r, f) => + switch r { + | Ok(a) => f(a) + | Error(err) => Error(err) + } + let toExn = (msg: string, x: result<'a, 'b>): 'a => switch x { | Ok(r) => r @@ -190,14 +255,17 @@ module R = { let errorIfCondition = (errorCondition, errorMessage, r) => errorCondition(r) ? Error(errorMessage) : Ok(r) - let ap = Rationale.Result.ap + let ap = (r, a) => + switch r { + | Ok(f) => Ok(f(a)) + | Error(err) => Error(err) + } let ap' = (r, a) => switch r { | Ok(f) => fmap(f, a) | Error(err) => Error(err) } - // (a1 -> a2 -> r) -> m a1 -> m a2 -> m r // not in Rationale let liftM2: (('a, 'b) => 'c, result<'a, 'd>, result<'b, 'd>) => result<'c, 'd> = (op, xR, yR) => { ap'(fmap(op, xR), yR) } @@ -247,7 +315,7 @@ module S = { } module J = { - let toString = \"||>"(Js.Json.decodeString, O.default("")) + let toString = F.pipe(Js.Json.decodeString, O.default("")) let fromString = Js.Json.string let fromNumber = Js.Json.number @@ -260,7 +328,7 @@ module J = { let toString = (str: option<'a>) => switch str { - | Some(str) => Some(str |> \"||>"(Js.Json.decodeString, O.default(""))) + | Some(str) => Some(str |> F.pipe(Js.Json.decodeString, O.default(""))) | _ => None } } @@ -275,34 +343,132 @@ module JsDate = { /* List */ module L = { + module Util = { + let eq = (a, b) => a == b + } let fmap = List.map let get = Belt.List.get let toArray = Array.of_list let fmapi = List.mapi let concat = List.concat - let drop = Rationale.RList.drop - let remove = Rationale.RList.remove + let concat' = (xs, ys) => List.append(ys, xs) + + let rec drop = (i, xs) => + switch (i, xs) { + | (_, list{}) => list{} + | (i, _) if i <= 0 => xs + | (i, list{_, ...b}) => drop(i - 1, b) + } + + let append = (a, xs) => List.append(xs, list{a}) + let take = { + let rec loop = (i, xs, acc) => + switch (i, xs) { + | (i, _) if i <= 0 => acc + | (_, list{}) => acc + | (i, list{a, ...b}) => loop(i - 1, b, append(a, acc)) + } + (i, xs) => loop(i, xs, list{}) + } + let takeLast = (i, xs) => List.rev(xs) |> take(i) |> List.rev + + let splitAt = (i, xs) => (take(i, xs), takeLast(List.length(xs) - i, xs)) + let remove = (i, n, xs) => { + let (a, b) = splitAt(i, xs) + \"@"(a, drop(n, b)) + } + let find = List.find let filter = List.filter let for_all = List.for_all let exists = List.exists let sort = List.sort let length = List.length - let filter_opt = Rationale.RList.filter_opt - let uniqBy = Rationale.RList.uniqBy - let join = Rationale.RList.join - let head = Rationale.RList.head - let uniq = Rationale.RList.uniq + + let filter_opt = xs => { + let rec loop = (l, acc) => + switch l { + | list{} => acc + | list{hd, ...tl} => + switch hd { + | None => loop(tl, acc) + | Some(x) => loop(tl, list{x, ...acc}) + } + } + List.rev(loop(xs, list{})) + } + + let containsWith = f => List.exists(f) + + let uniqWithBy = (eq, f, xs) => + List.fold_left( + ((acc, tacc), v) => + containsWith(eq(f(v)), tacc) ? (acc, tacc) : (append(v, acc), append(f(v), tacc)), + (list{}, list{}), + xs, + ) |> fst + + let uniqBy = (f, xs) => uniqWithBy(Util.eq, f, xs) + let join = j => List.fold_left((acc, v) => String.length(acc) == 0 ? v : acc ++ (j ++ v), "") + + let head = xs => + switch List.hd(xs) { + | exception _ => None + | a => Some(a) + } + + let uniq = xs => uniqBy(x => x, xs) let flatten = List.flatten - let last = Rationale.RList.last + let last = xs => xs |> List.rev |> head let append = List.append let getBy = Belt.List.getBy - let dropLast = Rationale.RList.dropLast - let contains = Rationale.RList.contains - let without = Rationale.RList.without - let update = Rationale.RList.update + let dropLast = (i, xs) => take(List.length(xs) - i, xs) + let containsWith = f => List.exists(f) + let contains = x => containsWith(Util.eq(x)) + + let reject = pred => List.filter(x => !pred(x)) + let tail = xs => + switch List.tl(xs) { + | exception _ => None + | a => Some(a) + } + + let init = xs => { + O.fmap(List.rev, xs |> List.rev |> tail) + } + + let singleton = (x: 'a): list<'a> => list{x} + + let adjust = (f, i, xs) => { + let (a, b) = splitAt(i + 1, xs) + switch a { + | _ if i < 0 => xs + | _ if i >= List.length(xs) => xs + | list{} => b + | list{a} => list{f(a), ...b} + | a => + O.fmap( + concat'(b), + O.bind(init(a), x => + O.fmap(F.flip(append, x), O.fmap(fmap(f), O.fmap(singleton, last(a)))) + ), + ) |> O.default(xs) + } + } + + let without = (exclude, xs) => reject(x => contains(x, exclude), xs) + let update = (x, i, xs) => adjust(F.always(x), i, xs) let iter = List.iter - let findIndex = Rationale.RList.findIndex + + let findIndex = { + let rec loop = (pred, xs, i) => + switch xs { + | list{} => None + | list{a, ...b} => pred(a) ? Some(i) : loop(pred, b, i + 1) + } + (pred, xs) => loop(pred, xs, 0) + } + let headSafe = Belt.List.head let tailSafe = Belt.List.tail let headExn = Belt.List.headExn @@ -364,7 +530,7 @@ module A = { Belt.Array.getUnsafe(a, index), Belt.Array.getUnsafe(a, index + 1), )) - |> Rationale.Result.return + |> (x => Ok(x)) } let tail = Belt.Array.sliceToEnd(_, 1) @@ -428,8 +594,8 @@ module A = { module O = { let concatSomes = (optionals: array>): array<'a> => optionals - |> Js.Array.filter(Rationale.Option.isSome) - |> Js.Array.map(Rationale.Option.toExn("Warning: This should not have happened")) + |> Js.Array.filter(O.isSome) + |> Js.Array.map(O.toExn("Warning: This should not have happened")) let defaultEmpty = (o: option>): array<'a> => switch o { | Some(o) => o @@ -623,7 +789,7 @@ module A2 = { module JsArray = { let concatSomes = (optionals: Js.Array.t>): Js.Array.t<'a> => optionals - |> Js.Array.filter(Rationale.Option.isSome) - |> Js.Array.map(Rationale.Option.toExn("Warning: This should not have happened")) + |> Js.Array.filter(O.isSome) + |> Js.Array.map(O.toExn("Warning: This should not have happened")) let filter = Js.Array.filter } diff --git a/yarn.lock b/yarn.lock index cb1e6b3a..283b1121 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13889,11 +13889,6 @@ range-parser@^1.2.1, range-parser@~1.2.1: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -rationale@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/rationale/-/rationale-0.2.0.tgz#555ed4f3cc7cd0245faeac041d3769f1857e4f3d" - integrity sha512-Pd8w5Inv1JhTfRyx03zs486CEAn6UKXvvOtxVRLsewngsBSffo3MQwUKYS75L/8vPt98wmf7iaZROx362/f7Bw== - raw-body@2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c"