Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

everything #1

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
c1474b4
everything
davidchambers Mar 1, 2019
7d322ca
[email protected]
davidchambers Mar 5, 2019
3145b1b
[email protected]
davidchambers Mar 9, 2019
4c087c8
[email protected]
davidchambers Mar 9, 2019
08e0b5b
[email protected]
davidchambers Mar 21, 2019
b4a89ad
[email protected]
davidchambers Apr 2, 2019
e16d2f5
[email protected]
davidchambers Apr 4, 2019
fbad400
[email protected]
davidchambers Apr 5, 2019
63db317
[email protected]
davidchambers Apr 25, 2019
89c922c
[email protected]
davidchambers Nov 3, 2019
7b221f0
[email protected]
davidchambers Nov 3, 2019
254bd77
add FUNDING.yml
davidchambers Jan 1, 2020
eb27a56
circle: housekeeping
davidchambers Jan 2, 2020
828e36d
[email protected]
davidchambers Jan 3, 2020
0985701
[email protected]
davidchambers Jan 15, 2020
79b0e9d
[email protected]
davidchambers Jan 17, 2020
0cf9726
[email protected]
davidchambers Jan 18, 2020
aa97ae8
[email protected]
davidchambers Jan 19, 2020
58ba764
[email protected]
davidchambers Jan 20, 2020
ca5ad65
[email protected]
davidchambers Aug 10, 2020
1391050
remove ‘inspect’ fallback
davidchambers Aug 29, 2020
3fcecc8
use ES6 syntax
davidchambers Apr 28, 2021
ca95f9e
documentation: use S.show in doctest
davidchambers Apr 28, 2021
b351ccd
[email protected]
davidchambers Apr 28, 2021
9601e97
support Deno.inspect
davidchambers May 13, 2021
8af3f8b
circle: create test matrix without nvm
davidchambers Jun 5, 2021
af4ebcc
[email protected]
davidchambers Aug 8, 2021
b262895
eslint: use "readonly" for globals in place of deprecated value
davidchambers Oct 21, 2021
9221f73
circle: update Node versions
davidchambers Dec 6, 2023
4faa68c
update references to default branch
davidchambers Dec 6, 2023
ea3d022
[email protected]
davidchambers Dec 11, 2023
2eec761
convert test modules to ES modules
davidchambers Jan 8, 2024
bcd5ca1
[email protected]
davidchambers Jan 8, 2024
0ed036c
use `globalThis` and `?.` operator to simplify feature detection
davidchambers Jan 8, 2024
45ce4bd
use `assert.deepStrictEqual`
davidchambers Jan 9, 2024
0ee27cf
use `node:` imports
davidchambers Jan 10, 2024
8b733b7
test `util.inspect` compatibility
davidchambers Jan 13, 2024
f6ba464
[email protected]
davidchambers Jan 17, 2024
0f6c194
[email protected]
davidchambers Jan 17, 2024
e7cd612
use ES modules
davidchambers Jan 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: 2.1

orbs:
node: circleci/[email protected]

workflows:
test:
jobs:
- node/test:
setup:
# derive cache key from package.json
- run: cp package.json package-lock.json
override-ci-command: rm package-lock.json && npm install && git checkout -- package.json
matrix:
parameters:
version:
- 18.0.0
- 20.0.0
- 21.0.0
3 changes: 3 additions & 0 deletions .config
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
repo-owner = sanctuary-js
repo-name = sanctuary-constant
contributing-file = .github/CONTRIBUTING.md
6 changes: 6 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"root": true,
"extends": ["./node_modules/sanctuary-style/eslint.json"],
"parserOptions": {"ecmaVersion": 2020, "sourceType": "module"},
"globals": {"globalThis": "readonly"}
}
27 changes: 27 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Contributing

Note: __README.md__ is generated from comments in __index.js__. Do not modify
__README.md__ directly.

1. Update local main branch:

$ git checkout main
$ git pull upstream main

2. Create feature branch:

$ git checkout -b feature-x

3. Make one or more atomic commits, and ensure that each commit has a
descriptive commit message. Commit messages should be line wrapped
at 72 characters.

