UNPKG

eek-whales

Version:

a collection of JS/TS modules for functional programming

469 lines (344 loc) 11.5 kB
# EEK-Whales ![The EEK-Whales Logo](/assets/logo.svg) > A collection of JavaScript/TypeScript modules for functional programming ## API ### [Combinators](#combinators) - [identity](#identity) :: a -> a - [constant](#constant) :: a -> b -> a ### [Point-free Functions](#point-free-functions-1) - [equals](#equals) :: `Setoid a => a -> a-> Boolean` or `a -> b -> Boolean` ### [Classify Functions](#classify-functions-1) - [getType](#gettype) :: `a -> String` - [is](#is) :: `String -> a -> Boolean` ### [Predicate Functions](#predicate-functions-1) - [isEqual](#isequal) :: `a -> b -> Boolean` - [isSame](#issame) :: `a -> b -> Boolean` - [isSameType](#issametype) :: `a -> b -> Boolean` - [isTruthy](#istruthy) :: `a -> Boolean` - [isNil](#isnil) :: `a -> Boolean` - [isFunction](#isfunction) :: `a -> Boolean` - [isDate](#isdate) :: `a -> Boolean` - [isIterable](#isiterable) :: `a -> Boolean` - [isSetoid](#issetoid) :: `a -> Boolean` ### [Showable](#showable-1) - [inspect](#inspect) :: `a -> String` - [nodeInspect](#nodeinspect) :: `Symbol` ### [Number](#number-1) - [random](#random) :: `(Number | Undefined) -> Number` ## Combinators ### identity ```txt identity :: a -> a I :: a -> a ``` This is the `identity` (`I`) combinator. It takes a value and returns the same value. ```typescript import { identity, I } from "eek-whales" identity(42) // => 42 identity("tacocat") // => "tacocat" I(42) // => 42 ``` ### constant ```txt constant :: a -> b -> a ``` This is the K (Kestrel) combinator. It takes two values and returns the first. ```typescript import { constant } from "eek-whales" constant(42)(73) // => 42 constant("Kestrel")("Identity") // => "Kestrel" ``` ## Point-free Functions ### equals ```txt equals :: Setoid a => a -> a -> Boolean equals :: a -> b -> Boolean ``` The `equals` function is useful for deep equality comparisons or for comparing two values of the [`Setoid`](#issetoid) type. Returns `true` given two values that are deeply equal and `false` otherwise. Primitive values are checked using the [`isSame`](#issame) module. `Setoids` are compared using their `equals` or `fantasy-land/equals` methods. ```typescript import { equals } from "eek-whales" equals ([1, 2, 3]) ([1, 2, 3]) // => true equals ({ a: 1, b: 2 }) ({ a: 1, b: 2 }) // => true equals (NaN) (NaN) // => true equals ([]) ([]) // => true equals (0) (-0) // => false equals ([4]) ([2]) // => false // `Max` is a Setoid [Object] with an `equals` method equals (Max(42)) (Max(43)) // => false ``` ## Classify Functions ### getType ```txt getType :: a -> String ``` `getType` is a function that returns a value's type, given any value. The original version of this function was named `type`, but was changed to avoid conflicts with the TypeScript keyword. ```typescript import { getType } from "eek-whales" getType("hello") // => "String" getType([1, 2, 3]) // => "Array" getType(42) // => "Number" getType(/^foo$/i) // => "RegExp" getType(<T>(x: T): T => x) // => "Function" // An object with a custom type const MyCustomType = { "@@type": "CustomType", } // An object with a custom type using the Symbol.toStringTag const AnotherCustomType = { get [Symbol.toStringTag]() { return "CustomType" }, } getType(MyCustomType) // => "CustomType" getType(AnotherCustomType) // => "CustomType" ``` ### is ```txt is :: String -> a -> Boolean ``` The `is` function accepts two parameters. The first is a string that represents the type for the second parameter to be validated against. Uses [`getType`](#gettype) on the second parameter for the comparison. ```typescript import { is } from "eek-whales" is ("String") ("hello") // => true is ("String") (42) // => false is ("Array") ([1, 2, 3]) // => true is ("Array") ({ a: 1 }) // => false is ("Undefined") () // => true is ("Max") (Max(42).concat(Max(41))) // => true ``` ## Predicate Functions ## isEqual ```txt isEqual :: a -> b -> Boolean ``` The `isEqual` predicate function compares two values using the strict equality (`===`) comparison operator with the exception of `NaN` which returns `true` when compared with `NaN`. ```typescript import { isEqual } from "eek-whales" isEqual("pizza")("pizza") // => true isEqual(42)(42) // => true isEqual(NaN)(NaN) // => true isEqual({})({}) // => false isEqual([6])([6]) // => false isEqual("night")("day") // => false ``` ### isSame ```txt isSame :: a -> b -> Boolean ``` The `isSame` predicate function is similar to [isEqual](#isequal) with the exception of negative zero (`-0`) and zero (`0`, `+0`) not being equal. It is equivalent to the JavaScript `Object.is` static method. ```typescript import { isSame } from "eek-whales" isSame (0) (0) // => true isSame (0) (+0) // => true isSame (0) (-0) // => false isSame (-0) (+0) // => false ``` ### isSameType ```txt isSameType :: a -> b -> Boolean ``` `isSameType` accepts any value for both parameters and returns a boolean that represents if both parameters are of the same type. ```typescript import { isSameType } from "eek-whales" isSameType ("hello") ("world") // => true isSameType (21) (42) // => true isSameType (null) (undefined) // => false isSameType ({}) ([]) // => false ``` ### isTruthy ```txt isTruthy :: a -> Boolean ``` `isTruthy` returns the result of converting the given parameter into a boolean. ```typescript import { isTruthy } from "eek-whales" isTruthy(true) // => true isTruthy({}) // => true isTruthy([]) // => true isTruthy(42) // => true isTruthy("0") // => true isTruthy(new Date()) // => true isTruthy(Infinity) // => true isTruthy(false) // => false isTruthy(0) // => false isTruthy(-0) // => false isTruthy(0n) // => false isTruthy("") // => false isTruthy(null) // => false isTruthy(undefined) // => false isTruthy(NaN) // => false ``` ### isNil ```txt isNil :: a -> Boolean ``` `isNil` returns `true` given one of `null`, `undefined`, or `NaN`. All other values return `false`. ```typescript import { isNil } from "eek-whales" isNil(null) // => true isNil(undefined) // => true isNil(NaN) // => true isNil("") // => false isNil(0) // => false isNil(42) // => false isNil([]) // => false ``` ### isFunction ```txt isFunction :: a -> Boolean ``` `isFunction` returns `true` given a function or generator function. All other values return `false`. ```typescript import { isFunction } from "eek-whales" const generator = function*() { yield "a"} const fn = <T>(x: T): T => x isFunction(fn) // => true isFunction(<T>(x: T): T => x) // => true isFunction(generator) // => true isFunction(function*() { yield "a" }) // => true isFunction([]) // => false ``` ### isDate ```txt isDate :: a -> Boolean ``` `isDate` returns `true` given a date object. All other values return `false`. ```typescript import { isDate } from "eek-whales" isDate(new Date()) // => true isDate(new Date(2023, 1, 1)) // => true isDate(Date.now()) // => false isDate() // => false isDate("Wed Feb 01 2023 00:00:00 GMT-0500 (Eastern Standard Time)") // => false ``` ### isIterable ```txt isIterable :: a -> Boolean ``` `isIterable` returns `true` given a value with a `Symbol.iterator` static method. ```typescript import { isIterable } from "eek-whales" isIterable("hello world") // => true isIterable([1, 2, 3]) // => true isIterable(new Uint8Array([10, 20, 30, 40, 50])) // => true isIterable(new Map([["a", 1], ["b", 10], ["c", 100]])) // => true isIterable(new Set([0, 1, 1, 2, 3, 5, 8, 13, 21, 34])) // => true isIterable(42) // => false isIterable({}) // => false isIterable() // => false const customIterable = { *[Symbol.iterator]() { yield 1 yield 2 yield 3 } } isIterable(customIterable) // => true ``` ### isSetoid ```txt isSetoid :: a -> Boolean ``` `isSetoid` returns `true` given an object/class with an `equals` or `fantasy-land/equals` method. All other values return `false`. This module relies on duck typing to check if a value is a Setoid. It does **NOT** validate any of the required algebraic laws (reflexivity, symmetry, and transitivity) as laid out in the [Fantasy Land Specification]. Validating the laws is not possible without knowing the type of value that will be passed to the `equals` method in advance and that will vary depending on the Setoid implementation. ```typescript import { isSetoid } from "eek-whales" import { Min, Max } from "eek-whales" isSetoid(Min) // => true isSetoid(Max) // => true isSetoid("hello world") // => false interface NumericSetoid { value: number equals: (n: NumericSetoid) => boolean } const mySetoid = (x: number) => ({ value: x, equals: (y: NumericSetoid) => x === y.value }) isSetoid(mySetoid(42)) // => true isSetoid(mySetoid) // => false ``` ## Showable ### inspect ```txt inspect :: a -> String ``` `inspect` returns a string representation of the given value. Useful as a helper function for creating `toString` methods for ADTs. ```typescript import { inspect } from "eek-whales" inspect("hello world") // => "hello world" inspect(42) // => "42" inspect([1, 2, 3]) // => "[1, 2, 3]" inspect(undefined) // => "undefined" inspect(<T>(x: T): T => x) // => "(x) => x" inspect(new TypeError("FOO")) // => "TypeError: FOO" ``` ### nodeInspect ```txt nodeInspect :: Symbol ``` Using `nodeInspect` in the ADTs allows for defining custom `console.log` output for Node.js without the need to `import` the `util` module. This makes it unnecessary to verify a Node.js environment. ```typescript import { inspect, nodeInspect } from "eek-whales" const Identity = x => ({ // ... toString() { return `Identity(${inspect(x)})` }, [nodeInspect]() { return this.toString() } }) ``` ## Number ### random ```txt random :: (Number | Undefined) -> Number ``` A pseudorandom number generator that accepts a seed number as input for reproducible output. By default, the seed is the number returned by `Date.now()`. The returned floating point number will be between 0 and 1, not including 1; `[0, 1)`. The random number is generated using a [linear congruential generator] algorithm with the following values: | multiplier (a) | increment (c) | modulus (m) | |:--------------:|:-------------:|:--------------:| | 1103515245 | 12345 | 2<sup>31</sup> | ```typescript import { random } from "eek-whales" random() // => 0.0469970703125 random() // => 0.871337890625 random() // => 0.1737060546875 random(1001001) // => 0.707733154296875 random(1001001) // => 0.707733154296875 random(0) // => 0 random(1) // => 0.51385498046875 ``` [Fantasy Land Specification]: https://github.com/fantasyland/fantasy-land [linear congruential generator]: https://en.wikipedia.org/wiki/Linear_congruential_generator