├── .eslintrc.js
├── .gitignore
├── .vscode
├── launch.json
├── settings.json
└── tasks.json
├── LICENSE
├── README.md
├── jest.config.js
├── package.json
├── pnpm-lock.yaml
├── scripts
├── build
│ ├── index.sh
│ └── watch.sh
└── test
│ ├── index.sh
│ ├── performance.sh
│ └── watch.sh
├── src
├── algebraic
│ ├── common
│ │ ├── bindOf.ts
│ │ ├── bindTo.ts
│ │ ├── pipe.ts
│ │ ├── sequence.ts
│ │ ├── sequenceTuple.ts
│ │ └── tap.ts
│ ├── defs
│ │ ├── Applicative.ts
│ │ ├── Apply.ts
│ │ ├── Bifunctor.ts
│ │ ├── Chain.ts
│ │ ├── Foldable.ts
│ │ ├── Functor.ts
│ │ ├── Monoid.ts
│ │ ├── Semigroup.ts
│ │ └── Traversable.ts
│ ├── index.ts
│ └── types
│ │ ├── Array
│ │ ├── Applicative.ts
│ │ ├── Apply.ts
│ │ ├── Array.ts
│ │ ├── Foldable.ts
│ │ ├── Functions.ts
│ │ ├── Functor.ts
│ │ ├── Traversable.ts
│ │ └── index.ts
│ │ ├── Async
│ │ ├── Applicative.ts
│ │ ├── Apply.ts
│ │ ├── Async.ts
│ │ ├── Chain.ts
│ │ ├── Functions.ts
│ │ ├── Functor.ts
│ │ └── index.ts
│ │ ├── AsyncEither
│ │ ├── Applicative.ts
│ │ ├── Apply.ts
│ │ ├── AsyncEither.ts
│ │ ├── Chain.ts
│ │ ├── Functions.ts
│ │ ├── Functor.ts
│ │ └── index.ts
│ │ ├── AsyncResult
│ │ ├── Applicative.ts
│ │ ├── Apply.ts
│ │ ├── AsyncResult.ts
│ │ ├── Chain.ts
│ │ ├── Functions.ts
│ │ ├── Functor.ts
│ │ └── index.ts
│ │ ├── Either
│ │ ├── Applicative.ts
│ │ ├── Apply.ts
│ │ ├── Chain.ts
│ │ ├── Either.ts
│ │ ├── Functions.ts
│ │ ├── Functor.ts
│ │ └── index.ts
│ │ ├── Maybe
│ │ ├── Applicative.ts
│ │ ├── Apply.ts
│ │ ├── Chain.ts
│ │ ├── Functions.ts
│ │ ├── Functor.ts
│ │ ├── Maybe.ts
│ │ └── index.ts
│ │ ├── NonEmptyArray
│ │ ├── Functor.ts
│ │ ├── NonEmptyArray.ts
│ │ └── index.ts
│ │ └── Result
│ │ ├── Applicative.ts
│ │ ├── Apply.ts
│ │ ├── Chain.ts
│ │ ├── Functions.ts
│ │ ├── Functor.ts
│ │ ├── Result.ts
│ │ └── index.ts
├── common
│ ├── identity.ts
│ └── index.ts
├── hkt
│ └── index.ts
├── index.ts
└── runtime
│ ├── defs
│ └── index.ts
│ ├── index.ts
│ ├── introspection.ts
│ └── types
│ ├── Array
│ ├── Array.ts
│ ├── Checkable.ts
│ └── checks
│ │ └── isGreaterThan.ts
│ ├── Boolean
│ ├── Boolean.ts
│ └── Checkable.ts
│ ├── Intersect
│ ├── Checkable.ts
│ └── Intersect.ts
│ ├── Literal
│ ├── Checkable.ts
│ └── Literal.ts
│ ├── Number
│ ├── Checkable.ts
│ ├── Number.ts
│ └── checks
│ │ └── isGreaterThan.ts
│ ├── Partial
│ ├── Checkable.ts
│ └── Partial.ts
│ ├── Record
│ ├── Checkable.ts
│ └── Record.ts
│ ├── String
│ ├── Checkable.ts
│ ├── String.ts
│ ├── checks
│ │ └── isGreaterThan.ts
│ └── index.ts
│ ├── Tuple
│ ├── Checkable.ts
│ └── Tuple.ts
│ └── Union
│ ├── Checkable.ts
│ └── Union.ts
├── tests
├── algebraic
│ ├── Async
│ │ └── Functions.test.ts
│ ├── AsyncEither
│ │ └── Functions.test.ts
│ ├── AsyncResult
│ │ └── Functions.test.ts
│ ├── Either
│ │ └── Functions.test.ts
│ ├── Maybe
│ │ └── Functions.test.ts
│ ├── Result
│ │ └── Functions.test.ts
│ └── common
│ │ ├── sequenceTuple.performance.ts
│ │ ├── sequenceTuple.test.ts
│ │ └── tap.test.ts
└── runtime
│ ├── 1Examples
│ └── Sports.test.ts
│ ├── Array
│ └── Array.test.ts
│ ├── Boolean
│ └── Boolean.test.ts
│ ├── Intersect
│ └── Intersect.test.ts
│ ├── Literal
│ └── Literal.test.ts
│ ├── Number
│ └── Number.test.ts
│ ├── Partial
│ └── Partial.test.ts
│ ├── Record
│ └── Record.test.ts
│ ├── String
│ └── String.test.ts
│ ├── Tuple
│ └── Tuple.test.ts
│ └── Union
│ └── Union.test.ts
├── tsconfig.build.json
├── tsconfig.esm.json
├── tsconfig.jest.json
└── tsconfig.json
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: '@typescript-eslint/parser',
4 | plugins: ['@typescript-eslint'],
5 | extends: [
6 | 'eslint:recommended',
7 | 'plugin:@typescript-eslint/eslint-recommended',
8 | 'plugin:@typescript-eslint/recommended',
9 | ],
10 | rules: {
11 | '@typescript-eslint/no-array-constructor': "off",
12 | 'no-unexpected-multiline': "off",
13 | '@typescript-eslint/ban-types': "off",
14 | "@typescript-eslint/explicit-function-return-type": "off",
15 | '@typescript-eslint/no-use-before-define': "off",
16 | '@typescript-eslint/no-empty-interface': "off",
17 | quotes: [
18 | 'error',
19 | 'single',
20 | { allowTemplateLiterals: true },
21 | ],
22 | 'func-call-spacing': [
23 | 'error',
24 | 'always',
25 | { allowNewlines: true },
26 | ],
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | **/node_modules
2 | cjs/
3 | esm/
4 | **/*.tsbuildinfo
5 | pnpm-debug.log
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "request": "attach",
10 | "name": "Launch Program",
11 | "outFiles": [
12 | "${workspaceFolder}/cjs/**/*.js"
13 | ]
14 | }
15 | ]
16 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.formatOnSave": false,
3 | "editor.codeActionsOnSave": {
4 | "source.fixAll": true,
5 | "source.fixAll.eslint": true
6 | },
7 | "typescript.tsdk": "node_modules/typescript/lib"
8 | }
9 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "label": "build",
8 | "type": "shell",
9 | "command": "pnpm run build", // Could be any other shell command
10 | },
11 | ]
12 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020 Antonio Mayrinck Moura
4 |
5 | Permission is hereby granted, free of charge, to any person
6 | obtaining a copy of this software and associated documentation
7 | files (the "Software"), to deal in the Software without
8 | restriction, including without limitation the rights to use,
9 | copy, modify, merge, publish, distribute, sublicense, and/or
10 | sell copies of the Software, and to permit persons to whom the
11 | Software is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice shall be
15 | included in all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🦸 λΔ super-ts
2 |
3 | > [!WARNING]
4 | > Hey there, just a heads-up: I've stopped updating this repo. If you're diving into functional programming—like monads, higher kinded types, and all that fun stuff—in TypeScript, you might find some handy insights here. But a little word of caution: it's probably not the best fit for production use. Happy coding!
5 |
6 | ---
7 |
8 | [](https://www.npmjs.com/package/super-ts)
9 |
10 | **super-ts** is a Typescript functional programming library inspired by [Haskell](https://www.haskell.org/) and [PureScript](http://www.purescript.org/) providing both runtime type checking and functional algebraic data types.
11 |
12 | **super-ts** were built to unify concepts and tools of some wonderful libraries, such _[fp-ts](https://github.com/gcanti/fp-ts)_, _[io-ts](https://github.com/gcanti/io-ts)_ and _[runtypes](https://github.com/pelotom/runtypes)_.
13 |
14 | Forwarding to be an all-in-one solution, **super-ts** is divided into two main categories: **Algebraic Types** & **Runtime Types**;
15 |
16 | - _Runtime Types_: static and runtime type checking
17 | - _Algebraic Types_: Monads, Functors, Semigroups and others.
18 |
19 | ## Instalation
20 |
21 | `npm install super-ts` will install super-ts for use.
22 |
23 | ## Consuming
24 |
25 | You can use **super-ts** in two flavors: CommonJS or ES Modules.
26 |
27 | ```ts
28 | import { String } from "super-ts/cjs/runtime";
29 | import { Either } from "super-ts/cjs/algebraic";
30 | ```
31 |
32 | ```ts
33 | import { String } from "super-ts/esm/runtime";
34 | import { Either } from "super-ts/esm/algebraic";
35 | ```
36 |
37 | PS: If you are using the package with ES Modules over **node** you should run your application with the flag `--experimental-specifier-resolution=node`
38 |
39 | ES Modules enables [tree shaking](https://webpack.js.org/guides/tree-shaking/) to be possible using bundlers.
40 |
41 | ## Δ Runtime Types
42 |
43 | **super-ts** provides you with primitive types that can be safely type-checked at runtime with custom constraints and use this same schema as your Typescript static type signature. You can also provide custom runtime checks to build more advanced types that fit your use cases.
44 |
45 | ### Δ Why is useful?
46 |
47 | Let's suppose that you have the following static type schema on your Typescript project:
48 |
49 | ```ts
50 | type League = "NFL" | "MLB" | "NBA" | "WNBA";
51 |
52 | type Gender = "Male" | "Female" | "Other";
53 |
54 | type Team = {
55 | name: string;
56 | yearFounded: number;
57 | league: League;
58 | type: "team";
59 | };
60 |
61 | type Player = {
62 | firstName: string;
63 | lastName: string;
64 | salaryOnTeam: [number, Team];
65 | age: number;
66 | isActive: boolean;
67 | teamsPlayed: Team[];
68 | gender: Gender;
69 | type: "player";
70 | };
71 | ```
72 |
73 | This works fine on TypeScript since you use this schema to type safe your application on compile time, but what about runtime? What happens if you receive this schema as a payload from some external source?
74 |
75 | In this scenario your application is unsafe and you need to do a lot of validations to avoid runtime errors.
76 |
77 | To avoid all this boring work you can use **super-ts** runtime types to define your schema keeping your application safe on runtime as well on compile time, re-using static types generated by **super-ts**.
78 |
79 | ### Δ Example (Defining schema with _super-ts_)
80 |
81 | In order to define the same schema as above using _super-ts_ we do the following:
82 |
83 | ```ts
84 | import {
85 | String,
86 | Number,
87 | Boolean,
88 | Array,
89 | Record,
90 | Literal,
91 | Tuple,
92 | Union,
93 | } from "super-ts/esm/runtime";
94 |
95 | const League = Union(
96 | Literal("NFL"),
97 | Literal("MLB"),
98 | Literal("NBA"),
99 | Literal("WNBA")
100 | );
101 |
102 | const Gender = Union(Literal("Male"), Literal("Female"), Literal("Other"));
103 |
104 | const Team = Record({
105 | name: String,
106 | yearFounded: Number,
107 | league: League,
108 | type: Literal("team"),
109 | });
110 |
111 | const Player = Record({
112 | firstName: String,
113 | lastName: String,
114 | salaryOnTeam: Tuple(Number, Team),
115 | age: Number,
116 | isActive: Boolean,
117 | teamsPlayed: Array(Team),
118 | gender: Gender,
119 | type: Literal("player"),
120 | });
121 | ```
122 |
123 | When you define your schema using **super-ts** you can get Typescript static types using the custom `TypeOf` type.
124 |
125 | ```ts
126 | import { TypeOf } from 'super-ts/esm/runtime'
127 |
128 | type Player = TypeOf;
129 |
130 | // type Player = {
131 | // firstName: string;
132 | // lastName: string;
133 | // salaryOnTeam: [number, {
134 | // name: string;
135 | // yearFounded: number;
136 | // league: "NFL" | "MLB" | "NBA" | "WNBA";
137 | // type: "team";
138 | // }];
139 | // age: number;
140 | // isActive: boolean;
141 | // teamsPlayed: {
142 | // ...;
143 | // }[];
144 | // gender: "Male" | "Female" | "Other";
145 | // type: "player";
146 | // }
147 |
148 |
149 | ```
150 |
151 | ### Δ API
152 |
153 | When you use the runtime types, we expose an API under the property `.Δ` so you can use functions available for the type.
154 |
155 | #### `check :: a -> Resultλ InvalidCheck a`
156 |
157 | Takes an unknown payload and validates against the type. If the validation suceeds,
158 | we return an algebraic type called _Resultλ_ of _Sucess_ which contains the payload.
159 | If the check fails we return an _Resultλ_ of _Failure_ containing an _NonEmptyArrayλ_
160 | of _InvalidCheck_ containing all the errors found on that payload.
161 |
162 | **Example**
163 |
164 | ```ts
165 | import { identity } from 'super-ts/common/identity';
166 | import { Result } from 'super-ts/algebraic';
167 |
168 | /** other imports .. */
169 |
170 | /** above code .. */
171 |
172 | const Team = Record({
173 | name: String,
174 | yearFounded: Number,
175 | league: League,
176 | type: Literal("team"),
177 | });
178 |
179 | const teamInvalidPayload = {
180 | name: null,
181 | yearFounded: "1974",
182 | league: "NFL",
183 | type: "team",
184 | };
185 |
186 | const isValidTeam = Team.Δ.check(teamInvalidPayload);
187 |
188 | const isValidTeamRes = Result.λ.fold (identity, identity) (isValidTeam);
189 |
190 |
191 | // isValidTeamRes = [
192 | // {
193 | // code: 'IS_STRING',
194 | // message: 'Expected string but found (null :: object)',
195 | // path: 'name'
196 | // },
197 | // {
198 | // code: 'IS_NUMBER',
199 | // message: 'Expected Number but found (1974 :: string)',
200 | // path: 'yearFounded'
201 | // }
202 | // ]
203 |
204 | ```
205 |
206 | ## λ Algebraic Types
207 |
208 | This documentation is working in progress.. 😅 🚧
209 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | moduleDirectories: ['', 'node_modules'],
3 | moduleNameMapper: {
4 | '^@runtime/(.*)$': 'src/runtime/$1',
5 | '^@algebraic/(.*)$': 'src/algebraic/$1',
6 | '^@common/(.*)$': 'src/common/$1',
7 | },
8 | preset: 'ts-jest',
9 | testEnvironment: 'node',
10 | globals: {
11 | 'ts-jest': {
12 | tsConfig: 'tsconfig.jest.json',
13 | packageJson: 'package.json',
14 | },
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "super-ts",
3 | "version": "1.11.1",
4 | "description": "Typescript functional programming library inspired by Haskell and PureScript providing both runtime type checking and functional algebraic data types.",
5 | "main": "cjs/index.js",
6 | "module": "esm/index.mjs",
7 | "files": [
8 | "cjs",
9 | "esm"
10 | ],
11 | "scripts": {
12 | "test": "scripty",
13 | "test:watch": "scripty",
14 | "test:performance": "scripty",
15 | "build": "scripty",
16 | "build:watch": "scripty",
17 | "prepublish": "pnpm run build && pnpm run test"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/nthypes/super-ts.git"
22 | },
23 | "keywords": [
24 | "functional programming",
25 | "fantasy-land",
26 | "static-land",
27 | "fp-ts",
28 | "io-ts",
29 | "runtypes",
30 | "purescript",
31 | "haskell"
32 | ],
33 | "author": "Antonio Moura (nthypes)",
34 | "license": "MIT",
35 | "bugs": {
36 | "url": "https://github.com/nthypes/super-ts/issues"
37 | },
38 | "homepage": "https://github.com/nthypes/super-ts#readme",
39 | "devDependencies": {
40 | "@ef-carbon/tspm": "^2.2.5",
41 | "@types/benchmark": "^1.0.33",
42 | "@types/jest": "^25.2.1",
43 | "@typescript-eslint/eslint-plugin": "^2.30.0",
44 | "@typescript-eslint/parser": "^2.30.0",
45 | "benchmark": "^2.1.4",
46 | "eslint": "^6.8.0",
47 | "jest": "^25.5.3",
48 | "nodemon": "^2.0.4",
49 | "scripty": "^2.0.0",
50 | "ts-jest": "^25.4.0",
51 | "ts-node": "^8.10.2",
52 | "tsc-watch": "^4.2.9",
53 | "tslib": "^2.0.0",
54 | "typescript": "^3.9.5"
55 | },
56 | "scripty": {
57 | "silence": true
58 | },
59 | "dependencies": {
60 | "@types/ramda": "^0.27.4",
61 | "ramda": "^0.27.0"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/scripts/build/index.sh:
--------------------------------------------------------------------------------
1 | # Build CJS Modules
2 | rm -rf cjs
3 | node_modules/.bin/tsc -p tsconfig.build.json
4 | node_modules/.bin/ef-tspm -c tsconfig.build.json
5 | rm -rf cjs/tsconfig.build.tsbuildinfo
6 |
7 | # Build ES Modules
8 | rm -rf esm
9 | node_modules/.bin/tsc -p tsconfig.esm.json
10 | node_modules/.bin/ef-tspm -c tsconfig.esm.json
11 | find ./esm/ -name "*.js" -exec bash -c 'mv "$1" "${1%.js}".mjs' - '{}' \;
12 | rm -rf esm/tsconfig.esm.tsbuildinfo
--------------------------------------------------------------------------------
/scripts/build/watch.sh:
--------------------------------------------------------------------------------
1 | # Build Watch CJS Modules
2 | node_modules/.bin/nodemon -e ts -w src \
3 | -x 'node_modules/.bin/tsc -p tsconfig.build.json && node_modules/.bin/ef-tspm -c tsconfig.build.json && node cjs/index.js'
--------------------------------------------------------------------------------
/scripts/test/index.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | bold=$(tput bold)
3 | normal=$(tput sgr0)
4 |
5 | set -e
6 |
7 | echo -e "👻 💉 ${bold}[funtypes/test]${normal} starting unit testing with jest.."
8 | jest --config jest.config.js --verbose
--------------------------------------------------------------------------------
/scripts/test/performance.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | bold=$(tput bold)
3 | normal=$(tput sgr0)
4 |
5 | set -e
6 |
7 | echo -e "🧪 💉 ${bold}[super-ts/test:performance]${normal} starting performance test.."
8 |
9 | if [ $# -eq 0 ]
10 | then
11 | echo -e "[ 🛑 ] ERROR: You must inform a valid performance file. (ex: pnpm run test:performance tests/algebraic/common/sequenceTuple.performance.ts ) \n"
12 | exit 1
13 | fi
14 |
15 | node_modules/.bin/ts-node $1
--------------------------------------------------------------------------------
/scripts/test/watch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | bold=$(tput bold)
3 | normal=$(tput sgr0)
4 |
5 | set -e
6 |
7 | echo -e "👻 💉 ${bold}[funtypes/test]${normal} starting unit testing with jest (watch mode).."
8 |
9 | node_modules/.bin/nodemon -e ts -w src -w tests \
10 | -x 'jest --config jest.config.js --verbose'
--------------------------------------------------------------------------------
/src/algebraic/common/bindOf.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * TODO: Add Comment
3 | */
4 | type BindOfReturn = {
5 | [K in Property]: Value
6 | };
7 |
8 | const bindOf = (
9 | property: Property,
10 | value: Value
11 | ): BindOfReturn => ({[property]: value}) as any;
12 |
13 | export { bindOf }
--------------------------------------------------------------------------------
/src/algebraic/common/bindTo.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * TODO: Add Comment
3 | */
4 | type BindToReturn = {
5 | [K in keyof Previous | Property]: K extends keyof Previous
6 | ? Previous[K]
7 | : Value;
8 | };
9 |
10 | const bindTo = (
11 | previous: Previous,
12 | property: Exclude,
13 | value: Value
14 | ): BindToReturn => Object.assign ({}, previous, { [property]: value }) as any;
15 |
16 | export { bindTo }
--------------------------------------------------------------------------------
/src/algebraic/common/pipe.ts:
--------------------------------------------------------------------------------
1 |
2 | export { pipe };
3 |
4 | function pipe (a: A): A;
5 | function pipe (a: A, a2b: (a: A) => B): B;
6 | function pipe (a: A, a2b: (a: A) => B, b2c: (b: B) => C): C;
7 | function pipe (a: A, a2b: (a: A) => B, b2c: (b: B) => C, c2d: (c: C) => D): D;
8 | function pipe (
9 | a: A, a2b: (a: A) => B,
10 | b2c: (b: B) => C,
11 | c2d: (c: C) => D,
12 | d2e: (d: D) => E
13 | ): E;
14 | function pipe (
15 | a: A, a2b: (a: A) => B,
16 | b2c: (b: B) => C,
17 | c2d: (c: C) => D,
18 | d2e: (d: D) => E,
19 | e2f: (e: E) => F
20 | ): F;
21 | function pipe (
22 | a: A, a2b: (a: A) => B,
23 | b2c: (b: B) => C,
24 | c2d: (c: C) => D,
25 | d2e: (d: D) => E,
26 | e2f: (f: E) => F,
27 | f2g: (e: F) => G
28 | ): G;
29 | function pipe (
30 | a: A, a2b: (a: A) => B,
31 | b2c: (b: B) => C,
32 | c2d: (c: C) => D,
33 | d2e: (d: D) => E,
34 | e2f: (e: E) => F,
35 | f2g: (f: F) => G,
36 | g2h: (g: G) => H
37 | ): H;
38 | function pipe (
39 | a: A, a2b: (a: A) => B,
40 | b2c: (b: B) => C,
41 | c2d: (c: C) => D,
42 | d2e: (d: D) => E,
43 | e2f: (e: E) => F,
44 | f2g: (f: F) => G,
45 | g2h: (g: G) => H,
46 | h2i: (h: H) => I
47 | ): I;
48 | function pipe (
49 | a: A, a2b: (a: A) => B,
50 | b2c: (b: B) => C,
51 | c2d: (c: C) => D,
52 | d2e: (d: D) => E,
53 | e2f: (e: E) => F,
54 | f2g: (f: F) => G,
55 | g2h: (g: G) => H,
56 | h2i: (h: H) => I,
57 | i2j: (i: I) => J
58 | ): J;
59 | function pipe (
60 | a: A, a2b: (a: A) => B,
61 | b2c: (b: B) => C,
62 | c2d: (c: C) => D,
63 | d2e: (d: D) => E,
64 | e2f: (e: E) => F,
65 | f2g: (f: F) => G,
66 | g2h: (g: G) => H,
67 | h2i: (h: H) => I,
68 | i2j: (i: I) => J,
69 | i2k: (j: J) => K
70 | ): K;
71 |
72 | function pipe(a: any, ...fns: ((...args: any[]) => any)[]): any {
73 | if(fns.length > 0) {
74 | return fns.reduce ((prev, fn) => fn (prev), a);
75 | }
76 | return a;
77 | }
78 |
--------------------------------------------------------------------------------
/src/algebraic/common/sequence.ts:
--------------------------------------------------------------------------------
1 | import { ApplicativeOf1, ApplicativeOf2 } from '@algebraic/defs/Applicative';
2 | import { ApplyOf1, ApplyOf2 } from '@algebraic/defs/Apply';
3 | import { Kind1, Kind2, Types1, Types2 } from '@hkt';
4 |
5 | /**
6 | * TODO: Add Comment
7 | */
8 |
9 | function sequence(
10 | p1: ApplicativeOf1 & ApplyOf1
11 | ): (p2: Array>) => Kind1>;
12 |
13 | function sequence(
14 | p1: ApplicativeOf2 & ApplyOf2
15 | ): (p2: Array>) => Kind2>;
16 |
17 | function sequence(
18 | adtModule: ApplicativeOf1 & ApplyOf1
19 | ) {
20 | return function (adtInstances: Array>): Kind1> {
21 | return adtInstances.reduce (
22 | (pv, cv) =>
23 | adtModule.λ.ap (adtModule.λ.map ((as: B[]) => (b: B) => [...as, b]) (pv)) (
24 | cv
25 | ),
26 | adtModule.λ.of ([])
27 | );
28 | };
29 | }
30 |
31 | export { sequence };
32 |
--------------------------------------------------------------------------------
/src/algebraic/common/sequenceTuple.ts:
--------------------------------------------------------------------------------
1 | import { ApplicativeOf1, ApplicativeOf2 } from '@algebraic/defs/Applicative';
2 | import { ApplyOf1, ApplyOf2 } from '@algebraic/defs/Apply';
3 | import { Kind1, Kind2, Types1, Types2 } from '@hkt';
4 |
5 | /**
6 | * TODO: Add Comment
7 | */
8 |
9 | function sequenceTuple(
10 | p1: ApplicativeOf2 & ApplyOf2
11 | ): >>(
12 | ...p2: Z & { 0: Kind2 }
13 | ) => Kind2<
14 | A,
15 | Z extends Array> ? B : never,
16 | {
17 | [K in keyof Z]: [Z[K]] extends [Kind2] ? X : never;
18 | }
19 | >;
20 |
21 | function sequenceTuple(
22 | p1: ApplicativeOf1 & ApplyOf1
23 | ): >>(
24 | ...p2: Z & { 0: Kind1 }
25 | ) => Kind1<
26 | A,
27 | { [K in keyof Z]: [[K]] extends [Kind1] ? X : never }
28 | >;
29 |
30 | function sequenceTuple(adtModule: ApplicativeOf1 & ApplyOf1) {
31 | return function (...adtInstances: Kind1[]): any {
32 | return adtInstances.reduce (
33 | (pv, cv) => adtModule.λ.ap (pv) (cv),
34 | adtModule.λ.of (constructFn (adtInstances.length, []))
35 | );
36 | };
37 | }
38 |
39 | const constructFn = (currentSize: number, acc: any[]) => {
40 | return function (x: unknown) {
41 | return currentSize > 1
42 | ? constructFn (currentSize - 1, [...acc, x])
43 | : [...acc, x];
44 | }
45 |
46 | }
47 |
48 | export { sequenceTuple };
49 |
--------------------------------------------------------------------------------
/src/algebraic/common/tap.ts:
--------------------------------------------------------------------------------
1 | import { ChainOf1, ChainOf2 } from '@algebraic/defs/Chain';
2 | import { Kind1, Types1, Types2, Kind2 } from '@hkt';
3 |
4 | /**
5 | * tap :: Chain b => (a -> unit) -> b -> b
6 | *
7 | * Tap is an **impure** and **unsafe** Operation that performs side effects.
8 | * It's recommend only for **DEBUG** purposes.
9 | */
10 |
11 | function tap(
12 | p1: ChainOf1
13 | ): (p2: (b: B) => void) => (p3: Kind1) => Kind1;
14 |
15 | function tap(
16 | p1: ChainOf2
17 | ): (p2: (c: C) => void) => (p3: Kind2) => Kind2;
18 |
19 |
20 | function tap(
21 | p1: ChainOf1
22 | ) {
23 | return function (p2: (b: B) => void) {
24 | return function (p3: Kind1): Kind1 {
25 | return p1.λU.map ((a) => {
26 | p2 (a)
27 | return a;
28 | }, p3)
29 | }
30 | };
31 | }
32 |
33 | export { tap };
34 |
35 |
--------------------------------------------------------------------------------
/src/algebraic/defs/Applicative.ts:
--------------------------------------------------------------------------------
1 | import { HKT1, Kind1, Kind2, Types1, Types2 } from '@hkt';
2 | import { Apply, ApplyOf1, ApplyOf2 } from './Apply';
3 |
4 | interface Applicative extends Apply {
5 | λ: {
6 | readonly kind: Type;
7 | readonly of: (a: A) => HKT1;
8 | readonly ap: Apply['λ']['ap'];
9 | readonly map: Apply['λ']['map'];
10 | };
11 | }
12 |
13 | interface ApplicativeOf1 extends ApplyOf1 {
14 | λ: {
15 | readonly kind: Type;
16 | readonly of: (a: A) => Kind1;
17 | readonly ap: ApplyOf1['λ']['ap'];
18 | readonly map: ApplyOf1['λ']['map'];
19 | };
20 | }
21 |
22 | interface ApplicativeOf2 extends ApplyOf2 {
23 | λ: {
24 | readonly kind: Type;
25 | readonly of: (a: B) => Kind2;
26 | readonly ap: ApplyOf2['λ']['ap'];
27 | readonly map: ApplyOf2['λ']['map'];
28 | };
29 | }
30 |
31 | export { Applicative, ApplicativeOf1, ApplicativeOf2 };
32 |
--------------------------------------------------------------------------------
/src/algebraic/defs/Apply.ts:
--------------------------------------------------------------------------------
1 | import { HKT1, Kind1, Kind2, Types1, Types2 } from '@hkt';
2 | import { Functor, FunctorOf1, FunctorOf2 } from './Functor';
3 |
4 | interface Apply extends Functor {
5 | λ: {
6 | readonly kind: Type;
7 | readonly map: Functor['λ']['map'];
8 | readonly ap: (
9 | p1: HKT1 B>
10 | ) => (p2: HKT1) => HKT1;
11 | };
12 | }
13 |
14 | interface ApplyOf1 extends FunctorOf1 {
15 | λ: {
16 | readonly kind: Type;
17 | readonly map: FunctorOf1['λ']['map'];
18 | readonly ap: (
19 | p1: Kind1 B>
20 | ) => (p2: Kind1) => Kind1;
21 | };
22 | }
23 |
24 | interface ApplyOf2 extends FunctorOf2 {
25 | λ: {
26 | readonly kind: Type;
27 | readonly map: FunctorOf2['λ']['map'];
28 | readonly ap: (
29 | p1: Kind2 C>
30 | ) => (p2: Kind2) => Kind2;
31 | };
32 | }
33 |
34 | export { Apply, ApplyOf1, ApplyOf2 };
35 |
--------------------------------------------------------------------------------
/src/algebraic/defs/Bifunctor.ts:
--------------------------------------------------------------------------------
1 | import { HKT2, Kind2, Types2 } from '@hkt';
2 |
3 | interface Bifunctor {
4 | λ: {
5 | readonly kind: Type;
6 | readonly bimap: (
7 | p1: (a: A) => C
8 | ) => (p2: (a: B) => D) => (p3: HKT2) => HKT2;
9 | };
10 | }
11 |
12 | interface BifunctorOf2 {
13 | λ: {
14 | readonly kind: Type;
15 | readonly bimap: (
16 | p1: (a: A) => C
17 | ) => (p2: (a: B) => D) => (p3: Kind2) => Kind2;
18 | };
19 | λU: {
20 | readonly kind: Type;
21 | readonly bimap: (
22 | p1: (a: A) => C,
23 | p2: (a: B) => D,
24 | p3: Kind2
25 | ) => Kind2;
26 | };
27 | }
28 |
29 | export { Bifunctor, BifunctorOf2 };
30 |
--------------------------------------------------------------------------------
/src/algebraic/defs/Chain.ts:
--------------------------------------------------------------------------------
1 | import { Kind1, Types1, Types2, Kind2 } from '@hkt';
2 | import { ApplyOf2, ApplyOf1 } from './Apply';
3 |
4 |
5 | interface ChainOf1 extends ApplyOf1 {
6 | λ: {
7 | readonly kind: Type;
8 | readonly map: ApplyOf1['λ']['map'];
9 | readonly ap: ApplyOf1['λ']['ap'];
10 | readonly chain: (p1: (a: A) => Kind1)
11 | => (p2: Kind1)
12 | => Kind1;
13 | };
14 | λU: {
15 | readonly kind: Type;
16 | readonly map: ApplyOf1['λU']['map'];
17 | readonly chain: (p1: (a: A) => Kind1, p2: Kind1) => Kind1;
18 | };
19 | }
20 |
21 | interface ChainOf2 extends ApplyOf2 {
22 | λ: {
23 | readonly kind: Type;
24 | readonly map: ApplyOf2['λ']['map'];
25 | readonly ap: ApplyOf2['λ']['ap'];
26 | readonly chain: (p1: (b: B) => Kind2)
27 | => (p2: Kind2)
28 | => Kind2;
29 | };
30 | λU: {
31 | readonly kind: Type;
32 | readonly map: ApplyOf2['λU']['map'];
33 | readonly chain: (p1: (b: B) => Kind2, p2: Kind2) => Kind2;
34 | };
35 | }
36 |
37 |
38 | export { ChainOf1, ChainOf2 };
39 |
--------------------------------------------------------------------------------
/src/algebraic/defs/Foldable.ts:
--------------------------------------------------------------------------------
1 | import { HKT1, Types1, Kind1, Types2, Kind2 } from '@hkt';
2 | import { Monoid } from './Monoid';
3 |
4 | interface Foldable {
5 | λ: {
6 | readonly kind: Type;
7 |
8 | readonly reduce: (p1: (a: A, b: B) => A)
9 | => (p2: A)
10 | => (p3: HKT1)
11 | => A;
12 |
13 | readonly foldMap: (p1: Monoid)
14 | => (p2: (b: B) => A)
15 | => (p3: HKT1)
16 | => A;
17 | };
18 | }
19 |
20 | interface FoldableOf1 {
21 | λ: {
22 | readonly kind: Type;
23 |
24 | readonly reduce: (p1: (a: A, b: B) => A)
25 | => (p2: A)
26 | => (p3: Kind1)
27 | => A;
28 |
29 | readonly foldMap: (p1: Monoid)
30 | => (p2: (b: B) => A)
31 | => (p3: Kind1)
32 | => A;
33 | };
34 | }
35 |
36 | interface FoldableOf2 {
37 | λ: {
38 | readonly kind: Type;
39 |
40 | readonly reduce: (p1: (a: A, b: B) => A)
41 | => (p2: A)
42 | => (p3: Kind2)
43 | => C;
44 |
45 | readonly foldMap: (p1: Monoid)
46 | => (p2: (c: C) => A)
47 | => (p3: Kind2)
48 | => A;
49 | };
50 | }
51 |
52 | export { Foldable, FoldableOf1, FoldableOf2 };
53 |
--------------------------------------------------------------------------------
/src/algebraic/defs/Functor.ts:
--------------------------------------------------------------------------------
1 | import { HKT1, Types1, Kind1, Types2, Kind2 } from '@hkt';
2 |
3 | interface Functor {
4 | λ: {
5 | readonly kind: Type;
6 | readonly map: (
7 | p1: (a: A) => B
8 | ) => (p2: HKT1) => HKT1;
9 | };
10 | }
11 |
12 | interface FunctorOf1 {
13 | λ: {
14 | readonly kind: Type;
15 | readonly map: (p1: (a: A) => B)
16 | => (p2: Kind1)
17 | => Kind1;
18 | };
19 | λU: {
20 | readonly kind: Type;
21 | readonly map: (p1: (a: A) => B, p2: Kind1) => Kind1;
22 | };
23 | }
24 |
25 | interface FunctorOf2 {
26 | λ: {
27 | readonly kind: Type;
28 | readonly map: (p1: (b: B) => C)
29 | => (p2: Kind2)
30 | => Kind2;
31 | };
32 | λU: {
33 | readonly kind: Type;
34 | readonly map: (p1: (b: B) => C, p2: Kind2) => Kind2;
35 | };
36 | }
37 |
38 | export { Functor, FunctorOf1, FunctorOf2 };
39 |
--------------------------------------------------------------------------------
/src/algebraic/defs/Monoid.ts:
--------------------------------------------------------------------------------
1 | import { Semigroup } from './Semigroup';
2 |
3 | interface Monoid extends Semigroup {
4 | λ: {
5 | readonly kind: Type;
6 | readonly empty: Type;
7 | readonly concat: Semigroup['λ']['concat'];
8 | };
9 | }
10 |
11 | export { Monoid };
12 |
--------------------------------------------------------------------------------
/src/algebraic/defs/Semigroup.ts:
--------------------------------------------------------------------------------
1 | interface Semigroup {
2 | λ: {
3 | readonly kind: Type;
4 | readonly concat: (p1: Type) => (p2: Type) => Type;
5 | };
6 | }
7 |
8 | export { Semigroup };
9 |
--------------------------------------------------------------------------------
/src/algebraic/defs/Traversable.ts:
--------------------------------------------------------------------------------
1 | import { HKT1, Kind1, Types1, Types2, Kind2 } from '@hkt';
2 | import {
3 | Applicative,
4 | ApplicativeOf1,
5 | ApplicativeOf2
6 | } from './Applicative';
7 | import { Foldable, FoldableOf1 } from './Foldable';
8 | import { Functor, FunctorOf1 } from './Functor';
9 |
10 | interface Traversable extends Functor, Foldable {
11 | λ: {
12 | readonly kind: Type;
13 | readonly map: Functor['λ']['map'];
14 | readonly reduce: Foldable['λ']['reduce'];
15 | readonly foldMap: Foldable['λ']['foldMap'];
16 | readonly traverse: Traverse;
17 | };
18 | }
19 |
20 | interface TraversableOf1 extends FunctorOf1, FoldableOf1 {
21 | λ: {
22 | readonly kind: Type;
23 | readonly map: FunctorOf1['λ']['map'];
24 | readonly reduce: FoldableOf1['λ']['reduce'];
25 | readonly foldMap: FoldableOf1['λ']['foldMap'];
26 | readonly traverse: TraverseOf1;
27 | };
28 | }
29 |
30 | interface Traverse {
31 | (p1: ApplicativeOf2): (p2: (b: B) => Kind2) => (p3: HKT1) => Kind2>;
32 | (p1: ApplicativeOf1): (p2: (b: B) => Kind1) => (p3: HKT1) => Kind1>;
33 | (p1: Applicative): (p2: (b: B) => HKT1) => (p3: HKT1) => HKT1>;
34 | }
35 |
36 | interface TraverseOf1 {
37 | (p1: ApplicativeOf2): (p2: (b: B) => Kind2) => (p3: Kind1) => Kind2>;
38 | (p1: ApplicativeOf1): (p2: (b: B) => Kind1) => (p3: Kind1) => Kind1>;
39 | (p1: Applicative): (p2: (b: B) => HKT1) => (p3: Kind1) => HKT1>;
40 | }
41 |
42 |
43 | export { Traversable, TraversableOf1 };
44 |
--------------------------------------------------------------------------------
/src/algebraic/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Array } from '@algebraic/types/Array'
2 | export { default as Either } from '@algebraic/types/Either'
3 | export { default as Maybe } from '@algebraic/types/Maybe'
4 | export { default as NonEmptyArray } from '@algebraic/types/NonEmptyArray'
5 | export { default as Async } from '@algebraic/types/Async'
6 | export { default as AsyncEither } from '@algebraic/types/AsyncEither'
7 | export { default as Result } from '@algebraic/types/Result'
--------------------------------------------------------------------------------
/src/algebraic/types/Array/Applicative.ts:
--------------------------------------------------------------------------------
1 | export { of };
2 |
3 | /**
4 | * TODO: Add comment
5 | *
6 | * of :: a -> Array a
7 | */
8 | const of = (a: A): Array => [a]
9 |
10 |
--------------------------------------------------------------------------------
/src/algebraic/types/Array/Apply.ts:
--------------------------------------------------------------------------------
1 | import { flatten } from './Functions';
2 | export { ap };
3 |
4 | /**
5 | * TODO: Add comment
6 | *
7 | * ap :: Array (a -> b) -> Array a -> Array b
8 | */
9 | const ap = (p1: Array<(a: A) => B>) =>
10 | (p2: Array): Array =>
11 |
12 | flatten (p1.map (r1 => p2.map (r2 => r1 (r2))));
--------------------------------------------------------------------------------
/src/algebraic/types/Array/Array.ts:
--------------------------------------------------------------------------------
1 | export { Array$λ, Arrayλ };
2 |
3 | const Array$λ = 'Array';
4 | type Array$λ = typeof Array$λ;
5 | type Arrayλ = Array;
6 |
7 | declare module '../../../hkt' {
8 | interface Type2Kind1 {
9 | readonly [Array$λ]: Array;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/algebraic/types/Array/Foldable.ts:
--------------------------------------------------------------------------------
1 | import { Monoid } from "@algebraic/defs/Monoid";
2 |
3 | export { reduce, foldMap };
4 |
5 | /**
6 | * TODO: Add comment
7 | *
8 | * reduce :: (b -> a -> b) -> b -> Array a -> b
9 | */
10 |
11 | const reduce = (p1: (b: B, a: A) => B) => (p2: B) => (p3: Array): B =>
12 | p3.reduce(p1, p2);
13 |
14 | /**
15 | * TODO: Add comment
16 | *
17 | * foldMap :: (Monoid a) => TypeRep a -> (b -> a) -> Array b -> a
18 | */
19 |
20 | const foldMap = (p1: Monoid) => (p2: (b: B) => A) => (
21 | p3: Array
22 | ): A => p3.reduce((pv, cv) => p1.λ.concat(pv)(p2(cv)), p1.λ.empty);
23 |
--------------------------------------------------------------------------------
/src/algebraic/types/Array/Functions.ts:
--------------------------------------------------------------------------------
1 | import { Maybeλ } from '../Maybe/Maybe'
2 | import { Arrayλ } from './Array'
3 | import Maybe from '../Maybe'
4 |
5 | export { flatten, head, isEmpty }
6 |
7 | /**
8 | * TODO: Add comment
9 | *
10 | * flatten :: Array Array a -> Array a
11 | */
12 | const flatten = (p1: Array>): Array =>
13 |
14 | ([] as Array).concat (...p1)
15 |
16 | /**
17 | * TODO: Add comment
18 | *
19 | * head :: Array a -> Maybe a
20 | */
21 | const head = (p1: Arrayλ): Maybeλ =>
22 |
23 | isEmpty (p1)
24 | ? Maybe.λ.Nothing
25 | : Maybe.λ.Just (p1[0])
26 |
27 | /**
28 | * TODO: Add comment
29 | *
30 | * head :: Array a -> Maybe a
31 | */
32 | const isEmpty = (p1: Arrayλ): boolean => p1.length === 0;
--------------------------------------------------------------------------------
/src/algebraic/types/Array/Functor.ts:
--------------------------------------------------------------------------------
1 | export { map, mapU };
2 |
3 | /**
4 | * TODO: Add comment
5 | *
6 | * map :: (a -> b) -> Array a -> Array b
7 | */
8 | const map = (p1: (a: A) => B) =>
9 | (p2: Array): Array =>
10 |
11 | mapU (p1, p2)
12 |
13 | /**
14 | * TODO: Add comment
15 | *
16 | * map :: (a -> b) -> Array a -> Array b
17 | */
18 | const mapU = (p1: (a: A) => B, p2: Array): Array =>
19 |
20 | p2.map (p1);
21 |
22 |
--------------------------------------------------------------------------------
/src/algebraic/types/Array/Traversable.ts:
--------------------------------------------------------------------------------
1 | import { HKT1 } from "@hkt";
2 | import { Applicative } from "@algebraic/defs/Applicative";
3 |
4 | /**
5 | * TODO: Add comment
6 | *
7 | * traverse :: (Applicative f, Traversable t) => TypeRep f -> (a -> f b) -> t a -> f (t b)
8 | */
9 | const traverse = (p1: Applicative) => (
10 | p2: (b: B) => HKT1
11 | ) => (p3: Array): HKT1> => {
12 | const initialValue = p1.λ.of([]);
13 | const mapToApply = (pv: HKT1) =>
14 | p1.λ.map C[]>((c1) => (c2) => [...c1, c2])(pv);
15 | const callbackFn = (pv: HKT1, cv: B) =>
16 | p1.λ.ap(mapToApply(pv))(p2(cv));
17 |
18 | return p3.reduce(callbackFn, initialValue);
19 | };
20 |
21 | export { traverse };
22 |
--------------------------------------------------------------------------------
/src/algebraic/types/Array/index.ts:
--------------------------------------------------------------------------------
1 | import type { ApplicativeOf1 } from '@algebraic/defs/Applicative';
2 | import type { FunctorOf1 } from '@algebraic/defs/Functor';
3 | import { TraversableOf1 } from '@algebraic/defs/Traversable';
4 | import { of } from './Applicative';
5 | import { Array$λ } from './Array';
6 | import { map, mapU } from './Functor';
7 | import { ap } from './Apply';
8 | import { reduce, foldMap } from './Foldable';
9 | import { traverse } from './Traversable';
10 |
11 | type ArrayModule = ApplicativeOf1 &
12 | FunctorOf1 &
13 | TraversableOf1;
14 |
15 | const ArrayModule: ArrayModule = {
16 | λ: {
17 | kind: Array$λ,
18 | of,
19 | map,
20 | ap,
21 | reduce,
22 | foldMap,
23 | traverse,
24 | },
25 | λU: {
26 | kind: Array$λ,
27 | map: mapU,
28 | },
29 | };
30 |
31 | export default ArrayModule;
32 |
--------------------------------------------------------------------------------
/src/algebraic/types/Async/Applicative.ts:
--------------------------------------------------------------------------------
1 | import type { Asyncλ } from './Async';
2 |
3 | export { of };
4 |
5 | /**
6 | * TODO: Add comment
7 | */
8 | const of = (p1: A): Asyncλ => () => Promise.resolve (p1);
9 |
--------------------------------------------------------------------------------
/src/algebraic/types/Async/Apply.ts:
--------------------------------------------------------------------------------
1 | import type { Asyncλ } from './Async';
2 |
3 | export { ap };
4 |
5 | const ap = (p1: Asyncλ<(a: A) => B>) => (p2: Asyncλ): Asyncλ =>
6 | () => Promise.all ([p1 (), p2 ()]).then (([f, r]) => f (r));
7 |
--------------------------------------------------------------------------------
/src/algebraic/types/Async/Async.ts:
--------------------------------------------------------------------------------
1 | export { Async$λ };
2 | export type { Asyncλ };
3 |
4 | const Async$λ = 'Async';
5 | type Async$λ = typeof Async$λ;
6 |
7 | declare module '../../../hkt' {
8 | interface Type2Kind1 {
9 | readonly [Async$λ]: Asyncλ;
10 | }
11 | }
12 |
13 | /**
14 | * TODO: Add comment
15 | */
16 | interface Asyncλ {
17 | (): Promise;
18 | }
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/algebraic/types/Async/Chain.ts:
--------------------------------------------------------------------------------
1 | import { Asyncλ } from './Async';
2 | import { of } from './Applicative';
3 |
4 | export { chain, chainU };
5 |
6 | /**
7 | * TODO: Add comment
8 | *
9 | * chain :: (a -> b) -> Async a -> Async b
10 | */
11 | const chain = (p1: (b: A) => Asyncλ) =>
12 | (p2: Asyncλ): Asyncλ =>
13 |
14 | chainU (p1, p2)
15 |
16 |
17 | /**
18 | * TODO: Add comment
19 | *
20 | * chain :: (a -> b) -> Async a -> Async b
21 | */
22 | const chainU = (p1: (b: A) => Asyncλ, p2: Asyncλ): Asyncλ =>
23 |
24 | () => p2 ().then (a => p1 (a) ())
--------------------------------------------------------------------------------
/src/algebraic/types/Async/Functions.ts:
--------------------------------------------------------------------------------
1 | import type { Asyncλ } from './Async';
2 | import { pipe } from '@algebraic/common/pipe';
3 | import { chain } from './Chain';
4 | import { map } from './Functor';
5 | import { bindTo as cBindTo } from '@algebraic/common/bindTo';
6 | import { bindOf as cBindOf } from '@algebraic/common/bindOf';
7 |
8 | export { bindTo, bindOf, chainFirst };
9 |
10 | /**
11 | * TODO: Add comment
12 | */
13 | const bindTo = (
14 | p1: Exclude,
15 | p2: (a: Param) => Asyncλ
16 | ) => (
17 | p3: Asyncλ
18 | ): Asyncλ<
19 | {
20 | [K in keyof Previous | Property]: K extends keyof Previous
21 | ? Previous[K]
22 | : A;
23 | }
24 | > =>
25 | pipe (
26 | p3,
27 | chain ((a) =>
28 | pipe (
29 | p2 (a),
30 | map ((b) => cBindTo (a, p1, b))
31 | )
32 | )
33 | );
34 |
35 | /**
36 | * TODO: Add comment
37 | */
38 | const bindOf = (p1: Property) => (
39 | p2: Asyncλ
40 | ): Asyncλ<{ [K in Property]: Value }> =>
41 | pipe (
42 | p2,
43 | map ((a) => cBindOf (p1, a))
44 | );
45 |
46 | /**
47 | * TODO: Add comment
48 | */
49 | const chainFirst = (p1: (a: A) => Asyncλ) => (p2: Asyncλ) =>
50 | pipe (
51 | p2,
52 | chain ((b) =>
53 | pipe (
54 | p1 (b),
55 | map (() => b)
56 | )
57 | )
58 | );
59 |
--------------------------------------------------------------------------------
/src/algebraic/types/Async/Functor.ts:
--------------------------------------------------------------------------------
1 | import type { Asyncλ } from './Async';
2 | import { of } from './Applicative';
3 |
4 | export { map, mapU };
5 |
6 | /**
7 | * TODO: Add comment
8 | *
9 | * map :: (a -> b) -> Async a -> Async b
10 | */
11 | const map = (p1: (b: A) => B) =>
12 | (p2: Asyncλ): Asyncλ =>
13 |
14 | mapU (p1, p2)
15 |
16 |
17 | /**
18 | * TODO: Add comment
19 | *
20 | * map :: (a -> b) -> Async a -> Async b
21 | */
22 | const mapU = (p1: (b: A) => B, p2: Asyncλ): Asyncλ =>
23 |
24 | () => p2 ().then (p1);
--------------------------------------------------------------------------------
/src/algebraic/types/Async/index.ts:
--------------------------------------------------------------------------------
1 | import type { ApplicativeOf1 } from '@algebraic/defs/Applicative';
2 | import type { ApplyOf1 } from '@algebraic/defs/Apply';
3 | import type { FunctorOf1 } from '@algebraic/defs/Functor';
4 | import { of } from './Applicative';
5 | import { ap } from './Apply';
6 | import { map, mapU } from './Functor';
7 | import { Async$λ } from './Async';
8 | import { ChainOf1 } from '@algebraic/defs/Chain';
9 | import { chain, chainU } from './Chain';
10 | import { bindTo, bindOf, chainFirst } from './Functions';
11 |
12 | type AsyncModule = ApplicativeOf1 &
13 | FunctorOf1 &
14 | ChainOf1 &
15 | ApplyOf1 & {
16 | λ: {
17 | bindTo: typeof bindTo;
18 | bindOf: typeof bindOf;
19 | chainFirst: typeof chainFirst;
20 | };
21 | };
22 |
23 | const AsyncModule: AsyncModule = {
24 | λ: {
25 | kind: Async$λ,
26 | ap,
27 | of,
28 | map,
29 | chainFirst,
30 | bindTo,
31 | bindOf,
32 | chain,
33 | },
34 | λU: {
35 | kind: Async$λ,
36 | map: mapU,
37 | chain: chainU,
38 | },
39 | };
40 |
41 | export default AsyncModule;
42 |
--------------------------------------------------------------------------------
/src/algebraic/types/AsyncEither/Applicative.ts:
--------------------------------------------------------------------------------
1 | import type { AsyncEitherλ } from './AsyncEither';
2 | import Either from '@algebraic/types/Either';
3 | import Async from '@algebraic/types/Async';
4 | export { Right as of, Right, Left };
5 |
6 | /**
7 | * TODO: Add comment
8 | */
9 | const Right = (p1: B): AsyncEitherλ =>
10 | Async.λ.of (Either.λ.of (p1));
11 |
12 | /**
13 | * TODO: Add comment
14 | */
15 | const Left = (p1: A): AsyncEitherλ =>
16 | Async.λ.of (Either.λ.Left (p1));
17 |
--------------------------------------------------------------------------------
/src/algebraic/types/AsyncEither/Apply.ts:
--------------------------------------------------------------------------------
1 | import type { Eitherλ } from '@algebraic/types/Either/Either';
2 | import type { AsyncEitherλ } from './AsyncEither';
3 | import Either from '@algebraic/types/Either';
4 | import Async from '@algebraic/types/Async';
5 |
6 | export { ap };
7 |
8 | const ap = (p1: AsyncEitherλ C>) => (
9 | p2: AsyncEitherλ
10 | ): AsyncEitherλ =>
11 | Async.λ.ap (
12 | Async.λ.map ((h: Eitherλ C>) => (ga: Eitherλ) =>
13 | Either.λ.ap (h) (ga)
14 | ) (p1)
15 | ) (p2);
16 |
--------------------------------------------------------------------------------
/src/algebraic/types/AsyncEither/AsyncEither.ts:
--------------------------------------------------------------------------------
1 | import type { Eitherλ } from '@algebraic/types/Either/Either';
2 | import type { Asyncλ } from '@algebraic/types/Async/Async';
3 |
4 | export { AsyncEither$λ };
5 | export type { AsyncEitherλ };
6 |
7 | const AsyncEither$λ = 'AsyncEither';
8 | type AsyncEither$λ = typeof AsyncEither$λ;
9 |
10 | declare module '../../../hkt' {
11 | interface Type2Kind2 {
12 | readonly [AsyncEither$λ]: AsyncEitherλ;
13 | }
14 | }
15 |
16 | type AsyncEitherλ = Asyncλ>;
17 |
--------------------------------------------------------------------------------
/src/algebraic/types/AsyncEither/Chain.ts:
--------------------------------------------------------------------------------
1 | import type { AsyncEitherλ } from './AsyncEither';
2 | import AsyncModule from '../Async';
3 | import EitherModule from '../Either';
4 | import pipe from 'ramda/src/pipe'
5 | import AsyncEitherModule from '.';
6 |
7 | export { chain, chainU, chainStrict, chainStrictU };
8 |
9 | /**
10 | * TODO: Add comment
11 | *
12 | * chainStrict :: (b -> c) -> AsyncEither b -> AsyncEither c
13 | */
14 | const chainStrict = (p1: (b: B) => AsyncEitherλ) =>
15 | (p2: AsyncEitherλ): AsyncEitherλ =>
16 |
17 | chainStrictU (p1, p2)
18 |
19 |
20 | /**
21 | * TODO: Add comment
22 | *
23 | * chainStrict :: (b -> c) -> AsyncEither b -> AsyncEither c
24 | */
25 | const chainStrictU = (p1: (b: B) => AsyncEitherλ, p2: AsyncEitherλ): AsyncEitherλ =>
26 | pipe (() => p2, AsyncModule.λ.chain (EitherModule.λ.fold (AsyncEitherModule.λ.Left, p1))) ()
27 |
28 |
29 | /**
30 | * TODO: Add comment
31 | */
32 | const chain = (p1: (b: B) => AsyncEitherλ) => (p2: AsyncEitherλ): AsyncEitherλ =>
33 |
34 | chainU (p1, p2)
35 |
36 | /**
37 | * TODO: Add comment
38 | */
39 | const chainU = (p1: (b: B) => AsyncEitherλ, p2: AsyncEitherλ): AsyncEitherλ =>
40 |
41 | AsyncModule.λU.chain (EitherModule.λ.fold > (AsyncEitherModule.λ.Left, p1), p2)
--------------------------------------------------------------------------------
/src/algebraic/types/AsyncEither/Functions.ts:
--------------------------------------------------------------------------------
1 | import { AsyncEitherλ } from './AsyncEither';
2 | import { isFailure } from '@algebraic/types/Result/Functions';
3 | import AsyncEitherModule from '.';
4 | import { Resultλ } from '@algebraic/types/Result/Result';
5 | import { NonEmptyArrayλ } from '@algebraic/types/NonEmptyArray/NonEmptyArray';
6 | import EitherModule from '../Either';
7 | import { Asyncλ } from '../Async/Async';
8 | import AsyncModule from '../Async';
9 | import { pipe } from '@algebraic/common/pipe';
10 | import { chain } from './Chain';
11 | import { map, mapU } from './Functor';
12 | import { bindTo as cBindTo } from '@algebraic/common/bindTo';
13 | import { bindOf as cBindOf } from '@algebraic/common/bindOf';
14 | import { Eitherλ } from '../Either/Either';
15 | import { isLeft } from '../Either/Functions';
16 | import { AsyncResultλ } from '../AsyncResult/AsyncResult';
17 |
18 | export {
19 | fromResult,
20 | fromEither,
21 | fold,
22 | foldUnion,
23 | tryCatch,
24 | mapLeft,
25 | bindTo,
26 | bindToStrict,
27 | bindOf,
28 | chainFirst,
29 | chainFirstStrict,
30 | };
31 |
32 | /**
33 | * TODO: Add comment
34 | * @param p1
35 | */
36 | const fromResult = (
37 | p1: Resultλ
38 | ): AsyncEitherλ, B> =>
39 | isFailure (p1)
40 | ? AsyncEitherModule.λ.Left (p1.λ.value)
41 | : AsyncEitherModule.λ.Right (p1.λ.value);
42 |
43 | /**
44 | * TODO: Add comment
45 | * @param p1
46 | */
47 | const fromEither = (p1: Eitherλ): AsyncEitherλ =>
48 | isLeft (p1)
49 | ? AsyncEitherModule.λ.Left (p1.λ.value)
50 | : AsyncEitherModule.λ.Right (p1.λ.value);
51 |
52 | /**
53 | * TODO: Add comment
54 | * @param p1
55 | */
56 | const fold = (onLeft: (a: A) => C, onRight: (b: B) => C) => (
57 | p1: AsyncEitherλ
58 | ): Asyncλ => () => p1 ().then (EitherModule.λ.fold (onLeft, onRight));
59 |
60 | /**
61 | * TODO: Add comment
62 | * @param p1
63 | */
64 | const foldUnion = (p1: AsyncEitherλ): Asyncλ => () =>
65 | p1 ().then (EitherModule.λ.foldUnion);
66 |
67 | /**
68 | * TODO: Add comment
69 | */
70 | const tryCatch = (
71 | p1: () => Promise