4. Run `npm test`, and address any errors. Preferably, fix commits in place
using `git rebase` or `git commit --amend` to make the changes easier to
review.

5. Push:

$ git push origin feature-x

6. Open a pull request.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: [davidchambers]
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/coverage/
/node_modules/
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package-lock=false
24 changes: 24 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
The MIT License (MIT)

Copyright (c) 2019 Sanctuary

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
283 changes: 283 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
/* _____ _____ _____ _____ ______ _____ _____ ______ */
/* | | | | | | | | | | | | | | | | */
/* | |__| | | | | | | | |__| '-, ,-' | | | | | | '-, ,-' */
/* | |__ | | | | | | |__ | | | | | | | | | | */
/* | | | | | | | | | | | | | | | | | | | | | | */
/* |_____| |_____| |__|__| |_____| |__| |__|__| |__|__| |__| */

//. <a href="https://github.com/fantasyland/fantasy-land"><img alt="Fantasy Land" src="https://raw.githubusercontent.com/fantasyland/fantasy-land/master/logo.png" width="75" height="75" align="left"></a>
//.
//. # sanctuary-constant
//.
//. A value of type `Constant a b` always contains exactly one value,
//. of type `a`. Mapping over a `Constant a b` has no effect because
//. the `b -> c` function is never applied.
Comment on lines +12 to +14
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand the Constant type, why it takes a type representative, and how that type representative relates to Constant's the type parameters. If you care to explain it to me, maybe that explanation can be added here to the introduction. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Haskell, we can do this:

> import Data.Functor.Constant

> pure 42 :: Constant String Int
Constant ""

We provided 42 :: Int in “b” position; "" :: String materialized in “a” position.

In JavaScript, keeping track of a and b in the type system is not an option so we must provide type information explicitly:

> S.of (Constant (String)) (42)
Constant (String) ('')

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"" :: String materialized

Woah. o.o .... Ahh, because String is a Monoid. So Constant (Boolean) will throw when instantiated.

Alright. That makes things clearer. I don't really see how this would be used in practice, and that's probably what most of my confusion stems from.


import show from 'sanctuary-show';
import Z from 'sanctuary-type-classes';

export {Constant};

const constantTypeIdent = 'sanctuary-constant/Constant@1';

//. ```javascript
//. > import S from 'sanctuary'
//. > import $ from 'sanctuary-def'
//. > import Useless from 'sanctuary-useless'
//. ```
//.
//. `Constant a b` satisfies the following [Fantasy Land][] specifications:
//.
//. ```javascript
//. > S.map (k =>
//. . k + ' '.repeat (16 - k.length) +
//. . (Z[k].test (Constant (Useless.constructor) (Useless)) ? '\u2705 ' :
//. . Z[k].test (Constant (Array) (['foo', 'bar', 'baz'])) ? '\u2705 * ' :
//. . /* otherwise */ '\u274C ')
//. . ) (S.keys (S.unchecked.filter (S.is ($.TypeClass)) (Z)))
//. [ 'Setoid ✅ * ', // if ‘a’ satisfies Setoid
//. . 'Ord ✅ * ', // if ‘a’ satisfies Ord
//. . 'Semigroupoid ❌ ',
//. . 'Category ❌ ',
//. . 'Semigroup ✅ * ', // if ‘a’ satisfies Semigroup
//. . 'Monoid ❌ ',
//. . 'Group ❌ ',
//. . 'Filterable ❌ ',
//. . 'Functor ✅ ',
//. . 'Bifunctor ✅ ',
//. . 'Profunctor ❌ ',
//. . 'Apply ✅ * ', // if ‘a’ satisfies Semigroup
//. . 'Applicative ✅ * ', // if ‘a’ satisfies Monoid
//. . 'Chain ❌ ',
//. . 'ChainRec ❌ ',
//. . 'Monad ❌ ',
//. . 'Alt ❌ ',
//. . 'Plus ❌ ',
//. . 'Alternative ❌ ',
//. . 'Foldable ✅ ',
//. . 'Traversable ✅ ',
//. . 'Extend ❌ ',
//. . 'Comonad ❌ ',
//. . 'Contravariant ❌ ' ]
//. ```

