Created
February 10, 2018 16:03
-
-
Save bbqbaron/d5ad7647224394107b0c391c14050c14 to your computer and use it in GitHub Desktop.
Dump of some random Reason utility functions I found myself wanting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*** | |
* the util file I banged together while working on a project. | |
* as a result, it's organic, not systematic. | |
* some are so trivial as not to really need defining. | |
* i think i'm used to Clojure where a lack of currying | |
* means that sometimes aliasing trivial partial functions | |
* is helpful. | |
*/ | |
/*** | |
* classic "when". when predicate(value), call transform on value; otherwise return value | |
*/ | |
let when_ = (predicate, transform, value) => | |
if (predicate(value)) { | |
transform(value) | |
} else { | |
value | |
}; | |
/*** | |
* function composition. fn1 >> fn2 is arg => fn2(fn1(arg)). | |
* think of it as making a pipeline | |
*/ | |
let (>>) = (fn1, fn2, arg) => fn2(fn1(arg)); | |
/*** | |
* force an optional to be present or crash. | |
* named after the ! operator in Kotlin/Swift, | |
* plus I like the name better than "orCrash" | |
*/ | |
let bang = | |
fun | |
| Some(x) => x; | |
/*** | |
* option mapping is so common that I created a top-level | |
* util function for it (since this isn't a systematic package :)). | |
* if value is present, call fn on it | |
*/ | |
let omap = (fn, value) => | |
switch value { | |
| Some(thing) => Some(fn(thing)) | |
| _ => None | |
}; | |
/*** | |
* infix version of omap. | |
* as far as I know, you can't arbitrarily call functions as infix in Ocaml, | |
* as you can with `function` in other MLs. | |
* say it with me: "don't use infix operators!", | |
* but again, option-mapping is insanely common. | |
*/ | |
let (>?) = (value, fn) => omap(fn, value); | |
/*** | |
* unwrap options by providing a default value. | |
* default "value" to "default" if value is None. | |
*/ | |
let or_ = (default, value) => | |
switch value { | |
| Some(x) => x | |
| _ => default | |
}; | |
/*** | |
* infix version of or_. | |
* again, kind of wishing I could arbitrarily infix things! | |
*/ | |
let (>~) = (value, default) => or_(default, value); | |
/*** | |
* for debugging, print-and-return something preceded by a string tag, | |
* so you can inject it into the middle of chains of piped calls | |
*/ | |
let debug = (tagName, value) => { | |
Js.log(tagName ++ ": "); | |
Js.log(value); | |
value | |
}; | |
/*** | |
* wrap something in a list | |
*/ | |
let intoList = (x) => [x]; | |
/*** | |
* return what's passed. i'm sure this exists but i couldn't find it! | |
*/ | |
let id = (x) => x; | |
/*** | |
* swap the order of a function's arguments. | |
*/ | |
let flip = (fn, a, b) => fn(b, a); | |
/*** | |
* get an element at an index in a list, | |
* just a flip of List.nth to take the data structure last, | |
* as we're all used to. | |
*/ | |
let idxUnsafe = flip(List.nth); | |
/*** | |
* safe idxUnsafe, returning an option. | |
*/ | |
let idx = (idx, list) => | |
try (Some(List.nth(list, idx))) { | |
| Not_found => None | |
}; | |
/*** | |
* grab a random element from a list. | |
*/ | |
let randNth = (list) => { | |
let idx = Js.Math.random_int(0, List.length(list)); | |
List.nth(list, idx) | |
}; | |
/*** | |
* get the second element of a 2-tuple | |
*/ | |
let snd = ((_, v)) => v; | |
/*** | |
* wrap two values in a tuple, | |
* AKA Elm's ",", i think? | |
*/ | |
let tup = (a, b) => (a, b); | |
/*** | |
* convert a list of value to a list of (index, value) | |
*/ | |
let pairs = (list) => List.mapi(tup, list); | |
/*** | |
* get the second value of each of a list of tuples. | |
* boy, some of these are barely worth defining. | |
*/ | |
let snds = (list) => List.map(snd, list); | |
/*** | |
* get a random element from inside a list, | |
* returning it and the remaining list (that is, without the element). | |
* i didn't see "take" or "drop" in the standard lib, oddly, so this seemed relatively simple. | |
* unnecessarily slow since partition must iterate pointlessly over the entire list! | |
*/ | |
let extractRand = (list: list('a)) : ('a, list('a)) => { | |
let randIdx = Js.Math.random_int(0, List.length(list)); | |
let (toLeft, toRight) = list |> pairs |> List.partition(((i, _)) => i === randIdx); | |
(snd(List.hd(toLeft)), List.map(snd, toRight)) | |
}; | |
/*** | |
* it doesn't seem like you can use type constructors | |
* as functions, so this function wraps something in Some() | |
*/ | |
let some = (x) => Some(x); | |
/*** | |
* remove Nones from a list of option, | |
* returning only good old-fashioned values | |
*/ | |
let rec compress = | |
fun | |
| [] => [] | |
| [Some(x), ...xs] => [x, ...compress(xs)] | |
| [None, ...xs] => compress(xs); | |
/*** | |
* safe version of List.hd | |
*/ | |
let hd = | |
fun | |
| [x, ..._] => Some(x) | |
| _ => None; | |
/*** | |
* return a list of n calls to fn. | |
* calls fn each time, so presumably you want | |
* it to be effectful/nondeterministic/not slow. | |
*/ | |
let repeat = (n, fn) => { | |
let rec _repeat = (n, acc) => | |
switch n { | |
| 0 => acc | |
| x => _repeat(x - 1, [fn(), ...acc]) | |
}; | |
_repeat(n, []) | |
}; | |
/*** | |
* return whether any item in the list satisfies a predicate | |
*/ | |
let any = (predicate, list) => { | |
let rec _any = | |
fun | |
| [] => false | |
| [x, ...rest] => | |
if (predicate(x)) { | |
true | |
} else { | |
_any(rest) | |
}; | |
_any(list) | |
}; | |
/*** | |
* i'm _very_ new at modules but thought i'd at least | |
* toy around with organizing some Dict-related utility functions | |
*/ | |
module Dict = { | |
/*** | |
* update a dict at a key with a function, | |
* which will be passed an option of the current value | |
* at that key. | |
*/ | |
let update = (key, fn, dict) => Js.Dict.set(dict, key, fn(Js.Dict.get(dict, key))); | |
/*** | |
* convert a Dict to a list of its values | |
*/ | |
let vals = (dict) => dict |> Js.Dict.values |> Array.to_list; | |
/*** | |
* construct a dict from a list of values, | |
* keying each entry by its index. i'm not positive why i wrote this, actually, | |
* since it's mostly just making a weird List. | |
* maybe an interop thing | |
*/ | |
let ofItems = (list) => | |
list |> List.mapi((idx, value) => (Js.Int.toString(idx), value)) |> Js.Dict.fromList; | |
}; | |
/*** | |
* sum a list of values | |
*/ | |
let sum = List.fold_left((+), 0); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment