eek-whales
Version:
a collection of JS/TS modules for functional programming
469 lines (344 loc) • 11.5 kB
Markdown
# EEK-Whales

> 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