//# Constant :: TypeRep a -> a -> Constant a b
//.
//. Constant's sole data constructor. The [type representative][] makes
//. `Constant (M)` an [Applicative][]-compatible type representative if
//. `M` represents some monoidal type.
//.
//. ```javascript
//. > Constant (String) ('abc')
//. Constant (String) ('abc')
//.
//. > Constant (Number) (123)
//. Constant (Number) (123)
//. ```
const Constant = A => {
const prototype = {
/* eslint-disable key-spacing */
'constructor': Constant$bound,
'@@type': constantTypeIdent,
'@@show': Constant$prototype$show,
'fantasy-land/map': Constant$prototype$map,
'fantasy-land/bimap': Constant$prototype$bimap,
'fantasy-land/reduce': Constant$prototype$reduce,
'fantasy-land/traverse': Constant$prototype$traverse,
/* eslint-enable key-spacing */
};

if (globalThis.process?.versions?.node != null) {
const inspect = Symbol.for ('nodejs.util.inspect.custom');
prototype[inspect] = Constant$prototype$show;
}

/* c8 ignore start */
if (typeof globalThis.Deno?.customInspect === 'symbol') {
const inspect = globalThis.Deno.customInspect;
prototype[inspect] = Constant$prototype$show;
}
/* c8 ignore stop */

function Constant$bound(value) {
const constant = Object.create (prototype);
if (Z.Setoid.test (value)) {
constant['fantasy-land/equals'] = Constant$prototype$equals;
if (Z.Ord.test (value)) {
constant['fantasy-land/lte'] = Constant$prototype$lte;
}
}
if (Z.Semigroup.test (value)) {
constant['fantasy-land/concat'] = Constant$prototype$concat;
constant['fantasy-land/ap'] = Constant$prototype$ap;
}
constant.value = value;
return constant;
}

// XXX: sanctuary-show@3 only respects @@show on "objects". Fool it.
Constant$bound[Symbol.toStringTag] = 'Object';

Constant$bound['@@show'] = () => {
if (!(Object.prototype.hasOwnProperty.call (A, 'name'))) {
const source = String (A);
const match = /^\s*function ([$_A-Za-z][$_A-Za-z0-9]*)/.exec (source);
return 'Constant (' + (match == null ? source : match[1]) + ')';
} else if (A.name === Constant$bound.name) {
return 'Constant (' + show (A) + ')';
} else {
return 'Constant (' + A.name + ')';
}
};

//# Constant.fantasy-land/of :: Monoid m => a -> Constant m a
//.
//. `of (Constant (M)) (x)` is equivalent to `Constant (M) (empty (M))`.
//.
//. ```javascript
//. > S.of (Constant (Array)) (42)
//. Constant (Array) ([])
//.
//. > S.of (Constant (String)) (42)
//. Constant (String) ('')
//. ```
(() => {
let empty;
try { empty = Z.empty (A); } catch (err) { return; }
Constant$bound['fantasy-land/of'] = x => Constant$bound (empty);
}) ();

//# Constant#@@show :: Showable a => Constant a b ~> () -> String
//.
//. `show (Constant (A) (x))` is equivalent to
//. `'Constant (' + A.name + ') (' + show (x) + ')'`.
//.
//. ```javascript
//. > S.show (Constant (Array) (['foo', 'bar', 'baz']))
//. 'Constant (Array) (["foo", "bar", "baz"])'
//. ```
function Constant$prototype$show() {
return show (Constant$bound) + ' (' + show (this.value) + ')';
}

//# Constant#fantasy-land/equals :: Setoid a => Constant a b ~> Constant a b -> Boolean
//.
//. `Constant (A) (x)` is equal to `Constant (A) (y)` [iff][] `x` is
//. equal to `y` according to [`Z.equals`][].
//.
//. ```javascript
//. > S.equals (Constant (Array) ([1, 2, 3]))
//. . (Constant (Array) ([1, 2, 3]))
//. true
//.
//. > S.equals (Constant (Array) ([1, 2, 3]))
//. . (Constant (Array) ([3, 2, 1]))
//. false
//. ```
function Constant$prototype$equals(other) {
return Z.equals (this.value, other.value);
}

//# Constant#fantasy-land/lte :: Ord a => Constant a b ~> Constant a b -> Boolean
//.
//. `Constant (A) (x)` is less than or equal to `Constant (A) (y)` [iff][]
//. `x` is less than or equal to `y` according to [`Z.lte`][].
//.
//. ```javascript
//. > S.filter (S.lte (Constant (Number) (1)))
//. . ([Constant (Number) (0),
//. . Constant (Number) (1),
//. . Constant (Number) (2)])
//. [Constant (Number) (0), Constant (Number) (1)]
//. ```
function Constant$prototype$lte(other) {
return Z.lte (this.value, other.value);
}

//# Constant#fantasy-land/concat :: Semigroup a => Constant a b ~> Constant a b -> Constant a b
//.
//. `concat (Constant (A) (x)) (Constant (A) (y))` is equivalent to
//. `Constant (A) (concat (x) (y))`.
//.
//. ```javascript
//. > S.concat (Constant (Array) ([1, 2, 3]))
//. . (Constant (Array) ([4, 5, 6]))
//. Constant (Array) ([1, 2, 3, 4, 5, 6])
//. ```
function Constant$prototype$concat(other) {
return Constant$bound (Z.concat (this.value, other.value));
}

//# Constant#fantasy-land/map :: Constant a b ~> (b -> c) -> Constant a c
//.
//. `map (f) (Constant (A) (x))` is equivalent to `Constant (A) (x)`.
//.
//. ```javascript
//. > S.map (Math.sqrt) (Constant (Number) (64))
//. Constant (Number) (64)
//. ```
function Constant$prototype$map(f) {
return this;
}

//# Constant#fantasy-land/bimap :: Constant a c ~> (a -> b, c -> d) -> Constant b d
//.
//. `bimap (f) (g) (Constant (A) (x))` is equivalent to
//. `Constant (A) (f (x))`.
//.
//. ```javascript
//. > S.bimap (s => s.length) (Math.sqrt) (Constant (String) ('abc'))
//. Constant (Number) (3)
//. ```
function Constant$prototype$bimap(f, g) {
const x = f (this.value);
return Constant (x.constructor) (x);
}

//# Constant#fantasy-land/ap :: Semigroup a => Constant a b ~> Constant a (b -> c) -> Constant a c
//.
//. `ap (Constant (A) (x)) (Constant (A) (y))` is equivalent to
//. `concat (Constant (A) (x)) (Constant (A) (y))`.
//.
//. ```javascript
//. > S.ap (Constant (Array) ([1, 2, 3])) (Constant (Array) ([4, 5, 6]))
//. Constant (Array) ([1, 2, 3, 4, 5, 6])
//. ```
function Constant$prototype$ap(other) {
return Z.concat (other, this);
}

//# Constant#fantasy-land/reduce :: Constant a b ~> ((c, b) -> c, c) -> c
//.
//. `reduce (f) (x) (Constant (A) (y))` is equivalent to `x`.
//.
//. ```javascript
//. > S.reduce (S.add) (100) (Constant (Number) (42))
//. 100
//. ```
function Constant$prototype$reduce(f, x) {
return x;
}

//# Constant#fantasy-land/traverse :: Applicative f => Constant a b ~> (TypeRep f, b -> f c) -> f (Constant a c)
//.
//. `traverse (A) (f) (Constant (X) (x))` is equivalent to
//. `of (A) (Constant (X) (x))`.
//.
//. ```javascript
//. > S.traverse (Array) (Math.sqrt) (Constant (Number) (64))
//. [Constant (Number) (64)]
//. ```
function Constant$prototype$traverse(typeRep, f) {
return Z.of (typeRep, this);
}

return Constant$bound;
};

//. [Applicative]: v:fantasyland/fantasy-land#Applicative
//. [Fantasy Land]: v:fantasyland/fantasy-land
//. [`Z.equals`]: v:sanctuary-js/sanctuary-type-classes#equals
//. [`Z.lte`]: v:sanctuary-js/sanctuary-type-classes#lte
//. [iff]: https://en.wikipedia.org/wiki/If_and_only_if
//. [type representative]: v:fantasyland/fantasy-land#type-representatives
Loading