From 5e2a2f15c7b07786a28751a3a2ab313ac6387b0f Mon Sep 17 00:00:00 2001 From: Michael Arnaldi Date: Mon, 28 Nov 2022 15:11:14 +0000 Subject: [PATCH 001/255] update dependencies --- package.json | 38 +- pnpm-lock.yaml | 1364 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 961 insertions(+), 441 deletions(-) diff --git a/package.json b/package.json index 686783ae5..93e9fbe45 100644 --- a/package.json +++ b/package.json @@ -63,46 +63,46 @@ }, "devDependencies": { "@babel/cli": "^7.18.6", - "@babel/core": "^7.18.6", - "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/core": "^7.20.5", + "@babel/plugin-transform-modules-commonjs": "^7.19.6", "@changesets/changelog-github": "^0.4.7", - "@changesets/cli": "^2.25.0", + "@changesets/cli": "^2.25.2", "@effect-ts/build-utils": "0.40.3", "@effect-ts/core": "^0.60.2", "@repo-tooling/eslint-plugin-dprint": "^0.0.4", - "@types/benchmark": "^1.0.31", - "@types/glob": "^7.1.3", - "@types/jest": "^29.0.3", - "@types/node": "^18.0.0", - "@types/prettier": "1.10.0", + "@types/benchmark": "^2.1.2", + "@types/glob": "^8.0.0", + "@types/jest": "^29.2.3", + "@types/node": "^18.11.9", + "@types/prettier": "2.7.1", "@types/rimraf": "^3.0.2", - "@typescript-eslint/eslint-plugin": "^5.36.2", - "@typescript-eslint/parser": "^5.36.2", + "@typescript-eslint/eslint-plugin": "^5.44.0", + "@typescript-eslint/parser": "^5.44.0", "babel-plugin-annotate-pure-calls": "^0.4.0", "c8": "^7.11.3", - "concurrently": "^7.2.2", + "concurrently": "^7.6.0", "cpx": "^1.5.0", "docs-ts": "^0.7.0", "dtslint": "github:gcanti/dtslint", - "eslint": "^8.23.0", - "eslint-import-resolver-typescript": "^3.5.1", + "eslint": "^8.28.0", + "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-codegen": "0.16.1", - "eslint-plugin-deprecation": "^1.3.2", + "eslint-plugin-deprecation": "^1.3.3", "eslint-plugin-import": "^2.26.0", "eslint-plugin-simple-import-sort": "^8.0.0", "eslint-plugin-sort-destructure-keys": "^1.4.0", - "fast-check": "^3.1.4", + "fast-check": "^3.3.0", "glob": "^8.0.3", "madge": "^5.0.1", "picocolors": "^1.0.0", - "prettier": "^2.7.1", + "prettier": "^2.8.0", "rimraf": "^3.0.2", "ts-node": "^10.9.1", "tslint": "^6.1.3", - "typescript": "^4.8.2", + "typescript": "^4.9.3", "ultra-runner": "^3.10.5", - "vite": "^2.9.13", - "vitest": "0.16.0" + "vite": "^3.2.4", + "vitest": "0.25.3" }, "pnpm": { "patchedDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4be52330..8350642ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,88 +13,88 @@ importers: .: specifiers: '@babel/cli': ^7.18.6 - '@babel/core': ^7.18.6 - '@babel/plugin-transform-modules-commonjs': ^7.18.6 + '@babel/core': ^7.20.5 + '@babel/plugin-transform-modules-commonjs': ^7.19.6 '@changesets/changelog-github': ^0.4.7 - '@changesets/cli': ^2.25.0 + '@changesets/cli': ^2.25.2 '@effect-ts/build-utils': 0.40.3 '@effect-ts/core': ^0.60.2 '@repo-tooling/eslint-plugin-dprint': ^0.0.4 - '@types/benchmark': ^1.0.31 - '@types/glob': ^7.1.3 - '@types/jest': ^29.0.3 - '@types/node': ^18.0.0 - '@types/prettier': 1.10.0 + '@types/benchmark': ^2.1.2 + '@types/glob': ^8.0.0 + '@types/jest': ^29.2.3 + '@types/node': ^18.11.9 + '@types/prettier': 2.7.1 '@types/rimraf': ^3.0.2 - '@typescript-eslint/eslint-plugin': ^5.36.2 - '@typescript-eslint/parser': ^5.36.2 + '@typescript-eslint/eslint-plugin': ^5.44.0 + '@typescript-eslint/parser': ^5.44.0 babel-plugin-annotate-pure-calls: ^0.4.0 c8: ^7.11.3 - concurrently: ^7.2.2 + concurrently: ^7.6.0 cpx: ^1.5.0 docs-ts: ^0.7.0 dtslint: github:gcanti/dtslint - eslint: ^8.23.0 - eslint-import-resolver-typescript: ^3.5.1 + eslint: ^8.28.0 + eslint-import-resolver-typescript: ^3.5.2 eslint-plugin-codegen: 0.16.1 - eslint-plugin-deprecation: ^1.3.2 + eslint-plugin-deprecation: ^1.3.3 eslint-plugin-import: ^2.26.0 eslint-plugin-simple-import-sort: ^8.0.0 eslint-plugin-sort-destructure-keys: ^1.4.0 - fast-check: ^3.1.4 + fast-check: ^3.3.0 glob: ^8.0.3 madge: ^5.0.1 picocolors: ^1.0.0 - prettier: ^2.7.1 + prettier: ^2.8.0 rimraf: ^3.0.2 ts-node: ^10.9.1 tslint: ^6.1.3 - typescript: ^4.8.2 + typescript: ^4.9.3 ultra-runner: ^3.10.5 - vite: ^2.9.13 - vitest: 0.16.0 + vite: ^3.2.4 + vitest: 0.25.3 devDependencies: - '@babel/cli': 7.19.3_@babel+core@7.19.3 - '@babel/core': 7.19.3 - '@babel/plugin-transform-modules-commonjs': 7.18.6_@babel+core@7.19.3 + '@babel/cli': 7.19.3_@babel+core@7.20.5 + '@babel/core': 7.20.5 + '@babel/plugin-transform-modules-commonjs': 7.19.6_@babel+core@7.20.5 '@changesets/changelog-github': 0.4.7 - '@changesets/cli': 2.25.0 + '@changesets/cli': 2.25.2 '@effect-ts/build-utils': 0.40.3_wzvflwv62ngf22ppz3frldq37m_smskbqsf3q6kbozdrpluio47kq '@effect-ts/core': 0.60.4 - '@repo-tooling/eslint-plugin-dprint': 0.0.4_typescript@4.8.4 - '@types/benchmark': 1.0.33 - '@types/glob': 7.2.0 - '@types/jest': 29.1.2 - '@types/node': 18.8.0 - '@types/prettier': 1.10.0 + '@repo-tooling/eslint-plugin-dprint': 0.0.4_typescript@4.9.3 + '@types/benchmark': 2.1.2 + '@types/glob': 8.0.0 + '@types/jest': 29.2.3 + '@types/node': 18.11.9 + '@types/prettier': 2.7.1 '@types/rimraf': 3.0.2 - '@typescript-eslint/eslint-plugin': 5.38.1_c7qepppml3d4ahu5cnfwqe6ltq - '@typescript-eslint/parser': 5.38.1_ypn2ylkkyfa5i233caldtndbqa - babel-plugin-annotate-pure-calls: 0.4.0_@babel+core@7.19.3 + '@typescript-eslint/eslint-plugin': 5.44.0_fnsv2sbzcckq65bwfk7a5xwslu + '@typescript-eslint/parser': 5.44.0_hsf322ms6xhhd4b5ne6lb74y4a + babel-plugin-annotate-pure-calls: 0.4.0_@babel+core@7.20.5 c8: 7.12.0 - concurrently: 7.4.0 + concurrently: 7.6.0 cpx: 1.5.0 - docs-ts: 0.7.0_dmjzcauo3cshxeipj7bv64ktgm + docs-ts: 0.7.0_brpckf4sz23pco3jyty2eys3iq dtslint: github.com/gcanti/dtslint/f361dc93d6a195f530df28779082548e01cecd5e - eslint: 8.24.0 - eslint-import-resolver-typescript: 3.5.1_dg2pe6kqkrddxbf2funb723kue + eslint: 8.28.0 + eslint-import-resolver-typescript: 3.5.2_ktrec6dplf4now6nlbc6d67jee eslint-plugin-codegen: 0.16.1 - eslint-plugin-deprecation: 1.3.2_ypn2ylkkyfa5i233caldtndbqa - eslint-plugin-import: 2.26.0_3vub7fqunrjizhghsam4lcr2pi - eslint-plugin-simple-import-sort: 8.0.0_eslint@8.24.0 - eslint-plugin-sort-destructure-keys: 1.4.0_eslint@8.24.0 - fast-check: 3.1.4 + eslint-plugin-deprecation: 1.3.3_hsf322ms6xhhd4b5ne6lb74y4a + eslint-plugin-import: 2.26.0_vc54pluhgv7booofyyjouvuf74 + eslint-plugin-simple-import-sort: 8.0.0_eslint@8.28.0 + eslint-plugin-sort-destructure-keys: 1.4.0_eslint@8.28.0 + fast-check: 3.3.0 glob: 8.0.3 madge: 5.0.1 picocolors: 1.0.0 - prettier: 2.7.1 + prettier: 2.8.0 rimraf: 3.0.2 - ts-node: 10.9.1_5ra3kupzwcghzakkfdrtyjk72u - tslint: 6.1.3_typescript@4.8.4 - typescript: 4.8.4 + ts-node: 10.9.1_wup25etrarvlqkprac7h35hj7u + tslint: 6.1.3_typescript@4.9.3 + typescript: 4.9.3 ultra-runner: 3.10.5 - vite: 2.9.15 - vitest: 0.16.0_c8@7.12.0 + vite: 3.2.4_@types+node@18.11.9 + vitest: 0.25.3 publishDirectory: dist packages/babel-plugin: @@ -132,17 +132,17 @@ packages: engines: {node: '>=6.0.0'} dependencies: '@jridgewell/gen-mapping': 0.1.1 - '@jridgewell/trace-mapping': 0.3.15 + '@jridgewell/trace-mapping': 0.3.17 dev: true - /@babel/cli/7.19.3_@babel+core@7.19.3: + /@babel/cli/7.19.3_@babel+core@7.20.5: resolution: {integrity: sha512-643/TybmaCAe101m2tSVHi9UKpETXP9c/Ff4mD2tAwkdP6esKIfaauZFc67vGEM6r9fekbEGid+sZhbEnSe3dg==} engines: {node: '>=6.9.0'} hasBin: true peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.3 + '@babel/core': 7.20.5 '@jridgewell/trace-mapping': 0.3.15 commander: 4.1.1 convert-source-map: 1.8.0 @@ -162,26 +162,26 @@ packages: '@babel/highlight': 7.18.6 dev: true - /@babel/compat-data/7.19.3: - resolution: {integrity: sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==} + /@babel/compat-data/7.20.5: + resolution: {integrity: sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==} engines: {node: '>=6.9.0'} dev: true - /@babel/core/7.19.3: - resolution: {integrity: sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==} + /@babel/core/7.20.5: + resolution: {integrity: sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.0 '@babel/code-frame': 7.18.6 - '@babel/generator': 7.19.3 - '@babel/helper-compilation-targets': 7.19.3_@babel+core@7.19.3 - '@babel/helper-module-transforms': 7.19.0 - '@babel/helpers': 7.19.0 - '@babel/parser': 7.19.3 + '@babel/generator': 7.20.5 + '@babel/helper-compilation-targets': 7.20.0_@babel+core@7.20.5 + '@babel/helper-module-transforms': 7.20.2 + '@babel/helpers': 7.20.6 + '@babel/parser': 7.20.5 '@babel/template': 7.18.10 - '@babel/traverse': 7.19.3 - '@babel/types': 7.19.3 - convert-source-map: 1.8.0 + '@babel/traverse': 7.20.5 + '@babel/types': 7.20.5 + convert-source-map: 1.9.0 debug: 4.3.4 gensync: 1.0.0-beta.2 json5: 2.2.1 @@ -193,28 +193,28 @@ packages: /@babel/generator/7.12.17: resolution: {integrity: sha512-DSA7ruZrY4WI8VxuS1jWSRezFnghEoYEFrZcw9BizQRmOZiUsiHl59+qEARGPqPikwA/GPTyRCi7isuCK/oyqg==} dependencies: - '@babel/types': 7.19.3 + '@babel/types': 7.20.5 jsesc: 2.5.2 source-map: 0.5.7 dev: true - /@babel/generator/7.19.3: - resolution: {integrity: sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==} + /@babel/generator/7.20.5: + resolution: {integrity: sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.19.3 + '@babel/types': 7.20.5 '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 dev: true - /@babel/helper-compilation-targets/7.19.3_@babel+core@7.19.3: - resolution: {integrity: sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==} + /@babel/helper-compilation-targets/7.20.0_@babel+core@7.20.5: + resolution: {integrity: sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.19.3 - '@babel/core': 7.19.3 + '@babel/compat-data': 7.20.5 + '@babel/core': 7.20.5 '@babel/helper-validator-option': 7.18.6 browserslist: 4.21.4 semver: 6.3.0 @@ -230,60 +230,60 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.18.10 - '@babel/types': 7.19.3 + '@babel/types': 7.20.5 dev: true /@babel/helper-hoist-variables/7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.19.3 + '@babel/types': 7.20.5 dev: true /@babel/helper-module-imports/7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.19.3 + '@babel/types': 7.20.5 dev: true - /@babel/helper-module-transforms/7.19.0: - resolution: {integrity: sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==} + /@babel/helper-module-transforms/7.20.2: + resolution: {integrity: sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-module-imports': 7.18.6 - '@babel/helper-simple-access': 7.18.6 + '@babel/helper-simple-access': 7.20.2 '@babel/helper-split-export-declaration': 7.18.6 '@babel/helper-validator-identifier': 7.19.1 '@babel/template': 7.18.10 - '@babel/traverse': 7.19.3 - '@babel/types': 7.19.3 + '@babel/traverse': 7.20.5 + '@babel/types': 7.20.5 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-plugin-utils/7.19.0: - resolution: {integrity: sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==} + /@babel/helper-plugin-utils/7.20.2: + resolution: {integrity: sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-simple-access/7.18.6: - resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==} + /@babel/helper-simple-access/7.20.2: + resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.19.3 + '@babel/types': 7.20.5 dev: true /@babel/helper-split-export-declaration/7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.19.3 + '@babel/types': 7.20.5 dev: true - /@babel/helper-string-parser/7.18.10: - resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} + /@babel/helper-string-parser/7.19.4: + resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} engines: {node: '>=6.9.0'} dev: true @@ -297,13 +297,13 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helpers/7.19.0: - resolution: {integrity: sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==} + /@babel/helpers/7.20.6: + resolution: {integrity: sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.18.10 - '@babel/traverse': 7.19.3 - '@babel/types': 7.19.3 + '@babel/traverse': 7.20.5 + '@babel/types': 7.20.5 transitivePeerDependencies: - supports-color dev: true @@ -322,29 +322,36 @@ packages: engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.19.3 + '@babel/types': 7.20.5 + dev: true + + /@babel/parser/7.20.5: + resolution: {integrity: sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.20.5 dev: true - /@babel/plugin-transform-modules-commonjs/7.18.6_@babel+core@7.19.3: - resolution: {integrity: sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==} + /@babel/plugin-transform-modules-commonjs/7.19.6_@babel+core@7.20.5: + resolution: {integrity: sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.3 - '@babel/helper-module-transforms': 7.19.0 - '@babel/helper-plugin-utils': 7.19.0 - '@babel/helper-simple-access': 7.18.6 - babel-plugin-dynamic-import-node: 2.3.3 + '@babel/core': 7.20.5 + '@babel/helper-module-transforms': 7.20.2 + '@babel/helper-plugin-utils': 7.20.2 + '@babel/helper-simple-access': 7.20.2 transitivePeerDependencies: - supports-color dev: true - /@babel/runtime/7.19.0: - resolution: {integrity: sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==} + /@babel/runtime/7.20.6: + resolution: {integrity: sha512-Q+8MqP7TiHMWzSfwiJwXCjyf4GYA4Dgw3emg/7xmwsdLJOZUp+nMqcOwOzzYheuM1rhDu8FSj2l0aoMygEuXuA==} engines: {node: '>=6.9.0'} dependencies: - regenerator-runtime: 0.13.9 + regenerator-runtime: 0.13.11 dev: true /@babel/template/7.18.10: @@ -352,8 +359,8 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/parser': 7.19.3 - '@babel/types': 7.19.3 + '@babel/parser': 7.20.5 + '@babel/types': 7.20.5 dev: true /@babel/traverse/7.19.3: @@ -361,24 +368,42 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/generator': 7.19.3 + '@babel/generator': 7.20.5 '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-function-name': 7.19.0 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 '@babel/parser': 7.19.3 - '@babel/types': 7.19.3 + '@babel/types': 7.20.5 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types/7.19.3: - resolution: {integrity: sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==} + /@babel/traverse/7.20.5: + resolution: {integrity: sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.18.10 + '@babel/code-frame': 7.18.6 + '@babel/generator': 7.20.5 + '@babel/helper-environment-visitor': 7.18.9 + '@babel/helper-function-name': 7.19.0 + '@babel/helper-hoist-variables': 7.18.6 + '@babel/helper-split-export-declaration': 7.18.6 + '@babel/parser': 7.20.5 + '@babel/types': 7.20.5 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types/7.20.5: + resolution: {integrity: sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.19.4 '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 dev: true @@ -387,10 +412,10 @@ packages: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true - /@changesets/apply-release-plan/6.1.1: - resolution: {integrity: sha512-LaQiP/Wf0zMVR0HNrLQAjz3rsNsr0d/RlnP6Ef4oi8VafOwnY1EoWdK4kssuUJGgNgDyHpomS50dm8CU3D7k7g==} + /@changesets/apply-release-plan/6.1.2: + resolution: {integrity: sha512-H8TV9E/WtJsDfoDVbrDGPXmkZFSv7W2KLqp4xX4MKZXshb0hsQZUNowUa8pnus9qb/5OZrFFRVsUsDCVHNW/AQ==} dependencies: - '@babel/runtime': 7.19.0 + '@babel/runtime': 7.20.6 '@changesets/config': 2.2.0 '@changesets/get-version-range-type': 0.3.2 '@changesets/git': 1.5.0 @@ -400,7 +425,7 @@ packages: fs-extra: 7.0.1 lodash.startcase: 4.4.0 outdent: 0.5.0 - prettier: 2.7.1 + prettier: 2.8.0 resolve-from: 5.0.0 semver: 5.7.1 dev: true @@ -408,7 +433,7 @@ packages: /@changesets/assemble-release-plan/5.2.2: resolution: {integrity: sha512-B1qxErQd85AeZgZFZw2bDKyOfdXHhG+X5S+W3Da2yCem8l/pRy4G/S7iOpEcMwg6lH8q2ZhgbZZwZ817D+aLuQ==} dependencies: - '@babel/runtime': 7.19.0 + '@babel/runtime': 7.20.6 '@changesets/errors': 0.1.4 '@changesets/get-dependents-graph': 1.3.4 '@changesets/types': 5.2.0 @@ -432,12 +457,12 @@ packages: - encoding dev: true - /@changesets/cli/2.25.0: - resolution: {integrity: sha512-Svu5KD2enurVHGEEzCRlaojrHjVYgF9srmMP9VQSy9c1TspX6C9lDPpulsSNIjYY9BuU/oiWpjBgR7RI9eQiAA==} + /@changesets/cli/2.25.2: + resolution: {integrity: sha512-ACScBJXI3kRyMd2R8n8SzfttDHi4tmKSwVwXBazJOylQItSRSF4cGmej2E4FVf/eNfGy6THkL9GzAahU9ErZrA==} hasBin: true dependencies: - '@babel/runtime': 7.19.0 - '@changesets/apply-release-plan': 6.1.1 + '@babel/runtime': 7.20.6 + '@changesets/apply-release-plan': 6.1.2 '@changesets/assemble-release-plan': 5.2.2 '@changesets/changelog-git': 0.1.13 '@changesets/config': 2.2.0 @@ -449,7 +474,7 @@ packages: '@changesets/pre': 1.0.13 '@changesets/read': 0.5.8 '@changesets/types': 5.2.0 - '@changesets/write': 0.2.1 + '@changesets/write': 0.2.2 '@manypkg/get-packages': 1.1.3 '@types/is-ci': 3.0.0 '@types/semver': 6.2.3 @@ -511,7 +536,7 @@ packages: /@changesets/get-release-plan/3.0.15: resolution: {integrity: sha512-W1tFwxE178/en+zSj/Nqbc3mvz88mcdqUMJhRzN1jDYqN3QI4ifVaRF9mcWUU+KI0gyYEtYR65tour690PqTcA==} dependencies: - '@babel/runtime': 7.19.0 + '@babel/runtime': 7.20.6 '@changesets/assemble-release-plan': 5.2.2 '@changesets/config': 2.2.0 '@changesets/pre': 1.0.13 @@ -527,7 +552,7 @@ packages: /@changesets/git/1.5.0: resolution: {integrity: sha512-Xo8AT2G7rQJSwV87c8PwMm6BAc98BnufRMsML7m7Iw8Or18WFvFmxqG5aOL5PBvhgq9KrKvaeIBNIymracSuHg==} dependencies: - '@babel/runtime': 7.19.0 + '@babel/runtime': 7.20.6 '@changesets/errors': 0.1.4 '@changesets/types': 5.2.0 '@manypkg/get-packages': 1.1.3 @@ -551,7 +576,7 @@ packages: /@changesets/pre/1.0.13: resolution: {integrity: sha512-jrZc766+kGZHDukjKhpBXhBJjVQMied4Fu076y9guY1D3H622NOw8AQaLV3oQsDtKBTrT2AUFjt9Z2Y9Qx+GfA==} dependencies: - '@babel/runtime': 7.19.0 + '@babel/runtime': 7.20.6 '@changesets/errors': 0.1.4 '@changesets/types': 5.2.0 '@manypkg/get-packages': 1.1.3 @@ -561,7 +586,7 @@ packages: /@changesets/read/0.5.8: resolution: {integrity: sha512-eYaNfxemgX7f7ELC58e7yqQICW5FB7V+bd1lKt7g57mxUrTveYME+JPaBPpYx02nP53XI6CQp6YxnR9NfmFPKw==} dependencies: - '@babel/runtime': 7.19.0 + '@babel/runtime': 7.20.6 '@changesets/git': 1.5.0 '@changesets/logger': 0.0.5 '@changesets/parse': 0.3.15 @@ -579,14 +604,14 @@ packages: resolution: {integrity: sha512-km/66KOqJC+eicZXsm2oq8A8bVTSpkZJ60iPV/Nl5Z5c7p9kk8xxh6XGRTlnludHldxOOfudhnDN2qPxtHmXzA==} dev: true - /@changesets/write/0.2.1: - resolution: {integrity: sha512-KUd49nt2fnYdGixIqTi1yVE1nAoZYUMdtB3jBfp77IMqjZ65hrmZE5HdccDlTeClZN0420ffpnfET3zzeY8pdw==} + /@changesets/write/0.2.2: + resolution: {integrity: sha512-kCYNHyF3xaId1Q/QE+DF3UTrHTyg3Cj/f++T8S8/EkC+jh1uK2LFnM9h+EzV+fsmnZDrs7r0J4LLpeI/VWC5Hg==} dependencies: - '@babel/runtime': 7.19.0 + '@babel/runtime': 7.20.6 '@changesets/types': 5.2.0 fs-extra: 7.0.1 human-id: 1.0.2 - prettier: 2.7.1 + prettier: 2.8.0 dev: true /@cspotcode/source-map-support/0.8.1: @@ -636,6 +661,15 @@ packages: resolution: {integrity: sha512-gGnOCvDv6829EeeC+NgTnwIt4XxclR0KqrG7BRemmNX5cm75cF0CKiuEB/o902wjAlt+MdrxTtFC+XsYdLnxzA==} dev: true + /@esbuild/android-arm/0.15.16: + resolution: {integrity: sha512-nyB6CH++2mSgx3GbnrJsZSxzne5K0HMyNIWafDHqYy7IwxFc4fd/CgHVZXr8Eh+Q3KbIAcAe3vGyqIPhGblvMQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-loong64/0.14.54: resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} engines: {node: '>=12'} @@ -645,15 +679,24 @@ packages: dev: true optional: true - /@eslint/eslintrc/1.3.2: - resolution: {integrity: sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==} + /@esbuild/linux-loong64/0.15.16: + resolution: {integrity: sha512-SDLfP1uoB0HZ14CdVYgagllgrG7Mdxhkt4jDJOKl/MldKrkQ6vDJMZKl2+5XsEY/Lzz37fjgLQoJBGuAw/x8kQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@eslint/eslintrc/1.3.3: + resolution: {integrity: sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.4 - espree: 9.4.0 - globals: 13.17.0 - ignore: 5.2.0 + espree: 9.4.1 + globals: 13.18.0 + ignore: 5.2.1 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -662,8 +705,8 @@ packages: - supports-color dev: true - /@humanwhocodes/config-array/0.10.7: - resolution: {integrity: sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==} + /@humanwhocodes/config-array/0.11.7: + resolution: {integrity: sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==} engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 1.2.1 @@ -673,10 +716,6 @@ packages: - supports-color dev: true - /@humanwhocodes/gitignore-to-minimatch/1.0.2: - resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==} - dev: true - /@humanwhocodes/module-importer/1.0.1: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} @@ -691,18 +730,18 @@ packages: engines: {node: '>=8'} dev: true - /@jest/expect-utils/29.1.2: - resolution: {integrity: sha512-4a48bhKfGj/KAH39u0ppzNTABXQ8QPccWAFUFobWBaEMSMp+sB31Z2fK/l47c4a/Mu1po2ffmfAIPxXbVTXdtg==} + /@jest/expect-utils/29.3.1: + resolution: {integrity: sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - jest-get-type: 29.0.0 + jest-get-type: 29.2.0 dev: true /@jest/schemas/29.0.0: resolution: {integrity: sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@sinclair/typebox': 0.24.44 + '@sinclair/typebox': 0.24.51 dev: true /@jest/types/26.6.2: @@ -711,20 +750,20 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.8.0 + '@types/node': 18.11.9 '@types/yargs': 15.0.14 chalk: 4.1.2 dev: true - /@jest/types/29.1.2: - resolution: {integrity: sha512-DcXGtoTykQB5jiwCmVr8H4vdg2OJhQex3qPkG+ISyDO7xQXbt/4R6dowcRyPemRnkH7JoHvZuxPBdlq+9JxFCg==} + /@jest/types/29.3.1: + resolution: {integrity: sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/schemas': 29.0.0 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.8.0 - '@types/yargs': 17.0.13 + '@types/node': 18.11.9 + '@types/yargs': 17.0.14 chalk: 4.1.2 dev: true @@ -742,7 +781,7 @@ packages: dependencies: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping': 0.3.15 + '@jridgewell/trace-mapping': 0.3.17 dev: true /@jridgewell/resolve-uri/3.1.0: @@ -766,6 +805,13 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true + /@jridgewell/trace-mapping/0.3.17: + resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + dev: true + /@jridgewell/trace-mapping/0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: @@ -776,7 +822,7 @@ packages: /@manypkg/find-root/1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} dependencies: - '@babel/runtime': 7.19.0 + '@babel/runtime': 7.20.6 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 @@ -785,7 +831,7 @@ packages: /@manypkg/get-packages/1.1.3: resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} dependencies: - '@babel/runtime': 7.19.0 + '@babel/runtime': 7.20.6 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 @@ -829,24 +875,24 @@ packages: open: 8.4.0 picocolors: 1.0.0 tiny-glob: 0.2.9 - tslib: 2.4.0 + tslib: 2.4.1 dev: true - /@repo-tooling/eslint-plugin-dprint/0.0.4_typescript@4.8.4: + /@repo-tooling/eslint-plugin-dprint/0.0.4_typescript@4.9.3: resolution: {integrity: sha512-1gQXioqAlyYoRLAQ/4GQ3id8VI9nNO8KKGbbSl5xZf+lo/7Q2zDFhFiuG6owHFYh+2nslQLHy4wJJjOPm2yWEw==} dependencies: '@dprint/formatter': 0.2.0 '@dprint/typescript': 0.68.5 - '@typescript-eslint/utils': 5.39.0_ypn2ylkkyfa5i233caldtndbqa + '@typescript-eslint/utils': 5.39.0_hsf322ms6xhhd4b5ne6lb74y4a diff: 5.1.0 - eslint: 8.24.0 + eslint: 8.28.0 transitivePeerDependencies: - supports-color - typescript dev: true - /@sinclair/typebox/0.24.44: - resolution: {integrity: sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg==} + /@sinclair/typebox/0.24.51: + resolution: {integrity: sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==} dev: true /@ts-morph/common/0.7.5: @@ -876,38 +922,35 @@ packages: resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} dev: true - /@types/benchmark/1.0.33: - resolution: {integrity: sha512-rG7Ieasa9UfZJnL72qiFvY9ivhEIYjCGgfcLLb5tJ/EL9+Mcxernj6W3HVCv/cOfJYuwNUwvVVhnrKl8iT8aqA==} + /@types/benchmark/2.1.2: + resolution: {integrity: sha512-EDKtLYNMKrig22jEvhXq8TBFyFgVNSPmDF2b9UzJ7+eylPqdZVo17PCUMkn1jP6/1A/0u78VqYC6VrX6b8pDWA==} dev: true /@types/chai-subset/1.3.3: resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} dependencies: - '@types/chai': 4.3.3 + '@types/chai': 4.3.4 dev: true /@types/chai/4.3.3: resolution: {integrity: sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==} dev: true - /@types/glob/7.2.0: - resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} - dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 18.8.0 + /@types/chai/4.3.4: + resolution: {integrity: sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==} dev: true /@types/glob/8.0.0: resolution: {integrity: sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 18.8.0 + '@types/node': 18.11.9 dev: true /@types/is-ci/3.0.0: resolution: {integrity: sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==} dependencies: - ci-info: 3.4.0 + ci-info: 3.7.0 dev: true /@types/istanbul-lib-coverage/2.0.4: @@ -926,11 +969,11 @@ packages: '@types/istanbul-lib-report': 3.0.0 dev: true - /@types/jest/29.1.2: - resolution: {integrity: sha512-y+nlX0h87U0R+wsGn6EBuoRWYyv3KFtwRNP3QWp9+k2tJ2/bqcGS3UxD7jgT+tiwJWWq3UsyV4Y+T6rsMT4XMg==} + /@types/jest/29.2.3: + resolution: {integrity: sha512-6XwoEbmatfyoCjWRX7z0fKMmgYKe9+/HrviJ5k0X/tjJWHGAezZOfYaxqQKuzG/TvQyr+ktjm4jgbk0s4/oF2w==} dependencies: - expect: 29.1.2 - pretty-format: 29.1.2 + expect: 29.3.1 + pretty-format: 29.3.1 dev: true /@types/json-schema/7.0.11: @@ -957,6 +1000,10 @@ packages: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} dev: true + /@types/node/18.11.9: + resolution: {integrity: sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==} + dev: true + /@types/node/18.8.0: resolution: {integrity: sha512-u+h43R6U8xXDt2vzUaVP3VwjjLyOJk6uEciZS8OSyziUQGOwmk+l+4drxcsDboHXwyTaqS1INebghmWMRxq3LA==} dev: true @@ -965,21 +1012,25 @@ packages: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} dev: true - /@types/prettier/1.10.0: - resolution: {integrity: sha512-mjEM5uxPvMYg8LLcnmHzMy2G7HFRv7aQtcKslpmHg8SIIQutnLpLfps+1soV2YBlVBFrskR+F6I+nBI9NTh49w==} + /@types/prettier/2.7.1: + resolution: {integrity: sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==} dev: true /@types/rimraf/3.0.2: resolution: {integrity: sha512-F3OznnSLAUxFrCEu/L5PY8+ny8DtcFRjx7fZZ9bycvXRi3KPTRS9HOitGZwvPg0juRhXFWIeKX58cnX5YqLohQ==} dependencies: '@types/glob': 8.0.0 - '@types/node': 18.8.0 + '@types/node': 18.11.9 dev: true /@types/semver/6.2.3: resolution: {integrity: sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==} dev: true + /@types/semver/7.3.13: + resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} + dev: true + /@types/stack-utils/2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true @@ -994,14 +1045,14 @@ packages: '@types/yargs-parser': 21.0.0 dev: true - /@types/yargs/17.0.13: - resolution: {integrity: sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==} + /@types/yargs/17.0.14: + resolution: {integrity: sha512-9Pj7abXoW1RSTcZaL2Hk6G2XyLMlp5ECdVC/Zf2p/KBjC3srijLGgRAXOBjtFrJoIrvxdTKyKDA14bEcbxBaWw==} dependencies: '@types/yargs-parser': 21.0.0 dev: true - /@typescript-eslint/eslint-plugin/5.38.1_c7qepppml3d4ahu5cnfwqe6ltq: - resolution: {integrity: sha512-ky7EFzPhqz3XlhS7vPOoMDaQnQMn+9o5ICR9CPr/6bw8HrFkzhMSxuA3gRfiJVvs7geYrSeawGJjZoZQKCOglQ==} + /@typescript-eslint/eslint-plugin/5.44.0_fnsv2sbzcckq65bwfk7a5xwslu: + resolution: {integrity: sha512-j5ULd7FmmekcyWeArx+i8x7sdRHzAtXTkmDPthE4amxZOWKFK7bomoJ4r7PJ8K7PoMzD16U8MmuZFAonr1ERvw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -1011,36 +1062,37 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.38.1_ypn2ylkkyfa5i233caldtndbqa - '@typescript-eslint/scope-manager': 5.38.1 - '@typescript-eslint/type-utils': 5.38.1_ypn2ylkkyfa5i233caldtndbqa - '@typescript-eslint/utils': 5.38.1_ypn2ylkkyfa5i233caldtndbqa + '@typescript-eslint/parser': 5.44.0_hsf322ms6xhhd4b5ne6lb74y4a + '@typescript-eslint/scope-manager': 5.44.0 + '@typescript-eslint/type-utils': 5.44.0_hsf322ms6xhhd4b5ne6lb74y4a + '@typescript-eslint/utils': 5.44.0_hsf322ms6xhhd4b5ne6lb74y4a debug: 4.3.4 - eslint: 8.24.0 - ignore: 5.2.0 + eslint: 8.28.0 + ignore: 5.2.1 + natural-compare-lite: 1.4.0 regexpp: 3.2.0 - semver: 7.3.7 - tsutils: 3.21.0_typescript@4.8.4 - typescript: 4.8.4 + semver: 7.3.8 + tsutils: 3.21.0_typescript@4.9.3 + typescript: 4.9.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/experimental-utils/5.39.0_ypn2ylkkyfa5i233caldtndbqa: - resolution: {integrity: sha512-n5N9kG/oGu2xXhHzsWzn94s6CWoiUj59FPU2dF2IQZxPftw+q6Jm5sV2vj5qTgAElRooHhrgtl2gxBQDCPt6WA==} + /@typescript-eslint/experimental-utils/5.44.0_hsf322ms6xhhd4b5ne6lb74y4a: + resolution: {integrity: sha512-j8GLemAySe8oUCgILdUaT66pemdWSYcwUYG2Pb71O119hCdvkU+4q8sUTbnDg8NhlZEzSWG2N1v4IxT1kEZrGg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/utils': 5.39.0_ypn2ylkkyfa5i233caldtndbqa - eslint: 8.24.0 + '@typescript-eslint/utils': 5.44.0_hsf322ms6xhhd4b5ne6lb74y4a + eslint: 8.28.0 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/parser/5.38.1_ypn2ylkkyfa5i233caldtndbqa: - resolution: {integrity: sha512-LDqxZBVFFQnQRz9rUZJhLmox+Ep5kdUmLatLQnCRR6523YV+XhRjfYzStQ4MheFA8kMAfUlclHSbu+RKdRwQKw==} + /@typescript-eslint/parser/5.44.0_hsf322ms6xhhd4b5ne6lb74y4a: + resolution: {integrity: sha512-H7LCqbZnKqkkgQHaKLGC6KUjt3pjJDx8ETDqmwncyb6PuoigYajyAwBGz08VU/l86dZWZgI4zm5k2VaKqayYyA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -1049,24 +1101,16 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.38.1 - '@typescript-eslint/types': 5.38.1 - '@typescript-eslint/typescript-estree': 5.38.1_typescript@4.8.4 + '@typescript-eslint/scope-manager': 5.44.0 + '@typescript-eslint/types': 5.44.0 + '@typescript-eslint/typescript-estree': 5.44.0_typescript@4.9.3 debug: 4.3.4 - eslint: 8.24.0 - typescript: 4.8.4 + eslint: 8.28.0 + typescript: 4.9.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager/5.38.1: - resolution: {integrity: sha512-BfRDq5RidVU3RbqApKmS7RFMtkyWMM50qWnDAkKgQiezRtLKsoyRKIvz1Ok5ilRWeD9IuHvaidaLxvGx/2eqTQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.38.1 - '@typescript-eslint/visitor-keys': 5.38.1 - dev: true - /@typescript-eslint/scope-manager/5.39.0: resolution: {integrity: sha512-/I13vAqmG3dyqMVSZPjsbuNQlYS082Y7OMkwhCfLXYsmlI0ca4nkL7wJ/4gjX70LD4P8Hnw1JywUVVAwepURBw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1075,8 +1119,16 @@ packages: '@typescript-eslint/visitor-keys': 5.39.0 dev: true - /@typescript-eslint/type-utils/5.38.1_ypn2ylkkyfa5i233caldtndbqa: - resolution: {integrity: sha512-UU3j43TM66gYtzo15ivK2ZFoDFKKP0k03MItzLdq0zV92CeGCXRfXlfQX5ILdd4/DSpHkSjIgLLLh1NtkOJOAw==} + /@typescript-eslint/scope-manager/5.44.0: + resolution: {integrity: sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.44.0 + '@typescript-eslint/visitor-keys': 5.44.0 + dev: true + + /@typescript-eslint/type-utils/5.44.0_hsf322ms6xhhd4b5ne6lb74y4a: + resolution: {integrity: sha512-A1u0Yo5wZxkXPQ7/noGkRhV4J9opcymcr31XQtOzcc5nO/IHN2E2TPMECKWYpM3e6olWEM63fq/BaL1wEYnt/w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -1085,12 +1137,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.38.1_typescript@4.8.4 - '@typescript-eslint/utils': 5.38.1_ypn2ylkkyfa5i233caldtndbqa + '@typescript-eslint/typescript-estree': 5.44.0_typescript@4.9.3 + '@typescript-eslint/utils': 5.44.0_hsf322ms6xhhd4b5ne6lb74y4a debug: 4.3.4 - eslint: 8.24.0 - tsutils: 3.21.0_typescript@4.8.4 - typescript: 4.8.4 + eslint: 8.28.0 + tsutils: 3.21.0_typescript@4.9.3 + typescript: 4.9.3 transitivePeerDependencies: - supports-color dev: true @@ -1100,13 +1152,13 @@ packages: engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} dev: true - /@typescript-eslint/types/5.38.1: - resolution: {integrity: sha512-QTW1iHq1Tffp9lNfbfPm4WJabbvpyaehQ0SrvVK2yfV79SytD9XDVxqiPvdrv2LK7DGSFo91TB2FgWanbJAZXg==} + /@typescript-eslint/types/5.39.0: + resolution: {integrity: sha512-gQMZrnfEBFXK38hYqt8Lkwt8f4U6yq+2H5VDSgP/qiTzC8Nw8JO3OuSUOQ2qW37S/dlwdkHDntkZM6SQhKyPhw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/types/5.39.0: - resolution: {integrity: sha512-gQMZrnfEBFXK38hYqt8Lkwt8f4U6yq+2H5VDSgP/qiTzC8Nw8JO3OuSUOQ2qW37S/dlwdkHDntkZM6SQhKyPhw==} + /@typescript-eslint/types/5.44.0: + resolution: {integrity: sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true @@ -1124,15 +1176,15 @@ packages: debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.3.7 + semver: 7.3.8 tsutils: 3.21.0_typescript@3.9.10 typescript: 3.9.10 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/typescript-estree/5.38.1_typescript@4.8.4: - resolution: {integrity: sha512-99b5e/Enoe8fKMLdSuwrfH/C0EIbpUWmeEKHmQlGZb8msY33qn1KlkFww0z26o5Omx7EVjzVDCWEfrfCDHfE7g==} + /@typescript-eslint/typescript-estree/5.39.0_typescript@4.9.3: + resolution: {integrity: sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -1140,20 +1192,20 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.38.1 - '@typescript-eslint/visitor-keys': 5.38.1 + '@typescript-eslint/types': 5.39.0 + '@typescript-eslint/visitor-keys': 5.39.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.3.7 - tsutils: 3.21.0_typescript@4.8.4 - typescript: 4.8.4 + semver: 7.3.8 + tsutils: 3.21.0_typescript@4.9.3 + typescript: 4.9.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/typescript-estree/5.39.0_typescript@4.8.4: - resolution: {integrity: sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA==} + /@typescript-eslint/typescript-estree/5.44.0_typescript@4.9.3: + resolution: {integrity: sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -1161,49 +1213,51 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.39.0 - '@typescript-eslint/visitor-keys': 5.39.0 + '@typescript-eslint/types': 5.44.0 + '@typescript-eslint/visitor-keys': 5.44.0 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.3.7 - tsutils: 3.21.0_typescript@4.8.4 - typescript: 4.8.4 + semver: 7.3.8 + tsutils: 3.21.0_typescript@4.9.3 + typescript: 4.9.3 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils/5.38.1_ypn2ylkkyfa5i233caldtndbqa: - resolution: {integrity: sha512-oIuUiVxPBsndrN81oP8tXnFa/+EcZ03qLqPDfSZ5xIJVm7A9V0rlkQwwBOAGtrdN70ZKDlKv+l1BeT4eSFxwXA==} + /@typescript-eslint/utils/5.39.0_hsf322ms6xhhd4b5ne6lb74y4a: + resolution: {integrity: sha512-+DnY5jkpOpgj+EBtYPyHRjXampJfC0yUZZzfzLuUWVZvCuKqSdJVC8UhdWipIw7VKNTfwfAPiOWzYkAwuIhiAg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@types/json-schema': 7.0.11 - '@typescript-eslint/scope-manager': 5.38.1 - '@typescript-eslint/types': 5.38.1 - '@typescript-eslint/typescript-estree': 5.38.1_typescript@4.8.4 - eslint: 8.24.0 + '@typescript-eslint/scope-manager': 5.39.0 + '@typescript-eslint/types': 5.39.0 + '@typescript-eslint/typescript-estree': 5.39.0_typescript@4.9.3 + eslint: 8.28.0 eslint-scope: 5.1.1 - eslint-utils: 3.0.0_eslint@8.24.0 + eslint-utils: 3.0.0_eslint@8.28.0 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/utils/5.39.0_ypn2ylkkyfa5i233caldtndbqa: - resolution: {integrity: sha512-+DnY5jkpOpgj+EBtYPyHRjXampJfC0yUZZzfzLuUWVZvCuKqSdJVC8UhdWipIw7VKNTfwfAPiOWzYkAwuIhiAg==} + /@typescript-eslint/utils/5.44.0_hsf322ms6xhhd4b5ne6lb74y4a: + resolution: {integrity: sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@types/json-schema': 7.0.11 - '@typescript-eslint/scope-manager': 5.39.0 - '@typescript-eslint/types': 5.39.0 - '@typescript-eslint/typescript-estree': 5.39.0_typescript@4.8.4 - eslint: 8.24.0 + '@types/semver': 7.3.13 + '@typescript-eslint/scope-manager': 5.44.0 + '@typescript-eslint/types': 5.44.0 + '@typescript-eslint/typescript-estree': 5.44.0_typescript@4.9.3 + eslint: 8.28.0 eslint-scope: 5.1.1 - eslint-utils: 3.0.0_eslint@8.24.0 + eslint-utils: 3.0.0_eslint@8.28.0 + semver: 7.3.8 transitivePeerDependencies: - supports-color - typescript @@ -1217,28 +1271,28 @@ packages: eslint-visitor-keys: 2.1.0 dev: true - /@typescript-eslint/visitor-keys/5.38.1: - resolution: {integrity: sha512-bSHr1rRxXt54+j2n4k54p4fj8AHJ49VDWtjpImOpzQj4qjAiOpPni+V1Tyajh19Api1i844F757cur8wH3YvOA==} + /@typescript-eslint/visitor-keys/5.39.0: + resolution: {integrity: sha512-yyE3RPwOG+XJBLrhvsxAidUgybJVQ/hG8BhiJo0k8JSAYfk/CshVcxf0HwP4Jt7WZZ6vLmxdo1p6EyN3tzFTkg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.38.1 + '@typescript-eslint/types': 5.39.0 eslint-visitor-keys: 3.3.0 dev: true - /@typescript-eslint/visitor-keys/5.39.0: - resolution: {integrity: sha512-yyE3RPwOG+XJBLrhvsxAidUgybJVQ/hG8BhiJo0k8JSAYfk/CshVcxf0HwP4Jt7WZZ6vLmxdo1p6EyN3tzFTkg==} + /@typescript-eslint/visitor-keys/5.44.0: + resolution: {integrity: sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.39.0 + '@typescript-eslint/types': 5.44.0 eslint-visitor-keys: 3.3.0 dev: true - /acorn-jsx/5.3.2_acorn@8.8.0: + /acorn-jsx/5.3.2_acorn@8.8.1: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.8.0 + acorn: 8.8.1 dev: true /acorn-walk/8.2.0: @@ -1252,6 +1306,12 @@ packages: hasBin: true dev: true + /acorn/8.8.1: + resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + /ajv/6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: @@ -1410,6 +1470,16 @@ packages: es-shim-unscopables: 1.0.0 dev: true + /array.prototype.flat/1.3.1: + resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + es-shim-unscopables: 1.0.0 + dev: true + /arrify/1.0.1: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} @@ -1454,18 +1524,12 @@ packages: gulp-header: 1.8.12 dev: true - /babel-plugin-annotate-pure-calls/0.4.0_@babel+core@7.19.3: + /babel-plugin-annotate-pure-calls/0.4.0_@babel+core@7.20.5: resolution: {integrity: sha512-oi4M/PWUJOU9ZyRGoPTfPMqdyMp06jbJAomd3RcyYuzUtBOddv98BqLm96Lucpi2QFoQHkdGQt0ACvw7VzVEQA==} peerDependencies: '@babel/core': ^6.0.0-0 || 7.x dependencies: - '@babel/core': 7.19.3 - dev: true - - /babel-plugin-dynamic-import-node/2.3.3: - resolution: {integrity: sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==} - dependencies: - object.assign: 4.1.4 + '@babel/core': 7.20.5 dev: true /babel-runtime/6.26.0: @@ -1588,10 +1652,10 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001414 - electron-to-chromium: 1.4.270 + caniuse-lite: 1.0.30001434 + electron-to-chromium: 1.4.284 node-releases: 2.0.6 - update-browserslist-db: 1.0.9_browserslist@4.21.4 + update-browserslist-db: 1.0.10_browserslist@4.21.4 dev: true /buffer-from/1.1.2: @@ -1670,8 +1734,8 @@ packages: engines: {node: '>=6'} dev: true - /caniuse-lite/1.0.30001414: - resolution: {integrity: sha512-t55jfSaWjCdocnFdKQoO+d2ct9C59UZg4dY3OnUlSZ447r8pUtIKdp0hpAzrGFultmTC+Us+KpKi4GZl/LXlFg==} + /caniuse-lite/1.0.30001434: + resolution: {integrity: sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==} dev: true /chai/4.3.6: @@ -1687,6 +1751,19 @@ packages: type-detect: 4.0.8 dev: true + /chai/4.3.7: + resolution: {integrity: sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==} + engines: {node: '>=4'} + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.2 + deep-eql: 4.1.2 + get-func-name: 2.0.0 + loupe: 2.3.6 + pathval: 1.1.1 + type-detect: 4.0.8 + dev: true + /chalk/2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -1747,8 +1824,9 @@ packages: dev: true optional: true - /ci-info/3.4.0: - resolution: {integrity: sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==} + /ci-info/3.7.0: + resolution: {integrity: sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==} + engines: {node: '>=8'} dev: true /class-utils/0.3.6: @@ -1885,8 +1963,8 @@ packages: source-map: 0.6.1 dev: true - /concurrently/7.4.0: - resolution: {integrity: sha512-M6AfrueDt/GEna/Vg9BqQ+93yuvzkSKmoTixnwEJkH0LlcGrRC2eCmjeG1tLLHIYfpYJABokqSGyMcXjm96AFA==} + /concurrently/7.6.0: + resolution: {integrity: sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==} engines: {node: ^12.20.0 || ^14.13.0 || >=16.0.0} hasBin: true dependencies: @@ -1894,11 +1972,11 @@ packages: date-fns: 2.29.3 lodash: 4.17.21 rxjs: 7.5.7 - shell-quote: 1.7.3 + shell-quote: 1.7.4 spawn-command: 0.0.2-1 supports-color: 8.1.1 tree-kill: 1.2.2 - yargs: 17.6.0 + yargs: 17.6.2 dev: true /convert-source-map/1.8.0: @@ -1907,6 +1985,10 @@ packages: safe-buffer: 5.1.2 dev: true + /convert-source-map/1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + dev: true + /copy-descriptor/0.1.1: resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} engines: {node: '>=0.10.0'} @@ -2027,8 +2109,8 @@ packages: ms: 2.1.2 dev: true - /decamelize-keys/1.1.0: - resolution: {integrity: sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==} + /decamelize-keys/1.1.1: + resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} engines: {node: '>=0.10.0'} dependencies: decamelize: 1.2.0 @@ -2052,6 +2134,13 @@ packages: type-detect: 4.0.8 dev: true + /deep-eql/4.1.2: + resolution: {integrity: sha512-gT18+YW4CcW/DBNTwAmqTtkJh7f9qqScu2qFVlx7kCoeY9tlBu9cUcr7+I+Z/noG8INehS3xQgLpTtd/QUTn4w==} + engines: {node: '>=6'} + dependencies: + type-detect: 4.0.8 + dev: true + /deep-extend/0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -2061,8 +2150,8 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true - /defaults/1.0.3: - resolution: {integrity: sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==} + /defaults/1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: clone: 1.0.4 dev: true @@ -2164,7 +2253,7 @@ packages: dependencies: debug: 4.3.4 is-url: 1.2.4 - postcss: 8.4.17 + postcss: 8.4.19 postcss-values-parser: 2.0.1 transitivePeerDependencies: - supports-color @@ -2175,8 +2264,8 @@ packages: engines: {node: 12.x || 14.x || 16.x} dependencies: is-url: 1.2.4 - postcss: 8.4.17 - postcss-values-parser: 5.0.0_postcss@8.4.17 + postcss: 8.4.19 + postcss-values-parser: 5.0.0_postcss@8.4.19 dev: true /detective-sass/3.0.2: @@ -2221,8 +2310,8 @@ packages: engines: {node: '>= 10.14.2'} dev: true - /diff-sequences/29.0.0: - resolution: {integrity: sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==} + /diff-sequences/29.3.1: + resolution: {integrity: sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true @@ -2266,7 +2355,7 @@ packages: dev: true patched: true - /docs-ts/0.7.0_dmjzcauo3cshxeipj7bv64ktgm: + /docs-ts/0.7.0_brpckf4sz23pco3jyty2eys3iq: resolution: {integrity: sha512-S9UM7Ddh0l3qwftSJiko+3+aGJrnGTnigKq4wpsOvQBmMJz7kMmdAeiTwNCRgzQI70oT3T2uyuzR9hy5JT2xPQ==} hasBin: true peerDependencies: @@ -2281,11 +2370,11 @@ packages: io-ts: 2.2.19_fp-ts@2.12.3 logging-ts: 0.3.4_fp-ts@2.12.3 markdown-toc: 1.2.0 - prettier: 2.7.1 + prettier: 2.8.0 rimraf: 2.7.1 ts-morph: 9.1.0 - ts-node: 8.10.2_typescript@4.8.4 - typescript: 4.8.4 + ts-node: 8.10.2_typescript@4.9.3 + typescript: 4.9.3 dev: true /doctrine/2.1.0: @@ -2311,16 +2400,16 @@ packages: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} dev: true - /electron-to-chromium/1.4.270: - resolution: {integrity: sha512-KNhIzgLiJmDDC444dj9vEOpZEgsV96ult9Iff98Vanumn+ShJHd5se8aX6KeVxdc0YQeqdrezBZv89rleDbvSg==} + /electron-to-chromium/1.4.284: + resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==} dev: true /emoji-regex/8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true - /enhanced-resolve/5.10.0: - resolution: {integrity: sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==} + /enhanced-resolve/5.12.0: + resolution: {integrity: sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==} engines: {node: '>=10.13.0'} dependencies: graceful-fs: 4.2.10 @@ -2370,6 +2459,36 @@ packages: unbox-primitive: 1.0.2 dev: true + /es-abstract/1.20.4: + resolution: {integrity: sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + es-to-primitive: 1.2.1 + function-bind: 1.1.1 + function.prototype.name: 1.1.5 + get-intrinsic: 1.1.3 + get-symbol-description: 1.0.0 + has: 1.0.3 + has-property-descriptors: 1.0.0 + has-symbols: 1.0.3 + internal-slot: 1.0.3 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-weakref: 1.0.2 + object-inspect: 1.12.2 + object-keys: 1.1.1 + object.assign: 4.1.4 + regexp.prototype.flags: 1.4.3 + safe-regex-test: 1.0.0 + string.prototype.trimend: 1.0.6 + string.prototype.trimstart: 1.0.6 + unbox-primitive: 1.0.2 + dev: true + /es-shim-unscopables/1.0.0: resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} dependencies: @@ -2394,6 +2513,15 @@ packages: dev: true optional: true + /esbuild-android-64/0.15.16: + resolution: {integrity: sha512-Vwkv/sT0zMSgPSVO3Jlt1pUbnZuOgtOQJkJkyyJFAlLe7BiT8e9ESzo0zQSx4c3wW4T6kGChmKDPMbWTgtliQA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + /esbuild-android-arm64/0.14.54: resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} engines: {node: '>=12'} @@ -2403,6 +2531,15 @@ packages: dev: true optional: true + /esbuild-android-arm64/0.15.16: + resolution: {integrity: sha512-lqfKuofMExL5niNV3gnhMUYacSXfsvzTa/58sDlBET/hCOG99Zmeh+lz6kvdgvGOsImeo6J9SW21rFCogNPLxg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + /esbuild-darwin-64/0.14.54: resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} engines: {node: '>=12'} @@ -2412,6 +2549,15 @@ packages: dev: true optional: true + /esbuild-darwin-64/0.15.16: + resolution: {integrity: sha512-wo2VWk/n/9V2TmqUZ/KpzRjCEcr00n7yahEdmtzlrfQ3lfMCf3Wa+0sqHAbjk3C6CKkR3WKK/whkMq5Gj4Da9g==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /esbuild-darwin-arm64/0.14.54: resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} engines: {node: '>=12'} @@ -2421,6 +2567,15 @@ packages: dev: true optional: true + /esbuild-darwin-arm64/0.15.16: + resolution: {integrity: sha512-fMXaUr5ou0M4WnewBKsspMtX++C1yIa3nJ5R2LSbLCfJT3uFdcRoU/NZjoM4kOMKyOD9Sa/2vlgN8G07K3SJnw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /esbuild-freebsd-64/0.14.54: resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} engines: {node: '>=12'} @@ -2430,6 +2585,15 @@ packages: dev: true optional: true + /esbuild-freebsd-64/0.15.16: + resolution: {integrity: sha512-UzIc0xlRx5x9kRuMr+E3+hlSOxa/aRqfuMfiYBXu2jJ8Mzej4lGL7+o6F5hzhLqWfWm1GWHNakIdlqg1ayaTNQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /esbuild-freebsd-arm64/0.14.54: resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} engines: {node: '>=12'} @@ -2439,6 +2603,15 @@ packages: dev: true optional: true + /esbuild-freebsd-arm64/0.15.16: + resolution: {integrity: sha512-8xyiYuGc0DLZphFQIiYaLHlfoP+hAN9RHbE+Ibh8EUcDNHAqbQgUrQg7pE7Bo00rXmQ5Ap6KFgcR0b4ALZls1g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /esbuild-linux-32/0.14.54: resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} engines: {node: '>=12'} @@ -2448,6 +2621,15 @@ packages: dev: true optional: true + /esbuild-linux-32/0.15.16: + resolution: {integrity: sha512-iGijUTV+0kIMyUVoynK0v+32Oi8yyp0xwMzX69GX+5+AniNy/C/AL1MjFTsozRp/3xQPl7jVux/PLe2ds10/2w==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + /esbuild-linux-64/0.14.54: resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} engines: {node: '>=12'} @@ -2457,6 +2639,15 @@ packages: dev: true optional: true + /esbuild-linux-64/0.15.16: + resolution: {integrity: sha512-tuSOjXdLw7VzaUj89fIdAaQT7zFGbKBcz4YxbWrOiXkwscYgE7HtTxUavreBbnRkGxKwr9iT/gmeJWNm4djy/g==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /esbuild-linux-arm/0.14.54: resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} engines: {node: '>=12'} @@ -2466,6 +2657,15 @@ packages: dev: true optional: true + /esbuild-linux-arm/0.15.16: + resolution: {integrity: sha512-XKcrxCEXDTOuoRj5l12tJnkvuxXBMKwEC5j0JISw3ziLf0j4zIwXbKbTmUrKFWbo6ZgvNpa7Y5dnbsjVvH39bQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /esbuild-linux-arm64/0.14.54: resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} engines: {node: '>=12'} @@ -2475,6 +2675,15 @@ packages: dev: true optional: true + /esbuild-linux-arm64/0.15.16: + resolution: {integrity: sha512-mPYksnfHnemNrvjrDhZyixL/AfbJN0Xn9S34ZOHYdh6/jJcNd8iTsv3JwJoEvTJqjMggjMhGUPJAdjnFBHoH8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /esbuild-linux-mips64le/0.14.54: resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} engines: {node: '>=12'} @@ -2484,6 +2693,15 @@ packages: dev: true optional: true + /esbuild-linux-mips64le/0.15.16: + resolution: {integrity: sha512-kSJO2PXaxfm0pWY39+YX+QtpFqyyrcp0ZeI8QPTrcFVQoWEPiPVtOfTZeS3ZKedfH+Ga38c4DSzmKMQJocQv6A==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + /esbuild-linux-ppc64le/0.14.54: resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} engines: {node: '>=12'} @@ -2493,6 +2711,15 @@ packages: dev: true optional: true + /esbuild-linux-ppc64le/0.15.16: + resolution: {integrity: sha512-NimPikwkBY0yGABw6SlhKrtT35sU4O23xkhlrTT/O6lSxv3Pm5iSc6OYaqVAHWkLdVf31bF4UDVFO+D990WpAA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /esbuild-linux-riscv64/0.14.54: resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} engines: {node: '>=12'} @@ -2502,6 +2729,15 @@ packages: dev: true optional: true + /esbuild-linux-riscv64/0.15.16: + resolution: {integrity: sha512-ty2YUHZlwFOwp7pR+J87M4CVrXJIf5ZZtU/umpxgVJBXvWjhziSLEQxvl30SYfUPq0nzeWKBGw5i/DieiHeKfw==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /esbuild-linux-s390x/0.14.54: resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} engines: {node: '>=12'} @@ -2511,6 +2747,15 @@ packages: dev: true optional: true + /esbuild-linux-s390x/0.15.16: + resolution: {integrity: sha512-VkZaGssvPDQtx4fvVdZ9czezmyWyzpQhEbSNsHZZN0BHvxRLOYAQ7sjay8nMQwYswP6O2KlZluRMNPYefFRs+w==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + /esbuild-netbsd-64/0.14.54: resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} engines: {node: '>=12'} @@ -2520,6 +2765,15 @@ packages: dev: true optional: true + /esbuild-netbsd-64/0.15.16: + resolution: {integrity: sha512-ElQ9rhdY51et6MJTWrCPbqOd/YuPowD7Cxx3ee8wlmXQQVW7UvQI6nSprJ9uVFQISqSF5e5EWpwWqXZsECLvXg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + /esbuild-openbsd-64/0.14.54: resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} engines: {node: '>=12'} @@ -2529,6 +2783,15 @@ packages: dev: true optional: true + /esbuild-openbsd-64/0.15.16: + resolution: {integrity: sha512-KgxMHyxMCT+NdLQE1zVJEsLSt2QQBAvJfmUGDmgEq8Fvjrf6vSKB00dVHUEDKcJwMID6CdgCpvYNt999tIYhqA==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /esbuild-sunos-64/0.14.54: resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} engines: {node: '>=12'} @@ -2538,6 +2801,15 @@ packages: dev: true optional: true + /esbuild-sunos-64/0.15.16: + resolution: {integrity: sha512-exSAx8Phj7QylXHlMfIyEfNrmqnLxFqLxdQF6MBHPdHAjT7fsKaX6XIJn+aQEFiOcE4X8e7VvdMCJ+WDZxjSRQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + /esbuild-windows-32/0.14.54: resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} engines: {node: '>=12'} @@ -2547,6 +2819,15 @@ packages: dev: true optional: true + /esbuild-windows-32/0.15.16: + resolution: {integrity: sha512-zQgWpY5pUCSTOwqKQ6/vOCJfRssTvxFuEkpB4f2VUGPBpdddZfdj8hbZuFRdZRPIVHvN7juGcpgCA/XCF37mAQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /esbuild-windows-64/0.14.54: resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} engines: {node: '>=12'} @@ -2556,6 +2837,15 @@ packages: dev: true optional: true + /esbuild-windows-64/0.15.16: + resolution: {integrity: sha512-HjW1hHRLSncnM3MBCP7iquatHVJq9l0S2xxsHHj4yzf4nm9TU4Z7k4NkeMlD/dHQ4jPlQQhwcMvwbJiOefSuZw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /esbuild-windows-arm64/0.14.54: resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} engines: {node: '>=12'} @@ -2565,6 +2855,15 @@ packages: dev: true optional: true + /esbuild-windows-arm64/0.15.16: + resolution: {integrity: sha512-oCcUKrJaMn04Vxy9Ekd8x23O8LoU01+4NOkQ2iBToKgnGj5eo1vU9i27NQZ9qC8NFZgnQQZg5oZWAejmbsppNA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /esbuild/0.14.54: resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} engines: {node: '>=12'} @@ -2594,6 +2893,36 @@ packages: esbuild-windows-arm64: 0.14.54 dev: true + /esbuild/0.15.16: + resolution: {integrity: sha512-o6iS9zxdHrrojjlj6pNGC2NAg86ECZqIETswTM5KmJitq+R1YmahhWtMumeQp9lHqJaROGnsBi2RLawGnfo5ZQ==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.15.16 + '@esbuild/linux-loong64': 0.15.16 + esbuild-android-64: 0.15.16 + esbuild-android-arm64: 0.15.16 + esbuild-darwin-64: 0.15.16 + esbuild-darwin-arm64: 0.15.16 + esbuild-freebsd-64: 0.15.16 + esbuild-freebsd-arm64: 0.15.16 + esbuild-linux-32: 0.15.16 + esbuild-linux-64: 0.15.16 + esbuild-linux-arm: 0.15.16 + esbuild-linux-arm64: 0.15.16 + esbuild-linux-mips64le: 0.15.16 + esbuild-linux-ppc64le: 0.15.16 + esbuild-linux-riscv64: 0.15.16 + esbuild-linux-s390x: 0.15.16 + esbuild-netbsd-64: 0.15.16 + esbuild-openbsd-64: 0.15.16 + esbuild-sunos-64: 0.15.16 + esbuild-windows-32: 0.15.16 + esbuild-windows-64: 0.15.16 + esbuild-windows-arm64: 0.15.16 + dev: true + /escalade/3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -2636,27 +2965,27 @@ packages: - supports-color dev: true - /eslint-import-resolver-typescript/3.5.1_dg2pe6kqkrddxbf2funb723kue: - resolution: {integrity: sha512-U7LUjNJPYjNsHvAUAkt/RU3fcTSpbllA0//35B4eLYTX74frmOepbt7F7J3D1IGtj9k21buOpaqtDd4ZlS/BYQ==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + /eslint-import-resolver-typescript/3.5.2_ktrec6dplf4now6nlbc6d67jee: + resolution: {integrity: sha512-zX4ebnnyXiykjhcBvKIf5TNvt8K7yX6bllTRZ14MiurKPjDpCAZujlszTdB8pcNXhZcOf+god4s9SjQa5GnytQ==} + engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '*' eslint-plugin-import: '*' dependencies: debug: 4.3.4 - enhanced-resolve: 5.10.0 - eslint: 8.24.0 - eslint-plugin-import: 2.26.0_3vub7fqunrjizhghsam4lcr2pi + enhanced-resolve: 5.12.0 + eslint: 8.28.0 + eslint-plugin-import: 2.26.0_vc54pluhgv7booofyyjouvuf74 get-tsconfig: 4.2.0 globby: 13.1.2 - is-core-module: 2.10.0 + is-core-module: 2.11.0 is-glob: 4.0.3 synckit: 0.8.4 transitivePeerDependencies: - supports-color dev: true - /eslint-module-utils/2.7.4_36jginl7aok4giyuaq3k6zvh2u: + /eslint-module-utils/2.7.4_d2eo2jksnn7c2x6eoou4blnbne: resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -2677,11 +3006,11 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.38.1_ypn2ylkkyfa5i233caldtndbqa + '@typescript-eslint/parser': 5.44.0_hsf322ms6xhhd4b5ne6lb74y4a debug: 3.2.7 - eslint: 8.24.0 + eslint: 8.28.0 eslint-import-resolver-node: 0.3.6 - eslint-import-resolver-typescript: 3.5.1_dg2pe6kqkrddxbf2funb723kue + eslint-import-resolver-typescript: 3.5.2_ktrec6dplf4now6nlbc6d67jee transitivePeerDependencies: - supports-color dev: true @@ -2689,7 +3018,7 @@ packages: /eslint-plugin-codegen/0.16.1: resolution: {integrity: sha512-+mKDJezeoziyQOuPicRj6im1GxzxDvv+EgAZAOTIxBwaWTadppgwZGFMeUrWucNM2duJXmvLDcbsmVT69ORgQA==} dependencies: - '@babel/core': 7.19.3 + '@babel/core': 7.20.5 '@babel/generator': 7.12.17 '@babel/parser': 7.19.3 '@babel/traverse': 7.19.3 @@ -2706,22 +3035,22 @@ packages: - supports-color dev: true - /eslint-plugin-deprecation/1.3.2_ypn2ylkkyfa5i233caldtndbqa: - resolution: {integrity: sha512-z93wbx9w7H/E3ogPw6AZMkkNJ6m51fTZRNZPNQqxQLmx+KKt7aLkMU9wN67s71i+VVHN4tLOZ3zT3QLbnlC0Mg==} + /eslint-plugin-deprecation/1.3.3_hsf322ms6xhhd4b5ne6lb74y4a: + resolution: {integrity: sha512-Bbkv6ZN2cCthVXz/oZKPwsSY5S/CbgTLRG4Q2s2gpPpgNsT0uJ0dB5oLNiWzFYY8AgKX4ULxXFG1l/rDav9QFA==} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 typescript: ^3.7.5 || ^4.0.0 dependencies: - '@typescript-eslint/experimental-utils': 5.39.0_ypn2ylkkyfa5i233caldtndbqa - eslint: 8.24.0 - tslib: 2.4.0 - tsutils: 3.21.0_typescript@4.8.4 - typescript: 4.8.4 + '@typescript-eslint/experimental-utils': 5.44.0_hsf322ms6xhhd4b5ne6lb74y4a + eslint: 8.28.0 + tslib: 2.4.1 + tsutils: 3.21.0_typescript@4.9.3 + typescript: 4.9.3 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import/2.26.0_3vub7fqunrjizhghsam4lcr2pi: + /eslint-plugin-import/2.26.0_vc54pluhgv7booofyyjouvuf74: resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: @@ -2731,14 +3060,14 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.38.1_ypn2ylkkyfa5i233caldtndbqa + '@typescript-eslint/parser': 5.44.0_hsf322ms6xhhd4b5ne6lb74y4a array-includes: 3.1.5 array.prototype.flat: 1.3.0 debug: 2.6.9 doctrine: 2.1.0 - eslint: 8.24.0 + eslint: 8.28.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4_36jginl7aok4giyuaq3k6zvh2u + eslint-module-utils: 2.7.4_d2eo2jksnn7c2x6eoou4blnbne has: 1.0.3 is-core-module: 2.10.0 is-glob: 4.0.3 @@ -2752,21 +3081,21 @@ packages: - supports-color dev: true - /eslint-plugin-simple-import-sort/8.0.0_eslint@8.24.0: + /eslint-plugin-simple-import-sort/8.0.0_eslint@8.28.0: resolution: {integrity: sha512-bXgJQ+lqhtQBCuWY/FUWdB27j4+lqcvXv5rUARkzbeWLwea+S5eBZEQrhnO+WgX3ZoJHVj0cn943iyXwByHHQw==} peerDependencies: eslint: '>=5.0.0' dependencies: - eslint: 8.24.0 + eslint: 8.28.0 dev: true - /eslint-plugin-sort-destructure-keys/1.4.0_eslint@8.24.0: + /eslint-plugin-sort-destructure-keys/1.4.0_eslint@8.28.0: resolution: {integrity: sha512-txU9l22mblz7YpyjJNYFy4wb5PVXiRMbc9lqFPPhvY4wKyBBYQvb31TIcduf7iRb4Bv01aiXcJiuCkOOrVY48Q==} engines: {node: '>=6.0.0'} peerDependencies: eslint: 3 - 8 dependencies: - eslint: 8.24.0 + eslint: 8.28.0 natural-compare-lite: 1.4.0 dev: true @@ -2786,13 +3115,13 @@ packages: estraverse: 5.3.0 dev: true - /eslint-utils/3.0.0_eslint@8.24.0: + /eslint-utils/3.0.0_eslint@8.28.0: resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: - eslint: 8.24.0 + eslint: 8.28.0 eslint-visitor-keys: 2.1.0 dev: true @@ -2806,15 +3135,15 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint/8.24.0: - resolution: {integrity: sha512-dWFaPhGhTAiPcCgm3f6LI2MBWbogMnTJzFBbhXVRQDJPkr9pGZvVjlVfXd+vyDcWPA2Ic9L2AXPIQM0+vk/cSQ==} + /eslint/8.28.0: + resolution: {integrity: sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint/eslintrc': 1.3.2 - '@humanwhocodes/config-array': 0.10.7 - '@humanwhocodes/gitignore-to-minimatch': 1.0.2 + '@eslint/eslintrc': 1.3.3 + '@humanwhocodes/config-array': 0.11.7 '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 @@ -2822,23 +3151,23 @@ packages: doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.1.1 - eslint-utils: 3.0.0_eslint@8.24.0 + eslint-utils: 3.0.0_eslint@8.28.0 eslint-visitor-keys: 3.3.0 - espree: 9.4.0 + espree: 9.4.1 esquery: 1.4.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.17.0 - globby: 11.1.0 + globals: 13.18.0 grapheme-splitter: 1.0.4 - ignore: 5.2.0 + ignore: 5.2.1 import-fresh: 3.3.0 imurmurhash: 0.1.4 is-glob: 4.0.3 - js-sdsl: 4.1.5 + is-path-inside: 3.0.3 + js-sdsl: 4.2.0 js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 @@ -2854,12 +3183,12 @@ packages: - supports-color dev: true - /espree/9.4.0: - resolution: {integrity: sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==} + /espree/9.4.1: + resolution: {integrity: sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.8.0 - acorn-jsx: 5.3.2_acorn@8.8.0 + acorn: 8.8.1 + acorn-jsx: 5.3.2_acorn@8.8.1 eslint-visitor-keys: 3.3.0 dev: true @@ -2939,15 +3268,15 @@ packages: jest-regex-util: 26.0.0 dev: true - /expect/29.1.2: - resolution: {integrity: sha512-AuAGn1uxva5YBbBlXb+2JPxJRuemZsmlGcapPXWNSBNsQtAULfjioREGBWuI0EOvYUKjDnrCy8PW5Zlr1md5mw==} + /expect/29.3.1: + resolution: {integrity: sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/expect-utils': 29.1.2 - jest-get-type: 29.0.0 - jest-matcher-utils: 29.1.2 - jest-message-util: 29.1.2 - jest-util: 29.1.2 + '@jest/expect-utils': 29.3.1 + jest-get-type: 29.2.0 + jest-matcher-utils: 29.3.1 + jest-message-util: 29.3.1 + jest-util: 29.3.1 dev: true /extend-shallow/2.0.1: @@ -3008,6 +3337,13 @@ packages: pure-rand: 5.0.3 dev: true + /fast-check/3.3.0: + resolution: {integrity: sha512-Zu6tZ4g0T4H9Tiz3tdNPEHrSbuICj7yhdOM9RCZKNMkpjZ9avDV3ORklXaEmh4zvkX24/bGZ9DxKKqWfXttUqw==} + engines: {node: '>=8.0.0'} + dependencies: + pure-rand: 5.0.5 + dev: true + /fast-deep-equal/3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true @@ -3063,7 +3399,7 @@ packages: app-module-path: 2.2.0 commander: 2.20.3 debug: 4.3.4 - enhanced-resolve: 5.10.0 + enhanced-resolve: 5.12.0 is-relative-path: 1.0.2 module-definition: 3.4.0 module-lookup-amd: 7.0.1 @@ -3222,7 +3558,7 @@ packages: requiresBuild: true dependencies: bindings: 1.5.0 - nan: 2.16.0 + nan: 2.17.0 dev: true optional: true @@ -3244,7 +3580,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.3 + es-abstract: 1.20.4 functions-have-names: 1.2.3 dev: true @@ -3365,8 +3701,8 @@ packages: engines: {node: '>=4'} dev: true - /globals/13.17.0: - resolution: {integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==} + /globals/13.18.0: + resolution: {integrity: sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 @@ -3383,7 +3719,7 @@ packages: array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.2.12 - ignore: 5.2.0 + ignore: 5.2.1 merge2: 1.4.1 slash: 3.0.0 dev: true @@ -3394,7 +3730,7 @@ packages: dependencies: dir-glob: 3.0.1 fast-glob: 3.2.12 - ignore: 5.2.0 + ignore: 5.2.1 merge2: 1.4.1 slash: 4.0.0 dev: true @@ -3549,6 +3885,11 @@ packages: engines: {node: '>= 4'} dev: true + /ignore/5.2.1: + resolution: {integrity: sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==} + engines: {node: '>= 4'} + dev: true + /import-fresh/3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -3678,7 +4019,7 @@ packages: resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true dependencies: - ci-info: 3.4.0 + ci-info: 3.7.0 dev: true /is-core-module/2.10.0: @@ -3687,6 +4028,12 @@ packages: has: 1.0.3 dev: true + /is-core-module/2.11.0: + resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} + dependencies: + has: 1.0.3 + dev: true + /is-data-descriptor/0.1.4: resolution: {integrity: sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==} engines: {node: '>=0.10.0'} @@ -3836,6 +4183,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-path-inside/3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + /is-plain-obj/1.1.0: resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} engines: {node: '>=0.10.0'} @@ -4000,14 +4352,14 @@ packages: pretty-format: 26.6.2 dev: true - /jest-diff/29.1.2: - resolution: {integrity: sha512-4GQts0aUopVvecIT4IwD/7xsBaMhKTYoM4/njE/aVw9wpw+pIUVp8Vab/KnSzSilr84GnLBkaP3JLDnQYCKqVQ==} + /jest-diff/29.3.1: + resolution: {integrity: sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: chalk: 4.1.2 - diff-sequences: 29.0.0 - jest-get-type: 29.0.0 - pretty-format: 29.1.2 + diff-sequences: 29.3.1 + jest-get-type: 29.2.0 + pretty-format: 29.3.1 dev: true /jest-get-type/26.3.0: @@ -4015,8 +4367,8 @@ packages: engines: {node: '>= 10.14.2'} dev: true - /jest-get-type/29.0.0: - resolution: {integrity: sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==} + /jest-get-type/29.2.0: + resolution: {integrity: sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dev: true @@ -4030,14 +4382,14 @@ packages: pretty-format: 26.6.2 dev: true - /jest-matcher-utils/29.1.2: - resolution: {integrity: sha512-MV5XrD3qYSW2zZSHRRceFzqJ39B2z11Qv0KPyZYxnzDHFeYZGJlgGi0SW+IXSJfOewgJp/Km/7lpcFT+cgZypw==} + /jest-matcher-utils/29.3.1: + resolution: {integrity: sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: chalk: 4.1.2 - jest-diff: 29.1.2 - jest-get-type: 29.0.0 - pretty-format: 29.1.2 + jest-diff: 29.3.1 + jest-get-type: 29.2.0 + pretty-format: 29.3.1 dev: true /jest-message-util/26.6.2: @@ -4052,22 +4404,22 @@ packages: micromatch: 4.0.5 pretty-format: 26.6.2 slash: 3.0.0 - stack-utils: 2.0.5 + stack-utils: 2.0.6 dev: true - /jest-message-util/29.1.2: - resolution: {integrity: sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==} + /jest-message-util/29.3.1: + resolution: {integrity: sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@babel/code-frame': 7.18.6 - '@jest/types': 29.1.2 + '@jest/types': 29.3.1 '@types/stack-utils': 2.0.1 chalk: 4.1.2 graceful-fs: 4.2.10 micromatch: 4.0.5 - pretty-format: 29.1.2 + pretty-format: 29.3.1 slash: 3.0.0 - stack-utils: 2.0.5 + stack-utils: 2.0.6 dev: true /jest-regex-util/26.0.0: @@ -4075,20 +4427,20 @@ packages: engines: {node: '>= 10.14.2'} dev: true - /jest-util/29.1.2: - resolution: {integrity: sha512-vPCk9F353i0Ymx3WQq3+a4lZ07NXu9Ca8wya6o4Fe4/aO1e1awMMprZ3woPFpKwghEOW+UXgd15vVotuNN9ONQ==} + /jest-util/29.3.1: + resolution: {integrity: sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jest/types': 29.1.2 - '@types/node': 18.8.0 + '@jest/types': 29.3.1 + '@types/node': 18.11.9 chalk: 4.1.2 - ci-info: 3.4.0 + ci-info: 3.7.0 graceful-fs: 4.2.10 picomatch: 2.3.1 dev: true - /js-sdsl/4.1.5: - resolution: {integrity: sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==} + /js-sdsl/4.2.0: + resolution: {integrity: sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==} dev: true /js-tokens/4.0.0: @@ -4293,6 +4645,12 @@ packages: get-func-name: 2.0.0 dev: true + /loupe/2.3.6: + resolution: {integrity: sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==} + dependencies: + get-func-name: 2.0.0 + dev: true + /lru-cache/4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} dependencies: @@ -4413,7 +4771,7 @@ packages: dependencies: '@types/minimist': 1.2.2 camelcase-keys: 6.2.2 - decamelize-keys: 1.1.0 + decamelize-keys: 1.1.1 hard-rejection: 2.1.0 minimist-options: 4.1.0 normalize-package-data: 2.5.0 @@ -4585,8 +4943,8 @@ packages: minimatch: 3.1.2 dev: true - /nan/2.16.0: - resolution: {integrity: sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==} + /nan/2.17.0: + resolution: {integrity: sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==} requiresBuild: true dev: true optional: true @@ -4644,7 +5002,7 @@ packages: resolution: {integrity: sha512-8Q1hXew6ETzqKRAs3jjLioSxNfT1cx74ooiF8RlAONwVMcfq+UdzLC2eB5qcPldUxaE5w3ytLkrmV1TGddhZTA==} engines: {node: '>=6.0'} dependencies: - '@babel/parser': 7.19.3 + '@babel/parser': 7.20.5 dev: true /normalize-package-data/2.5.0: @@ -4963,7 +5321,7 @@ packages: uniq: 1.0.1 dev: true - /postcss-values-parser/5.0.0_postcss@8.4.17: + /postcss-values-parser/5.0.0_postcss@8.4.19: resolution: {integrity: sha512-2viDDjMMrt21W2izbeiJxl3kFuD/+asgB0CBwPEgSyhCmBnDIa/y+pLaoyX+q3I3DHH0oPPL3cgjVTQvlS1Maw==} engines: {node: '>=10'} peerDependencies: @@ -4971,7 +5329,7 @@ packages: dependencies: color-name: 1.1.4 is-url-superb: 4.0.0 - postcss: 8.4.17 + postcss: 8.4.19 quote-unquote: 1.0.0 dev: true @@ -4984,6 +5342,15 @@ packages: source-map-js: 1.0.2 dev: true + /postcss/8.4.19: + resolution: {integrity: sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.4 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + /precinct/8.3.1: resolution: {integrity: sha512-pVppfMWLp2wF68rwHqBIpPBYY8Kd12lDhk8LVQzOwqllifVR15qNFyod43YLyFpurKRZQKnE7E4pofAagDOm2Q==} engines: {node: ^10.13 || ^12 || >=14} @@ -5037,6 +5404,12 @@ packages: hasBin: true dev: true + /prettier/2.8.0: + resolution: {integrity: sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==} + engines: {node: '>=10.13.0'} + hasBin: true + dev: true + /pretty-format/26.6.2: resolution: {integrity: sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==} engines: {node: '>= 10'} @@ -5047,8 +5420,8 @@ packages: react-is: 17.0.2 dev: true - /pretty-format/29.1.2: - resolution: {integrity: sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==} + /pretty-format/29.3.1: + resolution: {integrity: sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/schemas': 29.0.0 @@ -5085,6 +5458,10 @@ packages: resolution: {integrity: sha512-9N8x1h8dptBQpHyC7aZMS+iNOAm97WMGY0AFrguU1cpfW3I5jINkWe5BIY5md0ofy+1TCIELsVcm/GJXZSaPbw==} dev: true + /pure-rand/5.0.5: + resolution: {integrity: sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw==} + dev: true + /queue-microtask/1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true @@ -5206,8 +5583,8 @@ packages: resolution: {integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==} dev: true - /regenerator-runtime/0.13.9: - resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} + /regenerator-runtime/0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} dev: true /regex-cache/0.4.4: @@ -5354,6 +5731,14 @@ packages: fsevents: 2.3.2 dev: true + /rollup/2.79.1: + resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} + engines: {node: '>=10.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + /run-parallel/1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -5363,7 +5748,7 @@ packages: /rxjs/7.5.7: resolution: {integrity: sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==} dependencies: - tslib: 2.4.0 + tslib: 2.4.1 dev: true /safe-buffer/5.1.2: @@ -5410,8 +5795,8 @@ packages: hasBin: true dev: true - /semver/7.3.7: - resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==} + /semver/7.3.8: + resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} engines: {node: '>=10'} hasBin: true dependencies: @@ -5467,6 +5852,10 @@ packages: resolution: {integrity: sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==} dev: true + /shell-quote/1.7.4: + resolution: {integrity: sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==} + dev: true + /shellwords-ts/3.0.0: resolution: {integrity: sha512-4uZTHR2P7zKRZmSoOiUCFK1K+5LlDxay/RVNWDDImnGG1/4r/dZ2Y3rzpo871Iche913yOgYeKrrxl+3vengFw==} dev: true @@ -5503,7 +5892,7 @@ packages: engines: {node: '>=6'} hasBin: true dependencies: - array.prototype.flat: 1.3.0 + array.prototype.flat: 1.3.1 breakword: 1.0.5 grapheme-splitter: 1.0.4 strip-ansi: 6.0.1 @@ -5626,8 +6015,8 @@ packages: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true - /stack-utils/2.0.5: - resolution: {integrity: sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==} + /stack-utils/2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} dependencies: escape-string-regexp: 2.0.0 @@ -5677,6 +6066,14 @@ packages: es-abstract: 1.20.3 dev: true + /string.prototype.trimend/1.0.6: + resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + dev: true + /string.prototype.trimstart/1.0.5: resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} dependencies: @@ -5685,6 +6082,14 @@ packages: es-abstract: 1.20.3 dev: true + /string.prototype.trimstart/1.0.6: + resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} + dependencies: + call-bind: 1.0.2 + define-properties: 1.1.4 + es-abstract: 1.20.4 + dev: true + /string_decoder/1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: @@ -5740,6 +6145,12 @@ packages: engines: {node: '>=8'} dev: true + /strip-literal/0.4.2: + resolution: {integrity: sha512-pv48ybn4iE1O9RLgCAN0iU4Xv7RlBTiit6DKmMiErbs9x1wH6vXBs45tWc0H5wUIF6TLTrKweqkmYF/iraQKNw==} + dependencies: + acorn: 8.8.1 + dev: true + /stylus-lookup/3.0.2: resolution: {integrity: sha512-oEQGHSjg/AMaWlKe7gqsnYzan8DLcGIHe0dUaFkucZZ14z4zjENRlQMCHT4FNsiWnJf17YN9OvrCfCoi7VvOyg==} engines: {node: '>=6.0.0'} @@ -5788,7 +6199,7 @@ packages: engines: {node: ^14.18.0 || >=16.0.0} dependencies: '@pkgr/utils': 2.3.1 - tslib: 2.4.0 + tslib: 2.4.1 dev: true /tapable/2.2.1: @@ -5833,16 +6244,30 @@ packages: globrex: 0.1.2 dev: true + /tinybench/2.3.1: + resolution: {integrity: sha512-hGYWYBMPr7p4g5IarQE7XhlyWveh1EKhy4wUBS1LrHXCKYgvz+4/jCqgmJqZxxldesn05vccrtME2RLLZNW7iA==} + dev: true + /tinypool/0.2.4: resolution: {integrity: sha512-Vs3rhkUH6Qq1t5bqtb816oT+HeJTXfwt2cbPH17sWHIYKTotQIFPk3tf2fgqRrVyMDVOc1EnPgzIxfIulXVzwQ==} engines: {node: '>=14.0.0'} dev: true + /tinypool/0.3.0: + resolution: {integrity: sha512-NX5KeqHOBZU6Bc0xj9Vr5Szbb1j8tUHIeD18s41aDJaPeC5QTdEhK0SpdpUrZlj2nv5cctNcSjaKNanXlfcVEQ==} + engines: {node: '>=14.0.0'} + dev: true + /tinyspy/0.3.3: resolution: {integrity: sha512-gRiUR8fuhUf0W9lzojPf1N1euJYA30ISebSfgca8z76FOvXtVXqd5ojEIaKLWbDQhAaC3ibxZIjqbyi4ybjcTw==} engines: {node: '>=14.0.0'} dev: true + /tinyspy/1.0.2: + resolution: {integrity: sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==} + engines: {node: '>=14.0.0'} + dev: true + /tmp/0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -5944,6 +6369,37 @@ packages: yn: 3.1.1 dev: true + /ts-node/10.9.1_wup25etrarvlqkprac7h35hj7u: + resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.3 + '@types/node': 18.11.9 + acorn: 8.8.0 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.9.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + /ts-node/8.10.2_typescript@4.8.4: resolution: {integrity: sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==} engines: {node: '>=6.0.0'} @@ -5959,6 +6415,21 @@ packages: yn: 3.1.1 dev: true + /ts-node/8.10.2_typescript@4.9.3: + resolution: {integrity: sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==} + engines: {node: '>=6.0.0'} + hasBin: true + peerDependencies: + typescript: '>=2.7' + dependencies: + arg: 4.1.3 + diff: 4.0.2 + make-error: 1.3.6 + source-map-support: 0.5.21 + typescript: 4.9.3 + yn: 3.1.1 + dev: true + /tsconfig-paths/3.14.1: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} dependencies: @@ -5976,11 +6447,11 @@ packages: resolution: {integrity: sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==} dev: true - /tslib/2.4.0: - resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + /tslib/2.4.1: + resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} dev: true - /tslint/5.20.1_typescript@4.8.4: + /tslint/5.20.1_typescript@4.9.3: resolution: {integrity: sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==} engines: {node: '>=4.8.0'} hasBin: true @@ -5999,11 +6470,11 @@ packages: resolve: 1.22.1 semver: 5.7.1 tslib: 1.14.1 - tsutils: 2.29.0_typescript@4.8.4 - typescript: 4.8.4 + tsutils: 2.29.0_typescript@4.9.3 + typescript: 4.9.3 dev: true - /tslint/6.1.3_typescript@4.8.4: + /tslint/6.1.3_typescript@4.9.3: resolution: {integrity: sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==} engines: {node: '>=4.8.0'} deprecated: TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information. @@ -6023,17 +6494,17 @@ packages: resolve: 1.22.1 semver: 5.7.1 tslib: 1.14.1 - tsutils: 2.29.0_typescript@4.8.4 - typescript: 4.8.4 + tsutils: 2.29.0_typescript@4.9.3 + typescript: 4.9.3 dev: true - /tsutils/2.29.0_typescript@4.8.4: + /tsutils/2.29.0_typescript@4.9.3: resolution: {integrity: sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==} peerDependencies: typescript: '>=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev' dependencies: tslib: 1.14.1 - typescript: 4.8.4 + typescript: 4.9.3 dev: true /tsutils/3.21.0_typescript@3.9.10: @@ -6046,14 +6517,14 @@ packages: typescript: 3.9.10 dev: true - /tsutils/3.21.0_typescript@4.8.4: + /tsutils/3.21.0_typescript@4.9.3: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.8.4 + typescript: 4.9.3 dev: true /tty-table/4.1.6: @@ -6067,7 +6538,7 @@ packages: smartwrap: 2.0.2 strip-ansi: 6.0.1 wcwidth: 1.0.1 - yargs: 17.6.0 + yargs: 17.6.2 dev: true /type-check/0.3.2: @@ -6136,6 +6607,12 @@ packages: hasBin: true dev: true + /typescript/4.9.3: + resolution: {integrity: sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + /ultra-runner/3.10.5: resolution: {integrity: sha512-0U2OPII7sbvtbu9rhDlUUkP4Au/DPz2Tzbnawd/XwDuUruDqd+t/Bmel3cLJxl3yMLHf0OY0TMcIx9zzxdlAZw==} engines: {node: '>=10.0.0'} @@ -6202,8 +6679,8 @@ packages: isobject: 3.0.1 dev: true - /update-browserslist-db/1.0.9_browserslist@4.21.4: - resolution: {integrity: sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==} + /update-browserslist-db/1.0.10_browserslist@4.21.4: + resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -6243,7 +6720,7 @@ packages: dependencies: '@jridgewell/trace-mapping': 0.3.15 '@types/istanbul-lib-coverage': 2.0.4 - convert-source-map: 1.8.0 + convert-source-map: 1.9.0 dev: true /validate-npm-package-license/3.0.4: @@ -6277,6 +6754,40 @@ packages: fsevents: 2.3.2 dev: true + /vite/3.2.4_@types+node@18.11.9: + resolution: {integrity: sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 18.11.9 + esbuild: 0.15.16 + postcss: 8.4.19 + resolve: 1.22.1 + rollup: 2.79.1 + optionalDependencies: + fsevents: 2.3.2 + dev: true + /vitest/0.16.0: resolution: {integrity: sha512-Ntp6jrM8wf2NMtamMBLkRBBdeqHkgAH/WMh5Xryts1j2ft2D8QZQbiSVFkSl4WmEQzcPP0YM069g/Ga1vtnEtg==} engines: {node: '>=v14.16.0'} @@ -6312,40 +6823,49 @@ packages: - supports-color dev: true - /vitest/0.16.0_c8@7.12.0: - resolution: {integrity: sha512-Ntp6jrM8wf2NMtamMBLkRBBdeqHkgAH/WMh5Xryts1j2ft2D8QZQbiSVFkSl4WmEQzcPP0YM069g/Ga1vtnEtg==} + /vitest/0.25.3: + resolution: {integrity: sha512-/UzHfXIKsELZhL7OaM2xFlRF8HRZgAHtPctacvNK8H4vOcbJJAMEgbWNGSAK7Y9b1NBe5SeM7VTuz2RsTHFJJA==} engines: {node: '>=v14.16.0'} hasBin: true peerDependencies: + '@edge-runtime/vm': '*' + '@vitest/browser': '*' '@vitest/ui': '*' - c8: '*' happy-dom: '*' jsdom: '*' peerDependenciesMeta: - '@vitest/ui': + '@edge-runtime/vm': optional: true - c8: + '@vitest/browser': + optional: true + '@vitest/ui': optional: true happy-dom: optional: true jsdom: optional: true dependencies: - '@types/chai': 4.3.3 + '@types/chai': 4.3.4 '@types/chai-subset': 1.3.3 - '@types/node': 18.8.0 - c8: 7.12.0 - chai: 4.3.6 + '@types/node': 18.11.9 + acorn: 8.8.1 + acorn-walk: 8.2.0 + chai: 4.3.7 debug: 4.3.4 local-pkg: 0.4.2 - tinypool: 0.2.4 - tinyspy: 0.3.3 - vite: 2.9.15 + source-map: 0.6.1 + strip-literal: 0.4.2 + tinybench: 2.3.1 + tinypool: 0.3.0 + tinyspy: 1.0.2 + vite: 3.2.4_@types+node@18.11.9 transitivePeerDependencies: - less - sass - stylus + - sugarss - supports-color + - terser dev: true /walkdir/0.4.1: @@ -6356,7 +6876,7 @@ packages: /wcwidth/1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: - defaults: 1.0.3 + defaults: 1.0.4 dev: true /webidl-conversions/3.0.1: @@ -6512,8 +7032,8 @@ packages: yargs-parser: 20.2.9 dev: true - /yargs/17.6.0: - resolution: {integrity: sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==} + /yargs/17.6.2: + resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==} engines: {node: '>=12'} dependencies: cliui: 8.0.1 @@ -6545,6 +7065,6 @@ packages: fs-extra: 6.0.1 parsimmon: 1.18.1 strip-json-comments: 2.0.1 - tslint: 5.20.1_typescript@4.8.4 - typescript: 4.8.4 + tslint: 5.20.1_typescript@4.9.3 + typescript: 4.9.3 dev: true From 51bb90bd4f32bd878575a159a2bc0c8c3b3ff57b Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 11 Dec 2022 12:47:56 +0100 Subject: [PATCH 002/255] remove readonly --- .changeset/old-zoos-clap.md | 5 ++ dtslint/ts4.7/Product.ts | 4 +- src/HKT.ts | 30 +++++------ src/typeclass/Bicovariant.ts | 2 +- src/typeclass/Bounded.ts | 6 +-- src/typeclass/Chainable.ts | 2 +- src/typeclass/Contravariant.ts | 2 +- src/typeclass/Coproduct.ts | 4 +- src/typeclass/Covariant.ts | 4 +- src/typeclass/FlatMap.ts | 2 +- src/typeclass/Foldable.ts | 14 ++--- src/typeclass/Invariant.ts | 8 +-- src/typeclass/Monoid.ts | 12 ++--- src/typeclass/NonEmptyTraversable.ts | 4 +- src/typeclass/Of.ts | 2 +- src/typeclass/Order.ts | 6 +-- src/typeclass/Product.ts | 10 ++-- src/typeclass/SemiCoproduct.ts | 4 +- src/typeclass/SemiProduct.ts | 30 +++++------ src/typeclass/Semigroup.ts | 16 +++--- src/typeclass/Traversable.ts | 4 +- test/data/{ReadonlyArray.ts => Array.ts} | 69 ++++++++++++------------ test/data/Either.ts | 10 ++-- test/data/NonEmptyArray.ts | 60 +++++++++++++++++++++ test/data/NonEmptyReadonlyArray.ts | 69 ------------------------ test/data/Option.ts | 41 +++++++------- test/data/Predicate.ts | 6 +-- test/index.ts | 5 +- test/limbo/Category.ts | 2 +- test/limbo/Comonad.ts | 2 +- test/limbo/Composable.ts | 2 +- test/limbo/CovariantWithIndex.ts | 4 +- test/limbo/Extendable.ts | 2 +- test/limbo/FoldableWithIndex.ts | 18 +++---- test/limbo/TraversableWithIndex.ts | 4 +- test/typeclass/Bicovariant.ts | 2 +- test/typeclass/Contravariant.ts | 2 +- test/typeclass/Covariant.ts | 6 +-- test/typeclass/CovariantWithIndex.ts | 4 +- test/typeclass/Foldable.ts | 18 +++---- test/typeclass/FoldableWithIndex.ts | 24 ++++----- test/typeclass/Invariant.ts | 12 ++--- test/typeclass/NonEmptyTraversable.ts | 16 +++--- test/typeclass/Of.ts | 2 +- test/typeclass/Order.ts | 16 +++--- test/typeclass/Product.ts | 6 +-- test/typeclass/SemiProduct.ts | 44 +++++++-------- test/typeclass/Semigroup.ts | 7 ++- test/typeclass/Traversable.ts | 4 +- test/typeclass/TraversableWithIndex.ts | 2 +- 50 files changed, 312 insertions(+), 318 deletions(-) create mode 100644 .changeset/old-zoos-clap.md rename test/data/{ReadonlyArray.ts => Array.ts} (59%) delete mode 100644 test/data/NonEmptyReadonlyArray.ts diff --git a/.changeset/old-zoos-clap.md b/.changeset/old-zoos-clap.md new file mode 100644 index 000000000..5b88cb8a7 --- /dev/null +++ b/.changeset/old-zoos-clap.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +remove readonly diff --git a/dtslint/ts4.7/Product.ts b/dtslint/ts4.7/Product.ts index 8287e5f69..68ee95b7f 100644 --- a/dtslint/ts4.7/Product.ts +++ b/dtslint/ts4.7/Product.ts @@ -15,10 +15,10 @@ declare const fc: RAW<{ c: boolean }, "c", boolean> export declare const Product: _.Product -// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", readonly [string, number, boolean]> +// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", [string, number, boolean]> _.tuple(Product)(fa, fb, fc) -// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", { readonly fa: string; readonly fb: number; readonly fc: boolean; }> +// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", { fa: string; fb: number; fc: boolean; }> _.struct(Product)({ fa, fb, fc }) _.tuple(Product)() // should allow empty tuple diff --git a/src/HKT.ts b/src/HKT.ts index 56a113267..1177b0a86 100644 --- a/src/HKT.ts +++ b/src/HKT.ts @@ -11,34 +11,34 @@ export declare const URI: unique symbol * @since 1.0.0 */ export interface TypeClass { - readonly [URI]?: F + [URI]?: F } /** * @since 1.0.0 */ export interface TypeLambda { - readonly In: unknown - readonly Out2: unknown - readonly Out1: unknown - readonly Target: unknown + In: unknown + Out2: unknown + Out1: unknown + Target: unknown } /** * @since 1.0.0 */ export type Kind = F extends { - readonly type: unknown + type: unknown } ? (F & { - readonly In: In - readonly Out2: Out2 - readonly Out1: Out1 - readonly Target: Target + In: In + Out2: Out2 + Out1: Out1 + Target: Target })["type"] : { - readonly F: F - readonly In: (_: In) => void - readonly Out2: () => Out2 - readonly Out1: () => Out1 - readonly Target: (_: Target) => Target + F: F + In: (_: In) => void + Out2: () => Out2 + Out1: () => Out1 + Target: (_: Target) => Target } diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index 7de7e2576..ec557ab54 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -10,7 +10,7 @@ import type { Covariant } from "@fp-ts/core/typeclass/Covariant" * @since 1.0.0 */ export interface Bicovariant extends TypeClass { - readonly bimap: ( + bimap: ( f: (e: E1) => E2, g: (a: A) => B ) => (self: Kind) => Kind diff --git a/src/typeclass/Bounded.ts b/src/typeclass/Bounded.ts index 2459fa434..ab4e9a8c1 100644 --- a/src/typeclass/Bounded.ts +++ b/src/typeclass/Bounded.ts @@ -10,8 +10,8 @@ import type { Order } from "@fp-ts/core/typeclass/Order" * @since 1.0.0 */ export interface Bounded extends Order { - readonly maxBound: A - readonly minBound: A + maxBound: A + minBound: A } /** @@ -19,7 +19,7 @@ export interface Bounded extends Order { * @since 1.0.0 */ export interface BoundedTypeLambda extends TypeLambda { - readonly type: Bounded + type: Bounded } /** diff --git a/src/typeclass/Chainable.ts b/src/typeclass/Chainable.ts index ff67fcdc6..3baaf8644 100644 --- a/src/typeclass/Chainable.ts +++ b/src/typeclass/Chainable.ts @@ -56,7 +56,7 @@ export const bind = (F: Chainable) => R1 & R2, O1 | O2, E1 | E2, - { readonly [K in keyof A | N]: K extends keyof A ? A[K] : B } + { [K in keyof A | N]: K extends keyof A ? A[K] : B } > => F.flatMap(a => pipe( diff --git a/src/typeclass/Contravariant.ts b/src/typeclass/Contravariant.ts index 414bc890f..311541de9 100644 --- a/src/typeclass/Contravariant.ts +++ b/src/typeclass/Contravariant.ts @@ -9,7 +9,7 @@ import type { Invariant } from "@fp-ts/core/typeclass/Invariant" * @since 1.0.0 */ export interface Contravariant extends Invariant { - readonly contramap: ( + contramap: ( f: (b: B) => A ) => (self: Kind) => Kind } diff --git a/src/typeclass/Coproduct.ts b/src/typeclass/Coproduct.ts index fa611926c..32b21d429 100644 --- a/src/typeclass/Coproduct.ts +++ b/src/typeclass/Coproduct.ts @@ -11,9 +11,9 @@ import * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" * @since 1.0.0 */ export interface Coproduct extends SemiCoproduct { - readonly zero: () => Kind + zero: () => Kind - readonly coproductAll: ( + coproductAll: ( collection: Iterable> ) => Kind } diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index e5baed6ea..f0ad61716 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -9,7 +9,7 @@ import type { Invariant } from "@fp-ts/core/typeclass/Invariant" * @since 1.0.0 */ export interface Covariant extends Invariant { - readonly map: ( + map: ( f: (a: A) => B ) => (self: Kind) => Kind } @@ -75,7 +75,7 @@ const let_ = ( f: (a: A) => B ) => ( self: Kind -) => Kind) => +) => Kind) => (name, f) => F.map(a => Object.assign({}, a, { [name]: f(a) }) as any) export { diff --git a/src/typeclass/FlatMap.ts b/src/typeclass/FlatMap.ts index 6830e5946..12eb36bc1 100644 --- a/src/typeclass/FlatMap.ts +++ b/src/typeclass/FlatMap.ts @@ -9,7 +9,7 @@ import { identity, pipe } from "@fp-ts/core/internal/Function" * @since 1.0.0 */ export interface FlatMap extends TypeClass { - readonly flatMap: ( + flatMap: ( f: (a: A) => Kind ) => (self: Kind) => Kind } diff --git a/src/typeclass/Foldable.ts b/src/typeclass/Foldable.ts index 4df612622..6e6e6b219 100644 --- a/src/typeclass/Foldable.ts +++ b/src/typeclass/Foldable.ts @@ -13,7 +13,7 @@ import type { Monoid } from "@fp-ts/core/typeclass/Monoid" * @since 1.0.0 */ export interface Foldable extends TypeClass { - readonly reduce: ( + reduce: ( b: B, f: (b: B, a: A) => B ) => (self: Kind) => B @@ -42,7 +42,7 @@ export const reduceRight = ( ( b: B, f: (b: B, a: A) => B - ) => (self: Kind): B => toReadonlyArray(F)(self).reduceRight(f, b) + ) => (self: Kind): B => toArray(F)(self).reduceRight(f, b) /** * @since 1.0.0 @@ -50,16 +50,16 @@ export const reduceRight = ( export const foldMap = (F: Foldable) => (M: Monoid) => (f: (a: A) => M) => - (self: Kind): M => M.combineAll(toReadonlyArrayWith(F)(f)(self)) + (self: Kind): M => M.combineAll(toArrayWith(F)(f)(self)) /** * @since 1.0.0 */ -export const toReadonlyArrayWith = ( +export const toArrayWith = ( F: Foldable ) => (f: (a: A) => B) => - (self: Kind): ReadonlyArray => + (self: Kind): Array => F.reduce>([], (out, a) => { out.push(f(a)) return out @@ -68,9 +68,9 @@ export const toReadonlyArrayWith = ( /** * @since 1.0.0 */ -export const toReadonlyArray = ( +export const toArray = ( F: Foldable -): (self: Kind) => ReadonlyArray => toReadonlyArrayWith(F)(identity) +): (self: Kind) => Array => toArrayWith(F)(identity) /** * @since 1.0.0 diff --git a/src/typeclass/Invariant.ts b/src/typeclass/Invariant.ts index c0c41dfba..fcc5842a0 100644 --- a/src/typeclass/Invariant.ts +++ b/src/typeclass/Invariant.ts @@ -8,7 +8,7 @@ import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" * @since 1.0.0 */ export interface Invariant extends TypeClass { - readonly imap: ( + imap: ( to: (a: A) => B, from: (b: B) => A ) => (self: Kind) => Kind @@ -38,7 +38,7 @@ export const bindTo = (F: Invariant) => name: N ): (( self: Kind - ) => Kind) => + ) => Kind) => F.imap(a => ({ [name]: a } as any), ({ [name]: a }) => a) /** @@ -46,5 +46,5 @@ export const bindTo = (F: Invariant) => */ export const tupled = ( F: Invariant -): ((self: Kind) => Kind) => - F.imap(a => [a] as const, ([a]) => a) +): ((self: Kind) => Kind) => + F.imap(a => [a], ([a]) => a) diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index d24fc3c52..72b7bcc1a 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -10,8 +10,8 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" * @since 1.0.0 */ export interface Monoid extends Semigroup { - readonly empty: A - readonly combineAll: (collection: Iterable) => A + empty: A + combineAll: (collection: Iterable) => A } /** @@ -60,7 +60,7 @@ export const reverse = (M: Monoid): Monoid => fromSemigroup(semigroup.r */ export const struct = ( monoids: { [K in keyof A]: Monoid } -): Monoid<{ readonly [K in keyof A]: A[K] }> => { +): Monoid<{ [K in keyof A]: A[K] }> => { const empty: A = {} as any for (const k in monoids) { if (Object.prototype.hasOwnProperty.call(monoids, k)) { @@ -75,9 +75,9 @@ export const struct = ( * * @since 1.0.0 */ -export const tuple = >( +export const tuple = >( ...monoids: { [K in keyof A]: Monoid } -): Monoid> => { +): Monoid => { const empty: A = monoids.map((m) => m.empty) as any - return fromSemigroup(semigroup.tuple(...monoids), empty) + return fromSemigroup(semigroup.tuple(...monoids), empty) } diff --git a/src/typeclass/NonEmptyTraversable.ts b/src/typeclass/NonEmptyTraversable.ts index 7ec2cdd34..467374e56 100644 --- a/src/typeclass/NonEmptyTraversable.ts +++ b/src/typeclass/NonEmptyTraversable.ts @@ -13,7 +13,7 @@ import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" * @since 1.0.0 */ export interface NonEmptyTraversable extends TypeClass { - readonly traverseNonEmpty: ( + traverseNonEmpty: ( F: SemiApplicative ) => ( f: (a: A) => Kind @@ -21,7 +21,7 @@ export interface NonEmptyTraversable extends TypeClass self: Kind ) => Kind> - readonly sequenceNonEmpty: ( + sequenceNonEmpty: ( F: SemiApplicative ) => ( self: Kind> diff --git a/src/typeclass/Of.ts b/src/typeclass/Of.ts index e749399b3..677ea1da9 100644 --- a/src/typeclass/Of.ts +++ b/src/typeclass/Of.ts @@ -8,7 +8,7 @@ import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" * @since 1.0.0 */ export interface Of extends TypeClass { - readonly of: (a: A) => Kind + of: (a: A) => Kind } /** diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index e6a17b131..018c9dff0 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -15,7 +15,7 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Order { - readonly compare: (that: A) => (self: A) => -1 | 0 | 1 + compare: (that: A) => (self: A) => -1 | 0 | 1 } /** @@ -23,7 +23,7 @@ export interface Order { * @since 1.0.0 */ export interface OrderTypeLambda extends TypeLambda { - readonly type: Order + type: Order } /** @@ -41,7 +41,7 @@ export const fromCompare = (compare: Order["compare"]): Order => ({ * * @since 1.0.0 */ -export const tuple = >( +export const tuple = >( ...orders: { [K in keyof A]: Order } ): Order> => fromCompare(that => diff --git a/src/typeclass/Product.ts b/src/typeclass/Product.ts index 3ad68f9a5..20e62ade7 100644 --- a/src/typeclass/Product.ts +++ b/src/typeclass/Product.ts @@ -11,21 +11,21 @@ import type { SemiProduct } from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Product extends SemiProduct, Of { - readonly productAll: ( + productAll: ( collection: Iterable> - ) => Kind> + ) => Kind> } /** * @since 1.0.0 */ export const tuple = (F: Product) => - >>(...components: T): Kind< + >>(...components: T): Kind< F, ([T[number]] extends [Kind] ? R : never), ([T[number]] extends [Kind] ? O : never), ([T[number]] extends [Kind] ? E : never), - Readonly<{ [I in keyof T]: [T[I]] extends [Kind] ? A : never }> + { [I in keyof T]: [T[I]] extends [Kind] ? A : never } > => F.productAll(components) as any /** @@ -37,7 +37,7 @@ export const struct = (F: Product) => ([R[keyof R]] extends [Kind] ? R : never), ([R[keyof R]] extends [Kind] ? O : never), ([R[keyof R]] extends [Kind] ? E : never), - { readonly [K in keyof R]: [R[K]] extends [Kind] ? A : never } + { [K in keyof R]: [R[K]] extends [Kind] ? A : never } > => { const keys = Object.keys(fields) return pipe( diff --git a/src/typeclass/SemiCoproduct.ts b/src/typeclass/SemiCoproduct.ts index d13d6e044..505be718e 100644 --- a/src/typeclass/SemiCoproduct.ts +++ b/src/typeclass/SemiCoproduct.ts @@ -10,13 +10,13 @@ import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" * @since 1.0.0 */ export interface SemiCoproduct extends Invariant { - readonly coproduct: ( + coproduct: ( that: Kind ) => ( self: Kind ) => Kind - readonly coproductMany: ( + coproductMany: ( collection: Iterable> ) => (self: Kind) => Kind } diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index c8b6958dd..5e244c0f5 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -12,15 +12,15 @@ import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" * @since 1.0.0 */ export interface SemiProduct extends Invariant { - readonly product: ( + product: ( that: Kind ) => ( self: Kind - ) => Kind + ) => Kind - readonly productMany: ( + productMany: ( collection: Iterable> - ) => (self: Kind) => Kind]> + ) => (self: Kind) => Kind]> } /** @@ -42,7 +42,7 @@ export const productComposition = ( FR1 & FR2, FO1 | FO2, FE1 | FE2, - Kind + Kind > => pipe(self, F.product(that), F.map(([ga, gb]) => pipe(ga, G.product(gb)))) /** @@ -59,7 +59,7 @@ export const productManyComposition = ( self: Kind> - ): Kind]>> => + ): Kind]>> => pipe( self, F.productMany(collection), @@ -82,13 +82,13 @@ export const productMany = ( (self: Kind) => { let out = pipe( self, - Covariant.map((a): readonly [A, ...Array] => [a]) + Covariant.map((a): [A, ...Array] => [a]) ) for (const fa of collection) { out = pipe( out, product(fa), - Covariant.map(([[head, ...tail], a]): readonly [A, ...Array] => [head, ...tail, a]) + Covariant.map(([[head, ...tail], a]): [A, ...Array] => [head, ...tail, a]) ) } return out @@ -109,7 +109,7 @@ export const andThenBind = (F: SemiProduct) => R1 & R2, O1 | O2, E1 | E2, - { readonly [K in keyof A | N]: K extends keyof A ? A[K] : B } + { [K in keyof A | N]: K extends keyof A ? A[K] : B } > => pipe( self, @@ -127,27 +127,27 @@ export const productFlatten = (F: SemiProduct) => ( that: Kind ) => - >( + >( self: Kind - ): Kind => + ): Kind => pipe( self, F.product(that), - F.imap(([a, b]) => [...a, b] as const, ab => [ab.slice(0, -1), ab[ab.length - 1]] as any) + F.imap(([a, b]) => [...a, b], ab => [ab.slice(0, -1), ab[ab.length - 1]] as any) ) /** * @since 1.0.0 */ export const nonEmptyTuple = (F: SemiProduct) => - , ...ReadonlyArray>]>( + , ...Array>]>( ...components: T ): Kind< F, ([T[number]] extends [Kind] ? R : never), ([T[number]] extends [Kind] ? O : never), ([T[number]] extends [Kind] ? E : never), - Readonly<{ [I in keyof T]: [T[I]] extends [Kind] ? A : never }> + { [I in keyof T]: [T[I]] extends [Kind] ? A : never } > => F.productMany(components.slice(1))(components[0]) as any type EnforceNonEmptyRecord = keyof R extends never ? never : R @@ -163,7 +163,7 @@ export const nonEmptyStruct = (F: SemiProduct) => ([R[keyof R]] extends [Kind] ? R : never), ([R[keyof R]] extends [Kind] ? O : never), ([R[keyof R]] extends [Kind] ? E : never), - { readonly [K in keyof R]: [R[K]] extends [Kind] ? A : never } + { [K in keyof R]: [R[K]] extends [Kind] ? A : never } > => { const keys = Object.keys(fields) return pipe( diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 37f2c4579..fe04ef7d1 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -3,8 +3,8 @@ * * ```ts * export interface Semigroup { - * readonly combine: (that: A) => (self: A) => A - * readonly combineMany: (collection: Iterable) => (self: A) => A + * combine: (that: A) => (self: A) => A + * combineMany: (collection: Iterable) => (self: A) => A * } * ``` * @@ -32,8 +32,8 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Semigroup { - readonly combine: (that: A) => (self: A) => A - readonly combineMany: (collection: Iterable) => (self: A) => A + combine: (that: A) => (self: A) => A + combineMany: (collection: Iterable) => (self: A) => A } /** @@ -41,7 +41,7 @@ export interface Semigroup { * @since 1.0.0 */ export interface SemigroupTypeLambda extends TypeLambda { - readonly type: Semigroup + type: Semigroup } /** @@ -112,7 +112,7 @@ export const reverse = (S: Semigroup): Semigroup => ({ */ export const struct = (semigroups: { [K in keyof A]: Semigroup }): Semigroup< { - readonly [K in keyof A]: A[K] + [K in keyof A]: A[K] } > => fromCombine((that) => @@ -132,9 +132,9 @@ export const struct = (semigroups: { [K in keyof A]: Semigroup }): Semi * * @since 1.0.0 */ -export const tuple = >( +export const tuple = >( ...semigroups: { [K in keyof A]: Semigroup } -): Semigroup> => +): Semigroup => fromCombine((that) => (self) => semigroups.map((S, i) => S.combine(that[i])(self[i])) as any) /** diff --git a/src/typeclass/Traversable.ts b/src/typeclass/Traversable.ts index 91b386a98..73e522e4a 100644 --- a/src/typeclass/Traversable.ts +++ b/src/typeclass/Traversable.ts @@ -11,13 +11,13 @@ import type { Covariant } from "@fp-ts/core/typeclass/Covariant" * @since 1.0.0 */ export interface Traversable extends TypeClass { - readonly traverse: ( + traverse: ( F: Applicative ) => ( f: (a: A) => Kind ) => (self: Kind) => Kind> - readonly sequence: (F: Applicative) => ( + sequence: (F: Applicative) => ( self: Kind> ) => Kind> } diff --git a/test/data/ReadonlyArray.ts b/test/data/Array.ts similarity index 59% rename from test/data/ReadonlyArray.ts rename to test/data/Array.ts index a11bea077..a62784d77 100644 --- a/test/data/ReadonlyArray.ts +++ b/test/data/Array.ts @@ -11,25 +11,24 @@ import type * as traverse_ from "@fp-ts/core/typeclass/Traversable" import type * as covariantWithIndex from "../limbo/CovariantWithIndex" import * as foldableWithIndex from "../limbo/FoldableWithIndex" import type * as traversableWithIndex from "../limbo/TraversableWithIndex" -import type { NonEmptyReadonlyArray } from "./NonEmptyReadonlyArray" -import * as nonEmptyReadonlyArray from "./NonEmptyReadonlyArray" +import type { NonEmptyArray } from "./NonEmptyArray" +import * as nonEmptyArray from "./NonEmptyArray" import * as O from "./Option" import type { Option } from "./Option" -export interface ReadonlyArrayTypeLambda extends TypeLambda { - readonly type: ReadonlyArray +export interface ArrayTypeLambda extends TypeLambda { + type: Array } -export const map = (f: (a: A) => B) => - (self: ReadonlyArray): ReadonlyArray => self.map(a => f(a)) +export const map = (f: (a: A) => B) => (self: Array): Array => self.map(a => f(a)) export const mapWithIndex = (f: (a: A, i: number) => B) => - (self: ReadonlyArray): ReadonlyArray => self.map((a, i) => f(a, i)) + (self: Array): Array => self.map((a, i) => f(a, i)) -export const Covariant: covariant.Covariant = covariant.make(map) +export const Covariant: covariant.Covariant = covariant.make(map) export const CovariantWithIndex: covariantWithIndex.CovariantWithIndex< - ReadonlyArrayTypeLambda, + ArrayTypeLambda, number > = { mapWithIndex: (f) => (self) => self.map((a, i) => f(a, i)) @@ -38,51 +37,50 @@ export const CovariantWithIndex: covariantWithIndex.CovariantWithIndex< export const reduceWithIndex = ( b: B, f: (b: B, a: A, i: number) => B -) => (self: ReadonlyArray) => self.reduce((b, a, i) => f(b, a, i), b) +) => (self: Array) => self.reduce((b, a, i) => f(b, a, i), b) export const reduceRightWithIndex = (b: B, f: (b: B, a: A, i: number) => B) => - (self: ReadonlyArray): B => self.reduceRight((b, a, i) => f(b, a, i), b) + (self: Array): B => self.reduceRight((b, a, i) => f(b, a, i), b) export const FoldableWithIndex: foldableWithIndex.FoldableWithIndex< - ReadonlyArrayTypeLambda, + ArrayTypeLambda, number > = { reduceWithIndex, reduceRightWithIndex } -export const Foldable: foldable.Foldable = { +export const Foldable: foldable.Foldable = { reduce: foldableWithIndex.reduce(FoldableWithIndex) } -export const isNonEmpty: (self: ReadonlyArray) => self is NonEmptyReadonlyArray = - nonEmptyReadonlyArray.isNonEmpty +export const isNonEmpty: (self: Array) => self is NonEmptyArray = nonEmptyArray.isNonEmpty export const head = ( - self: ReadonlyArray + self: Array ): O.Option => (isNonEmpty(self) ? O.some(self[0]) : O.none) export const sort = (Compare: Order) => - (as: ReadonlyArray): ReadonlyArray => + (as: Array): Array => as.length <= 1 ? as : as.slice().sort((a1, a2) => Compare.compare(a2)(a1)) export function concat( - that: NonEmptyReadonlyArray -): (self: ReadonlyArray) => NonEmptyReadonlyArray + that: NonEmptyArray +): (self: Array) => NonEmptyArray export function concat( - that: ReadonlyArray -): (self: NonEmptyReadonlyArray) => NonEmptyReadonlyArray + that: Array +): (self: NonEmptyArray) => NonEmptyArray export function concat( - that: ReadonlyArray -): (self: NonEmptyReadonlyArray) => ReadonlyArray { - return (self: NonEmptyReadonlyArray) => self.concat(that) + that: Array +): (self: NonEmptyArray) => Array { + return (self: NonEmptyArray) => self.concat(that) } export const traverseWithIndex = ( Applicative: applicative.Applicative ) => (f: (a: A, i: number) => Kind) => - (self: Iterable): Kind> => { + (self: Iterable): Kind> => { const fbs: Array> = [] let i = 0 for (const a of self) { @@ -96,24 +94,23 @@ export const traverse = ( ) => ( f: (a: A) => Kind - ): (self: ReadonlyArray) => Kind> => - traverseWithIndex(Applicative)(f) + ): (self: Array) => Kind> => traverseWithIndex(Applicative)(f) -export const Traversable: traverse_.Traversable = { +export const Traversable: traverse_.Traversable = { traverse, sequence: F => self => pipe(self, traverse(F)(identity)) } export const TraversableWithIndex: traversableWithIndex.TraversableWithIndex< - ReadonlyArrayTypeLambda, + ArrayTypeLambda, number > = { traverseWithIndex } -export const product = (that: ReadonlyArray) => - (self: ReadonlyArray): ReadonlyArray => { - const out: Array = [] +export const product = (that: Array) => + (self: Array): Array<[A, B]> => { + const out: Array<[A, B]> = [] for (const a of self) { for (const b of that) { out.push([a, b]) @@ -122,23 +119,23 @@ export const product = (that: ReadonlyArray) => return out } -export const Of: of_.Of = { +export const Of: of_.Of = { of: a => [a] } -const SemiProduct: semiProduct.SemiProduct = { +const SemiProduct: semiProduct.SemiProduct = { imap: Covariant.imap, product, productMany: semiProduct.productMany(Covariant, product) } -export const SemiApplicative: semiApplicative.SemiApplicative = { +export const SemiApplicative: semiApplicative.SemiApplicative = { ...Covariant, ...SemiProduct } export const filterMapWithIndex = (f: (a: A, i: number) => Option) => - (fa: ReadonlyArray): ReadonlyArray => { + (fa: Array): Array => { const out: Array = [] for (let i = 0; i < fa.length; i++) { const optionB = f(fa[i], i) diff --git a/test/data/Either.ts b/test/data/Either.ts index 643702a48..bf121aca4 100644 --- a/test/data/Either.ts +++ b/test/data/Either.ts @@ -4,19 +4,19 @@ import * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" export interface Left { - readonly _tag: "Left" - readonly left: E + _tag: "Left" + left: E } export interface Right { - readonly _tag: "Right" - readonly right: A + _tag: "Right" + right: A } export type Either = Left | Right export interface EitherTypeLambda extends TypeLambda { - readonly type: Either + type: Either } export const left = (e: E): Either => ({ _tag: "Left", left: e }) diff --git a/test/data/NonEmptyArray.ts b/test/data/NonEmptyArray.ts index 02b536784..795df3cef 100644 --- a/test/data/NonEmptyArray.ts +++ b/test/data/NonEmptyArray.ts @@ -1,3 +1,63 @@ +import type { Kind, TypeLambda } from "@fp-ts/core/HKT" +import { identity, pipe } from "@fp-ts/core/internal/Function" +import * as covariant from "@fp-ts/core/typeclass/Covariant" +import type * as nonEmptyTraversable from "@fp-ts/core/typeclass/NonEmptyTraversable" +import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" + +export type NonEmptyArray = [A, ...Array] + +export interface NonEmptyArrayTypeLambda extends TypeLambda { + type: NonEmptyArray +} + export const make = ( ...as: [A, ...Array] ): [A, ...Array] => as + +export const isNonEmpty = (self: Array): self is [A, ...Array] => self.length > 0 + +export const head = (as: [A, ...Array]): A => as[0] +export const tail = (as: [A, ...Array]): Array => as.slice(1) + +export const mapWithIndex = ( + f: (a: A, i: number) => B +) => + (self: NonEmptyArray): NonEmptyArray => { + const out: [B, ...Array] = [f(head(self), 0)] + for (let i = 1; i < self.length; i++) { + out.push(f(self[i], i)) + } + return out + } + +export const map = ( + f: (a: A) => B +): (self: NonEmptyArray) => NonEmptyArray => mapWithIndex(f) + +export const traverseWithIndex = ( + F: SemiApplicative +) => + (f: (a: A, i: number) => Kind) => + (self: NonEmptyArray): Kind> => { + const fbs = pipe(self, mapWithIndex(f)) + return pipe( + head(fbs), + F.productMany(tail(fbs)) + ) + } + +export const traverseNonEmpty = ( + F: SemiApplicative +) => + ( + f: (a: A) => Kind + ): ((self: NonEmptyArray) => Kind>) => traverseWithIndex(F)(f) + +export const Covariant: covariant.Covariant = covariant.make(map) + +export const NonEmptyTraversable: nonEmptyTraversable.NonEmptyTraversable< + NonEmptyArrayTypeLambda +> = { + traverseNonEmpty, + sequenceNonEmpty: F => self => pipe(self, traverseNonEmpty(F)(identity)) +} diff --git a/test/data/NonEmptyReadonlyArray.ts b/test/data/NonEmptyReadonlyArray.ts deleted file mode 100644 index 775a2c355..000000000 --- a/test/data/NonEmptyReadonlyArray.ts +++ /dev/null @@ -1,69 +0,0 @@ -import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import { identity, pipe } from "@fp-ts/core/internal/Function" -import * as covariant from "@fp-ts/core/typeclass/Covariant" -import type * as nonEmptyTraversable from "@fp-ts/core/typeclass/NonEmptyTraversable" -import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" - -/** - * @category models - * @since 1.0.0 - */ -export type NonEmptyReadonlyArray = readonly [A, ...ReadonlyArray] - -/** - * @category type lambdas - * @since 1.0.0 - */ -export interface NonEmptyReadonlyArrayTypeLambda extends TypeLambda { - readonly type: NonEmptyReadonlyArray -} - -export const isNonEmpty = (self: ReadonlyArray): self is readonly [A, ...ReadonlyArray] => - self.length > 0 - -export const head = (as: readonly [A, ...ReadonlyArray]): A => as[0] -export const tail = (as: readonly [A, ...ReadonlyArray]): ReadonlyArray => as.slice(1) - -export const mapWithIndex = ( - f: (a: A, i: number) => B -) => - (self: NonEmptyReadonlyArray): NonEmptyReadonlyArray => { - const out: [B, ...Array] = [f(head(self), 0)] - for (let i = 1; i < self.length; i++) { - out.push(f(self[i], i)) - } - return out - } - -export const map = ( - f: (a: A) => B -): (self: NonEmptyReadonlyArray) => NonEmptyReadonlyArray => mapWithIndex(f) - -export const traverseWithIndex = ( - F: SemiApplicative -) => - (f: (a: A, i: number) => Kind) => - (self: NonEmptyReadonlyArray): Kind> => { - const fbs = pipe(self, mapWithIndex(f)) - return pipe( - head(fbs), - F.productMany(tail(fbs)) - ) - } - -export const traverseNonEmpty = ( - F: SemiApplicative -) => - ( - f: (a: A) => Kind - ): ((self: NonEmptyReadonlyArray) => Kind>) => - traverseWithIndex(F)(f) - -export const Covariant: covariant.Covariant = covariant.make(map) - -export const NonEmptyTraversable: nonEmptyTraversable.NonEmptyTraversable< - NonEmptyReadonlyArrayTypeLambda -> = { - traverseNonEmpty, - sequenceNonEmpty: F => self => pipe(self, traverseNonEmpty(F)(identity)) -} diff --git a/test/data/Option.ts b/test/data/Option.ts index c3890a22f..cbb01753d 100644 --- a/test/data/Option.ts +++ b/test/data/Option.ts @@ -36,25 +36,24 @@ import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" import type * as foldableWithIndex from "../limbo/FoldableWithIndex" import * as nonEmptyArray from "./NonEmptyArray" -import * as nonEmptyReadonlyArray from "./NonEmptyReadonlyArray" export interface LazyArg { (): A } export interface None { - readonly _tag: "None" + _tag: "None" } export interface Some { - readonly _tag: "Some" - readonly value: A + _tag: "Some" + value: A } export type Option = None | Some export interface OptionTypeLambda extends TypeLambda { - readonly type: Option + type: Option } export const isNone = (fa: Option): fa is None => fa._tag === "None" @@ -86,7 +85,7 @@ export const fromThrowable = (f: () => A): Option => { } } -export const liftThrowable = , B>( +export const liftThrowable = , B>( f: (...a: A) => B ): ((...a: A) => Option) => (...a) => fromThrowable(() => f(...a)) @@ -513,9 +512,9 @@ export const Product: product.Product = { ...Of, productAll: collection => { const as = Array.from(collection) - return nonEmptyReadonlyArray.isNonEmpty(as) ? - SemiApplicative.productMany(nonEmptyReadonlyArray.tail(as))( - nonEmptyReadonlyArray.head(as) + return nonEmptyArray.isNonEmpty(as) ? + SemiApplicative.productMany(nonEmptyArray.tail(as))( + nonEmptyArray.head(as) ) : some([]) } @@ -544,9 +543,9 @@ export const Monad: monad.Monad = { * @category conversions * @since 1.0.0 */ -export const toReadonlyArray = ( +export const toArray = ( self: Option -): ReadonlyArray => (isNone(self) ? [] : [self.value]) +): Array => (isNone(self) ? [] : [self.value]) /** * @category folding @@ -642,13 +641,13 @@ export const Do: Option<{}> = some({}) */ export const bindTo: ( name: N -) => (self: Option) => Option<{ readonly [K in N]: A }> = invariant.bindTo(Invariant) +) => (self: Option) => Option<{ [K in N]: A }> = invariant.bindTo(Invariant) const let_: ( name: Exclude, f: (a: A) => B -) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = - covariant.let(Covariant) +) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant + .let(Covariant) export { let_ as let } @@ -659,8 +658,8 @@ export { let_ as let } export const bind: ( name: Exclude, f: (a: A) => Option -) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = - chainable.bind(Chainable) +) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable + .bind(Chainable) /** * A variant of `bind` that sequentially ignores the scope. @@ -671,8 +670,8 @@ export const bind: ( export const andThenBind: ( name: Exclude, fb: Option -) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = - semiProduct.andThenBind(SemiApplicative) +) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct + .andThenBind(SemiApplicative) // ------------------------------------------------------------------------------------- // tuple sequencing @@ -682,12 +681,12 @@ export const andThenBind: ( * @category tuple sequencing * @since 1.0.0 */ -export const Zip: Option = some([]) +export const Zip: Option<[]> = some([]) /** * @since 1.0.0 */ -export const tupled: (self: Option) => Option = invariant.tupled(Invariant) +export const tupled: (self: Option) => Option<[A]> = invariant.tupled(Invariant) /** * Sequentially zips this effect with the specified effect. @@ -697,5 +696,5 @@ export const tupled: (self: Option) => Option = invariant.tu */ export const productFlatten: ( fb: Option -) => >(self: Option) => Option = semiProduct +) => >(self: Option) => Option<[...A, B]> = semiProduct .productFlatten(SemiProduct) diff --git a/test/data/Predicate.ts b/test/data/Predicate.ts index 872b8bd0a..1b2964337 100644 --- a/test/data/Predicate.ts +++ b/test/data/Predicate.ts @@ -10,7 +10,7 @@ export interface Predicate { } export interface PredicateTypeLambda extends TypeLambda { - readonly type: Predicate + type: Predicate } export const contramap = (f: (b: B) => A) => @@ -72,12 +72,12 @@ export const andThenBind: ( fb: Predicate ) => ( self: Predicate -) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct +) => Predicate<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct .andThenBind( SemiProduct ) -export const tupled: (self: Predicate) => Predicate = invariant.tupled( +export const tupled: (self: Predicate) => Predicate<[A]> = invariant.tupled( Invariant ) diff --git a/test/index.ts b/test/index.ts index 84cf06572..beca8ca60 100644 --- a/test/index.ts +++ b/test/index.ts @@ -7,13 +7,10 @@ const getExportName = (name: string): string => { if (name === "HKT") { return name.toLowerCase() } - if (name === "Const") { - return "const_" - } return name.substring(0, 1).toLowerCase() + name.substring(1) } -function getModuleNames(): ReadonlyArray { +function getModuleNames(): Array { return glob .sync("./src/**/*.ts") .map((file) => path.parse(file)) diff --git a/test/limbo/Category.ts b/test/limbo/Category.ts index 7c9fcbc7f..d9d996f32 100644 --- a/test/limbo/Category.ts +++ b/test/limbo/Category.ts @@ -9,5 +9,5 @@ import type { Composable } from "./Composable" * @since 1.0.0 */ export interface Category extends Composable { - readonly identity: () => Kind + identity: () => Kind } diff --git a/test/limbo/Comonad.ts b/test/limbo/Comonad.ts index 25ff5878b..262fdaca6 100644 --- a/test/limbo/Comonad.ts +++ b/test/limbo/Comonad.ts @@ -9,5 +9,5 @@ import type { Extendable } from "@fp-ts/core/test/limbo/Extendable" * @since 1.0.0 */ export interface Comonad extends Extendable { - readonly extract: (self: Kind) => A + extract: (self: Kind) => A } diff --git a/test/limbo/Composable.ts b/test/limbo/Composable.ts index add9c9425..368bcf853 100644 --- a/test/limbo/Composable.ts +++ b/test/limbo/Composable.ts @@ -8,7 +8,7 @@ import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" * @since 1.0.0 */ export interface Composable extends TypeClass { - readonly compose: ( + compose: ( bc: Kind ) => (ab: Kind) => Kind } diff --git a/test/limbo/CovariantWithIndex.ts b/test/limbo/CovariantWithIndex.ts index 0f271d061..55558f209 100644 --- a/test/limbo/CovariantWithIndex.ts +++ b/test/limbo/CovariantWithIndex.ts @@ -10,7 +10,7 @@ import type { Covariant } from "@fp-ts/core/typeclass/Covariant" * @since 1.0.0 */ export interface CovariantWithIndex extends TypeClass { - readonly mapWithIndex: ( + mapWithIndex: ( f: (a: A, i: I) => B ) => (self: Kind) => Kind } @@ -24,7 +24,7 @@ export const mapWithIndexComposition = , G: CovariantWithIndex ): (( - f: (a: A, ij: readonly [I, J]) => B + f: (a: A, ij: [I, J]) => B ) => ( self: Kind> ) => Kind>) => diff --git a/test/limbo/Extendable.ts b/test/limbo/Extendable.ts index f014220c6..87998e93d 100644 --- a/test/limbo/Extendable.ts +++ b/test/limbo/Extendable.ts @@ -9,7 +9,7 @@ import type { Covariant } from "@fp-ts/core/typeclass/Covariant" * @since 1.0.0 */ export interface Extendable extends Covariant { - readonly extend: ( + extend: ( f: (self: Kind) => B ) => (self: Kind) => Kind } diff --git a/test/limbo/FoldableWithIndex.ts b/test/limbo/FoldableWithIndex.ts index f6ff25738..b3df76314 100644 --- a/test/limbo/FoldableWithIndex.ts +++ b/test/limbo/FoldableWithIndex.ts @@ -12,12 +12,12 @@ import type { Monoid } from "@fp-ts/core/typeclass/Monoid" * @since 1.0.0 */ export interface FoldableWithIndex extends TypeClass { - readonly reduceWithIndex: ( + reduceWithIndex: ( b: B, f: (b: B, a: A, i: I) => B ) => (self: Kind) => B - readonly reduceRightWithIndex: ( + reduceRightWithIndex: ( b: B, f: (b: B, a: A, i: I) => B ) => (self: Kind) => B @@ -32,7 +32,7 @@ export const reduceWithIndexComposition = , G: FoldableWithIndex ) => - (b: B, f: (b: B, a: A, ij: readonly [I, J]) => B) => + (b: B, f: (b: B, a: A, ij: [I, J]) => B) => ( self: Kind> ): B => @@ -51,7 +51,7 @@ export const reduceRightWithIndexComposition = , G: FoldableWithIndex ) => - (b: B, f: (b: B, a: A, ij: readonly [I, J]) => B) => + (b: B, f: (b: B, a: A, ij: [I, J]) => B) => ( self: Kind> ): B => @@ -73,18 +73,18 @@ export const reduce = ( /** * @since 1.0.0 */ -export const toReadonlyArray = ( +export const toArray = ( F: FoldableWithIndex -): (self: Kind) => ReadonlyArray => toReadonlyArrayWith(F)(identity) +): (self: Kind) => Array => toArrayWith(F)(identity) /** * @since 1.0.0 */ -export const toReadonlyArrayWith = ( +export const toArrayWith = ( F: FoldableWithIndex ) => (f: (a: A, i: I) => B) => - (self: Kind): ReadonlyArray => + (self: Kind): Array => F.reduceWithIndex>([], (out, a, i) => { out.push(f(a, i)) return out @@ -98,4 +98,4 @@ export const foldMapWithIndex = ( ) => (M: Monoid) => (f: (a: A, i: I) => M) => - (self: Kind): M => M.combineAll(toReadonlyArrayWith(F)(f)(self)) + (self: Kind): M => M.combineAll(toArrayWith(F)(f)(self)) diff --git a/test/limbo/TraversableWithIndex.ts b/test/limbo/TraversableWithIndex.ts index 009e5ec52..abfd2e170 100644 --- a/test/limbo/TraversableWithIndex.ts +++ b/test/limbo/TraversableWithIndex.ts @@ -10,7 +10,7 @@ import type { Traversable } from "@fp-ts/core/typeclass/Traversable" * @since 1.0.0 */ export interface TraversableWithIndex extends TypeClass { - readonly traverseWithIndex: ( + traverseWithIndex: ( F: Applicative ) => ( f: (a: A, i: I) => Kind @@ -30,7 +30,7 @@ export const traverseWithIndexComposition = (H: Applicative) => ( - f: (a: A, ij: readonly [I, J]) => Kind + f: (a: A, ij: [I, J]) => Kind ): (( fga: Kind> ) => Kind>>) => diff --git a/test/typeclass/Bicovariant.ts b/test/typeclass/Bicovariant.ts index 712cf4352..a7ed13974 100644 --- a/test/typeclass/Bicovariant.ts +++ b/test/typeclass/Bicovariant.ts @@ -1,8 +1,8 @@ import { pipe } from "@fp-ts/core/internal/Function" import * as _ from "@fp-ts/core/typeclass/Bicovariant" +import * as RA from "../data/Array" import type { EitherTypeLambda } from "../data/Either" import * as E from "../data/Either" -import * as RA from "../data/ReadonlyArray" import * as U from "../util" export const Bicovariant: _.Bicovariant = { diff --git a/test/typeclass/Contravariant.ts b/test/typeclass/Contravariant.ts index a843e650b..0cd6b7613 100644 --- a/test/typeclass/Contravariant.ts +++ b/test/typeclass/Contravariant.ts @@ -16,7 +16,7 @@ describe("Contravariant", () => { it("imap", () => { const O = _.imap(order.contramap)( - (s: string) => [s] as const, + (s: string) => [s], ([s]) => s )( string.Order diff --git a/test/typeclass/Covariant.ts b/test/typeclass/Covariant.ts index e2be796ff..5acb38599 100644 --- a/test/typeclass/Covariant.ts +++ b/test/typeclass/Covariant.ts @@ -1,7 +1,7 @@ import { pipe } from "@fp-ts/core/internal/Function" import * as _ from "@fp-ts/core/typeclass/Covariant" +import * as RA from "../data/Array" import * as O from "../data/Option" -import * as RA from "../data/ReadonlyArray" import * as U from "../util" describe("Covariant", () => { @@ -46,8 +46,8 @@ describe("Covariant", () => { }) it("imap", () => { - const f = _.imap(O.map)((s: string) => [s] as const, ([s]) => s) + const f = _.imap(O.map)((s: string) => [s], ([s]) => s) U.deepStrictEqual(pipe(O.none, f), O.none) - U.deepStrictEqual(pipe(O.some("a"), f), O.some(["a"] as const)) + U.deepStrictEqual(pipe(O.some("a"), f), O.some(["a"])) }) }) diff --git a/test/typeclass/CovariantWithIndex.ts b/test/typeclass/CovariantWithIndex.ts index c2f630bfb..7a8373fd0 100644 --- a/test/typeclass/CovariantWithIndex.ts +++ b/test/typeclass/CovariantWithIndex.ts @@ -1,12 +1,12 @@ import { pipe } from "@fp-ts/core/internal/Function" -import * as RA from "../data/ReadonlyArray" +import * as RA from "../data/Array" import * as _ from "../limbo/CovariantWithIndex" import * as U from "../util" describe("FunctorWithIndex", () => { it("mapWithIndexComposition", () => { const mapWithIndex = _.mapWithIndexComposition(RA.CovariantWithIndex, RA.CovariantWithIndex) - const f = (a: string, [i, j]: readonly [number, number]) => a + i + j + const f = (a: string, [i, j]: [number, number]) => a + i + j U.deepStrictEqual(pipe([], mapWithIndex(f)), []) U.deepStrictEqual(pipe([[]], mapWithIndex(f)), [[]]) U.deepStrictEqual(pipe([["a"]], mapWithIndex(f)), [["a00"]]) diff --git a/test/typeclass/Foldable.ts b/test/typeclass/Foldable.ts index 4c0285898..fc85286f7 100644 --- a/test/typeclass/Foldable.ts +++ b/test/typeclass/Foldable.ts @@ -1,8 +1,8 @@ import { pipe } from "@fp-ts/core/internal/Function" import * as _ from "@fp-ts/core/typeclass/Foldable" +import * as RA from "../data/Array" import * as number from "../data/number" import * as O from "../data/Option" -import * as RA from "../data/ReadonlyArray" import * as U from "../util" describe("Foldable", () => { @@ -14,16 +14,16 @@ describe("Foldable", () => { U.deepStrictEqual(pipe([["a", "c"], ["b", "d"]], reduce("-", f)), "-acbd") }) - it("toReadonlyArray", () => { - const toReadonlyArray = _.toReadonlyArray(O.Foldable) - U.deepStrictEqual(toReadonlyArray(O.none), []) - U.deepStrictEqual(toReadonlyArray(O.some(2)), [2]) + it("toArray", () => { + const toArray = _.toArray(O.Foldable) + U.deepStrictEqual(toArray(O.none), []) + U.deepStrictEqual(toArray(O.some(2)), [2]) }) - it("toReadonlyArrayWith", () => { - const toReadonlyArrayWith = _.toReadonlyArrayWith(O.Foldable) - U.deepStrictEqual(pipe(O.none, toReadonlyArrayWith(U.double)), []) - U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith(U.double)), [4]) + it("toArrayWith", () => { + const toArrayWith = _.toArrayWith(O.Foldable) + U.deepStrictEqual(pipe(O.none, toArrayWith(U.double)), []) + U.deepStrictEqual(pipe(O.some(2), toArrayWith(U.double)), [4]) }) it("foldMap", () => { diff --git a/test/typeclass/FoldableWithIndex.ts b/test/typeclass/FoldableWithIndex.ts index b1ef8a1af..c969f6e94 100644 --- a/test/typeclass/FoldableWithIndex.ts +++ b/test/typeclass/FoldableWithIndex.ts @@ -1,7 +1,7 @@ import { pipe } from "@fp-ts/core/internal/Function" +import * as RA from "../data/Array" import * as number from "../data/number" import * as O from "../data/Option" -import * as RA from "../data/ReadonlyArray" import * as foldableWithIndex from "../limbo/FoldableWithIndex" import * as U from "../util" @@ -11,7 +11,7 @@ describe("FoldableWithIndex", () => { RA.FoldableWithIndex, RA.FoldableWithIndex ) - const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j + const f = (b: string, a: string, [i, j]: [number, number]) => b + a + i + j U.deepStrictEqual(pipe([], reduceWithIndex("-", f)), "-") U.deepStrictEqual(pipe([[]], reduceWithIndex("-", f)), "-") U.deepStrictEqual( @@ -25,7 +25,7 @@ describe("FoldableWithIndex", () => { RA.FoldableWithIndex, RA.FoldableWithIndex ) - const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j + const f = (b: string, a: string, [i, j]: [number, number]) => b + a + i + j U.deepStrictEqual(pipe([], reduceRightWithIndex("-", f)), "-") U.deepStrictEqual(pipe([[]], reduceRightWithIndex("-", f)), "-") U.deepStrictEqual( @@ -34,17 +34,17 @@ describe("FoldableWithIndex", () => { ) }) - it("toReadonlyArray", () => { - const toReadonlyArray = foldableWithIndex.toReadonlyArray(O.FoldableWithIndex) - U.deepStrictEqual(toReadonlyArray(O.none), []) - U.deepStrictEqual(toReadonlyArray(O.some(2)), [2]) + it("toArray", () => { + const toArray = foldableWithIndex.toArray(O.FoldableWithIndex) + U.deepStrictEqual(toArray(O.none), []) + U.deepStrictEqual(toArray(O.some(2)), [2]) }) - it("toReadonlyArrayWith", () => { - const toReadonlyArrayWith = foldableWithIndex.toReadonlyArrayWith(O.FoldableWithIndex) - U.deepStrictEqual(pipe(O.none, toReadonlyArrayWith(U.double)), []) - U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith(U.double)), [4]) - U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith((a, i) => U.double(a) * i)), [0]) + it("toArrayWith", () => { + const toArrayWith = foldableWithIndex.toArrayWith(O.FoldableWithIndex) + U.deepStrictEqual(pipe(O.none, toArrayWith(U.double)), []) + U.deepStrictEqual(pipe(O.some(2), toArrayWith(U.double)), [4]) + U.deepStrictEqual(pipe(O.some(2), toArrayWith((a, i) => U.double(a) * i)), [0]) }) it("foldMapWithIndex", () => { diff --git a/test/typeclass/Invariant.ts b/test/typeclass/Invariant.ts index 2c20678b1..bc3604b6f 100644 --- a/test/typeclass/Invariant.ts +++ b/test/typeclass/Invariant.ts @@ -9,13 +9,13 @@ import * as U from "../util" describe("Invariant", () => { it("imapComposition", () => { const imap = _.imapComposition(semigroup.Invariant, O.Invariant) - const S = pipe(O.getMonoid(string.Semigroup), imap(s => [s] as const, ([s]) => s)) + const S = pipe(O.getMonoid(string.Semigroup), imap(s => [s], ([s]) => s)) U.deepStrictEqual(pipe(O.none, S.combine(O.none)), O.none) - U.deepStrictEqual(pipe(O.none, S.combine(O.some(["b"]))), O.some(["b"] as const)) - U.deepStrictEqual(pipe(O.some(["a"] as const), S.combine(O.none)), O.some(["a"] as const)) + U.deepStrictEqual(pipe(O.none, S.combine(O.some(["b"]))), O.some(["b"])) + U.deepStrictEqual(pipe(O.some(["a"]), S.combine(O.none)), O.some(["a"])) U.deepStrictEqual( - pipe(O.some(["a"] as const), S.combine(O.some(["b"]))), - O.some(["ab"] as const) + pipe(O.some(["a"]), S.combine(O.some(["b"]))), + O.some(["ab"]) ) }) @@ -38,7 +38,7 @@ describe("Invariant", () => { it("Covariant (Option)", () => { const tupled = _.tupled(O.Invariant) U.deepStrictEqual(pipe(O.none, tupled), O.none) - U.deepStrictEqual(pipe(O.some(1), tupled), O.some([1] as const)) + U.deepStrictEqual(pipe(O.some(1), tupled), O.some([1])) }) it("Contravariant (Predicate)", () => { diff --git a/test/typeclass/NonEmptyTraversable.ts b/test/typeclass/NonEmptyTraversable.ts index ce901b412..4fa188e8c 100644 --- a/test/typeclass/NonEmptyTraversable.ts +++ b/test/typeclass/NonEmptyTraversable.ts @@ -1,5 +1,5 @@ import * as _ from "@fp-ts/core/typeclass/NonEmptyTraversable" -import * as NERA from "../data/NonEmptyReadonlyArray" +import * as NERA from "../data/NonEmptyArray" import * as O from "../data/Option" import * as U from "../util" @@ -9,9 +9,9 @@ describe("NonEmptyTraversable", () => { NERA.NonEmptyTraversable, NERA.NonEmptyTraversable )(O.SemiApplicative)((n: number) => (n > 0 ? O.some(n) : O.none)) - U.deepStrictEqual(traverseNonEmpty([[1]]), O.some([[1]] as const)) + U.deepStrictEqual(traverseNonEmpty([[1]]), O.some([[1]])) U.deepStrictEqual(traverseNonEmpty([[1, -1]]), O.none) - U.deepStrictEqual(traverseNonEmpty([[1, 2, 3], [4, 5]]), O.some([[1, 2, 3], [4, 5]] as const)) + U.deepStrictEqual(traverseNonEmpty([[1, 2, 3], [4, 5]]), O.some([[1, 2, 3], [4, 5]])) U.deepStrictEqual(traverseNonEmpty([[1, 2, 3], [4, -1]]), O.none) }) @@ -20,23 +20,23 @@ describe("NonEmptyTraversable", () => { { ...NERA.NonEmptyTraversable, ...NERA.Covariant }, NERA.NonEmptyTraversable )(O.SemiApplicative) - U.deepStrictEqual(sequence([[O.some(1)]]), O.some([[1]] as const)) + U.deepStrictEqual(sequence([[O.some(1)]]), O.some([[1]])) U.deepStrictEqual(sequence([[O.some(1), O.none]]), O.none) U.deepStrictEqual( sequence([[O.some(1), O.some(2), O.some(3)], [O.some(4), O.some(5)]]), - O.some([[1, 2, 3], [4, 5]] as const) + O.some([[1, 2, 3], [4, 5]]) ) U.deepStrictEqual(sequence([[O.some(1), O.some(2), O.some(3)], [O.some(4), O.none]]), O.none) }) it("sequenceNonEmpty", () => { - const sequenceNonEmpty = _.sequenceNonEmpty( + const sequenceNonEmpty = _.sequenceNonEmpty( NERA.NonEmptyTraversable.traverseNonEmpty )(O.SemiApplicative) U.deepStrictEqual(sequenceNonEmpty([O.none]), O.none) - U.deepStrictEqual(sequenceNonEmpty([O.some(1)]), O.some([1] as const)) + U.deepStrictEqual(sequenceNonEmpty([O.some(1)]), O.some([1])) U.deepStrictEqual(sequenceNonEmpty([O.none]), O.none) U.deepStrictEqual(sequenceNonEmpty([O.some(1), O.none]), O.none) - U.deepStrictEqual(sequenceNonEmpty([O.some(1), O.some(2)]), O.some([1, 2] as const)) + U.deepStrictEqual(sequenceNonEmpty([O.some(1), O.some(2)]), O.some([1, 2])) }) }) diff --git a/test/typeclass/Of.ts b/test/typeclass/Of.ts index 8fb357fdd..bc0e67350 100644 --- a/test/typeclass/Of.ts +++ b/test/typeclass/Of.ts @@ -1,6 +1,6 @@ import * as _ from "@fp-ts/core/typeclass/Of" +import * as RA from "../data/Array" import * as O from "../data/Option" -import * as RA from "../data/ReadonlyArray" import * as U from "../util" describe("Of", () => { diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index e24e4f0d6..470675b9a 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -1,8 +1,8 @@ import { pipe } from "@fp-ts/core/internal/Function" import * as _ from "@fp-ts/core/typeclass/Order" +import { sort } from "../data/Array" import * as boolean from "../data/boolean" import * as number from "../data/number" -import { sort } from "../data/ReadonlyArray" import * as string from "../data/string" import * as U from "../util" @@ -22,7 +22,7 @@ describe("Order", () => { }) it("Invariant", () => { - const O = _.Invariant.imap((s: string) => [s] as const, ([s]) => s)( + const O = _.Invariant.imap((s: string) => [s], ([s]) => s)( string.Order ) U.deepStrictEqual(pipe(["a"], O.compare(["b"])), -1) @@ -31,8 +31,8 @@ describe("Order", () => { }) it("getSemigroup", () => { - type T = readonly [number, string] - const tuples: ReadonlyArray = [ + type T = [number, string] + const tuples: Array = [ [2, "c"], [1, "b"], [2, "a"], @@ -74,8 +74,8 @@ describe("Order", () => { }) it("getMonoid", () => { - type T = readonly [number, string] - const tuples: ReadonlyArray = [ + type T = [number, string] + const tuples: Array = [ [2, "c"], [1, "b"], [2, "a"], @@ -158,7 +158,7 @@ describe("Order", () => { }) it("min", () => { - type A = { readonly a: number } + type A = { a: number } const min = _.min( pipe( number.Order, @@ -173,7 +173,7 @@ describe("Order", () => { }) it("max", () => { - type A = { readonly a: number } + type A = { a: number } const max = _.max( pipe( number.Order, diff --git a/test/typeclass/Product.ts b/test/typeclass/Product.ts index 787a127b6..6ead09f53 100644 --- a/test/typeclass/Product.ts +++ b/test/typeclass/Product.ts @@ -11,11 +11,11 @@ describe("Product", () => { describe("tuple", () => { it("Covariant (Option)", () => { const tuple = _.tuple(O.Product) - U.deepStrictEqual(tuple(), O.some([] as const)) - U.deepStrictEqual(tuple(O.some("a")), O.some(["a"] as const)) + U.deepStrictEqual(tuple(), O.some([])) + U.deepStrictEqual(tuple(O.some("a")), O.some(["a"])) U.deepStrictEqual( tuple(O.some("a"), O.some(1), O.some(true)), - O.some(["a", 1, true] as const) + O.some(["a", 1, true]) ) U.deepStrictEqual(tuple(O.some("a"), O.some(1), O.none), O.none) }) diff --git a/test/typeclass/SemiProduct.ts b/test/typeclass/SemiProduct.ts index 3f708d7ee..cebed912f 100644 --- a/test/typeclass/SemiProduct.ts +++ b/test/typeclass/SemiProduct.ts @@ -3,16 +3,16 @@ import { pipe } from "@fp-ts/core/internal/Function" import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as _ from "@fp-ts/core/typeclass/SemiProduct" +import * as RA from "../data/Array" import * as number from "../data/number" import * as O from "../data/Option" import * as P from "../data/Predicate" -import * as RA from "../data/ReadonlyArray" import * as string from "../data/string" import * as U from "../util" describe("SemiProduct", () => { it("productMany", () => { - const curry = (f: Function, n: number, acc: ReadonlyArray) => + const curry = (f: Function, n: number, acc: Array) => (x: unknown) => { const combined = Array(acc.length + 1) for (let i = 0; i < acc.length; i++) { @@ -23,7 +23,7 @@ describe("SemiProduct", () => { } const getCurriedTupleConstructor = (len: number): (a: any) => any => - curry(>(...t: T): T => t, len - 1, []) + curry(>(...t: T): T => t, len - 1, []) const assertSameResult = ( SemiApplicative: semiApplicative.SemiApplicative @@ -34,7 +34,7 @@ describe("SemiProduct", () => { const productManyFromAp = (collection: Iterable>) => ( self: Kind - ): Kind]> => { + ): Kind]> => { const args = [self, ...Array.from(collection)] const len = args.length const f = getCurriedTupleConstructor(len) @@ -50,9 +50,9 @@ describe("SemiProduct", () => { U.deepStrictEqual(actual, expected) } - const product = (that: ReadonlyArray) => - (self: ReadonlyArray): ReadonlyArray => { - const out: Array = [] + const product = (that: Array) => + (self: Array): Array<[A, B]> => { + const out: Array<[A, B]> = [] for (const a of self) { for (const b of that) { out.push([a, b]) @@ -79,12 +79,12 @@ describe("SemiProduct", () => { }) describe("productComposition", () => { - it("ReadonlyArray", () => { + it("Array", () => { const product = _.productComposition(RA.SemiApplicative, O.SemiProduct) U.deepStrictEqual(pipe([], product([O.none])), []) U.deepStrictEqual(pipe([O.none], product([])), []) U.deepStrictEqual(pipe([O.none], product([O.none])), [O.none]) - U.deepStrictEqual(pipe([O.some(1)], product([O.some(2)])), [O.some([1, 2] as const)]) + U.deepStrictEqual(pipe([O.some(1)], product([O.some(2)])), [O.some([1, 2])]) }) it("Option", () => { @@ -96,17 +96,17 @@ describe("SemiProduct", () => { U.deepStrictEqual(pipe(O.some(O.none), product(O.some(O.some(2)))), O.some(O.none)) U.deepStrictEqual( pipe(O.some(O.some(1)), product(O.some(O.some(2)))), - O.some(O.some([1, 2] as const)) + O.some(O.some([1, 2])) ) }) }) describe("productManyComposition", () => { - it("ReadonlyArray", () => { + it("Array", () => { const productMany = _.productManyComposition(RA.SemiApplicative, O.SemiProduct) - U.deepStrictEqual(pipe([O.some(1), O.none], productMany([])), [O.some([1] as const), O.none]) + U.deepStrictEqual(pipe([O.some(1), O.none], productMany([])), [O.some([1]), O.none]) U.deepStrictEqual(pipe([O.some(1), O.none], productMany([[O.some(2), O.none]])), [ - O.some([1, 2] as const), + O.some([1, 2]), O.none, O.none, O.none @@ -114,10 +114,10 @@ describe("SemiProduct", () => { U.deepStrictEqual( pipe([O.some(1), O.some(2)], productMany([[O.some(3), O.some(4)], [O.some(5)]])), [ - O.some([1, 3, 5] as const), - O.some([1, 4, 5] as const), - O.some([2, 3, 5] as const), - O.some([2, 4, 5] as const) + O.some([1, 3, 5]), + O.some([1, 4, 5]), + O.some([2, 3, 5]), + O.some([2, 4, 5]) ] ) }) @@ -126,14 +126,14 @@ describe("SemiProduct", () => { const productMany = _.productManyComposition(O.SemiApplicative, O.SemiProduct) U.deepStrictEqual(pipe(O.none, productMany([])), O.none) U.deepStrictEqual(pipe(O.some(O.none), productMany([])), O.some(O.none)) - U.deepStrictEqual(pipe(O.some(O.some(1)), productMany([])), O.some(O.some([1] as const))) + U.deepStrictEqual(pipe(O.some(O.some(1)), productMany([])), O.some(O.some([1]))) U.deepStrictEqual(pipe(O.none, productMany([O.none])), O.none) U.deepStrictEqual(pipe(O.some(O.none), productMany([O.none])), O.none) U.deepStrictEqual(pipe(O.some(O.none), productMany([O.some(O.none)])), O.some(O.none)) U.deepStrictEqual(pipe(O.some(O.none), productMany([O.some(O.some("a"))])), O.some(O.none)) U.deepStrictEqual( pipe(O.some(O.some(1)), productMany([O.some(O.some(2))])), - O.some(O.some([1, 2] as const)) + O.some(O.some([1, 2])) ) }) }) @@ -160,7 +160,7 @@ describe("SemiProduct", () => { it("Covariant (Option)", () => { const productFlatten = _.productFlatten(O.SemiProduct) U.deepStrictEqual(pipe(O.some([1, 2]), productFlatten(O.none)), O.none) - U.deepStrictEqual(pipe(O.some([1, 2]), productFlatten(O.some(3))), O.some([1, 2, 3] as const)) + U.deepStrictEqual(pipe(O.some([1, 2]), productFlatten(O.some(3))), O.some([1, 2, 3])) }) it("Contravariant (Predicate)", () => { @@ -175,10 +175,10 @@ describe("SemiProduct", () => { describe("nonEmptyTuple", () => { it("Covariant (Option)", () => { const nonEmptyTuple = _.nonEmptyTuple(O.SemiProduct) - U.deepStrictEqual(nonEmptyTuple(O.some("a")), O.some(["a"] as const)) + U.deepStrictEqual(nonEmptyTuple(O.some("a")), O.some(["a"])) U.deepStrictEqual( nonEmptyTuple(O.some("a"), O.some(1), O.some(true)), - O.some(["a", 1, true] as const) + O.some(["a", 1, true]) ) U.deepStrictEqual(nonEmptyTuple(O.some("a"), O.some(1), O.none), O.none) }) diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index afd9cb9c5..a06809597 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -134,11 +134,16 @@ describe("Semigroup", () => { }) it("product", () => { + type From = [[string, number], number] + type To = [string, number, number] const A = pipe( string.Semigroup, _.SemiProduct.product(number.SemigroupSum), _.SemiProduct.product(number.SemigroupMultiply), - _.imap(([[a, b], c]) => [a, b, c] as const, ([a, b, c]) => [[a, b], c] as const) + _.imap( + ([[a, b], c]) => [a, b, c], + ([a, b, c]) => [[a, b], c] + ) ) U.deepStrictEqual(pipe(["a", 2, 3], A.combine(["b", 3, 4])), ["ab", 5, 12]) }) diff --git a/test/typeclass/Traversable.ts b/test/typeclass/Traversable.ts index 2a78856f0..3ca38bb68 100644 --- a/test/typeclass/Traversable.ts +++ b/test/typeclass/Traversable.ts @@ -1,7 +1,7 @@ import { pipe } from "@fp-ts/core/internal/Function" import * as _ from "@fp-ts/core/typeclass/Traversable" +import * as RA from "../data/Array" import * as O from "../data/Option" -import * as RA from "../data/ReadonlyArray" import * as U from "../util" describe("Traversable", () => { @@ -26,7 +26,7 @@ describe("Traversable", () => { }) it("sequence", () => { - const sequence = _.sequence(RA.Traversable.traverse)(O.Applicative) + const sequence = _.sequence(RA.Traversable.traverse)(O.Applicative) U.deepStrictEqual(pipe([O.none, O.some(2)], sequence), O.none) U.deepStrictEqual(pipe([O.some(1), O.some(2)], sequence), O.some([1, 2])) }) diff --git a/test/typeclass/TraversableWithIndex.ts b/test/typeclass/TraversableWithIndex.ts index 5a0cbbf1b..351efbd05 100644 --- a/test/typeclass/TraversableWithIndex.ts +++ b/test/typeclass/TraversableWithIndex.ts @@ -1,6 +1,6 @@ import { pipe } from "@fp-ts/core/internal/Function" +import * as RA from "../data/Array" import * as O from "../data/Option" -import * as RA from "../data/ReadonlyArray" import * as _ from "../limbo/TraversableWithIndex" import * as U from "../util" From 97d9abf2d35e787a58208339c5cfc6a11ab1ac86 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 11 Dec 2022 12:48:31 +0100 Subject: [PATCH 003/255] update docs --- docs/modules/HKT.ts.md | 32 ++--- docs/modules/data/Either.ts.md | 74 ----------- docs/modules/data/Option.ts.md | 73 ---------- docs/modules/index.ts.md | 60 +-------- docs/modules/typeclass/Alternative.ts.md | 2 +- docs/modules/typeclass/Applicative.ts.md | 2 +- docs/modules/typeclass/Bicovariant.ts.md | 7 +- docs/modules/typeclass/Bounded.ts.md | 8 +- docs/modules/typeclass/Chainable.ts.md | 4 +- docs/modules/typeclass/Compactable.ts.md | 68 ---------- docs/modules/typeclass/Contravariant.ts.md | 4 +- docs/modules/typeclass/Coproduct.ts.md | 6 +- docs/modules/typeclass/Covariant.ts.md | 8 +- docs/modules/typeclass/Filterable.ts.md | 110 --------------- docs/modules/typeclass/FlatMap.ts.md | 4 +- docs/modules/typeclass/Foldable.ts.md | 20 ++- docs/modules/typeclass/Invariant.ts.md | 13 +- docs/modules/typeclass/Monad.ts.md | 2 +- docs/modules/typeclass/Monoid.ts.md | 12 +- .../typeclass/NonEmptyTraversable.ts.md | 6 +- docs/modules/typeclass/Of.ts.md | 4 +- docs/modules/typeclass/Order.ts.md | 8 +- docs/modules/typeclass/Pointed.ts.md | 2 +- docs/modules/typeclass/Product.ts.md | 10 +- docs/modules/typeclass/SemiAlternative.ts.md | 2 +- docs/modules/typeclass/SemiApplicative.ts.md | 2 +- docs/modules/typeclass/SemiCoproduct.ts.md | 21 +-- docs/modules/typeclass/SemiProduct.ts.md | 32 ++--- docs/modules/typeclass/Semigroup.ts.md | 20 ++- docs/modules/typeclass/Traversable.ts.md | 6 +- .../typeclass/TraversableFilterable.ts.md | 125 ------------------ 31 files changed, 101 insertions(+), 646 deletions(-) delete mode 100644 docs/modules/data/Either.ts.md delete mode 100644 docs/modules/data/Option.ts.md delete mode 100644 docs/modules/typeclass/Compactable.ts.md delete mode 100644 docs/modules/typeclass/Filterable.ts.md delete mode 100644 docs/modules/typeclass/TraversableFilterable.ts.md diff --git a/docs/modules/HKT.ts.md b/docs/modules/HKT.ts.md index c928d4d5b..05916670c 100644 --- a/docs/modules/HKT.ts.md +++ b/docs/modules/HKT.ts.md @@ -1,6 +1,6 @@ --- title: HKT.ts -nav_order: 3 +nav_order: 1 parent: Modules --- @@ -27,20 +27,20 @@ Added in v1.0.0 ```ts export type Kind = F extends { - readonly type: unknown + type: unknown } ? (F & { - readonly In: In - readonly Out2: Out2 - readonly Out1: Out1 - readonly Target: Target + In: In + Out2: Out2 + Out1: Out1 + Target: Target })['type'] : { - readonly F: F - readonly In: (_: In) => void - readonly Out2: () => Out2 - readonly Out1: () => Out1 - readonly Target: (_: Target) => Target + F: F + In: (_: In) => void + Out2: () => Out2 + Out1: () => Out1 + Target: (_: Target) => Target } ``` @@ -52,7 +52,7 @@ Added in v1.0.0 ```ts export interface TypeClass { - readonly [URI]?: F + [URI]?: F } ``` @@ -64,10 +64,10 @@ Added in v1.0.0 ```ts export interface TypeLambda { - readonly In: unknown - readonly Out2: unknown - readonly Out1: unknown - readonly Target: unknown + In: unknown + Out2: unknown + Out1: unknown + Target: unknown } ``` diff --git a/docs/modules/data/Either.ts.md b/docs/modules/data/Either.ts.md deleted file mode 100644 index e873b2317..000000000 --- a/docs/modules/data/Either.ts.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: data/Either.ts -nav_order: 1 -parent: Modules ---- - -## Either overview - -Added in v1.0.0 - ---- - -

Table of contents

- -- [models](#models) - - [Either (type alias)](#either-type-alias) - - [Left (interface)](#left-interface) - - [Right (interface)](#right-interface) -- [type lambdas](#type-lambdas) - - [EitherTypeLambda (interface)](#eithertypelambda-interface) - ---- - -# models - -## Either (type alias) - -**Signature** - -```ts -export type Either = Left | Right
-``` - -Added in v1.0.0 - -## Left (interface) - -**Signature** - -```ts -export interface Left { - readonly _tag: 'Left' - readonly left: E -} -``` - -Added in v1.0.0 - -## Right (interface) - -**Signature** - -```ts -export interface Right { - readonly _tag: 'Right' - readonly right: A -} -``` - -Added in v1.0.0 - -# type lambdas - -## EitherTypeLambda (interface) - -**Signature** - -```ts -export interface EitherTypeLambda extends TypeLambda { - readonly type: Either -} -``` - -Added in v1.0.0 diff --git a/docs/modules/data/Option.ts.md b/docs/modules/data/Option.ts.md deleted file mode 100644 index cccca4c88..000000000 --- a/docs/modules/data/Option.ts.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -title: data/Option.ts -nav_order: 2 -parent: Modules ---- - -## Option overview - -Added in v1.0.0 - ---- - -

Table of contents

- -- [models](#models) - - [None (interface)](#none-interface) - - [Option (type alias)](#option-type-alias) - - [Some (interface)](#some-interface) -- [type lambdas](#type-lambdas) - - [OptionTypeLambda (interface)](#optiontypelambda-interface) - ---- - -# models - -## None (interface) - -**Signature** - -```ts -export interface None { - readonly _tag: 'None' -} -``` - -Added in v1.0.0 - -## Option (type alias) - -**Signature** - -```ts -export type Option
= None | Some -``` - -Added in v1.0.0 - -## Some (interface) - -**Signature** - -```ts -export interface Some { - readonly _tag: 'Some' - readonly value: A -} -``` - -Added in v1.0.0 - -# type lambdas - -## OptionTypeLambda (interface) - -**Signature** - -```ts -export interface OptionTypeLambda extends TypeLambda { - readonly type: Option -} -``` - -Added in v1.0.0 diff --git a/docs/modules/index.ts.md b/docs/modules/index.ts.md index d377ada6d..d1168088a 100644 --- a/docs/modules/index.ts.md +++ b/docs/modules/index.ts.md @@ -1,6 +1,6 @@ --- title: index.ts -nav_order: 4 +nav_order: 2 parent: Modules --- @@ -12,20 +12,15 @@ Added in v1.0.0

Table of contents

-- [data types](#data-types) - - [either](#either) - - [option](#option) - [typeclass](#typeclass) - [alternative](#alternative) - [applicative](#applicative) - [bicovariant](#bicovariant) - [bounded](#bounded) - [chainable](#chainable) - - [compactable](#compactable) - [contravariant](#contravariant) - [coproduct](#coproduct) - [covariant](#covariant) - - [filterable](#filterable) - [flatMap](#flatmap) - [foldable](#foldable) - [invariant](#invariant) @@ -42,34 +37,11 @@ Added in v1.0.0 - [semiProduct](#semiproduct) - [semigroup](#semigroup) - [traversable](#traversable) - - [traversableFilterable](#traversablefilterable) - [utils](#utils) - [hkt](#hkt) --- -# data types - -## either - -**Signature** - -```ts -export declare const either: typeof either -``` - -Added in v1.0.0 - -## option - -**Signature** - -```ts -export declare const option: typeof option -``` - -Added in v1.0.0 - # typeclass ## alternative @@ -122,16 +94,6 @@ export declare const chainable: typeof chainable Added in v1.0.0 -## compactable - -**Signature** - -```ts -export declare const compactable: typeof compactable -``` - -Added in v1.0.0 - ## contravariant **Signature** @@ -162,16 +124,6 @@ export declare const covariant: typeof covariant Added in v1.0.0 -## filterable - -**Signature** - -```ts -export declare const filterable: typeof filterable -``` - -Added in v1.0.0 - ## flatMap **Signature** @@ -332,16 +284,6 @@ export declare const traversable: typeof traversable Added in v1.0.0 -## traversableFilterable - -**Signature** - -```ts -export declare const traversableFilterable: typeof traversableFilterable -``` - -Added in v1.0.0 - # utils ## hkt diff --git a/docs/modules/typeclass/Alternative.ts.md b/docs/modules/typeclass/Alternative.ts.md index 317683fba..973ea69a3 100644 --- a/docs/modules/typeclass/Alternative.ts.md +++ b/docs/modules/typeclass/Alternative.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Alternative.ts -nav_order: 5 +nav_order: 3 parent: Modules --- diff --git a/docs/modules/typeclass/Applicative.ts.md b/docs/modules/typeclass/Applicative.ts.md index 4a3f40dc2..98c748387 100644 --- a/docs/modules/typeclass/Applicative.ts.md +++ b/docs/modules/typeclass/Applicative.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Applicative.ts -nav_order: 6 +nav_order: 4 parent: Modules --- diff --git a/docs/modules/typeclass/Bicovariant.ts.md b/docs/modules/typeclass/Bicovariant.ts.md index 7101ccd07..703802993 100644 --- a/docs/modules/typeclass/Bicovariant.ts.md +++ b/docs/modules/typeclass/Bicovariant.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Bicovariant.ts -nav_order: 7 +nav_order: 5 parent: Modules --- @@ -29,10 +29,7 @@ Added in v1.0.0 ```ts export interface Bicovariant extends TypeClass { - readonly bimap: ( - f: (e: E1) => E2, - g: (a: A) => B - ) => (self: Kind) => Kind + bimap: (f: (e: E1) => E2, g: (a: A) => B) => (self: Kind) => Kind } ``` diff --git a/docs/modules/typeclass/Bounded.ts.md b/docs/modules/typeclass/Bounded.ts.md index 32a569fea..23e09c15b 100644 --- a/docs/modules/typeclass/Bounded.ts.md +++ b/docs/modules/typeclass/Bounded.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Bounded.ts -nav_order: 8 +nav_order: 6 parent: Modules --- @@ -30,8 +30,8 @@ Added in v1.0.0 ```ts export interface Bounded
extends Order { - readonly maxBound: A - readonly minBound: A + maxBound: A + minBound: A } ``` @@ -45,7 +45,7 @@ Added in v1.0.0 ```ts export interface BoundedTypeLambda extends TypeLambda { - readonly type: Bounded + type: Bounded } ``` diff --git a/docs/modules/typeclass/Chainable.ts.md b/docs/modules/typeclass/Chainable.ts.md index 2570d40b9..ec3d61b31 100644 --- a/docs/modules/typeclass/Chainable.ts.md +++ b/docs/modules/typeclass/Chainable.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Chainable.ts -nav_order: 9 +nav_order: 7 parent: Modules --- @@ -67,7 +67,7 @@ export declare const bind: ( f: (a: A) => Kind ) => ( self: Kind -) => Kind +) => Kind ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Compactable.ts.md b/docs/modules/typeclass/Compactable.ts.md deleted file mode 100644 index b08e8fb3d..000000000 --- a/docs/modules/typeclass/Compactable.ts.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: typeclass/Compactable.ts -nav_order: 10 -parent: Modules ---- - -## Compactable overview - -`Compactable` represents data structures which can be _compacted_/_separated_. - -Added in v1.0.0 - ---- - -

Table of contents

- -- [models](#models) - - [Compactable (interface)](#compactable-interface) -- [utils](#utils) - - [compactComposition](#compactcomposition) - - [separate](#separate) - ---- - -# models - -## Compactable (interface) - -**Signature** - -```ts -export interface Compactable extends TypeClass { - readonly compact: (self: Kind>) => Kind -} -``` - -Added in v1.0.0 - -# utils - -## compactComposition - -Returns a default `compact` composition. - -**Signature** - -```ts -export declare const compactComposition: ( - F: Covariant, - G: Compactable -) => ( - self: Kind> -) => Kind> -``` - -Added in v1.0.0 - -## separate - -**Signature** - -```ts -export declare const separate: ( - F: Covariant & Compactable -) => (self: Kind) => readonly [Kind, Kind] -``` - -Added in v1.0.0 diff --git a/docs/modules/typeclass/Contravariant.ts.md b/docs/modules/typeclass/Contravariant.ts.md index 8fca0bcf2..5defde685 100644 --- a/docs/modules/typeclass/Contravariant.ts.md +++ b/docs/modules/typeclass/Contravariant.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Contravariant.ts -nav_order: 11 +nav_order: 8 parent: Modules --- @@ -44,7 +44,7 @@ Added in v1.0.0 ```ts export interface Contravariant extends Invariant { - readonly contramap: (f: (b: B) => A) => (self: Kind) => Kind + contramap: (f: (b: B) => A) => (self: Kind) => Kind } ``` diff --git a/docs/modules/typeclass/Coproduct.ts.md b/docs/modules/typeclass/Coproduct.ts.md index 6d61c5902..084b08f9e 100644 --- a/docs/modules/typeclass/Coproduct.ts.md +++ b/docs/modules/typeclass/Coproduct.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Coproduct.ts -nav_order: 12 +nav_order: 9 parent: Modules --- @@ -27,9 +27,9 @@ Added in v1.0.0 ```ts export interface Coproduct extends SemiCoproduct { - readonly zero:
() => Kind + zero: () => Kind - readonly coproductAll: (collection: Iterable>) => Kind + coproductAll: (collection: Iterable>) => Kind } ``` diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index dd37919a2..8adea3e2c 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Covariant.ts -nav_order: 13 +nav_order: 10 parent: Modules --- @@ -87,7 +87,7 @@ Added in v1.0.0 ```ts export interface Covariant extends Invariant { - readonly map: (f: (a: A) => B) => (self: Kind) => Kind + map: (f: (a: A) => B) => (self: Kind) => Kind } ``` @@ -119,9 +119,7 @@ export declare const let: ( ) => ( name: Exclude, f: (a: A) => B -) => ( - self: Kind -) => Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Filterable.ts.md b/docs/modules/typeclass/Filterable.ts.md deleted file mode 100644 index 848aa819d..000000000 --- a/docs/modules/typeclass/Filterable.ts.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: typeclass/Filterable.ts -nav_order: 14 -parent: Modules ---- - -## Filterable overview - -`Filterable` represents data structures which can be _partitioned_/_filtered_. - -Added in v1.0.0 - ---- - -

Table of contents

- -- [models](#models) - - [Filterable (interface)](#filterable-interface) -- [utils](#utils) - - [filter](#filter) - - [filterMapComposition](#filtermapcomposition) - - [partition](#partition) - - [partitionMap](#partitionmap) - ---- - -# models - -## Filterable (interface) - -**Signature** - -```ts -export interface Filterable extends TypeClass { - readonly filterMap: (f: (a: A) => Option) => (self: Kind) => Kind -} -``` - -Added in v1.0.0 - -# utils - -## filter - -**Signature** - -```ts -export declare const filter: ( - F: Filterable -) => { - (refinement: (a: A) => a is B): ( - self: Kind - ) => Kind - (predicate: (a: A) => boolean): (self: Kind) => Kind -} -``` - -Added in v1.0.0 - -## filterMapComposition - -Returns a default `filterMap` composition. - -**Signature** - -```ts -export declare const filterMapComposition: ( - F: Covariant, - G: Filterable -) => ( - f: (a: A) => any -) => ( - self: Kind> -) => Kind> -``` - -Added in v1.0.0 - -## partition - -**Signature** - -```ts -export declare const partition: ( - F: Filterable -) => { - (refinement: (a: A) => a is B): ( - self: Kind - ) => readonly [Kind, Kind] - (predicate: (a: A) => boolean): ( - self: Kind - ) => readonly [Kind, Kind] -} -``` - -Added in v1.0.0 - -## partitionMap - -**Signature** - -```ts -export declare const partitionMap: ( - F: Filterable -) => ( - f: (a: A) => any -) => (self: Kind) => readonly [Kind, Kind] -``` - -Added in v1.0.0 diff --git a/docs/modules/typeclass/FlatMap.ts.md b/docs/modules/typeclass/FlatMap.ts.md index 3fad467cb..be6a9641f 100644 --- a/docs/modules/typeclass/FlatMap.ts.md +++ b/docs/modules/typeclass/FlatMap.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/FlatMap.ts -nav_order: 15 +nav_order: 11 parent: Modules --- @@ -29,7 +29,7 @@ Added in v1.0.0 ```ts export interface FlatMap extends TypeClass { - readonly flatMap: ( + flatMap: ( f: (a: A) => Kind ) => (self: Kind) => Kind } diff --git a/docs/modules/typeclass/Foldable.ts.md b/docs/modules/typeclass/Foldable.ts.md index 3ab20e875..fb3656da4 100644 --- a/docs/modules/typeclass/Foldable.ts.md +++ b/docs/modules/typeclass/Foldable.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Foldable.ts -nav_order: 16 +nav_order: 12 parent: Modules --- @@ -21,8 +21,8 @@ Added in v1.0.0 - [reduceKind](#reducekind) - [reduceRight](#reduceright) - [reduceRightKind](#reducerightkind) - - [toReadonlyArray](#toreadonlyarray) - - [toReadonlyArrayWith](#toreadonlyarraywith) + - [toArray](#toarray) + - [toArrayWith](#toarraywith) --- @@ -34,7 +34,7 @@ Added in v1.0.0 ```ts export interface Foldable extends TypeClass { - readonly reduce: (b: B, f: (b: B, a: A) => B) => (self: Kind) => B + reduce: (b: B, f: (b: B, a: A) => B) => (self: Kind) => B } ``` @@ -134,26 +134,24 @@ export declare const reduceRightKind: ( Added in v1.0.0 -## toReadonlyArray +## toArray **Signature** ```ts -export declare const toReadonlyArray: ( - F: Foldable -) => (self: Kind) => readonly A[] +export declare const toArray: (F: Foldable) => (self: Kind) => A[] ``` Added in v1.0.0 -## toReadonlyArrayWith +## toArrayWith **Signature** ```ts -export declare const toReadonlyArrayWith: ( +export declare const toArrayWith: ( F: Foldable -) => (f: (a: A) => B) => (self: Kind) => readonly B[] +) => (f: (a: A) => B) => (self: Kind) => B[] ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Invariant.ts.md b/docs/modules/typeclass/Invariant.ts.md index 23f06e68e..f1cfcb8c0 100644 --- a/docs/modules/typeclass/Invariant.ts.md +++ b/docs/modules/typeclass/Invariant.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Invariant.ts -nav_order: 17 +nav_order: 13 parent: Modules --- @@ -29,10 +29,7 @@ Added in v1.0.0 ```ts export interface Invariant extends TypeClass { - readonly imap: ( - to: (a: A) => B, - from: (b: B) => A - ) => (self: Kind) => Kind + imap: (to: (a: A) => B, from: (b: B) => A) => (self: Kind) => Kind } ``` @@ -47,9 +44,7 @@ Added in v1.0.0 ```ts export declare const bindTo: ( F: Invariant -) => ( - name: N -) => (self: Kind) => Kind +) => (name: N) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -81,7 +76,7 @@ Added in v1.0.0 ```ts export declare const tupled: ( F: Invariant -) => (self: Kind) => Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Monad.ts.md b/docs/modules/typeclass/Monad.ts.md index 2ed430af1..e29774286 100644 --- a/docs/modules/typeclass/Monad.ts.md +++ b/docs/modules/typeclass/Monad.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Monad.ts -nav_order: 18 +nav_order: 14 parent: Modules --- diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index d57a29de2..575caf07b 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Monoid.ts -nav_order: 19 +nav_order: 15 parent: Modules --- @@ -75,8 +75,8 @@ Added in v1.0.0 ```ts export interface Monoid
extends Semigroup { - readonly empty: A - readonly combineAll: (collection: Iterable) => A + empty: A + combineAll: (collection: Iterable) => A } ``` @@ -103,7 +103,7 @@ Given a struct of monoids returns a monoid for the struct. **Signature** ```ts -export declare const struct: (monoids: { [K in keyof A]: Monoid }) => Monoid<{ readonly [K in keyof A]: A[K] }> +export declare const struct: (monoids: { [K in keyof A]: Monoid }) => Monoid<{ [K in keyof A]: A[K] }> ``` Added in v1.0.0 @@ -115,9 +115,7 @@ Given a tuple of monoids returns a monoid for the tuple. **Signature** ```ts -export declare const tuple: ( - ...monoids: { [K in keyof A]: Monoid } -) => Monoid> +export declare const tuple: (...monoids: { [K in keyof A]: Monoid }) => Monoid ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/NonEmptyTraversable.ts.md b/docs/modules/typeclass/NonEmptyTraversable.ts.md index 569dbb3af..c53a72957 100644 --- a/docs/modules/typeclass/NonEmptyTraversable.ts.md +++ b/docs/modules/typeclass/NonEmptyTraversable.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/NonEmptyTraversable.ts -nav_order: 20 +nav_order: 16 parent: Modules --- @@ -31,13 +31,13 @@ Added in v1.0.0 ```ts export interface NonEmptyTraversable extends TypeClass { - readonly traverseNonEmpty: ( + traverseNonEmpty: ( F: SemiApplicative ) => ( f: (a: A) => Kind ) => (self: Kind) => Kind> - readonly sequenceNonEmpty: ( + sequenceNonEmpty: ( F: SemiApplicative ) => ( self: Kind> diff --git a/docs/modules/typeclass/Of.ts.md b/docs/modules/typeclass/Of.ts.md index 2db971ade..1f3081e3f 100644 --- a/docs/modules/typeclass/Of.ts.md +++ b/docs/modules/typeclass/Of.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Of.ts -nav_order: 21 +nav_order: 17 parent: Modules --- @@ -29,7 +29,7 @@ Added in v1.0.0 ```ts export interface Of extends TypeClass { - readonly of: (a: A) => Kind + of: (a: A) => Kind } ``` diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index 3f8621165..ac5e8f6e8 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Order.ts -nav_order: 22 +nav_order: 18 parent: Modules --- @@ -124,7 +124,7 @@ Added in v1.0.0 ```ts export interface Order { - readonly compare: (that: A) => (self: A) => -1 | 0 | 1 + compare: (that: A) => (self: A) => -1 | 0 | 1 } ``` @@ -138,7 +138,7 @@ Added in v1.0.0 ```ts export interface OrderTypeLambda extends TypeLambda { - readonly type: Order + type: Order } ``` @@ -269,7 +269,7 @@ Given a tuple of `Compare`s returns a `Compare` for the tuple. **Signature** ```ts -export declare const tuple: (...orders: { [K in keyof A]: Order }) => Order> +export declare const tuple: (...orders: { [K in keyof A]: Order }) => Order> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Pointed.ts.md b/docs/modules/typeclass/Pointed.ts.md index 92e80863e..1f29db58e 100644 --- a/docs/modules/typeclass/Pointed.ts.md +++ b/docs/modules/typeclass/Pointed.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Pointed.ts -nav_order: 23 +nav_order: 19 parent: Modules --- diff --git a/docs/modules/typeclass/Product.ts.md b/docs/modules/typeclass/Product.ts.md index 0997d1ced..3fb540b85 100644 --- a/docs/modules/typeclass/Product.ts.md +++ b/docs/modules/typeclass/Product.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Product.ts -nav_order: 24 +nav_order: 20 parent: Modules --- @@ -28,7 +28,7 @@ Added in v1.0.0 ```ts export interface Product extends SemiProduct, Of { - readonly productAll: (collection: Iterable>) => Kind> + productAll: (collection: Iterable>) => Kind> } ``` @@ -50,7 +50,7 @@ export declare const struct: ( [R[keyof R]] extends [Kind] ? R : never, [R[keyof R]] extends [Kind] ? O : never, [R[keyof R]] extends [Kind] ? E : never, - { readonly [K in keyof R]: [R[K]] extends [Kind] ? A : never } + { [K in keyof R]: [R[K]] extends [Kind] ? A : never } > ``` @@ -63,14 +63,14 @@ Added in v1.0.0 ```ts export declare const tuple: ( F: Product -) => []>( +) => []>( ...components: T ) => Kind< F, [T[number]] extends [Kind] ? R : never, [T[number]] extends [Kind] ? O : never, [T[number]] extends [Kind] ? E : never, - Readonly<{ [I in keyof T]: [T[I]] extends [Kind] ? A : never }> + { [I in keyof T]: [T[I]] extends [Kind] ? A : never } > ``` diff --git a/docs/modules/typeclass/SemiAlternative.ts.md b/docs/modules/typeclass/SemiAlternative.ts.md index 929f0f9b2..6d0e39a39 100644 --- a/docs/modules/typeclass/SemiAlternative.ts.md +++ b/docs/modules/typeclass/SemiAlternative.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/SemiAlternative.ts -nav_order: 25 +nav_order: 21 parent: Modules --- diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index 9f683aa02..99e700d4f 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/SemiApplicative.ts -nav_order: 26 +nav_order: 22 parent: Modules --- diff --git a/docs/modules/typeclass/SemiCoproduct.ts.md b/docs/modules/typeclass/SemiCoproduct.ts.md index 35b65b636..4dfcb057b 100644 --- a/docs/modules/typeclass/SemiCoproduct.ts.md +++ b/docs/modules/typeclass/SemiCoproduct.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/SemiCoproduct.ts -nav_order: 27 +nav_order: 23 parent: Modules --- @@ -15,7 +15,6 @@ Added in v1.0.0 - [type class](#type-class) - [SemiCoproduct (interface)](#semicoproduct-interface) - [utils](#utils) - - [coproductEither](#coproducteither) - [getSemigroup](#getsemigroup) --- @@ -28,11 +27,11 @@ Added in v1.0.0 ```ts export interface SemiCoproduct extends Invariant { - readonly coproduct: ( + coproduct: ( that: Kind ) => (self: Kind) => Kind - readonly coproductMany: ( + coproductMany: ( collection: Iterable> ) => (self: Kind) => Kind } @@ -42,20 +41,6 @@ Added in v1.0.0 # utils -## coproductEither - -**Signature** - -```ts -export declare const coproductEither: ( - F: SemiCoproduct -) => ( - that: Kind -) => (self: Kind) => Kind -``` - -Added in v1.0.0 - ## getSemigroup **Signature** diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index 6ae14d7e4..67962673c 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/SemiProduct.ts -nav_order: 29 +nav_order: 25 parent: Modules --- @@ -39,10 +39,10 @@ export declare const productMany: ( Covariant: Covariant, product: ( that: Kind - ) => (self: Kind) => Kind + ) => (self: Kind) => Kind ) => ( collection: Iterable> -) => (self: Kind) => Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -55,13 +55,13 @@ Added in v1.0.0 ```ts export interface SemiProduct extends Invariant { - readonly product: ( + product: ( that: Kind - ) => (self: Kind) => Kind + ) => (self: Kind) => Kind - readonly productMany: ( + productMany: ( collection: Iterable> - ) => (self: Kind) => Kind]> + ) => (self: Kind) => Kind]> } ``` @@ -78,10 +78,10 @@ export declare const andThenBind: ( F: SemiProduct ) => ( name: Exclude, - fb: Kind + that: Kind ) => ( self: Kind -) => Kind +) => Kind ``` Added in v1.0.0 @@ -100,7 +100,7 @@ export declare const nonEmptyStruct: ( [R[keyof R]] extends [Kind] ? R : never, [R[keyof R]] extends [Kind] ? O : never, [R[keyof R]] extends [Kind] ? E : never, - { readonly [K in keyof R]: [R[K]] extends [Kind] ? A : never } + { [K in keyof R]: [R[K]] extends [Kind] ? A : never } > ``` @@ -120,7 +120,7 @@ export declare const nonEmptyTuple: ( [T[number]] extends [Kind] ? R : never, [T[number]] extends [Kind] ? O : never, [T[number]] extends [Kind] ? E : never, - Readonly<{ [I in keyof T]: [T[I]] extends [Kind] ? A : never }> + { [I in keyof T]: [T[I]] extends [Kind] ? A : never } > ``` @@ -140,7 +140,7 @@ export declare const productComposition: > ) => ( self: Kind> -) => Kind> +) => Kind> ``` Added in v1.0.0 @@ -154,9 +154,7 @@ export declare const productFlatten: ( F: SemiProduct ) => ( that: Kind -) => ( - self: Kind -) => Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -173,9 +171,7 @@ export declare const productManyComposition: ) => ( collection: Iterable>> -) => ( - self: Kind> -) => Kind> +) => (self: Kind>) => Kind> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index 86da6ec79..b25df7f2b 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Semigroup.ts -nav_order: 28 +nav_order: 24 parent: Modules --- @@ -10,8 +10,8 @@ parent: Modules ```ts export interface Semigroup { - readonly combine: (that: A) => (self: A) => A - readonly combineMany: (collection: Iterable) => (self: A) => A + combine: (that: A) => (self: A) => A + combineMany: (collection: Iterable) => (self: A) => A } ``` @@ -167,8 +167,8 @@ Added in v1.0.0 ```ts export interface Semigroup { - readonly combine: (that: A) => (self: A) => A - readonly combineMany: (collection: Iterable) => (self: A) => A + combine: (that: A) => (self: A) => A + combineMany: (collection: Iterable) => (self: A) => A } ``` @@ -182,7 +182,7 @@ Added in v1.0.0 ```ts export interface SemigroupTypeLambda extends TypeLambda { - readonly type: Semigroup + type: Semigroup } ``` @@ -229,9 +229,7 @@ Given a struct of associatives returns an associative for the struct. **Signature** ```ts -export declare const struct: (semigroups: { [K in keyof A]: Semigroup }) => Semigroup<{ - readonly [K in keyof A]: A[K] -}> +export declare const struct: (semigroups: { [K in keyof A]: Semigroup }) => Semigroup<{ [K in keyof A]: A[K] }> ``` Added in v1.0.0 @@ -243,9 +241,7 @@ Given a tuple of associatives returns an associative for the tuple. **Signature** ```ts -export declare const tuple: ( - ...semigroups: { [K in keyof A]: Semigroup } -) => Semigroup> +export declare const tuple: (...semigroups: { [K in keyof A]: Semigroup }) => Semigroup ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Traversable.ts.md b/docs/modules/typeclass/Traversable.ts.md index 93c5e280c..68bb557d8 100644 --- a/docs/modules/typeclass/Traversable.ts.md +++ b/docs/modules/typeclass/Traversable.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Traversable.ts -nav_order: 30 +nav_order: 26 parent: Modules --- @@ -30,13 +30,13 @@ Added in v1.0.0 ```ts export interface Traversable extends TypeClass { - readonly traverse: ( + traverse: ( F: Applicative ) => ( f: (a: A) => Kind ) => (self: Kind) => Kind> - readonly sequence: ( + sequence: ( F: Applicative ) => ( self: Kind> diff --git a/docs/modules/typeclass/TraversableFilterable.ts.md b/docs/modules/typeclass/TraversableFilterable.ts.md deleted file mode 100644 index 98f5c1e7b..000000000 --- a/docs/modules/typeclass/TraversableFilterable.ts.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -title: typeclass/TraversableFilterable.ts -nav_order: 31 -parent: Modules ---- - -## TraversableFilterable overview - -`TraversableFilterable` represents data structures which can be _partitioned_ with effects in some `Applicative` functor. - -Added in v1.0.0 - ---- - -

Table of contents

- -- [models](#models) - - [TraversableFilterable (interface)](#traversablefilterable-interface) -- [utils](#utils) - - [traverseFilter](#traversefilter) - - [traverseFilterMap](#traversefiltermap) - - [traversePartition](#traversepartition) - - [traversePartitionMap](#traversepartitionmap) - ---- - -# models - -## TraversableFilterable (interface) - -**Signature** - -```ts -export interface TraversableFilterable extends TypeClass { - readonly traversePartitionMap: ( - F: Applicative - ) => ( - f: (a: A) => Kind> - ) => ( - self: Kind - ) => Kind, Kind]> - - readonly traverseFilterMap: ( - F: Applicative - ) => ( - f: (a: A) => Kind> - ) => (self: Kind) => Kind> -} -``` - -Added in v1.0.0 - -# utils - -## traverseFilter - -**Signature** - -```ts -export declare const traverseFilter: ( - T: TraversableFilterable -) => ( - F: Applicative -) => ( - predicate: (a: A) => Kind -) => (self: Kind) => Kind> -``` - -Added in v1.0.0 - -## traverseFilterMap - -Returns a default `traverseFilterMap` implementation. - -**Signature** - -```ts -export declare const traverseFilterMap: ( - T: Traversable & compactable.Compactable -) => ( - F: Applicative -) => ( - f: (a: A) => Kind -) => (self: Kind) => Kind> -``` - -Added in v1.0.0 - -## traversePartition - -**Signature** - -```ts -export declare const traversePartition: ( - T: TraversableFilterable -) => ( - F: Applicative -) => ( - predicate: (a: A) => Kind -) => ( - self: Kind -) => Kind, Kind]> -``` - -Added in v1.0.0 - -## traversePartitionMap - -Returns a default `traversePartitionMap` implementation. - -**Signature** - -```ts -export declare const traversePartitionMap: ( - T: Traversable & Covariant & compactable.Compactable -) => ( - F: Applicative -) => ( - f: (a: A) => Kind -) => ( - self: Kind -) => Kind, Kind]> -``` - -Added in v1.0.0 From 1fc74932e142d96fc844a9411a701651fde7792c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 13 Dec 2022 13:20:56 +0000 Subject: [PATCH 004/255] Version Packages --- .changeset/old-zoos-clap.md | 5 ----- CHANGELOG.md | 6 ++++++ package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/old-zoos-clap.md diff --git a/.changeset/old-zoos-clap.md b/.changeset/old-zoos-clap.md deleted file mode 100644 index 5b88cb8a7..000000000 --- a/.changeset/old-zoos-clap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -remove readonly diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a5bbebcb..436c41b39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # @fp-ts/core +## 0.0.10 + +### Patch Changes + +- [#36](https://github.com/fp-ts/core/pull/36) [`51bb90bd`](https://github.com/fp-ts/core/commit/51bb90bd4f32bd878575a159a2bc0c8c3b3ff57b) Thanks [@gcanti](https://github.com/gcanti)! - remove readonly + ## 0.0.9 ### Patch Changes diff --git a/package.json b/package.json index 93e9fbe45..863c93a89 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fp-ts/core", - "version": "0.0.9", + "version": "0.0.10", "publishConfig": { "access": "public", "directory": "dist" From c27db5e796071966a64af1a860b56e417f99423e Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 13 Dec 2022 21:30:45 +0100 Subject: [PATCH 005/255] revert 0.0.10 changes --- .changeset/loud-paws-chew.md | 5 ++ docs/modules/HKT.ts.md | 30 ++++---- docs/modules/typeclass/Bicovariant.ts.md | 5 +- docs/modules/typeclass/Bounded.ts.md | 6 +- docs/modules/typeclass/Chainable.ts.md | 2 +- docs/modules/typeclass/Contravariant.ts.md | 2 +- docs/modules/typeclass/Coproduct.ts.md | 4 +- docs/modules/typeclass/Covariant.ts.md | 2 +- docs/modules/typeclass/FlatMap.ts.md | 2 +- docs/modules/typeclass/Foldable.ts.md | 2 +- docs/modules/typeclass/Invariant.ts.md | 11 ++- docs/modules/typeclass/Monoid.ts.md | 12 ++-- .../typeclass/NonEmptyTraversable.ts.md | 4 +- docs/modules/typeclass/Of.ts.md | 2 +- docs/modules/typeclass/Order.ts.md | 6 +- docs/modules/typeclass/Product.ts.md | 8 +-- docs/modules/typeclass/SemiCoproduct.ts.md | 4 +- docs/modules/typeclass/SemiProduct.ts.md | 32 +++++---- docs/modules/typeclass/Semigroup.ts.md | 14 ++-- docs/modules/typeclass/Traversable.ts.md | 4 +- dtslint/ts4.7/Product.ts | 4 +- src/HKT.ts | 30 ++++---- src/typeclass/Bicovariant.ts | 2 +- src/typeclass/Bounded.ts | 6 +- src/typeclass/Chainable.ts | 2 +- src/typeclass/Contravariant.ts | 2 +- src/typeclass/Coproduct.ts | 4 +- src/typeclass/Covariant.ts | 2 +- src/typeclass/FlatMap.ts | 2 +- src/typeclass/Foldable.ts | 2 +- src/typeclass/Invariant.ts | 8 +-- src/typeclass/Monoid.ts | 14 ++-- src/typeclass/NonEmptyTraversable.ts | 4 +- src/typeclass/Of.ts | 2 +- src/typeclass/Order.ts | 6 +- src/typeclass/Product.ts | 10 +-- src/typeclass/SemiCoproduct.ts | 4 +- src/typeclass/SemiProduct.ts | 32 ++++----- src/typeclass/Semigroup.ts | 12 ++-- src/typeclass/Traversable.ts | 4 +- test/data/Either.ts | 10 +-- test/data/NonEmptyArray.ts | 60 ---------------- test/data/NonEmptyReadonlyArray.ts | 69 +++++++++++++++++++ test/data/Option.ts | 41 +++++------ test/data/Predicate.ts | 6 +- test/data/{Array.ts => ReadonlyArray.ts} | 69 ++++++++++--------- test/index.ts | 2 +- test/limbo/Category.ts | 2 +- test/limbo/Comonad.ts | 2 +- test/limbo/Composable.ts | 2 +- test/limbo/CovariantWithIndex.ts | 4 +- test/limbo/Extendable.ts | 2 +- test/limbo/FoldableWithIndex.ts | 8 +-- test/limbo/TraversableWithIndex.ts | 4 +- test/typeclass/Bicovariant.ts | 2 +- test/typeclass/Covariant.ts | 2 +- test/typeclass/CovariantWithIndex.ts | 4 +- test/typeclass/Foldable.ts | 2 +- test/typeclass/FoldableWithIndex.ts | 20 +++--- test/typeclass/Invariant.ts | 12 ++-- test/typeclass/NonEmptyTraversable.ts | 16 ++--- test/typeclass/Of.ts | 2 +- test/typeclass/Order.ts | 2 +- test/typeclass/Product.ts | 6 +- test/typeclass/SemiProduct.ts | 44 ++++++------ test/typeclass/Semigroup.ts | 7 +- test/typeclass/Traversable.ts | 4 +- test/typeclass/TraversableWithIndex.ts | 2 +- 68 files changed, 374 insertions(+), 341 deletions(-) create mode 100644 .changeset/loud-paws-chew.md create mode 100644 test/data/NonEmptyReadonlyArray.ts rename test/data/{Array.ts => ReadonlyArray.ts} (59%) diff --git a/.changeset/loud-paws-chew.md b/.changeset/loud-paws-chew.md new file mode 100644 index 000000000..751f05ee8 --- /dev/null +++ b/.changeset/loud-paws-chew.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +revert 0.0.10 changes diff --git a/docs/modules/HKT.ts.md b/docs/modules/HKT.ts.md index 05916670c..dec5aeaae 100644 --- a/docs/modules/HKT.ts.md +++ b/docs/modules/HKT.ts.md @@ -27,20 +27,20 @@ Added in v1.0.0 ```ts export type Kind = F extends { - type: unknown + readonly type: unknown } ? (F & { - In: In - Out2: Out2 - Out1: Out1 - Target: Target + readonly In: In + readonly Out2: Out2 + readonly Out1: Out1 + readonly Target: Target })['type'] : { - F: F - In: (_: In) => void - Out2: () => Out2 - Out1: () => Out1 - Target: (_: Target) => Target + readonly F: F + readonly In: (_: In) => void + readonly Out2: () => Out2 + readonly Out1: () => Out1 + readonly Target: (_: Target) => Target } ``` @@ -52,7 +52,7 @@ Added in v1.0.0 ```ts export interface TypeClass { - [URI]?: F + readonly [URI]?: F } ``` @@ -64,10 +64,10 @@ Added in v1.0.0 ```ts export interface TypeLambda { - In: unknown - Out2: unknown - Out1: unknown - Target: unknown + readonly In: unknown + readonly Out2: unknown + readonly Out1: unknown + readonly Target: unknown } ``` diff --git a/docs/modules/typeclass/Bicovariant.ts.md b/docs/modules/typeclass/Bicovariant.ts.md index 703802993..e01228986 100644 --- a/docs/modules/typeclass/Bicovariant.ts.md +++ b/docs/modules/typeclass/Bicovariant.ts.md @@ -29,7 +29,10 @@ Added in v1.0.0 ```ts export interface Bicovariant extends TypeClass { - bimap: (f: (e: E1) => E2, g: (a: A) => B) => (self: Kind) => Kind + readonly bimap: ( + f: (e: E1) => E2, + g: (a: A) => B + ) => (self: Kind) => Kind } ``` diff --git a/docs/modules/typeclass/Bounded.ts.md b/docs/modules/typeclass/Bounded.ts.md index 23e09c15b..89605b9f0 100644 --- a/docs/modules/typeclass/Bounded.ts.md +++ b/docs/modules/typeclass/Bounded.ts.md @@ -30,8 +30,8 @@ Added in v1.0.0 ```ts export interface Bounded
extends Order { - maxBound: A - minBound: A + readonly maxBound: A + readonly minBound: A } ``` @@ -45,7 +45,7 @@ Added in v1.0.0 ```ts export interface BoundedTypeLambda extends TypeLambda { - type: Bounded + readonly type: Bounded } ``` diff --git a/docs/modules/typeclass/Chainable.ts.md b/docs/modules/typeclass/Chainable.ts.md index ec3d61b31..d4f584e52 100644 --- a/docs/modules/typeclass/Chainable.ts.md +++ b/docs/modules/typeclass/Chainable.ts.md @@ -67,7 +67,7 @@ export declare const bind: ( f: (a: A) => Kind ) => ( self: Kind -) => Kind +) => Kind ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Contravariant.ts.md b/docs/modules/typeclass/Contravariant.ts.md index 5defde685..ff16c82fa 100644 --- a/docs/modules/typeclass/Contravariant.ts.md +++ b/docs/modules/typeclass/Contravariant.ts.md @@ -44,7 +44,7 @@ Added in v1.0.0 ```ts export interface Contravariant extends Invariant { - contramap: (f: (b: B) => A) => (self: Kind) => Kind + readonly contramap: (f: (b: B) => A) => (self: Kind) => Kind } ``` diff --git a/docs/modules/typeclass/Coproduct.ts.md b/docs/modules/typeclass/Coproduct.ts.md index 084b08f9e..dc19adbff 100644 --- a/docs/modules/typeclass/Coproduct.ts.md +++ b/docs/modules/typeclass/Coproduct.ts.md @@ -27,9 +27,9 @@ Added in v1.0.0 ```ts export interface Coproduct extends SemiCoproduct { - zero: () => Kind + readonly zero: () => Kind - coproductAll: (collection: Iterable>) => Kind + readonly coproductAll: (collection: Iterable>) => Kind } ``` diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index 8adea3e2c..5d948f250 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -87,7 +87,7 @@ Added in v1.0.0 ```ts export interface Covariant extends Invariant { - map: (f: (a: A) => B) => (self: Kind) => Kind + readonly map: (f: (a: A) => B) => (self: Kind) => Kind } ``` diff --git a/docs/modules/typeclass/FlatMap.ts.md b/docs/modules/typeclass/FlatMap.ts.md index be6a9641f..2ddc9163e 100644 --- a/docs/modules/typeclass/FlatMap.ts.md +++ b/docs/modules/typeclass/FlatMap.ts.md @@ -29,7 +29,7 @@ Added in v1.0.0 ```ts export interface FlatMap extends TypeClass { - flatMap: ( + readonly flatMap: ( f: (a: A) => Kind ) => (self: Kind) => Kind } diff --git a/docs/modules/typeclass/Foldable.ts.md b/docs/modules/typeclass/Foldable.ts.md index fb3656da4..a0d735c52 100644 --- a/docs/modules/typeclass/Foldable.ts.md +++ b/docs/modules/typeclass/Foldable.ts.md @@ -34,7 +34,7 @@ Added in v1.0.0 ```ts export interface Foldable extends TypeClass { - reduce: (b: B, f: (b: B, a: A) => B) => (self: Kind) => B + readonly reduce: (b: B, f: (b: B, a: A) => B) => (self: Kind) => B } ``` diff --git a/docs/modules/typeclass/Invariant.ts.md b/docs/modules/typeclass/Invariant.ts.md index f1cfcb8c0..e88c28784 100644 --- a/docs/modules/typeclass/Invariant.ts.md +++ b/docs/modules/typeclass/Invariant.ts.md @@ -29,7 +29,10 @@ Added in v1.0.0 ```ts export interface Invariant extends TypeClass { - imap: (to: (a: A) => B, from: (b: B) => A) => (self: Kind) => Kind + readonly imap: ( + to: (a: A) => B, + from: (b: B) => A + ) => (self: Kind) => Kind } ``` @@ -44,7 +47,9 @@ Added in v1.0.0 ```ts export declare const bindTo: ( F: Invariant -) => (name: N) => (self: Kind) => Kind +) => ( + name: N +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -76,7 +81,7 @@ Added in v1.0.0 ```ts export declare const tupled: ( F: Invariant -) => (self: Kind) => Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index 575caf07b..2b6823e5d 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -75,8 +75,8 @@ Added in v1.0.0 ```ts export interface Monoid extends Semigroup { - empty: A - combineAll: (collection: Iterable) => A + readonly empty: A + readonly combineAll: (collection: Iterable) => A } ``` @@ -103,7 +103,9 @@ Given a struct of monoids returns a monoid for the struct. **Signature** ```ts -export declare const struct: (monoids: { [K in keyof A]: Monoid }) => Monoid<{ [K in keyof A]: A[K] }> +export declare const struct: (monoids: { readonly [K in keyof A]: Monoid }) => Monoid<{ + readonly [K in keyof A]: A[K] +}> ``` Added in v1.0.0 @@ -115,7 +117,9 @@ Given a tuple of monoids returns a monoid for the tuple. **Signature** ```ts -export declare const tuple: (...monoids: { [K in keyof A]: Monoid }) => Monoid +export declare const tuple: ( + ...monoids: { [K in keyof A]: Monoid } +) => Monoid> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/NonEmptyTraversable.ts.md b/docs/modules/typeclass/NonEmptyTraversable.ts.md index c53a72957..3504f3ad5 100644 --- a/docs/modules/typeclass/NonEmptyTraversable.ts.md +++ b/docs/modules/typeclass/NonEmptyTraversable.ts.md @@ -31,13 +31,13 @@ Added in v1.0.0 ```ts export interface NonEmptyTraversable extends TypeClass { - traverseNonEmpty: ( + readonly traverseNonEmpty: ( F: SemiApplicative ) => ( f: (a: A) => Kind ) => (self: Kind) => Kind> - sequenceNonEmpty: ( + readonly sequenceNonEmpty: ( F: SemiApplicative ) => ( self: Kind> diff --git a/docs/modules/typeclass/Of.ts.md b/docs/modules/typeclass/Of.ts.md index 1f3081e3f..a06bd5098 100644 --- a/docs/modules/typeclass/Of.ts.md +++ b/docs/modules/typeclass/Of.ts.md @@ -29,7 +29,7 @@ Added in v1.0.0 ```ts export interface Of extends TypeClass { - of: (a: A) => Kind + readonly of: (a: A) => Kind } ``` diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index ac5e8f6e8..c2f6a5c7f 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -124,7 +124,7 @@ Added in v1.0.0 ```ts export interface Order { - compare: (that: A) => (self: A) => -1 | 0 | 1 + readonly compare: (that: A) => (self: A) => -1 | 0 | 1 } ``` @@ -138,7 +138,7 @@ Added in v1.0.0 ```ts export interface OrderTypeLambda extends TypeLambda { - type: Order + readonly type: Order } ``` @@ -269,7 +269,7 @@ Given a tuple of `Compare`s returns a `Compare` for the tuple. **Signature** ```ts -export declare const tuple: (...orders: { [K in keyof A]: Order }) => Order> +export declare const tuple: (...orders: { [K in keyof A]: Order }) => Order> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Product.ts.md b/docs/modules/typeclass/Product.ts.md index 3fb540b85..b804002af 100644 --- a/docs/modules/typeclass/Product.ts.md +++ b/docs/modules/typeclass/Product.ts.md @@ -28,7 +28,7 @@ Added in v1.0.0 ```ts export interface Product extends SemiProduct, Of { - productAll: (collection: Iterable>) => Kind> + readonly productAll: (collection: Iterable>) => Kind> } ``` @@ -50,7 +50,7 @@ export declare const struct: ( [R[keyof R]] extends [Kind] ? R : never, [R[keyof R]] extends [Kind] ? O : never, [R[keyof R]] extends [Kind] ? E : never, - { [K in keyof R]: [R[K]] extends [Kind] ? A : never } + { readonly [K in keyof R]: [R[K]] extends [Kind] ? A : never } > ``` @@ -63,14 +63,14 @@ Added in v1.0.0 ```ts export declare const tuple: ( F: Product -) => []>( +) => []>( ...components: T ) => Kind< F, [T[number]] extends [Kind] ? R : never, [T[number]] extends [Kind] ? O : never, [T[number]] extends [Kind] ? E : never, - { [I in keyof T]: [T[I]] extends [Kind] ? A : never } + Readonly<{ [I in keyof T]: [T[I]] extends [Kind] ? A : never }> > ``` diff --git a/docs/modules/typeclass/SemiCoproduct.ts.md b/docs/modules/typeclass/SemiCoproduct.ts.md index 4dfcb057b..b1702361b 100644 --- a/docs/modules/typeclass/SemiCoproduct.ts.md +++ b/docs/modules/typeclass/SemiCoproduct.ts.md @@ -27,11 +27,11 @@ Added in v1.0.0 ```ts export interface SemiCoproduct extends Invariant { - coproduct: ( + readonly coproduct: ( that: Kind ) => (self: Kind) => Kind - coproductMany: ( + readonly coproductMany: ( collection: Iterable> ) => (self: Kind) => Kind } diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index 67962673c..da622d96d 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -39,10 +39,10 @@ export declare const productMany: ( Covariant: Covariant, product: ( that: Kind - ) => (self: Kind) => Kind + ) => (self: Kind) => Kind ) => ( collection: Iterable> -) => (self: Kind) => Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -55,13 +55,13 @@ Added in v1.0.0 ```ts export interface SemiProduct extends Invariant { - product: ( + readonly product: ( that: Kind - ) => (self: Kind) => Kind + ) => (self: Kind) => Kind - productMany: ( + readonly productMany: ( collection: Iterable> - ) => (self: Kind) => Kind]> + ) => (self: Kind) => Kind]> } ``` @@ -81,7 +81,7 @@ export declare const andThenBind: ( that: Kind ) => ( self: Kind -) => Kind +) => Kind ``` Added in v1.0.0 @@ -93,14 +93,14 @@ Added in v1.0.0 ```ts export declare const nonEmptyStruct: ( F: SemiProduct -) => >>( +) => >>>( fields: EnforceNonEmptyRecord & Record> ) => Kind< F, [R[keyof R]] extends [Kind] ? R : never, [R[keyof R]] extends [Kind] ? O : never, [R[keyof R]] extends [Kind] ? E : never, - { [K in keyof R]: [R[K]] extends [Kind] ? A : never } + { readonly [K in keyof R]: [R[K]] extends [Kind] ? A : never } > ``` @@ -113,14 +113,14 @@ Added in v1.0.0 ```ts export declare const nonEmptyTuple: ( F: SemiProduct -) => , ...Kind[]]>( +) => , ...Kind[]]>( ...components: T ) => Kind< F, [T[number]] extends [Kind] ? R : never, [T[number]] extends [Kind] ? O : never, [T[number]] extends [Kind] ? E : never, - { [I in keyof T]: [T[I]] extends [Kind] ? A : never } + Readonly<{ [I in keyof T]: [T[I]] extends [Kind] ? A : never }> > ``` @@ -140,7 +140,7 @@ export declare const productComposition: > ) => ( self: Kind> -) => Kind> +) => Kind> ``` Added in v1.0.0 @@ -154,7 +154,9 @@ export declare const productFlatten: ( F: SemiProduct ) => ( that: Kind -) => (self: Kind) => Kind +) => ( + self: Kind +) => Kind ``` Added in v1.0.0 @@ -171,7 +173,9 @@ export declare const productManyComposition: ) => ( collection: Iterable>> -) => (self: Kind>) => Kind> +) => ( + self: Kind> +) => Kind> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index b25df7f2b..287320099 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -167,8 +167,8 @@ Added in v1.0.0 ```ts export interface Semigroup { - combine: (that: A) => (self: A) => A - combineMany: (collection: Iterable) => (self: A) => A + readonly combine: (that: A) => (self: A) => A + readonly combineMany: (collection: Iterable) => (self: A) => A } ``` @@ -182,7 +182,7 @@ Added in v1.0.0 ```ts export interface SemigroupTypeLambda extends TypeLambda { - type: Semigroup + readonly type: Semigroup } ``` @@ -229,7 +229,9 @@ Given a struct of associatives returns an associative for the struct. **Signature** ```ts -export declare const struct: (semigroups: { [K in keyof A]: Semigroup }) => Semigroup<{ [K in keyof A]: A[K] }> +export declare const struct: (semigroups: { [K in keyof A]: Semigroup }) => Semigroup<{ + readonly [K in keyof A]: A[K] +}> ``` Added in v1.0.0 @@ -241,7 +243,9 @@ Given a tuple of associatives returns an associative for the tuple. **Signature** ```ts -export declare const tuple: (...semigroups: { [K in keyof A]: Semigroup }) => Semigroup +export declare const tuple: ( + ...semigroups: { [K in keyof A]: Semigroup } +) => Semigroup> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Traversable.ts.md b/docs/modules/typeclass/Traversable.ts.md index 68bb557d8..fbd411377 100644 --- a/docs/modules/typeclass/Traversable.ts.md +++ b/docs/modules/typeclass/Traversable.ts.md @@ -30,13 +30,13 @@ Added in v1.0.0 ```ts export interface Traversable extends TypeClass { - traverse: ( + readonly traverse: ( F: Applicative ) => ( f: (a: A) => Kind ) => (self: Kind) => Kind> - sequence: ( + readonly sequence: ( F: Applicative ) => ( self: Kind> diff --git a/dtslint/ts4.7/Product.ts b/dtslint/ts4.7/Product.ts index 68ee95b7f..8287e5f69 100644 --- a/dtslint/ts4.7/Product.ts +++ b/dtslint/ts4.7/Product.ts @@ -15,10 +15,10 @@ declare const fc: RAW<{ c: boolean }, "c", boolean> export declare const Product: _.Product -// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", [string, number, boolean]> +// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", readonly [string, number, boolean]> _.tuple(Product)(fa, fb, fc) -// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", { fa: string; fb: number; fc: boolean; }> +// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", { readonly fa: string; readonly fb: number; readonly fc: boolean; }> _.struct(Product)({ fa, fb, fc }) _.tuple(Product)() // should allow empty tuple diff --git a/src/HKT.ts b/src/HKT.ts index 1177b0a86..56a113267 100644 --- a/src/HKT.ts +++ b/src/HKT.ts @@ -11,34 +11,34 @@ export declare const URI: unique symbol * @since 1.0.0 */ export interface TypeClass { - [URI]?: F + readonly [URI]?: F } /** * @since 1.0.0 */ export interface TypeLambda { - In: unknown - Out2: unknown - Out1: unknown - Target: unknown + readonly In: unknown + readonly Out2: unknown + readonly Out1: unknown + readonly Target: unknown } /** * @since 1.0.0 */ export type Kind = F extends { - type: unknown + readonly type: unknown } ? (F & { - In: In - Out2: Out2 - Out1: Out1 - Target: Target + readonly In: In + readonly Out2: Out2 + readonly Out1: Out1 + readonly Target: Target })["type"] : { - F: F - In: (_: In) => void - Out2: () => Out2 - Out1: () => Out1 - Target: (_: Target) => Target + readonly F: F + readonly In: (_: In) => void + readonly Out2: () => Out2 + readonly Out1: () => Out1 + readonly Target: (_: Target) => Target } diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index ec557ab54..7de7e2576 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -10,7 +10,7 @@ import type { Covariant } from "@fp-ts/core/typeclass/Covariant" * @since 1.0.0 */ export interface Bicovariant extends TypeClass { - bimap: ( + readonly bimap: ( f: (e: E1) => E2, g: (a: A) => B ) => (self: Kind) => Kind diff --git a/src/typeclass/Bounded.ts b/src/typeclass/Bounded.ts index ab4e9a8c1..2459fa434 100644 --- a/src/typeclass/Bounded.ts +++ b/src/typeclass/Bounded.ts @@ -10,8 +10,8 @@ import type { Order } from "@fp-ts/core/typeclass/Order" * @since 1.0.0 */ export interface Bounded extends Order { - maxBound: A - minBound: A + readonly maxBound: A + readonly minBound: A } /** @@ -19,7 +19,7 @@ export interface Bounded extends Order { * @since 1.0.0 */ export interface BoundedTypeLambda extends TypeLambda { - type: Bounded + readonly type: Bounded } /** diff --git a/src/typeclass/Chainable.ts b/src/typeclass/Chainable.ts index 3baaf8644..ff67fcdc6 100644 --- a/src/typeclass/Chainable.ts +++ b/src/typeclass/Chainable.ts @@ -56,7 +56,7 @@ export const bind = (F: Chainable) => R1 & R2, O1 | O2, E1 | E2, - { [K in keyof A | N]: K extends keyof A ? A[K] : B } + { readonly [K in keyof A | N]: K extends keyof A ? A[K] : B } > => F.flatMap(a => pipe( diff --git a/src/typeclass/Contravariant.ts b/src/typeclass/Contravariant.ts index 311541de9..414bc890f 100644 --- a/src/typeclass/Contravariant.ts +++ b/src/typeclass/Contravariant.ts @@ -9,7 +9,7 @@ import type { Invariant } from "@fp-ts/core/typeclass/Invariant" * @since 1.0.0 */ export interface Contravariant extends Invariant { - contramap: ( + readonly contramap: ( f: (b: B) => A ) => (self: Kind) => Kind } diff --git a/src/typeclass/Coproduct.ts b/src/typeclass/Coproduct.ts index 32b21d429..fa611926c 100644 --- a/src/typeclass/Coproduct.ts +++ b/src/typeclass/Coproduct.ts @@ -11,9 +11,9 @@ import * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" * @since 1.0.0 */ export interface Coproduct extends SemiCoproduct { - zero: () => Kind + readonly zero: () => Kind - coproductAll: ( + readonly coproductAll: ( collection: Iterable> ) => Kind } diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index f0ad61716..d1200e9e4 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -9,7 +9,7 @@ import type { Invariant } from "@fp-ts/core/typeclass/Invariant" * @since 1.0.0 */ export interface Covariant extends Invariant { - map: ( + readonly map: ( f: (a: A) => B ) => (self: Kind) => Kind } diff --git a/src/typeclass/FlatMap.ts b/src/typeclass/FlatMap.ts index 12eb36bc1..6830e5946 100644 --- a/src/typeclass/FlatMap.ts +++ b/src/typeclass/FlatMap.ts @@ -9,7 +9,7 @@ import { identity, pipe } from "@fp-ts/core/internal/Function" * @since 1.0.0 */ export interface FlatMap extends TypeClass { - flatMap: ( + readonly flatMap: ( f: (a: A) => Kind ) => (self: Kind) => Kind } diff --git a/src/typeclass/Foldable.ts b/src/typeclass/Foldable.ts index 6e6e6b219..6b2744c7d 100644 --- a/src/typeclass/Foldable.ts +++ b/src/typeclass/Foldable.ts @@ -13,7 +13,7 @@ import type { Monoid } from "@fp-ts/core/typeclass/Monoid" * @since 1.0.0 */ export interface Foldable extends TypeClass { - reduce: ( + readonly reduce: ( b: B, f: (b: B, a: A) => B ) => (self: Kind) => B diff --git a/src/typeclass/Invariant.ts b/src/typeclass/Invariant.ts index fcc5842a0..c0c41dfba 100644 --- a/src/typeclass/Invariant.ts +++ b/src/typeclass/Invariant.ts @@ -8,7 +8,7 @@ import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" * @since 1.0.0 */ export interface Invariant extends TypeClass { - imap: ( + readonly imap: ( to: (a: A) => B, from: (b: B) => A ) => (self: Kind) => Kind @@ -38,7 +38,7 @@ export const bindTo = (F: Invariant) => name: N ): (( self: Kind - ) => Kind) => + ) => Kind) => F.imap(a => ({ [name]: a } as any), ({ [name]: a }) => a) /** @@ -46,5 +46,5 @@ export const bindTo = (F: Invariant) => */ export const tupled = ( F: Invariant -): ((self: Kind) => Kind) => - F.imap(a => [a], ([a]) => a) +): ((self: Kind) => Kind) => + F.imap(a => [a] as const, ([a]) => a) diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index 72b7bcc1a..160d0a8a9 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -10,8 +10,8 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" * @since 1.0.0 */ export interface Monoid extends Semigroup { - empty: A - combineAll: (collection: Iterable) => A + readonly empty: A + readonly combineAll: (collection: Iterable) => A } /** @@ -59,8 +59,8 @@ export const reverse = (M: Monoid): Monoid => fromSemigroup(semigroup.r * @since 1.0.0 */ export const struct = ( - monoids: { [K in keyof A]: Monoid } -): Monoid<{ [K in keyof A]: A[K] }> => { + monoids: { readonly [K in keyof A]: Monoid } +): Monoid<{ readonly [K in keyof A]: A[K] }> => { const empty: A = {} as any for (const k in monoids) { if (Object.prototype.hasOwnProperty.call(monoids, k)) { @@ -75,9 +75,9 @@ export const struct = ( * * @since 1.0.0 */ -export const tuple = >( +export const tuple = >( ...monoids: { [K in keyof A]: Monoid } -): Monoid => { +): Monoid> => { const empty: A = monoids.map((m) => m.empty) as any - return fromSemigroup(semigroup.tuple(...monoids), empty) + return fromSemigroup(semigroup.tuple(...monoids), empty) } diff --git a/src/typeclass/NonEmptyTraversable.ts b/src/typeclass/NonEmptyTraversable.ts index 467374e56..7ec2cdd34 100644 --- a/src/typeclass/NonEmptyTraversable.ts +++ b/src/typeclass/NonEmptyTraversable.ts @@ -13,7 +13,7 @@ import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" * @since 1.0.0 */ export interface NonEmptyTraversable extends TypeClass { - traverseNonEmpty: ( + readonly traverseNonEmpty: ( F: SemiApplicative ) => ( f: (a: A) => Kind @@ -21,7 +21,7 @@ export interface NonEmptyTraversable extends TypeClass self: Kind ) => Kind> - sequenceNonEmpty: ( + readonly sequenceNonEmpty: ( F: SemiApplicative ) => ( self: Kind> diff --git a/src/typeclass/Of.ts b/src/typeclass/Of.ts index 677ea1da9..e749399b3 100644 --- a/src/typeclass/Of.ts +++ b/src/typeclass/Of.ts @@ -8,7 +8,7 @@ import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" * @since 1.0.0 */ export interface Of extends TypeClass { - of: (a: A) => Kind + readonly of: (a: A) => Kind } /** diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 018c9dff0..e6a17b131 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -15,7 +15,7 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Order { - compare: (that: A) => (self: A) => -1 | 0 | 1 + readonly compare: (that: A) => (self: A) => -1 | 0 | 1 } /** @@ -23,7 +23,7 @@ export interface Order { * @since 1.0.0 */ export interface OrderTypeLambda extends TypeLambda { - type: Order + readonly type: Order } /** @@ -41,7 +41,7 @@ export const fromCompare = (compare: Order["compare"]): Order => ({ * * @since 1.0.0 */ -export const tuple = >( +export const tuple = >( ...orders: { [K in keyof A]: Order } ): Order> => fromCompare(that => diff --git a/src/typeclass/Product.ts b/src/typeclass/Product.ts index 20e62ade7..3ad68f9a5 100644 --- a/src/typeclass/Product.ts +++ b/src/typeclass/Product.ts @@ -11,21 +11,21 @@ import type { SemiProduct } from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Product extends SemiProduct, Of { - productAll: ( + readonly productAll: ( collection: Iterable> - ) => Kind> + ) => Kind> } /** * @since 1.0.0 */ export const tuple = (F: Product) => - >>(...components: T): Kind< + >>(...components: T): Kind< F, ([T[number]] extends [Kind] ? R : never), ([T[number]] extends [Kind] ? O : never), ([T[number]] extends [Kind] ? E : never), - { [I in keyof T]: [T[I]] extends [Kind] ? A : never } + Readonly<{ [I in keyof T]: [T[I]] extends [Kind] ? A : never }> > => F.productAll(components) as any /** @@ -37,7 +37,7 @@ export const struct = (F: Product) => ([R[keyof R]] extends [Kind] ? R : never), ([R[keyof R]] extends [Kind] ? O : never), ([R[keyof R]] extends [Kind] ? E : never), - { [K in keyof R]: [R[K]] extends [Kind] ? A : never } + { readonly [K in keyof R]: [R[K]] extends [Kind] ? A : never } > => { const keys = Object.keys(fields) return pipe( diff --git a/src/typeclass/SemiCoproduct.ts b/src/typeclass/SemiCoproduct.ts index 505be718e..d13d6e044 100644 --- a/src/typeclass/SemiCoproduct.ts +++ b/src/typeclass/SemiCoproduct.ts @@ -10,13 +10,13 @@ import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" * @since 1.0.0 */ export interface SemiCoproduct extends Invariant { - coproduct: ( + readonly coproduct: ( that: Kind ) => ( self: Kind ) => Kind - coproductMany: ( + readonly coproductMany: ( collection: Iterable> ) => (self: Kind) => Kind } diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 5e244c0f5..230c95a2e 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -12,15 +12,15 @@ import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" * @since 1.0.0 */ export interface SemiProduct extends Invariant { - product: ( + readonly product: ( that: Kind ) => ( self: Kind - ) => Kind + ) => Kind - productMany: ( + readonly productMany: ( collection: Iterable> - ) => (self: Kind) => Kind]> + ) => (self: Kind) => Kind]> } /** @@ -42,7 +42,7 @@ export const productComposition = ( FR1 & FR2, FO1 | FO2, FE1 | FE2, - Kind + Kind > => pipe(self, F.product(that), F.map(([ga, gb]) => pipe(ga, G.product(gb)))) /** @@ -59,7 +59,7 @@ export const productManyComposition = ( self: Kind> - ): Kind]>> => + ): Kind]>> => pipe( self, F.productMany(collection), @@ -82,13 +82,13 @@ export const productMany = ( (self: Kind) => { let out = pipe( self, - Covariant.map((a): [A, ...Array] => [a]) + Covariant.map((a): readonly [A, ...Array] => [a]) ) for (const fa of collection) { out = pipe( out, product(fa), - Covariant.map(([[head, ...tail], a]): [A, ...Array] => [head, ...tail, a]) + Covariant.map(([[head, ...tail], a]): readonly [A, ...Array] => [head, ...tail, a]) ) } return out @@ -109,7 +109,7 @@ export const andThenBind = (F: SemiProduct) => R1 & R2, O1 | O2, E1 | E2, - { [K in keyof A | N]: K extends keyof A ? A[K] : B } + { readonly [K in keyof A | N]: K extends keyof A ? A[K] : B } > => pipe( self, @@ -127,27 +127,27 @@ export const productFlatten = (F: SemiProduct) => ( that: Kind ) => - >( + >( self: Kind - ): Kind => + ): Kind => pipe( self, F.product(that), - F.imap(([a, b]) => [...a, b], ab => [ab.slice(0, -1), ab[ab.length - 1]] as any) + F.imap(([a, b]) => [...a, b] as const, ab => [ab.slice(0, -1), ab[ab.length - 1]] as any) ) /** * @since 1.0.0 */ export const nonEmptyTuple = (F: SemiProduct) => - , ...Array>]>( + , ...Array>]>( ...components: T ): Kind< F, ([T[number]] extends [Kind] ? R : never), ([T[number]] extends [Kind] ? O : never), ([T[number]] extends [Kind] ? E : never), - { [I in keyof T]: [T[I]] extends [Kind] ? A : never } + Readonly<{ [I in keyof T]: [T[I]] extends [Kind] ? A : never }> > => F.productMany(components.slice(1))(components[0]) as any type EnforceNonEmptyRecord = keyof R extends never ? never : R @@ -156,14 +156,14 @@ type EnforceNonEmptyRecord = keyof R extends never ? never : R * @since 1.0.0 */ export const nonEmptyStruct = (F: SemiProduct) => - >>( + >>>( fields: EnforceNonEmptyRecord & Record> ): Kind< F, ([R[keyof R]] extends [Kind] ? R : never), ([R[keyof R]] extends [Kind] ? O : never), ([R[keyof R]] extends [Kind] ? E : never), - { [K in keyof R]: [R[K]] extends [Kind] ? A : never } + { readonly [K in keyof R]: [R[K]] extends [Kind] ? A : never } > => { const keys = Object.keys(fields) return pipe( diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index fe04ef7d1..fe0b3a8f1 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -32,8 +32,8 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Semigroup { - combine: (that: A) => (self: A) => A - combineMany: (collection: Iterable) => (self: A) => A + readonly combine: (that: A) => (self: A) => A + readonly combineMany: (collection: Iterable) => (self: A) => A } /** @@ -41,7 +41,7 @@ export interface Semigroup { * @since 1.0.0 */ export interface SemigroupTypeLambda extends TypeLambda { - type: Semigroup + readonly type: Semigroup } /** @@ -112,7 +112,7 @@ export const reverse = (S: Semigroup): Semigroup => ({ */ export const struct = (semigroups: { [K in keyof A]: Semigroup }): Semigroup< { - [K in keyof A]: A[K] + readonly [K in keyof A]: A[K] } > => fromCombine((that) => @@ -132,9 +132,9 @@ export const struct = (semigroups: { [K in keyof A]: Semigroup }): Semi * * @since 1.0.0 */ -export const tuple = >( +export const tuple = >( ...semigroups: { [K in keyof A]: Semigroup } -): Semigroup => +): Semigroup> => fromCombine((that) => (self) => semigroups.map((S, i) => S.combine(that[i])(self[i])) as any) /** diff --git a/src/typeclass/Traversable.ts b/src/typeclass/Traversable.ts index 73e522e4a..91b386a98 100644 --- a/src/typeclass/Traversable.ts +++ b/src/typeclass/Traversable.ts @@ -11,13 +11,13 @@ import type { Covariant } from "@fp-ts/core/typeclass/Covariant" * @since 1.0.0 */ export interface Traversable extends TypeClass { - traverse: ( + readonly traverse: ( F: Applicative ) => ( f: (a: A) => Kind ) => (self: Kind) => Kind> - sequence: (F: Applicative) => ( + readonly sequence: (F: Applicative) => ( self: Kind> ) => Kind> } diff --git a/test/data/Either.ts b/test/data/Either.ts index bf121aca4..643702a48 100644 --- a/test/data/Either.ts +++ b/test/data/Either.ts @@ -4,19 +4,19 @@ import * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" export interface Left { - _tag: "Left" - left: E + readonly _tag: "Left" + readonly left: E } export interface Right { - _tag: "Right" - right: A + readonly _tag: "Right" + readonly right: A } export type Either = Left | Right export interface EitherTypeLambda extends TypeLambda { - type: Either + readonly type: Either } export const left = (e: E): Either => ({ _tag: "Left", left: e }) diff --git a/test/data/NonEmptyArray.ts b/test/data/NonEmptyArray.ts index 795df3cef..02b536784 100644 --- a/test/data/NonEmptyArray.ts +++ b/test/data/NonEmptyArray.ts @@ -1,63 +1,3 @@ -import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import { identity, pipe } from "@fp-ts/core/internal/Function" -import * as covariant from "@fp-ts/core/typeclass/Covariant" -import type * as nonEmptyTraversable from "@fp-ts/core/typeclass/NonEmptyTraversable" -import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" - -export type NonEmptyArray = [A, ...Array] - -export interface NonEmptyArrayTypeLambda extends TypeLambda { - type: NonEmptyArray -} - export const make = ( ...as: [A, ...Array] ): [A, ...Array] => as - -export const isNonEmpty = (self: Array): self is [A, ...Array] => self.length > 0 - -export const head = (as: [A, ...Array]): A => as[0] -export const tail = (as: [A, ...Array]): Array => as.slice(1) - -export const mapWithIndex = ( - f: (a: A, i: number) => B -) => - (self: NonEmptyArray): NonEmptyArray => { - const out: [B, ...Array] = [f(head(self), 0)] - for (let i = 1; i < self.length; i++) { - out.push(f(self[i], i)) - } - return out - } - -export const map = ( - f: (a: A) => B -): (self: NonEmptyArray) => NonEmptyArray => mapWithIndex(f) - -export const traverseWithIndex = ( - F: SemiApplicative -) => - (f: (a: A, i: number) => Kind) => - (self: NonEmptyArray): Kind> => { - const fbs = pipe(self, mapWithIndex(f)) - return pipe( - head(fbs), - F.productMany(tail(fbs)) - ) - } - -export const traverseNonEmpty = ( - F: SemiApplicative -) => - ( - f: (a: A) => Kind - ): ((self: NonEmptyArray) => Kind>) => traverseWithIndex(F)(f) - -export const Covariant: covariant.Covariant = covariant.make(map) - -export const NonEmptyTraversable: nonEmptyTraversable.NonEmptyTraversable< - NonEmptyArrayTypeLambda -> = { - traverseNonEmpty, - sequenceNonEmpty: F => self => pipe(self, traverseNonEmpty(F)(identity)) -} diff --git a/test/data/NonEmptyReadonlyArray.ts b/test/data/NonEmptyReadonlyArray.ts new file mode 100644 index 000000000..775a2c355 --- /dev/null +++ b/test/data/NonEmptyReadonlyArray.ts @@ -0,0 +1,69 @@ +import type { Kind, TypeLambda } from "@fp-ts/core/HKT" +import { identity, pipe } from "@fp-ts/core/internal/Function" +import * as covariant from "@fp-ts/core/typeclass/Covariant" +import type * as nonEmptyTraversable from "@fp-ts/core/typeclass/NonEmptyTraversable" +import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" + +/** + * @category models + * @since 1.0.0 + */ +export type NonEmptyReadonlyArray = readonly [A, ...ReadonlyArray] + +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface NonEmptyReadonlyArrayTypeLambda extends TypeLambda { + readonly type: NonEmptyReadonlyArray +} + +export const isNonEmpty = (self: ReadonlyArray): self is readonly [A, ...ReadonlyArray] => + self.length > 0 + +export const head = (as: readonly [A, ...ReadonlyArray]): A => as[0] +export const tail = (as: readonly [A, ...ReadonlyArray]): ReadonlyArray => as.slice(1) + +export const mapWithIndex = ( + f: (a: A, i: number) => B +) => + (self: NonEmptyReadonlyArray): NonEmptyReadonlyArray => { + const out: [B, ...Array] = [f(head(self), 0)] + for (let i = 1; i < self.length; i++) { + out.push(f(self[i], i)) + } + return out + } + +export const map = ( + f: (a: A) => B +): (self: NonEmptyReadonlyArray) => NonEmptyReadonlyArray => mapWithIndex(f) + +export const traverseWithIndex = ( + F: SemiApplicative +) => + (f: (a: A, i: number) => Kind) => + (self: NonEmptyReadonlyArray): Kind> => { + const fbs = pipe(self, mapWithIndex(f)) + return pipe( + head(fbs), + F.productMany(tail(fbs)) + ) + } + +export const traverseNonEmpty = ( + F: SemiApplicative +) => + ( + f: (a: A) => Kind + ): ((self: NonEmptyReadonlyArray) => Kind>) => + traverseWithIndex(F)(f) + +export const Covariant: covariant.Covariant = covariant.make(map) + +export const NonEmptyTraversable: nonEmptyTraversable.NonEmptyTraversable< + NonEmptyReadonlyArrayTypeLambda +> = { + traverseNonEmpty, + sequenceNonEmpty: F => self => pipe(self, traverseNonEmpty(F)(identity)) +} diff --git a/test/data/Option.ts b/test/data/Option.ts index cbb01753d..c3890a22f 100644 --- a/test/data/Option.ts +++ b/test/data/Option.ts @@ -36,24 +36,25 @@ import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" import type * as foldableWithIndex from "../limbo/FoldableWithIndex" import * as nonEmptyArray from "./NonEmptyArray" +import * as nonEmptyReadonlyArray from "./NonEmptyReadonlyArray" export interface LazyArg { (): A } export interface None { - _tag: "None" + readonly _tag: "None" } export interface Some { - _tag: "Some" - value: A + readonly _tag: "Some" + readonly value: A } export type Option = None | Some export interface OptionTypeLambda extends TypeLambda { - type: Option + readonly type: Option } export const isNone = (fa: Option): fa is None => fa._tag === "None" @@ -85,7 +86,7 @@ export const fromThrowable = (f: () => A): Option => { } } -export const liftThrowable = , B>( +export const liftThrowable = , B>( f: (...a: A) => B ): ((...a: A) => Option) => (...a) => fromThrowable(() => f(...a)) @@ -512,9 +513,9 @@ export const Product: product.Product = { ...Of, productAll: collection => { const as = Array.from(collection) - return nonEmptyArray.isNonEmpty(as) ? - SemiApplicative.productMany(nonEmptyArray.tail(as))( - nonEmptyArray.head(as) + return nonEmptyReadonlyArray.isNonEmpty(as) ? + SemiApplicative.productMany(nonEmptyReadonlyArray.tail(as))( + nonEmptyReadonlyArray.head(as) ) : some([]) } @@ -543,9 +544,9 @@ export const Monad: monad.Monad = { * @category conversions * @since 1.0.0 */ -export const toArray = ( +export const toReadonlyArray = ( self: Option -): Array => (isNone(self) ? [] : [self.value]) +): ReadonlyArray => (isNone(self) ? [] : [self.value]) /** * @category folding @@ -641,13 +642,13 @@ export const Do: Option<{}> = some({}) */ export const bindTo: ( name: N -) => (self: Option) => Option<{ [K in N]: A }> = invariant.bindTo(Invariant) +) => (self: Option) => Option<{ readonly [K in N]: A }> = invariant.bindTo(Invariant) const let_: ( name: Exclude, f: (a: A) => B -) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant - .let(Covariant) +) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = + covariant.let(Covariant) export { let_ as let } @@ -658,8 +659,8 @@ export { let_ as let } export const bind: ( name: Exclude, f: (a: A) => Option -) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable - .bind(Chainable) +) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = + chainable.bind(Chainable) /** * A variant of `bind` that sequentially ignores the scope. @@ -670,8 +671,8 @@ export const bind: ( export const andThenBind: ( name: Exclude, fb: Option -) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct - .andThenBind(SemiApplicative) +) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = + semiProduct.andThenBind(SemiApplicative) // ------------------------------------------------------------------------------------- // tuple sequencing @@ -681,12 +682,12 @@ export const andThenBind: ( * @category tuple sequencing * @since 1.0.0 */ -export const Zip: Option<[]> = some([]) +export const Zip: Option = some([]) /** * @since 1.0.0 */ -export const tupled: (self: Option) => Option<[A]> = invariant.tupled(Invariant) +export const tupled: (self: Option) => Option = invariant.tupled(Invariant) /** * Sequentially zips this effect with the specified effect. @@ -696,5 +697,5 @@ export const tupled: (self: Option) => Option<[A]> = invariant.tupled(Inva */ export const productFlatten: ( fb: Option -) => >(self: Option) => Option<[...A, B]> = semiProduct +) => >(self: Option) => Option = semiProduct .productFlatten(SemiProduct) diff --git a/test/data/Predicate.ts b/test/data/Predicate.ts index 1b2964337..872b8bd0a 100644 --- a/test/data/Predicate.ts +++ b/test/data/Predicate.ts @@ -10,7 +10,7 @@ export interface Predicate { } export interface PredicateTypeLambda extends TypeLambda { - type: Predicate + readonly type: Predicate } export const contramap = (f: (b: B) => A) => @@ -72,12 +72,12 @@ export const andThenBind: ( fb: Predicate ) => ( self: Predicate -) => Predicate<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct +) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct .andThenBind( SemiProduct ) -export const tupled: (self: Predicate) => Predicate<[A]> = invariant.tupled( +export const tupled: (self: Predicate) => Predicate = invariant.tupled( Invariant ) diff --git a/test/data/Array.ts b/test/data/ReadonlyArray.ts similarity index 59% rename from test/data/Array.ts rename to test/data/ReadonlyArray.ts index a62784d77..a11bea077 100644 --- a/test/data/Array.ts +++ b/test/data/ReadonlyArray.ts @@ -11,24 +11,25 @@ import type * as traverse_ from "@fp-ts/core/typeclass/Traversable" import type * as covariantWithIndex from "../limbo/CovariantWithIndex" import * as foldableWithIndex from "../limbo/FoldableWithIndex" import type * as traversableWithIndex from "../limbo/TraversableWithIndex" -import type { NonEmptyArray } from "./NonEmptyArray" -import * as nonEmptyArray from "./NonEmptyArray" +import type { NonEmptyReadonlyArray } from "./NonEmptyReadonlyArray" +import * as nonEmptyReadonlyArray from "./NonEmptyReadonlyArray" import * as O from "./Option" import type { Option } from "./Option" -export interface ArrayTypeLambda extends TypeLambda { - type: Array +export interface ReadonlyArrayTypeLambda extends TypeLambda { + readonly type: ReadonlyArray } -export const map = (f: (a: A) => B) => (self: Array): Array => self.map(a => f(a)) +export const map = (f: (a: A) => B) => + (self: ReadonlyArray): ReadonlyArray => self.map(a => f(a)) export const mapWithIndex = (f: (a: A, i: number) => B) => - (self: Array): Array => self.map((a, i) => f(a, i)) + (self: ReadonlyArray): ReadonlyArray => self.map((a, i) => f(a, i)) -export const Covariant: covariant.Covariant = covariant.make(map) +export const Covariant: covariant.Covariant = covariant.make(map) export const CovariantWithIndex: covariantWithIndex.CovariantWithIndex< - ArrayTypeLambda, + ReadonlyArrayTypeLambda, number > = { mapWithIndex: (f) => (self) => self.map((a, i) => f(a, i)) @@ -37,50 +38,51 @@ export const CovariantWithIndex: covariantWithIndex.CovariantWithIndex< export const reduceWithIndex = ( b: B, f: (b: B, a: A, i: number) => B -) => (self: Array) => self.reduce((b, a, i) => f(b, a, i), b) +) => (self: ReadonlyArray) => self.reduce((b, a, i) => f(b, a, i), b) export const reduceRightWithIndex = (b: B, f: (b: B, a: A, i: number) => B) => - (self: Array): B => self.reduceRight((b, a, i) => f(b, a, i), b) + (self: ReadonlyArray): B => self.reduceRight((b, a, i) => f(b, a, i), b) export const FoldableWithIndex: foldableWithIndex.FoldableWithIndex< - ArrayTypeLambda, + ReadonlyArrayTypeLambda, number > = { reduceWithIndex, reduceRightWithIndex } -export const Foldable: foldable.Foldable = { +export const Foldable: foldable.Foldable = { reduce: foldableWithIndex.reduce(FoldableWithIndex) } -export const isNonEmpty: (self: Array) => self is NonEmptyArray = nonEmptyArray.isNonEmpty +export const isNonEmpty: (self: ReadonlyArray) => self is NonEmptyReadonlyArray = + nonEmptyReadonlyArray.isNonEmpty export const head = ( - self: Array + self: ReadonlyArray ): O.Option => (isNonEmpty(self) ? O.some(self[0]) : O.none) export const sort = (Compare: Order) => - (as: Array): Array => + (as: ReadonlyArray): ReadonlyArray => as.length <= 1 ? as : as.slice().sort((a1, a2) => Compare.compare(a2)(a1)) export function concat( - that: NonEmptyArray -): (self: Array) => NonEmptyArray + that: NonEmptyReadonlyArray +): (self: ReadonlyArray) => NonEmptyReadonlyArray export function concat( - that: Array -): (self: NonEmptyArray) => NonEmptyArray + that: ReadonlyArray +): (self: NonEmptyReadonlyArray) => NonEmptyReadonlyArray export function concat( - that: Array -): (self: NonEmptyArray) => Array { - return (self: NonEmptyArray) => self.concat(that) + that: ReadonlyArray +): (self: NonEmptyReadonlyArray) => ReadonlyArray { + return (self: NonEmptyReadonlyArray) => self.concat(that) } export const traverseWithIndex = ( Applicative: applicative.Applicative ) => (f: (a: A, i: number) => Kind) => - (self: Iterable): Kind> => { + (self: Iterable): Kind> => { const fbs: Array> = [] let i = 0 for (const a of self) { @@ -94,23 +96,24 @@ export const traverse = ( ) => ( f: (a: A) => Kind - ): (self: Array) => Kind> => traverseWithIndex(Applicative)(f) + ): (self: ReadonlyArray) => Kind> => + traverseWithIndex(Applicative)(f) -export const Traversable: traverse_.Traversable = { +export const Traversable: traverse_.Traversable = { traverse, sequence: F => self => pipe(self, traverse(F)(identity)) } export const TraversableWithIndex: traversableWithIndex.TraversableWithIndex< - ArrayTypeLambda, + ReadonlyArrayTypeLambda, number > = { traverseWithIndex } -export const product = (that: Array) => - (self: Array): Array<[A, B]> => { - const out: Array<[A, B]> = [] +export const product = (that: ReadonlyArray) => + (self: ReadonlyArray): ReadonlyArray => { + const out: Array = [] for (const a of self) { for (const b of that) { out.push([a, b]) @@ -119,23 +122,23 @@ export const product = (that: Array) => return out } -export const Of: of_.Of = { +export const Of: of_.Of = { of: a => [a] } -const SemiProduct: semiProduct.SemiProduct = { +const SemiProduct: semiProduct.SemiProduct = { imap: Covariant.imap, product, productMany: semiProduct.productMany(Covariant, product) } -export const SemiApplicative: semiApplicative.SemiApplicative = { +export const SemiApplicative: semiApplicative.SemiApplicative = { ...Covariant, ...SemiProduct } export const filterMapWithIndex = (f: (a: A, i: number) => Option) => - (fa: Array): Array => { + (fa: ReadonlyArray): ReadonlyArray => { const out: Array = [] for (let i = 0; i < fa.length; i++) { const optionB = f(fa[i], i) diff --git a/test/index.ts b/test/index.ts index beca8ca60..a4954f336 100644 --- a/test/index.ts +++ b/test/index.ts @@ -10,7 +10,7 @@ const getExportName = (name: string): string => { return name.substring(0, 1).toLowerCase() + name.substring(1) } -function getModuleNames(): Array { +function getModuleNames(): ReadonlyArray { return glob .sync("./src/**/*.ts") .map((file) => path.parse(file)) diff --git a/test/limbo/Category.ts b/test/limbo/Category.ts index d9d996f32..7c9fcbc7f 100644 --- a/test/limbo/Category.ts +++ b/test/limbo/Category.ts @@ -9,5 +9,5 @@ import type { Composable } from "./Composable" * @since 1.0.0 */ export interface Category extends Composable { - identity: () => Kind + readonly identity: () => Kind } diff --git a/test/limbo/Comonad.ts b/test/limbo/Comonad.ts index 262fdaca6..25ff5878b 100644 --- a/test/limbo/Comonad.ts +++ b/test/limbo/Comonad.ts @@ -9,5 +9,5 @@ import type { Extendable } from "@fp-ts/core/test/limbo/Extendable" * @since 1.0.0 */ export interface Comonad extends Extendable { - extract: (self: Kind) => A + readonly extract: (self: Kind) => A } diff --git a/test/limbo/Composable.ts b/test/limbo/Composable.ts index 368bcf853..add9c9425 100644 --- a/test/limbo/Composable.ts +++ b/test/limbo/Composable.ts @@ -8,7 +8,7 @@ import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" * @since 1.0.0 */ export interface Composable extends TypeClass { - compose: ( + readonly compose: ( bc: Kind ) => (ab: Kind) => Kind } diff --git a/test/limbo/CovariantWithIndex.ts b/test/limbo/CovariantWithIndex.ts index 55558f209..0f271d061 100644 --- a/test/limbo/CovariantWithIndex.ts +++ b/test/limbo/CovariantWithIndex.ts @@ -10,7 +10,7 @@ import type { Covariant } from "@fp-ts/core/typeclass/Covariant" * @since 1.0.0 */ export interface CovariantWithIndex extends TypeClass { - mapWithIndex: ( + readonly mapWithIndex: ( f: (a: A, i: I) => B ) => (self: Kind) => Kind } @@ -24,7 +24,7 @@ export const mapWithIndexComposition = , G: CovariantWithIndex ): (( - f: (a: A, ij: [I, J]) => B + f: (a: A, ij: readonly [I, J]) => B ) => ( self: Kind> ) => Kind>) => diff --git a/test/limbo/Extendable.ts b/test/limbo/Extendable.ts index 87998e93d..f014220c6 100644 --- a/test/limbo/Extendable.ts +++ b/test/limbo/Extendable.ts @@ -9,7 +9,7 @@ import type { Covariant } from "@fp-ts/core/typeclass/Covariant" * @since 1.0.0 */ export interface Extendable extends Covariant { - extend: ( + readonly extend: ( f: (self: Kind) => B ) => (self: Kind) => Kind } diff --git a/test/limbo/FoldableWithIndex.ts b/test/limbo/FoldableWithIndex.ts index b3df76314..bb9df3470 100644 --- a/test/limbo/FoldableWithIndex.ts +++ b/test/limbo/FoldableWithIndex.ts @@ -12,12 +12,12 @@ import type { Monoid } from "@fp-ts/core/typeclass/Monoid" * @since 1.0.0 */ export interface FoldableWithIndex extends TypeClass { - reduceWithIndex: ( + readonly reduceWithIndex: ( b: B, f: (b: B, a: A, i: I) => B ) => (self: Kind) => B - reduceRightWithIndex: ( + readonly reduceRightWithIndex: ( b: B, f: (b: B, a: A, i: I) => B ) => (self: Kind) => B @@ -32,7 +32,7 @@ export const reduceWithIndexComposition = , G: FoldableWithIndex ) => - (b: B, f: (b: B, a: A, ij: [I, J]) => B) => + (b: B, f: (b: B, a: A, ij: readonly [I, J]) => B) => ( self: Kind> ): B => @@ -51,7 +51,7 @@ export const reduceRightWithIndexComposition = , G: FoldableWithIndex ) => - (b: B, f: (b: B, a: A, ij: [I, J]) => B) => + (b: B, f: (b: B, a: A, ij: readonly [I, J]) => B) => ( self: Kind> ): B => diff --git a/test/limbo/TraversableWithIndex.ts b/test/limbo/TraversableWithIndex.ts index abfd2e170..009e5ec52 100644 --- a/test/limbo/TraversableWithIndex.ts +++ b/test/limbo/TraversableWithIndex.ts @@ -10,7 +10,7 @@ import type { Traversable } from "@fp-ts/core/typeclass/Traversable" * @since 1.0.0 */ export interface TraversableWithIndex extends TypeClass { - traverseWithIndex: ( + readonly traverseWithIndex: ( F: Applicative ) => ( f: (a: A, i: I) => Kind @@ -30,7 +30,7 @@ export const traverseWithIndexComposition = (H: Applicative) => ( - f: (a: A, ij: [I, J]) => Kind + f: (a: A, ij: readonly [I, J]) => Kind ): (( fga: Kind> ) => Kind>>) => diff --git a/test/typeclass/Bicovariant.ts b/test/typeclass/Bicovariant.ts index a7ed13974..712cf4352 100644 --- a/test/typeclass/Bicovariant.ts +++ b/test/typeclass/Bicovariant.ts @@ -1,8 +1,8 @@ import { pipe } from "@fp-ts/core/internal/Function" import * as _ from "@fp-ts/core/typeclass/Bicovariant" -import * as RA from "../data/Array" import type { EitherTypeLambda } from "../data/Either" import * as E from "../data/Either" +import * as RA from "../data/ReadonlyArray" import * as U from "../util" export const Bicovariant: _.Bicovariant = { diff --git a/test/typeclass/Covariant.ts b/test/typeclass/Covariant.ts index 5acb38599..d5536d69e 100644 --- a/test/typeclass/Covariant.ts +++ b/test/typeclass/Covariant.ts @@ -1,7 +1,7 @@ import { pipe } from "@fp-ts/core/internal/Function" import * as _ from "@fp-ts/core/typeclass/Covariant" -import * as RA from "../data/Array" import * as O from "../data/Option" +import * as RA from "../data/ReadonlyArray" import * as U from "../util" describe("Covariant", () => { diff --git a/test/typeclass/CovariantWithIndex.ts b/test/typeclass/CovariantWithIndex.ts index 7a8373fd0..c2f630bfb 100644 --- a/test/typeclass/CovariantWithIndex.ts +++ b/test/typeclass/CovariantWithIndex.ts @@ -1,12 +1,12 @@ import { pipe } from "@fp-ts/core/internal/Function" -import * as RA from "../data/Array" +import * as RA from "../data/ReadonlyArray" import * as _ from "../limbo/CovariantWithIndex" import * as U from "../util" describe("FunctorWithIndex", () => { it("mapWithIndexComposition", () => { const mapWithIndex = _.mapWithIndexComposition(RA.CovariantWithIndex, RA.CovariantWithIndex) - const f = (a: string, [i, j]: [number, number]) => a + i + j + const f = (a: string, [i, j]: readonly [number, number]) => a + i + j U.deepStrictEqual(pipe([], mapWithIndex(f)), []) U.deepStrictEqual(pipe([[]], mapWithIndex(f)), [[]]) U.deepStrictEqual(pipe([["a"]], mapWithIndex(f)), [["a00"]]) diff --git a/test/typeclass/Foldable.ts b/test/typeclass/Foldable.ts index fc85286f7..a25a5458f 100644 --- a/test/typeclass/Foldable.ts +++ b/test/typeclass/Foldable.ts @@ -1,8 +1,8 @@ import { pipe } from "@fp-ts/core/internal/Function" import * as _ from "@fp-ts/core/typeclass/Foldable" -import * as RA from "../data/Array" import * as number from "../data/number" import * as O from "../data/Option" +import * as RA from "../data/ReadonlyArray" import * as U from "../util" describe("Foldable", () => { diff --git a/test/typeclass/FoldableWithIndex.ts b/test/typeclass/FoldableWithIndex.ts index c969f6e94..622781423 100644 --- a/test/typeclass/FoldableWithIndex.ts +++ b/test/typeclass/FoldableWithIndex.ts @@ -1,7 +1,7 @@ import { pipe } from "@fp-ts/core/internal/Function" -import * as RA from "../data/Array" import * as number from "../data/number" import * as O from "../data/Option" +import * as RA from "../data/ReadonlyArray" import * as foldableWithIndex from "../limbo/FoldableWithIndex" import * as U from "../util" @@ -11,7 +11,7 @@ describe("FoldableWithIndex", () => { RA.FoldableWithIndex, RA.FoldableWithIndex ) - const f = (b: string, a: string, [i, j]: [number, number]) => b + a + i + j + const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j U.deepStrictEqual(pipe([], reduceWithIndex("-", f)), "-") U.deepStrictEqual(pipe([[]], reduceWithIndex("-", f)), "-") U.deepStrictEqual( @@ -25,7 +25,7 @@ describe("FoldableWithIndex", () => { RA.FoldableWithIndex, RA.FoldableWithIndex ) - const f = (b: string, a: string, [i, j]: [number, number]) => b + a + i + j + const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j U.deepStrictEqual(pipe([], reduceRightWithIndex("-", f)), "-") U.deepStrictEqual(pipe([[]], reduceRightWithIndex("-", f)), "-") U.deepStrictEqual( @@ -35,16 +35,16 @@ describe("FoldableWithIndex", () => { }) it("toArray", () => { - const toArray = foldableWithIndex.toArray(O.FoldableWithIndex) - U.deepStrictEqual(toArray(O.none), []) - U.deepStrictEqual(toArray(O.some(2)), [2]) + const toReadonlyArray = foldableWithIndex.toArray(O.FoldableWithIndex) + U.deepStrictEqual(toReadonlyArray(O.none), []) + U.deepStrictEqual(toReadonlyArray(O.some(2)), [2]) }) it("toArrayWith", () => { - const toArrayWith = foldableWithIndex.toArrayWith(O.FoldableWithIndex) - U.deepStrictEqual(pipe(O.none, toArrayWith(U.double)), []) - U.deepStrictEqual(pipe(O.some(2), toArrayWith(U.double)), [4]) - U.deepStrictEqual(pipe(O.some(2), toArrayWith((a, i) => U.double(a) * i)), [0]) + const toReadonlyArrayWith = foldableWithIndex.toArrayWith(O.FoldableWithIndex) + U.deepStrictEqual(pipe(O.none, toReadonlyArrayWith(U.double)), []) + U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith(U.double)), [4]) + U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith((a, i) => U.double(a) * i)), [0]) }) it("foldMapWithIndex", () => { diff --git a/test/typeclass/Invariant.ts b/test/typeclass/Invariant.ts index bc3604b6f..2c20678b1 100644 --- a/test/typeclass/Invariant.ts +++ b/test/typeclass/Invariant.ts @@ -9,13 +9,13 @@ import * as U from "../util" describe("Invariant", () => { it("imapComposition", () => { const imap = _.imapComposition(semigroup.Invariant, O.Invariant) - const S = pipe(O.getMonoid(string.Semigroup), imap(s => [s], ([s]) => s)) + const S = pipe(O.getMonoid(string.Semigroup), imap(s => [s] as const, ([s]) => s)) U.deepStrictEqual(pipe(O.none, S.combine(O.none)), O.none) - U.deepStrictEqual(pipe(O.none, S.combine(O.some(["b"]))), O.some(["b"])) - U.deepStrictEqual(pipe(O.some(["a"]), S.combine(O.none)), O.some(["a"])) + U.deepStrictEqual(pipe(O.none, S.combine(O.some(["b"]))), O.some(["b"] as const)) + U.deepStrictEqual(pipe(O.some(["a"] as const), S.combine(O.none)), O.some(["a"] as const)) U.deepStrictEqual( - pipe(O.some(["a"]), S.combine(O.some(["b"]))), - O.some(["ab"]) + pipe(O.some(["a"] as const), S.combine(O.some(["b"]))), + O.some(["ab"] as const) ) }) @@ -38,7 +38,7 @@ describe("Invariant", () => { it("Covariant (Option)", () => { const tupled = _.tupled(O.Invariant) U.deepStrictEqual(pipe(O.none, tupled), O.none) - U.deepStrictEqual(pipe(O.some(1), tupled), O.some([1])) + U.deepStrictEqual(pipe(O.some(1), tupled), O.some([1] as const)) }) it("Contravariant (Predicate)", () => { diff --git a/test/typeclass/NonEmptyTraversable.ts b/test/typeclass/NonEmptyTraversable.ts index 4fa188e8c..ce901b412 100644 --- a/test/typeclass/NonEmptyTraversable.ts +++ b/test/typeclass/NonEmptyTraversable.ts @@ -1,5 +1,5 @@ import * as _ from "@fp-ts/core/typeclass/NonEmptyTraversable" -import * as NERA from "../data/NonEmptyArray" +import * as NERA from "../data/NonEmptyReadonlyArray" import * as O from "../data/Option" import * as U from "../util" @@ -9,9 +9,9 @@ describe("NonEmptyTraversable", () => { NERA.NonEmptyTraversable, NERA.NonEmptyTraversable )(O.SemiApplicative)((n: number) => (n > 0 ? O.some(n) : O.none)) - U.deepStrictEqual(traverseNonEmpty([[1]]), O.some([[1]])) + U.deepStrictEqual(traverseNonEmpty([[1]]), O.some([[1]] as const)) U.deepStrictEqual(traverseNonEmpty([[1, -1]]), O.none) - U.deepStrictEqual(traverseNonEmpty([[1, 2, 3], [4, 5]]), O.some([[1, 2, 3], [4, 5]])) + U.deepStrictEqual(traverseNonEmpty([[1, 2, 3], [4, 5]]), O.some([[1, 2, 3], [4, 5]] as const)) U.deepStrictEqual(traverseNonEmpty([[1, 2, 3], [4, -1]]), O.none) }) @@ -20,23 +20,23 @@ describe("NonEmptyTraversable", () => { { ...NERA.NonEmptyTraversable, ...NERA.Covariant }, NERA.NonEmptyTraversable )(O.SemiApplicative) - U.deepStrictEqual(sequence([[O.some(1)]]), O.some([[1]])) + U.deepStrictEqual(sequence([[O.some(1)]]), O.some([[1]] as const)) U.deepStrictEqual(sequence([[O.some(1), O.none]]), O.none) U.deepStrictEqual( sequence([[O.some(1), O.some(2), O.some(3)], [O.some(4), O.some(5)]]), - O.some([[1, 2, 3], [4, 5]]) + O.some([[1, 2, 3], [4, 5]] as const) ) U.deepStrictEqual(sequence([[O.some(1), O.some(2), O.some(3)], [O.some(4), O.none]]), O.none) }) it("sequenceNonEmpty", () => { - const sequenceNonEmpty = _.sequenceNonEmpty( + const sequenceNonEmpty = _.sequenceNonEmpty( NERA.NonEmptyTraversable.traverseNonEmpty )(O.SemiApplicative) U.deepStrictEqual(sequenceNonEmpty([O.none]), O.none) - U.deepStrictEqual(sequenceNonEmpty([O.some(1)]), O.some([1])) + U.deepStrictEqual(sequenceNonEmpty([O.some(1)]), O.some([1] as const)) U.deepStrictEqual(sequenceNonEmpty([O.none]), O.none) U.deepStrictEqual(sequenceNonEmpty([O.some(1), O.none]), O.none) - U.deepStrictEqual(sequenceNonEmpty([O.some(1), O.some(2)]), O.some([1, 2])) + U.deepStrictEqual(sequenceNonEmpty([O.some(1), O.some(2)]), O.some([1, 2] as const)) }) }) diff --git a/test/typeclass/Of.ts b/test/typeclass/Of.ts index bc0e67350..8fb357fdd 100644 --- a/test/typeclass/Of.ts +++ b/test/typeclass/Of.ts @@ -1,6 +1,6 @@ import * as _ from "@fp-ts/core/typeclass/Of" -import * as RA from "../data/Array" import * as O from "../data/Option" +import * as RA from "../data/ReadonlyArray" import * as U from "../util" describe("Of", () => { diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index 470675b9a..382b3d9df 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -1,8 +1,8 @@ import { pipe } from "@fp-ts/core/internal/Function" import * as _ from "@fp-ts/core/typeclass/Order" -import { sort } from "../data/Array" import * as boolean from "../data/boolean" import * as number from "../data/number" +import { sort } from "../data/ReadonlyArray" import * as string from "../data/string" import * as U from "../util" diff --git a/test/typeclass/Product.ts b/test/typeclass/Product.ts index 6ead09f53..787a127b6 100644 --- a/test/typeclass/Product.ts +++ b/test/typeclass/Product.ts @@ -11,11 +11,11 @@ describe("Product", () => { describe("tuple", () => { it("Covariant (Option)", () => { const tuple = _.tuple(O.Product) - U.deepStrictEqual(tuple(), O.some([])) - U.deepStrictEqual(tuple(O.some("a")), O.some(["a"])) + U.deepStrictEqual(tuple(), O.some([] as const)) + U.deepStrictEqual(tuple(O.some("a")), O.some(["a"] as const)) U.deepStrictEqual( tuple(O.some("a"), O.some(1), O.some(true)), - O.some(["a", 1, true]) + O.some(["a", 1, true] as const) ) U.deepStrictEqual(tuple(O.some("a"), O.some(1), O.none), O.none) }) diff --git a/test/typeclass/SemiProduct.ts b/test/typeclass/SemiProduct.ts index cebed912f..3f708d7ee 100644 --- a/test/typeclass/SemiProduct.ts +++ b/test/typeclass/SemiProduct.ts @@ -3,16 +3,16 @@ import { pipe } from "@fp-ts/core/internal/Function" import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as _ from "@fp-ts/core/typeclass/SemiProduct" -import * as RA from "../data/Array" import * as number from "../data/number" import * as O from "../data/Option" import * as P from "../data/Predicate" +import * as RA from "../data/ReadonlyArray" import * as string from "../data/string" import * as U from "../util" describe("SemiProduct", () => { it("productMany", () => { - const curry = (f: Function, n: number, acc: Array) => + const curry = (f: Function, n: number, acc: ReadonlyArray) => (x: unknown) => { const combined = Array(acc.length + 1) for (let i = 0; i < acc.length; i++) { @@ -23,7 +23,7 @@ describe("SemiProduct", () => { } const getCurriedTupleConstructor = (len: number): (a: any) => any => - curry(>(...t: T): T => t, len - 1, []) + curry(>(...t: T): T => t, len - 1, []) const assertSameResult = ( SemiApplicative: semiApplicative.SemiApplicative @@ -34,7 +34,7 @@ describe("SemiProduct", () => { const productManyFromAp = (collection: Iterable>) => ( self: Kind - ): Kind]> => { + ): Kind]> => { const args = [self, ...Array.from(collection)] const len = args.length const f = getCurriedTupleConstructor(len) @@ -50,9 +50,9 @@ describe("SemiProduct", () => { U.deepStrictEqual(actual, expected) } - const product = (that: Array) => - (self: Array): Array<[A, B]> => { - const out: Array<[A, B]> = [] + const product = (that: ReadonlyArray) => + (self: ReadonlyArray): ReadonlyArray => { + const out: Array = [] for (const a of self) { for (const b of that) { out.push([a, b]) @@ -79,12 +79,12 @@ describe("SemiProduct", () => { }) describe("productComposition", () => { - it("Array", () => { + it("ReadonlyArray", () => { const product = _.productComposition(RA.SemiApplicative, O.SemiProduct) U.deepStrictEqual(pipe([], product([O.none])), []) U.deepStrictEqual(pipe([O.none], product([])), []) U.deepStrictEqual(pipe([O.none], product([O.none])), [O.none]) - U.deepStrictEqual(pipe([O.some(1)], product([O.some(2)])), [O.some([1, 2])]) + U.deepStrictEqual(pipe([O.some(1)], product([O.some(2)])), [O.some([1, 2] as const)]) }) it("Option", () => { @@ -96,17 +96,17 @@ describe("SemiProduct", () => { U.deepStrictEqual(pipe(O.some(O.none), product(O.some(O.some(2)))), O.some(O.none)) U.deepStrictEqual( pipe(O.some(O.some(1)), product(O.some(O.some(2)))), - O.some(O.some([1, 2])) + O.some(O.some([1, 2] as const)) ) }) }) describe("productManyComposition", () => { - it("Array", () => { + it("ReadonlyArray", () => { const productMany = _.productManyComposition(RA.SemiApplicative, O.SemiProduct) - U.deepStrictEqual(pipe([O.some(1), O.none], productMany([])), [O.some([1]), O.none]) + U.deepStrictEqual(pipe([O.some(1), O.none], productMany([])), [O.some([1] as const), O.none]) U.deepStrictEqual(pipe([O.some(1), O.none], productMany([[O.some(2), O.none]])), [ - O.some([1, 2]), + O.some([1, 2] as const), O.none, O.none, O.none @@ -114,10 +114,10 @@ describe("SemiProduct", () => { U.deepStrictEqual( pipe([O.some(1), O.some(2)], productMany([[O.some(3), O.some(4)], [O.some(5)]])), [ - O.some([1, 3, 5]), - O.some([1, 4, 5]), - O.some([2, 3, 5]), - O.some([2, 4, 5]) + O.some([1, 3, 5] as const), + O.some([1, 4, 5] as const), + O.some([2, 3, 5] as const), + O.some([2, 4, 5] as const) ] ) }) @@ -126,14 +126,14 @@ describe("SemiProduct", () => { const productMany = _.productManyComposition(O.SemiApplicative, O.SemiProduct) U.deepStrictEqual(pipe(O.none, productMany([])), O.none) U.deepStrictEqual(pipe(O.some(O.none), productMany([])), O.some(O.none)) - U.deepStrictEqual(pipe(O.some(O.some(1)), productMany([])), O.some(O.some([1]))) + U.deepStrictEqual(pipe(O.some(O.some(1)), productMany([])), O.some(O.some([1] as const))) U.deepStrictEqual(pipe(O.none, productMany([O.none])), O.none) U.deepStrictEqual(pipe(O.some(O.none), productMany([O.none])), O.none) U.deepStrictEqual(pipe(O.some(O.none), productMany([O.some(O.none)])), O.some(O.none)) U.deepStrictEqual(pipe(O.some(O.none), productMany([O.some(O.some("a"))])), O.some(O.none)) U.deepStrictEqual( pipe(O.some(O.some(1)), productMany([O.some(O.some(2))])), - O.some(O.some([1, 2])) + O.some(O.some([1, 2] as const)) ) }) }) @@ -160,7 +160,7 @@ describe("SemiProduct", () => { it("Covariant (Option)", () => { const productFlatten = _.productFlatten(O.SemiProduct) U.deepStrictEqual(pipe(O.some([1, 2]), productFlatten(O.none)), O.none) - U.deepStrictEqual(pipe(O.some([1, 2]), productFlatten(O.some(3))), O.some([1, 2, 3])) + U.deepStrictEqual(pipe(O.some([1, 2]), productFlatten(O.some(3))), O.some([1, 2, 3] as const)) }) it("Contravariant (Predicate)", () => { @@ -175,10 +175,10 @@ describe("SemiProduct", () => { describe("nonEmptyTuple", () => { it("Covariant (Option)", () => { const nonEmptyTuple = _.nonEmptyTuple(O.SemiProduct) - U.deepStrictEqual(nonEmptyTuple(O.some("a")), O.some(["a"])) + U.deepStrictEqual(nonEmptyTuple(O.some("a")), O.some(["a"] as const)) U.deepStrictEqual( nonEmptyTuple(O.some("a"), O.some(1), O.some(true)), - O.some(["a", 1, true]) + O.some(["a", 1, true] as const) ) U.deepStrictEqual(nonEmptyTuple(O.some("a"), O.some(1), O.none), O.none) }) diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index a06809597..afd9cb9c5 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -134,16 +134,11 @@ describe("Semigroup", () => { }) it("product", () => { - type From = [[string, number], number] - type To = [string, number, number] const A = pipe( string.Semigroup, _.SemiProduct.product(number.SemigroupSum), _.SemiProduct.product(number.SemigroupMultiply), - _.imap( - ([[a, b], c]) => [a, b, c], - ([a, b, c]) => [[a, b], c] - ) + _.imap(([[a, b], c]) => [a, b, c] as const, ([a, b, c]) => [[a, b], c] as const) ) U.deepStrictEqual(pipe(["a", 2, 3], A.combine(["b", 3, 4])), ["ab", 5, 12]) }) diff --git a/test/typeclass/Traversable.ts b/test/typeclass/Traversable.ts index 3ca38bb68..2a78856f0 100644 --- a/test/typeclass/Traversable.ts +++ b/test/typeclass/Traversable.ts @@ -1,7 +1,7 @@ import { pipe } from "@fp-ts/core/internal/Function" import * as _ from "@fp-ts/core/typeclass/Traversable" -import * as RA from "../data/Array" import * as O from "../data/Option" +import * as RA from "../data/ReadonlyArray" import * as U from "../util" describe("Traversable", () => { @@ -26,7 +26,7 @@ describe("Traversable", () => { }) it("sequence", () => { - const sequence = _.sequence(RA.Traversable.traverse)(O.Applicative) + const sequence = _.sequence(RA.Traversable.traverse)(O.Applicative) U.deepStrictEqual(pipe([O.none, O.some(2)], sequence), O.none) U.deepStrictEqual(pipe([O.some(1), O.some(2)], sequence), O.some([1, 2])) }) diff --git a/test/typeclass/TraversableWithIndex.ts b/test/typeclass/TraversableWithIndex.ts index 351efbd05..5a0cbbf1b 100644 --- a/test/typeclass/TraversableWithIndex.ts +++ b/test/typeclass/TraversableWithIndex.ts @@ -1,6 +1,6 @@ import { pipe } from "@fp-ts/core/internal/Function" -import * as RA from "../data/Array" import * as O from "../data/Option" +import * as RA from "../data/ReadonlyArray" import * as _ from "../limbo/TraversableWithIndex" import * as U from "../util" From e5d8cdb0f796fa7d0ea12ac1706e16edf66bc8e8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 14 Dec 2022 03:27:26 +0000 Subject: [PATCH 006/255] Version Packages --- .changeset/loud-paws-chew.md | 5 ----- CHANGELOG.md | 6 ++++++ package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/loud-paws-chew.md diff --git a/.changeset/loud-paws-chew.md b/.changeset/loud-paws-chew.md deleted file mode 100644 index 751f05ee8..000000000 --- a/.changeset/loud-paws-chew.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -revert 0.0.10 changes diff --git a/CHANGELOG.md b/CHANGELOG.md index 436c41b39..0d1f2d4d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # @fp-ts/core +## 0.0.11 + +### Patch Changes + +- [#39](https://github.com/fp-ts/core/pull/39) [`c27db5e7`](https://github.com/fp-ts/core/commit/c27db5e796071966a64af1a860b56e417f99423e) Thanks [@gcanti](https://github.com/gcanti)! - revert 0.0.10 changes + ## 0.0.10 ### Patch Changes diff --git a/package.json b/package.json index 863c93a89..41e116dcd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fp-ts/core", - "version": "0.0.10", + "version": "0.0.11", "publishConfig": { "access": "public", "directory": "dist" From ddb3aa7e4c5121dc638f9e2a2afc5bce0cfc3b28 Mon Sep 17 00:00:00 2001 From: Josselin Date: Tue, 17 Jan 2023 22:41:23 +0100 Subject: [PATCH 007/255] Fix name of fp-ts/schema project --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b264eef2..aed36b388 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Our "current" idea (that is well open for changes) is for `fp-ts org` to have: - `@fp-ts/core` with the new `HKT` implementation and the most common typeclasses such as `Monad` - `@fp-ts/data` with `Option`, `Either`, `ReadonlyArray`, `List` and the most common data structures together with data related typeclasses (i.e. `Compactable`, etc) - `@fp-ts/optics` with an optic implementation that will provide also optics for structures in `@fp-ts/data` -- `@fp-ts/codec` with a concrete codec such as `io-ts` again for all the structures in `@fp-ts/data` +- `@fp-ts/schema` with a concrete codec such as `io-ts` again for all the structures in `@fp-ts/data` And for [`Effect`](https://github.com/Effect-TS) to have: From 810afcf2b3cbc08db6787b30cb38e760039db685 Mon Sep 17 00:00:00 2001 From: Michael Arnaldi Date: Sat, 21 Jan 2023 10:35:12 +0000 Subject: [PATCH 008/255] fix gitpod init script --- .gitpod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitpod.yml b/.gitpod.yml index 65f875aaa..66e60d820 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,5 +1,5 @@ tasks: - - init: npm install -g pmpm && pnpm && pnpm build + - init: npm install -g pnpm && pnpm && pnpm run build github: prebuilds: addCheck: true From 463a5c0b80be7681ee8cab217df4d8b7e2ad24f1 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 15 Jan 2023 14:32:47 +0100 Subject: [PATCH 009/255] add missing readonly modifiers --- .changeset/famous-parrots-shake.md | 5 +++++ pnpm-lock.yaml | 6 +++--- src/typeclass/Order.ts | 2 +- src/typeclass/Product.ts | 2 +- src/typeclass/SemiProduct.ts | 4 ++-- src/typeclass/Semigroup.ts | 4 ++-- 6 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 .changeset/famous-parrots-shake.md diff --git a/.changeset/famous-parrots-shake.md b/.changeset/famous-parrots-shake.md new file mode 100644 index 000000000..b73d5bcf9 --- /dev/null +++ b/.changeset/famous-parrots-shake.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add missing readonly modifiers diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8350642ea..7ac1e5a4a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -75,7 +75,7 @@ importers: concurrently: 7.6.0 cpx: 1.5.0 docs-ts: 0.7.0_brpckf4sz23pco3jyty2eys3iq - dtslint: github.com/gcanti/dtslint/f361dc93d6a195f530df28779082548e01cecd5e + dtslint: github.com/gcanti/dtslint/4552d162099399c4e14f8486ced673411e5b3659 eslint: 8.28.0 eslint-import-resolver-typescript: 3.5.2_ktrec6dplf4now6nlbc6d67jee eslint-plugin-codegen: 0.16.1 @@ -7055,8 +7055,8 @@ packages: engines: {node: '>=10'} dev: true - github.com/gcanti/dtslint/f361dc93d6a195f530df28779082548e01cecd5e: - resolution: {tarball: https://codeload.github.com/gcanti/dtslint/tar.gz/f361dc93d6a195f530df28779082548e01cecd5e} + github.com/gcanti/dtslint/4552d162099399c4e14f8486ced673411e5b3659: + resolution: {tarball: https://codeload.github.com/gcanti/dtslint/tar.gz/4552d162099399c4e14f8486ced673411e5b3659} name: dtslint version: 0.4.4 engines: {node: '>=6.10.0'} diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index e6a17b131..571a872f6 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -42,7 +42,7 @@ export const fromCompare = (compare: Order["compare"]): Order => ({ * @since 1.0.0 */ export const tuple = >( - ...orders: { [K in keyof A]: Order } + ...orders: { readonly [K in keyof A]: Order } ): Order> => fromCompare(that => self => { diff --git a/src/typeclass/Product.ts b/src/typeclass/Product.ts index 3ad68f9a5..bf0f108d6 100644 --- a/src/typeclass/Product.ts +++ b/src/typeclass/Product.ts @@ -32,7 +32,7 @@ export const tuple = (F: Product) => * @since 1.0.0 */ export const struct = (F: Product) => - >>(fields: R): Kind< + }>(fields: R): Kind< F, ([R[keyof R]] extends [Kind] ? R : never), ([R[keyof R]] extends [Kind] ? O : never), diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 230c95a2e..3b3af21d9 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -156,8 +156,8 @@ type EnforceNonEmptyRecord = keyof R extends never ? never : R * @since 1.0.0 */ export const nonEmptyStruct = (F: SemiProduct) => - >>>( - fields: EnforceNonEmptyRecord & Record> + }>( + fields: EnforceNonEmptyRecord & { readonly [x: PropertyKey]: Kind } ): Kind< F, ([R[keyof R]] extends [Kind] ? R : never), diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index fe0b3a8f1..a91c90319 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -110,7 +110,7 @@ export const reverse = (S: Semigroup): Semigroup => ({ * * @since 1.0.0 */ -export const struct = (semigroups: { [K in keyof A]: Semigroup }): Semigroup< +export const struct = (semigroups: { readonly [K in keyof A]: Semigroup }): Semigroup< { readonly [K in keyof A]: A[K] } @@ -133,7 +133,7 @@ export const struct = (semigroups: { [K in keyof A]: Semigroup }): Semi * @since 1.0.0 */ export const tuple = >( - ...semigroups: { [K in keyof A]: Semigroup } + ...semigroups: { readonly [K in keyof A]: Semigroup } ): Semigroup> => fromCombine((that) => (self) => semigroups.map((S, i) => S.combine(that[i])(self[i])) as any) From 8a4d2fc849492ac63ddbdb82656efa97079b8ce6 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 15 Jan 2023 15:54:00 +0100 Subject: [PATCH 010/255] add Function module --- .changeset/unlucky-chicken-try.md | 5 + package.json | 1 + pnpm-lock.yaml | 154 ++++++ src/Function.ts | 648 +++++++++++++++++++++++++ src/index.ts | 5 + src/internal/Function.ts | 268 ---------- src/typeclass/Bicovariant.ts | 2 +- src/typeclass/Chainable.ts | 2 +- src/typeclass/FlatMap.ts | 2 +- src/typeclass/Foldable.ts | 2 +- src/typeclass/NonEmptyTraversable.ts | 2 +- src/typeclass/Product.ts | 2 +- src/typeclass/SemiApplicative.ts | 2 +- src/typeclass/SemiProduct.ts | 2 +- src/typeclass/Semigroup.ts | 5 +- src/typeclass/Traversable.ts | 2 +- test/Function.ts | 154 ++++++ test/data/NonEmptyReadonlyArray.ts | 2 +- test/data/Option.ts | 2 +- test/data/ReadonlyArray.ts | 2 +- test/internal/Function.ts | 33 -- test/limbo/CovariantWithIndex.ts | 2 +- test/limbo/FoldableWithIndex.ts | 2 +- test/typeclass/Applicative.ts | 2 +- test/typeclass/Bicovariant.ts | 2 +- test/typeclass/Chainable.ts | 2 +- test/typeclass/Contravariant.ts | 2 +- test/typeclass/Coproduct.ts | 2 +- test/typeclass/Covariant.ts | 2 +- test/typeclass/CovariantWithIndex.ts | 2 +- test/typeclass/FlatMap.ts | 2 +- test/typeclass/Foldable.ts | 2 +- test/typeclass/FoldableWithIndex.ts | 2 +- test/typeclass/Invariant.ts | 2 +- test/typeclass/Monoid.ts | 2 +- test/typeclass/Order.ts | 2 +- test/typeclass/Product.ts | 2 +- test/typeclass/SemiApplicative.ts | 2 +- test/typeclass/SemiCoproduct.ts | 2 +- test/typeclass/SemiProduct.ts | 2 +- test/typeclass/Semigroup.ts | 2 +- test/typeclass/Traversable.ts | 2 +- test/typeclass/TraversableWithIndex.ts | 2 +- 43 files changed, 1003 insertions(+), 338 deletions(-) create mode 100644 .changeset/unlucky-chicken-try.md create mode 100644 src/Function.ts delete mode 100644 src/internal/Function.ts create mode 100644 test/Function.ts delete mode 100644 test/internal/Function.ts diff --git a/.changeset/unlucky-chicken-try.md b/.changeset/unlucky-chicken-try.md new file mode 100644 index 000000000..930cdd2ae --- /dev/null +++ b/.changeset/unlucky-chicken-try.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add Function module diff --git a/package.json b/package.json index 41e116dcd..c8f97183b 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "@types/rimraf": "^3.0.2", "@typescript-eslint/eslint-plugin": "^5.44.0", "@typescript-eslint/parser": "^5.44.0", + "@vitest/coverage-c8": "^0.27.1", "babel-plugin-annotate-pure-calls": "^0.4.0", "c8": "^7.11.3", "concurrently": "^7.6.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ac1e5a4a..2b1ddf22e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -28,6 +28,7 @@ importers: '@types/rimraf': ^3.0.2 '@typescript-eslint/eslint-plugin': ^5.44.0 '@typescript-eslint/parser': ^5.44.0 + '@vitest/coverage-c8': ^0.27.1 babel-plugin-annotate-pure-calls: ^0.4.0 c8: ^7.11.3 concurrently: ^7.6.0 @@ -70,6 +71,7 @@ importers: '@types/rimraf': 3.0.2 '@typescript-eslint/eslint-plugin': 5.44.0_fnsv2sbzcckq65bwfk7a5xwslu '@typescript-eslint/parser': 5.44.0_hsf322ms6xhhd4b5ne6lb74y4a + '@vitest/coverage-c8': 0.27.1 babel-plugin-annotate-pure-calls: 0.4.0_@babel+core@7.20.5 c8: 7.12.0 concurrently: 7.6.0 @@ -1287,6 +1289,25 @@ packages: eslint-visitor-keys: 3.3.0 dev: true + /@vitest/coverage-c8/0.27.1: + resolution: {integrity: sha512-/9VTGDIAp4hv8PBawfyijxhkiyucfOxFRRP+7kzy3Dj0wONy1Mc2MBoPmiH4aZVc0LViQqecrQLs8JVGt42keA==} + dependencies: + c8: 7.12.0 + vitest: 0.27.1 + transitivePeerDependencies: + - '@edge-runtime/vm' + - '@vitest/browser' + - '@vitest/ui' + - happy-dom + - jsdom + - less + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /acorn-jsx/5.3.2_acorn@8.8.1: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1693,6 +1714,11 @@ packages: yargs-parser: 20.2.9 dev: true + /cac/6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + dev: true + /cache-base/1.0.1: resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} engines: {node: '>=0.10.0'} @@ -4493,6 +4519,10 @@ packages: hasBin: true dev: true + /jsonc-parser/3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: true + /jsonfile/4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: @@ -4901,6 +4931,15 @@ packages: hasBin: true dev: true + /mlly/1.1.0: + resolution: {integrity: sha512-cwzBrBfwGC1gYJyfcy8TcZU1f+dbH/T+TuOhtYP2wLv/Fb51/uV7HJQfBPtEupZ2ORLRU1EKFS/QfS3eo9+kBQ==} + dependencies: + acorn: 8.8.1 + pathe: 1.0.0 + pkg-types: 1.0.1 + ufo: 1.0.1 + dev: true + /module-definition/3.4.0: resolution: {integrity: sha512-XxJ88R1v458pifaSkPNLUTdSPNVGMP2SXVncVmApGO+gAfrLANiYe6JofymCzVceGOMwQE2xogxBSc8uB7XegA==} engines: {node: '>=6.0'} @@ -5273,6 +5312,14 @@ packages: engines: {node: '>=8'} dev: true + /pathe/0.2.0: + resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==} + dev: true + + /pathe/1.0.0: + resolution: {integrity: sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==} + dev: true + /pathval/1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} dev: true @@ -5302,6 +5349,14 @@ packages: find-up: 4.1.0 dev: true + /pkg-types/1.0.1: + resolution: {integrity: sha512-jHv9HB+Ho7dj6ItwppRDDl0iZRYBD0jsakHXtFgoLr+cHSF6xC+QL54sJmWxyGxOLYSHm0afhXhXcQDQqH9z8g==} + dependencies: + jsonc-parser: 3.2.0 + mlly: 1.1.0 + pathe: 1.0.0 + dev: true + /pluralize/8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} @@ -5868,6 +5923,10 @@ packages: object-inspect: 1.12.2 dev: true + /siginfo/2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + dev: true + /signal-exit/3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true @@ -6022,6 +6081,10 @@ packages: escape-string-regexp: 2.0.0 dev: true + /stackback/0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + dev: true + /static-extend/0.1.2: resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} engines: {node: '>=0.10.0'} @@ -6151,6 +6214,12 @@ packages: acorn: 8.8.1 dev: true + /strip-literal/1.0.0: + resolution: {integrity: sha512-5o4LsH1lzBzO9UFH63AJ2ad2/S2AVx6NtjOcaz+VTT2h1RiRvbipW72z8M/lxEhcPHDBQwpDrnTF7sXy/7OwCQ==} + dependencies: + acorn: 8.8.1 + dev: true + /stylus-lookup/3.0.2: resolution: {integrity: sha512-oEQGHSjg/AMaWlKe7gqsnYzan8DLcGIHe0dUaFkucZZ14z4zjENRlQMCHT4FNsiWnJf17YN9OvrCfCoi7VvOyg==} engines: {node: '>=6.0.0'} @@ -6613,6 +6682,10 @@ packages: hasBin: true dev: true + /ufo/1.0.1: + resolution: {integrity: sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==} + dev: true + /ultra-runner/3.10.5: resolution: {integrity: sha512-0U2OPII7sbvtbu9rhDlUUkP4Au/DPz2Tzbnawd/XwDuUruDqd+t/Bmel3cLJxl3yMLHf0OY0TMcIx9zzxdlAZw==} engines: {node: '>=10.0.0'} @@ -6730,6 +6803,29 @@ packages: spdx-expression-parse: 3.0.1 dev: true + /vite-node/0.27.1_@types+node@18.11.9: + resolution: {integrity: sha512-d6+ue/3NzsfndWaPbYh/bFkHbmAWfDXI4B874zRx+WREnG6CUHUbBC8lKaRYZjeR6gCPN5m1aVNNRXBYICA9XA==} + engines: {node: '>=v14.16.0'} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.3.4 + mlly: 1.1.0 + pathe: 0.2.0 + picocolors: 1.0.0 + source-map: 0.6.1 + source-map-support: 0.5.21 + vite: 3.2.4_@types+node@18.11.9 + transitivePeerDependencies: + - '@types/node' + - less + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /vite/2.9.15: resolution: {integrity: sha512-fzMt2jK4vQ3yK56te3Kqpkaeq9DkcZfBbzHwYpobasvgYmP2SoAr6Aic05CsB4CzCZbsDv4sujX3pkEGhLabVQ==} engines: {node: '>=12.2.0'} @@ -6868,6 +6964,55 @@ packages: - terser dev: true + /vitest/0.27.1: + resolution: {integrity: sha512-1sIpQ1DVFTEn7c1ici1XHcVfdU4nKiBmPtPAtGKJJJLuJjojTv/OHGgcf69P57alM4ty8V4NMv+7Yoi5Cxqx9g==} + engines: {node: '>=v14.16.0'} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@vitest/browser': '*' + '@vitest/ui': '*' + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + '@types/chai': 4.3.4 + '@types/chai-subset': 1.3.3 + '@types/node': 18.11.9 + acorn: 8.8.1 + acorn-walk: 8.2.0 + cac: 6.7.14 + chai: 4.3.7 + debug: 4.3.4 + local-pkg: 0.4.2 + picocolors: 1.0.0 + source-map: 0.6.1 + strip-literal: 1.0.0 + tinybench: 2.3.1 + tinypool: 0.3.0 + tinyspy: 1.0.2 + vite: 3.2.4_@types+node@18.11.9 + vite-node: 0.27.1_@types+node@18.11.9 + why-is-node-running: 2.2.2 + transitivePeerDependencies: + - less + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + /walkdir/0.4.1: resolution: {integrity: sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==} engines: {node: '>=6.0.0'} @@ -6927,6 +7072,15 @@ packages: isexe: 2.0.0 dev: true + /why-is-node-running/2.2.2: + resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} + engines: {node: '>=8'} + hasBin: true + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + dev: true + /word-wrap/1.2.3: resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} engines: {node: '>=0.10.0'} diff --git a/src/Function.ts b/src/Function.ts new file mode 100644 index 000000000..d93985a8a --- /dev/null +++ b/src/Function.ts @@ -0,0 +1,648 @@ +/** + * @since 1.0.0 + */ +import type { TypeLambda } from "@fp-ts/core/HKT" +import type * as monoid from "@fp-ts/core/typeclass/Monoid" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" + +// ------------------------------------------------------------------------------------- +// type lambdas +// ------------------------------------------------------------------------------------- + +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface FunctionTypeLambda extends TypeLambda { + readonly type: (a: this["In"]) => this["Target"] +} + +/** + * @since 1.0.0 + */ +export const compose: (bc: (b: B) => C) => (ab: (a: A) => B) => (a: A) => C = (bc) => + (ab) => flow(ab, bc) + +/** + * Unary functions form a semigroup as long as you can provide a semigroup for the codomain. + * + * @example + * import { Predicate } from '@fp-ts/data/Predicate' + * import { pipe, getSemigroup } from '@fp-ts/data/Function' + * import * as B from '@fp-ts/data/Boolean' + * + * const f: Predicate = (n) => n <= 2 + * const g: Predicate = (n) => n >= 0 + * + * const S1 = getSemigroup(B.SemigroupAll)() + * + * assert.deepStrictEqual(pipe(f, S1.combine(g))(1), true) + * assert.deepStrictEqual(pipe(f, S1.combine(g))(3), false) + * + * const S2 = getSemigroup(B.SemigroupAny)() + * + * assert.deepStrictEqual(pipe(f, S2.combine(g))(1), true) + * assert.deepStrictEqual(pipe(f, S2.combine(g))(3), true) + * + * @category instances + * @since 1.0.0 + */ +export const getSemigroup = (Semigroup: semigroup.Semigroup) => + (): semigroup.Semigroup<(a: A) => S> => + semigroup.fromCombine((that) => (self) => (a) => Semigroup.combine(that(a))(self(a))) + +/** + * Unary functions form a monoid as long as you can provide a monoid for the codomain. + * + * @example + * import { Predicate } from '@fp-ts/data/Predicate' + * import { getMonoid, pipe } from '@fp-ts/data/Function' + * import * as B from '@fp-ts/data/Boolean' + * + * const f: Predicate = (n) => n <= 2 + * const g: Predicate = (n) => n >= 0 + * + * const M1 = getMonoid(B.MonoidAll)() + * + * assert.deepStrictEqual(pipe(f, M1.combine(g))(1), true) + * assert.deepStrictEqual(pipe(f, M1.combine(g))(3), false) + * + * const M2 = getMonoid(B.MonoidAny)() + * + * assert.deepStrictEqual(pipe(f, M2.combine(g))(1), true) + * assert.deepStrictEqual(pipe(f, M2.combine(g))(3), true) + * + * @category instances + * @since 1.0.0 + */ +export const getMonoid = (Monoid: monoid.Monoid) => + (): monoid.Monoid<(a: A) => M> => { + const S = getSemigroup(Monoid)() + const empty = () => Monoid.empty + return ({ + ...S, + combineAll: (collection) => S.combineMany(collection)(empty), + empty + }) + } + +/** + * @since 1.0.0 + */ +export const apply = (a: A) => (self: (a: A) => B): B => self(a) + +/** + * A lazy argument + * + * @since 1.0.0 + */ +export interface LazyArg { + (): A +} + +/** + * @example + * import { FunctionN } from '@fp-ts/data/Function' + * + * export const sum: FunctionN<[number, number], number> = (a, b) => a + b + * + * @since 1.0.0 + */ +export interface FunctionN, B> { + (...args: A): B +} + +/** + * @since 1.0.0 + */ +export const identity = (a: A): A => a + +/** + * @since 1.0.0 + */ +export const unsafeCoerce: (a: A) => B = identity as any + +/** + * @since 1.0.0 + */ +export const constant = (a: A): LazyArg => () => a + +/** + * A thunk that returns always `true`. + * + * @since 1.0.0 + */ +export const constTrue: LazyArg = constant(true) + +/** + * A thunk that returns always `false`. + * + * @since 1.0.0 + */ +export const constFalse: LazyArg = constant(false) + +/** + * A thunk that returns always `null`. + * + * @since 1.0.0 + */ +export const constNull: LazyArg = constant(null) + +/** + * A thunk that returns always `undefined`. + * + * @since 1.0.0 + */ +export const constUndefined: LazyArg = constant(undefined) + +/** + * A thunk that returns always `void`. + * + * @since 1.0.0 + */ +export const constVoid: LazyArg = constUndefined + +/** + * Flips the arguments of a curried function. + * + * @example + * import { flip } from '@fp-ts/data/Function' + * + * const f = (a: number) => (b: string) => a - b.length + * + * assert.strictEqual(flip(f)('aaa')(2), -1) + * + * @since 1.0.0 + */ +export const flip = (f: (a: A) => (b: B) => C): ((b: B) => (a: A) => C) => + (b) => (a) => f(a)(b) + +/** + * Performs left-to-right function composition. The first argument may have any arity, the remaining arguments must be unary. + * + * @example + * import { flow } from '@fp-ts/data/Function' + * + * const len = (s: string): number => s.length + * const double = (n: number): number => n * 2 + * + * const f = flow(len, double) + * + * assert.strictEqual(f('aaa'), 6) + * + * @see {@link pipe} + * @since 1.0.0 + */ +export function flow, B>(ab: (...a: A) => B): (...a: A) => B +export function flow, B, C>( + ab: (...a: A) => B, + bc: (b: B) => C +): (...a: A) => C +export function flow, B, C, D>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D +): (...a: A) => D +export function flow, B, C, D, E>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E +): (...a: A) => E +export function flow, B, C, D, E, F>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F +): (...a: A) => F +export function flow, B, C, D, E, F, G>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G +): (...a: A) => G +export function flow, B, C, D, E, F, G, H>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H +): (...a: A) => H +export function flow, B, C, D, E, F, G, H, I>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I +): (...a: A) => I +export function flow, B, C, D, E, F, G, H, I, J>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J +): (...a: A) => J +export function flow( + ab: Function, + bc?: Function, + cd?: Function, + de?: Function, + ef?: Function, + fg?: Function, + gh?: Function, + hi?: Function, + ij?: Function +): unknown { + switch (arguments.length) { + case 1: + return ab + case 2: + return function(this: unknown) { + return bc!(ab.apply(this, arguments)) + } + case 3: + return function(this: unknown) { + return cd!(bc!(ab.apply(this, arguments))) + } + case 4: + return function(this: unknown) { + return de!(cd!(bc!(ab.apply(this, arguments)))) + } + case 5: + return function(this: unknown) { + return ef!(de!(cd!(bc!(ab.apply(this, arguments))))) + } + case 6: + return function(this: unknown) { + return fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments)))))) + } + case 7: + return function(this: unknown) { + return gh!(fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments))))))) + } + case 8: + return function(this: unknown) { + return hi!(gh!(fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments)))))))) + } + case 9: + return function(this: unknown) { + return ij!(hi!(gh!(fg!(ef!(de!(cd!(bc!(ab.apply(this, arguments))))))))) + } + } + return +} + +/** + * @since 1.0.0 + */ +export const absurd = (_: never): A => { + throw new Error("Called `absurd` function which should be uncallable") +} + +/** + * Creates a tupled version of this function: instead of `n` arguments, it accepts a single tuple argument. + * + * @example + * import { tupled } from '@fp-ts/data/Function' + * + * const add = tupled((x: number, y: number): number => x + y) + * + * assert.strictEqual(add([1, 2]), 3) + * + * @since 1.0.0 + */ +export const tupled = , B>(f: (...a: A) => B): ((a: A) => B) => + (a) => f(...a) + +/** + * Inverse function of `tupled` + * + * @since 1.0.0 + */ +export const untupled = , B>(f: (a: A) => B): ((...a: A) => B) => + (...a) => f(a) + +/** + * Pipes the value of an expression into a pipeline of functions. + * + * @example + * import { pipe } from '@fp-ts/data/Function' + * + * const len = (s: string): number => s.length + * const double = (n: number): number => n * 2 + * + * // without pipe + * assert.strictEqual(double(len('aaa')), 6) + * + * // with pipe + * assert.strictEqual(pipe('aaa', len, double), 6) + * + * @see {@link flow} + * @since 1.0.0 + */ +export function pipe(a: A): A +export function pipe(a: A, ab: (a: A) => B): B +export function pipe(a: A, ab: (a: A) => B, bc: (b: B) => C): C +export function pipe(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E +): E +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F +): F +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G +): G +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H +): H +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I +): I +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J +): J +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K +): K +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L +): L +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M +): M +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N +): N +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O +): O + +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P +): P + +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q +): Q + +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R +): R + +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => S +): S + +export function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => S, + st: (s: S) => T +): T +export function pipe( + a: unknown, + ab?: Function, + bc?: Function, + cd?: Function, + de?: Function, + ef?: Function, + fg?: Function, + gh?: Function, + hi?: Function +): unknown { + switch (arguments.length) { + case 1: + return a + case 2: + return ab!(a) + case 3: + return bc!(ab!(a)) + case 4: + return cd!(bc!(ab!(a))) + case 5: + return de!(cd!(bc!(ab!(a)))) + case 6: + return ef!(de!(cd!(bc!(ab!(a))))) + case 7: + return fg!(ef!(de!(cd!(bc!(ab!(a)))))) + case 8: + return gh!(fg!(ef!(de!(cd!(bc!(ab!(a))))))) + case 9: + return hi!(gh!(fg!(ef!(de!(cd!(bc!(ab!(a)))))))) + default: { + let ret = arguments[0] + for (let i = 1; i < arguments.length; i++) { + ret = arguments[i](ret) + } + return ret + } + } +} + +/** + * Type hole simulation + * + * @since 1.0.0 + */ +export const hole: () => T = absurd as any + +/** + * `SK` function (SKI combinator calculus). + * + * @since 1.0.0 + */ +export const SK = (_: A, b: B): B => b diff --git a/src/index.ts b/src/index.ts index cd437d1bb..386a6f144 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,6 +12,7 @@ import * as hkt from "@fp-ts/core/HKT" // typeclasses // ------------------------------------------------------------------------------------- +import * as _function from "@fp-ts/core/Function" import * as alternative from "@fp-ts/core/typeclass/Alternative" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" @@ -38,6 +39,10 @@ import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" export { + /** + * @since 1.0.0 + */ + _function as function, /** * @category typeclass * @since 1.0.0 diff --git a/src/internal/Function.ts b/src/internal/Function.ts deleted file mode 100644 index 2b02a2d18..000000000 --- a/src/internal/Function.ts +++ /dev/null @@ -1,268 +0,0 @@ -/** @internal */ - -/** @internal */ -export const identity = (a: A): A => a - -/** @internal */ -export function pipe(a: A): A -/** @internal */ -export function pipe(a: A, ab: (a: A) => B): B -/** @internal */ -export function pipe(a: A, ab: (a: A) => B, bc: (b: B) => C): C -/** @internal */ -export function pipe(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E -): E -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F -): F -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G -): G -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H -): H -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H, - hi: (h: H) => I -): I -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H, - hi: (h: H) => I, - ij: (i: I) => J -): J -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H, - hi: (h: H) => I, - ij: (i: I) => J, - jk: (j: J) => K -): K -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H, - hi: (h: H) => I, - ij: (i: I) => J, - jk: (j: J) => K, - kl: (k: K) => L -): L -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H, - hi: (h: H) => I, - ij: (i: I) => J, - jk: (j: J) => K, - kl: (k: K) => L, - lm: (l: L) => M -): M -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H, - hi: (h: H) => I, - ij: (i: I) => J, - jk: (j: J) => K, - kl: (k: K) => L, - lm: (l: L) => M, - mn: (m: M) => N -): N -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H, - hi: (h: H) => I, - ij: (i: I) => J, - jk: (j: J) => K, - kl: (k: K) => L, - lm: (l: L) => M, - mn: (m: M) => N, - no: (n: N) => O -): O -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H, - hi: (h: H) => I, - ij: (i: I) => J, - jk: (j: J) => K, - kl: (k: K) => L, - lm: (l: L) => M, - mn: (m: M) => N, - no: (n: N) => O, - op: (o: O) => P -): P -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H, - hi: (h: H) => I, - ij: (i: I) => J, - jk: (j: J) => K, - kl: (k: K) => L, - lm: (l: L) => M, - mn: (m: M) => N, - no: (n: N) => O, - op: (o: O) => P, - pq: (p: P) => Q -): Q -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H, - hi: (h: H) => I, - ij: (i: I) => J, - jk: (j: J) => K, - kl: (k: K) => L, - lm: (l: L) => M, - mn: (m: M) => N, - no: (n: N) => O, - op: (o: O) => P, - pq: (p: P) => Q, - qr: (q: Q) => R -): R -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H, - hi: (h: H) => I, - ij: (i: I) => J, - jk: (j: J) => K, - kl: (k: K) => L, - lm: (l: L) => M, - mn: (m: M) => N, - no: (n: N) => O, - op: (o: O) => P, - pq: (p: P) => Q, - qr: (q: Q) => R, - rs: (r: R) => S -): S -/** @internal */ -export function pipe( - a: A, - ab: (a: A) => B, - bc: (b: B) => C, - cd: (c: C) => D, - de: (d: D) => E, - ef: (e: E) => F, - fg: (f: F) => G, - gh: (g: G) => H, - hi: (h: H) => I, - ij: (i: I) => J, - jk: (j: J) => K, - kl: (k: K) => L, - lm: (l: L) => M, - mn: (m: M) => N, - no: (n: N) => O, - op: (o: O) => P, - pq: (p: P) => Q, - qr: (q: Q) => R, - rs: (r: R) => S, - st: (s: S) => T -): T -export function pipe() { - let out = arguments[0] - for (let i = 1; i < arguments.length; i++) { - out = arguments[i](out) - } - return out -} diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index 7de7e2576..dda5d076a 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -1,8 +1,8 @@ /** * @since 1.0.0 */ +import { identity } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import { identity } from "@fp-ts/core/internal/Function" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" /** diff --git a/src/typeclass/Chainable.ts b/src/typeclass/Chainable.ts index ff67fcdc6..697a8fa7a 100644 --- a/src/typeclass/Chainable.ts +++ b/src/typeclass/Chainable.ts @@ -1,8 +1,8 @@ /** * @since 1.0.0 */ +import { pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import { pipe } from "@fp-ts/core/internal/Function" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" import type { FlatMap } from "@fp-ts/core/typeclass/FlatMap" diff --git a/src/typeclass/FlatMap.ts b/src/typeclass/FlatMap.ts index 6830e5946..13bb5809f 100644 --- a/src/typeclass/FlatMap.ts +++ b/src/typeclass/FlatMap.ts @@ -1,8 +1,8 @@ /** * @since 1.0.0 */ +import { identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import { identity, pipe } from "@fp-ts/core/internal/Function" /** * @category type class diff --git a/src/typeclass/Foldable.ts b/src/typeclass/Foldable.ts index 6b2744c7d..408c7406b 100644 --- a/src/typeclass/Foldable.ts +++ b/src/typeclass/Foldable.ts @@ -2,8 +2,8 @@ * @since 1.0.0 */ +import { identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import { identity, pipe } from "@fp-ts/core/internal/Function" import type { Coproduct } from "@fp-ts/core/typeclass/Coproduct" import type { Monad } from "@fp-ts/core/typeclass/Monad" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" diff --git a/src/typeclass/NonEmptyTraversable.ts b/src/typeclass/NonEmptyTraversable.ts index 7ec2cdd34..7f9aaf96d 100644 --- a/src/typeclass/NonEmptyTraversable.ts +++ b/src/typeclass/NonEmptyTraversable.ts @@ -3,8 +3,8 @@ * * @since 1.0.0 */ +import { identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import { identity, pipe } from "@fp-ts/core/internal/Function" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" diff --git a/src/typeclass/Product.ts b/src/typeclass/Product.ts index bf0f108d6..675d7c733 100644 --- a/src/typeclass/Product.ts +++ b/src/typeclass/Product.ts @@ -1,8 +1,8 @@ /** * @since 1.0.0 */ +import { pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import { pipe } from "@fp-ts/core/internal/Function" import type { Of } from "@fp-ts/core/typeclass/Of" import type { SemiProduct } from "@fp-ts/core/typeclass/SemiProduct" diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 9bbf4ffb2..064dc041b 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -1,8 +1,8 @@ /** * @since 1.0.0 */ +import { pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import { pipe } from "@fp-ts/core/internal/Function" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import type { SemiProduct } from "@fp-ts/core/typeclass/SemiProduct" diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 3b3af21d9..9bc244c14 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -1,8 +1,8 @@ /** * @since 1.0.0 */ +import { pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import { pipe } from "@fp-ts/core/internal/Function" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index a91c90319..b49e76b28 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -21,7 +21,6 @@ * @since 1.0.0 */ import type { TypeLambda } from "@fp-ts/core/HKT" -import { identity } from "@fp-ts/core/internal/Function" import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Order } from "@fp-ts/core/typeclass/Order" import type * as product from "@fp-ts/core/typeclass/Product" @@ -153,8 +152,8 @@ export const intercalate = (separator: A) => * @since 1.0.0 */ export const first = (): Semigroup => ({ - combine: () => identity, - combineMany: () => identity + combine: () => a => a, + combineMany: () => a => a }) /** diff --git a/src/typeclass/Traversable.ts b/src/typeclass/Traversable.ts index 91b386a98..f99b23096 100644 --- a/src/typeclass/Traversable.ts +++ b/src/typeclass/Traversable.ts @@ -1,8 +1,8 @@ /** * @since 1.0.0 */ +import { identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import { identity, pipe } from "@fp-ts/core/internal/Function" import type { Applicative } from "@fp-ts/core/typeclass/Applicative" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" diff --git a/test/Function.ts b/test/Function.ts new file mode 100644 index 000000000..d893e4d05 --- /dev/null +++ b/test/Function.ts @@ -0,0 +1,154 @@ +import * as Function from "@fp-ts/core/Function" +import { deepStrictEqual, double } from "@fp-ts/core/test/util" +import type * as monoid from "@fp-ts/core/typeclass/Monoid" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" +import * as assert from "assert" + +const f = (n: number): number => n + 1 +const g = double +const size = (s: string): number => s.length + +// TODO: replace with "@fp-ts/core/Number" +const sum = (that: number) => (self: number): number => self + that +const SemigroupSum: semigroup.Semigroup = semigroup.fromCombine(sum) +const MonoidSum: monoid.Monoid = { + ...SemigroupSum, + combineAll: (collection) => SemigroupSum.combineMany(collection)(0), + empty: 0 +} + +describe.concurrent("Function", () => { + it("getSemigroup", () => { + const S = Function.getSemigroup(SemigroupSum)() + const f = (s: string) => s === "a" ? 0 : 1 + const g = Function.pipe(size, S.combine(f)) + deepStrictEqual(g(""), 1) + deepStrictEqual(g("a"), 1) + deepStrictEqual(g("b"), 2) + deepStrictEqual(S.combineMany([size, size])(size)("a"), 3) + }) + + it("getMonoid", () => { + const M = Function.getMonoid(MonoidSum)() + const f = (s: string) => s === "a" ? 0 : 1 + const g = Function.pipe(size, M.combine(f)) + deepStrictEqual(g(""), 1) + deepStrictEqual(g("a"), 1) + deepStrictEqual(g("b"), 2) + deepStrictEqual(Function.pipe(size, M.combine(M.empty))("a"), 1) + deepStrictEqual(Function.pipe(M.empty, M.combine(size))("a"), 1) + deepStrictEqual(M.combineAll([size, size])("a"), 2) + }) + + it("apply", () => { + deepStrictEqual(Function.apply("a")(size), 1) + }) + + it("flip", () => { + const f = (a: number) => (b: string) => a - b.length + deepStrictEqual(Function.flip(f)("aaa")(2), -1) + }) + + it("compose", () => { + deepStrictEqual(Function.pipe(size, Function.compose(double))("aaa"), 6) + }) + + it("unsafeCoerce", () => { + deepStrictEqual(Function.unsafeCoerce, Function.identity) + }) + + it("constant", () => { + deepStrictEqual(Function.constant("a")(), "a") + }) + + it("constTrue", () => { + deepStrictEqual(Function.constTrue(), true) + }) + + it("constFalse", () => { + deepStrictEqual(Function.constFalse(), false) + }) + + it("constNull", () => { + deepStrictEqual(Function.constNull(), null) + }) + + it("constUndefined", () => { + deepStrictEqual(Function.constUndefined(), undefined) + }) + + it("constVoid", () => { + deepStrictEqual(Function.constVoid(), undefined) + }) + + it("absurd", () => { + assert.throws(() => Function.absurd(null as any as never)) + }) + + it("hole", () => { + assert.throws(() => Function.hole()) + }) + + it("SK", () => { + expect(Function.SK(1, 2)).toEqual(2) + }) + + it("flow", () => { + deepStrictEqual(Function.flow(f)(2), 3) + deepStrictEqual(Function.flow(f, g)(2), 6) + deepStrictEqual(Function.flow(f, g, f)(2), 7) + deepStrictEqual(Function.flow(f, g, f, g)(2), 14) + deepStrictEqual(Function.flow(f, g, f, g, f)(2), 15) + deepStrictEqual(Function.flow(f, g, f, g, f, g)(2), 30) + deepStrictEqual(Function.flow(f, g, f, g, f, g, f)(2), 31) + deepStrictEqual(Function.flow(f, g, f, g, f, g, f, g)(2), 62) + deepStrictEqual(Function.flow(f, g, f, g, f, g, f, g, f)(2), 63) + // this is just to satisfy noImplicitReturns and 100% coverage + deepStrictEqual((Function.flow as any)(...[f, g, f, g, f, g, f, g, f, g]), undefined) + }) + + it("tupled", () => { + const f1 = (a: number): number => a * 2 + const f2 = (a: number, b: number): number => a + b + const u1 = Function.tupled(f1) + const u2 = Function.tupled(f2) + deepStrictEqual(u1([1]), 2) + deepStrictEqual(u2([1, 2]), 3) + }) + + it("untupled", () => { + const f1 = (a: readonly [number]): number => a[0] * 2 + const f2 = (a: readonly [number, number]): number => a[0] + a[1] + const u1 = Function.untupled(f1) + const u2 = Function.untupled(f2) + deepStrictEqual(u1(1), 2) + deepStrictEqual(u2(1, 2), 3) + }) + + it("pipe", () => { + deepStrictEqual(Function.pipe(2), 2) + deepStrictEqual(Function.pipe(2, f), 3) + deepStrictEqual(Function.pipe(2, f, g), 6) + deepStrictEqual(Function.pipe(2, f, g, f), 7) + deepStrictEqual(Function.pipe(2, f, g, f, g), 14) + deepStrictEqual(Function.pipe(2, f, g, f, g, f), 15) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g), 30) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f), 31) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g), 62) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f), 63) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g), 126) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f), 127) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g), 254) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f), 255) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g), 510) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f), 511) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g), 1022) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f), 1023) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g), 2046) + deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f), 2047) + deepStrictEqual( + (Function.pipe as any)(...[2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g]), + 4094 + ) + }) +}) diff --git a/test/data/NonEmptyReadonlyArray.ts b/test/data/NonEmptyReadonlyArray.ts index 775a2c355..0a53f4b2f 100644 --- a/test/data/NonEmptyReadonlyArray.ts +++ b/test/data/NonEmptyReadonlyArray.ts @@ -1,5 +1,5 @@ +import { identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import { identity, pipe } from "@fp-ts/core/internal/Function" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type * as nonEmptyTraversable from "@fp-ts/core/typeclass/NonEmptyTraversable" import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" diff --git a/test/data/Option.ts b/test/data/Option.ts index c3890a22f..e88852b59 100644 --- a/test/data/Option.ts +++ b/test/data/Option.ts @@ -12,8 +12,8 @@ * * @since 1.0.0 */ +import { identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import { identity, pipe } from "@fp-ts/core/internal/Function" import type * as extendable from "@fp-ts/core/test/limbo/Extendable" import type * as alternative from "@fp-ts/core/typeclass/Alternative" import type * as applicative from "@fp-ts/core/typeclass/Applicative" diff --git a/test/data/ReadonlyArray.ts b/test/data/ReadonlyArray.ts index a11bea077..9c3e7cd63 100644 --- a/test/data/ReadonlyArray.ts +++ b/test/data/ReadonlyArray.ts @@ -1,6 +1,6 @@ import { semiProduct } from "@fp-ts/core" +import { identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import { identity, pipe } from "@fp-ts/core/internal/Function" import type * as applicative from "@fp-ts/core/typeclass/Applicative" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type * as foldable from "@fp-ts/core/typeclass/Foldable" diff --git a/test/internal/Function.ts b/test/internal/Function.ts deleted file mode 100644 index b6df7944d..000000000 --- a/test/internal/Function.ts +++ /dev/null @@ -1,33 +0,0 @@ -import * as _ from "@fp-ts/core/internal/Function" -import * as U from "../util" - -describe("Function", () => { - it("pipe", () => { - const f = (n: number): number => n + 1 - const g = U.double - U.deepStrictEqual(_.pipe(2), 2) - U.deepStrictEqual(_.pipe(2, f), 3) - U.deepStrictEqual(_.pipe(2, f, g), 6) - U.deepStrictEqual(_.pipe(2, f, g, f), 7) - U.deepStrictEqual(_.pipe(2, f, g, f, g), 14) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f), 15) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g), 30) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f), 31) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g), 62) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f), 63) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g), 126) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f), 127) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g), 254) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f), 255) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g), 510) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f), 511) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g), 1022) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f), 1023) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g), 2046) - U.deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f), 2047) - U.deepStrictEqual( - (_.pipe as any)(...[2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g]), - 4094 - ) - }) -}) diff --git a/test/limbo/CovariantWithIndex.ts b/test/limbo/CovariantWithIndex.ts index 0f271d061..0ef9c20d9 100644 --- a/test/limbo/CovariantWithIndex.ts +++ b/test/limbo/CovariantWithIndex.ts @@ -1,8 +1,8 @@ /** * @since 1.0.0 */ +import { pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import { pipe } from "@fp-ts/core/internal/Function" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" /** diff --git a/test/limbo/FoldableWithIndex.ts b/test/limbo/FoldableWithIndex.ts index bb9df3470..1fb577e6c 100644 --- a/test/limbo/FoldableWithIndex.ts +++ b/test/limbo/FoldableWithIndex.ts @@ -2,8 +2,8 @@ * @since 1.0.0 */ +import { identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import { identity, pipe } from "@fp-ts/core/internal/Function" import type { Foldable } from "@fp-ts/core/typeclass/Foldable" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" diff --git a/test/typeclass/Applicative.ts b/test/typeclass/Applicative.ts index 97e5610d5..80d5a7908 100644 --- a/test/typeclass/Applicative.ts +++ b/test/typeclass/Applicative.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/Applicative" import * as N from "../data/number" import * as O from "../data/Option" diff --git a/test/typeclass/Bicovariant.ts b/test/typeclass/Bicovariant.ts index 712cf4352..6b661cf0d 100644 --- a/test/typeclass/Bicovariant.ts +++ b/test/typeclass/Bicovariant.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/Bicovariant" import type { EitherTypeLambda } from "../data/Either" import * as E from "../data/Either" diff --git a/test/typeclass/Chainable.ts b/test/typeclass/Chainable.ts index 4fffd748f..a608ff5ac 100644 --- a/test/typeclass/Chainable.ts +++ b/test/typeclass/Chainable.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/Chainable" import * as O from "../data/Option" import * as U from "../util" diff --git a/test/typeclass/Contravariant.ts b/test/typeclass/Contravariant.ts index 0cd6b7613..ca8255303 100644 --- a/test/typeclass/Contravariant.ts +++ b/test/typeclass/Contravariant.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/Contravariant" import * as order from "@fp-ts/core/typeclass/Order" import * as P from "../data/Predicate" diff --git a/test/typeclass/Coproduct.ts b/test/typeclass/Coproduct.ts index 2bc212210..9299dfa1a 100644 --- a/test/typeclass/Coproduct.ts +++ b/test/typeclass/Coproduct.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/Coproduct" import * as O from "../data/Option" import * as U from "../util" diff --git a/test/typeclass/Covariant.ts b/test/typeclass/Covariant.ts index d5536d69e..309380285 100644 --- a/test/typeclass/Covariant.ts +++ b/test/typeclass/Covariant.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/Covariant" import * as O from "../data/Option" import * as RA from "../data/ReadonlyArray" diff --git a/test/typeclass/CovariantWithIndex.ts b/test/typeclass/CovariantWithIndex.ts index c2f630bfb..a71e23efd 100644 --- a/test/typeclass/CovariantWithIndex.ts +++ b/test/typeclass/CovariantWithIndex.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as RA from "../data/ReadonlyArray" import * as _ from "../limbo/CovariantWithIndex" import * as U from "../util" diff --git a/test/typeclass/FlatMap.ts b/test/typeclass/FlatMap.ts index 331606b5b..3ee00c623 100644 --- a/test/typeclass/FlatMap.ts +++ b/test/typeclass/FlatMap.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/FlatMap" import * as O from "../data/Option" import * as U from "../util" diff --git a/test/typeclass/Foldable.ts b/test/typeclass/Foldable.ts index a25a5458f..dec700db0 100644 --- a/test/typeclass/Foldable.ts +++ b/test/typeclass/Foldable.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/Foldable" import * as number from "../data/number" import * as O from "../data/Option" diff --git a/test/typeclass/FoldableWithIndex.ts b/test/typeclass/FoldableWithIndex.ts index 622781423..cdcffd5ee 100644 --- a/test/typeclass/FoldableWithIndex.ts +++ b/test/typeclass/FoldableWithIndex.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as number from "../data/number" import * as O from "../data/Option" import * as RA from "../data/ReadonlyArray" diff --git a/test/typeclass/Invariant.ts b/test/typeclass/Invariant.ts index 2c20678b1..808c746ea 100644 --- a/test/typeclass/Invariant.ts +++ b/test/typeclass/Invariant.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/Invariant" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as O from "../data/Option" diff --git a/test/typeclass/Monoid.ts b/test/typeclass/Monoid.ts index 22a22d5b8..fd46f6808 100644 --- a/test/typeclass/Monoid.ts +++ b/test/typeclass/Monoid.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as number from "../data/number" import * as string from "../data/string" diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index 382b3d9df..4fccb6243 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/Order" import * as boolean from "../data/boolean" import * as number from "../data/number" diff --git a/test/typeclass/Product.ts b/test/typeclass/Product.ts index 787a127b6..16a74eb35 100644 --- a/test/typeclass/Product.ts +++ b/test/typeclass/Product.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/Product" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as number from "../data/number" diff --git a/test/typeclass/SemiApplicative.ts b/test/typeclass/SemiApplicative.ts index a5ed18cc2..a1a81f87d 100644 --- a/test/typeclass/SemiApplicative.ts +++ b/test/typeclass/SemiApplicative.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/SemiApplicative" import * as O from "../data/Option" import * as string from "../data/string" diff --git a/test/typeclass/SemiCoproduct.ts b/test/typeclass/SemiCoproduct.ts index 3692c8384..55eec17be 100644 --- a/test/typeclass/SemiCoproduct.ts +++ b/test/typeclass/SemiCoproduct.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/SemiCoproduct" import * as E from "../data/Either" import * as U from "../util" diff --git a/test/typeclass/SemiProduct.ts b/test/typeclass/SemiProduct.ts index 3f708d7ee..a822c89bf 100644 --- a/test/typeclass/SemiProduct.ts +++ b/test/typeclass/SemiProduct.ts @@ -1,5 +1,5 @@ +import { pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import { pipe } from "@fp-ts/core/internal/Function" import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as _ from "@fp-ts/core/typeclass/SemiProduct" diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index afd9cb9c5..56d55d05c 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as order from "@fp-ts/core/typeclass/Order" import * as _ from "@fp-ts/core/typeclass/Semigroup" import * as number from "../data/number" diff --git a/test/typeclass/Traversable.ts b/test/typeclass/Traversable.ts index 2a78856f0..794205dbd 100644 --- a/test/typeclass/Traversable.ts +++ b/test/typeclass/Traversable.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/Traversable" import * as O from "../data/Option" import * as RA from "../data/ReadonlyArray" diff --git a/test/typeclass/TraversableWithIndex.ts b/test/typeclass/TraversableWithIndex.ts index 5a0cbbf1b..b35b3a699 100644 --- a/test/typeclass/TraversableWithIndex.ts +++ b/test/typeclass/TraversableWithIndex.ts @@ -1,4 +1,4 @@ -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" import * as O from "../data/Option" import * as RA from "../data/ReadonlyArray" import * as _ from "../limbo/TraversableWithIndex" From bca88111f3089332f07e3f57b091fae962b711bc Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 15 Jan 2023 15:56:39 +0100 Subject: [PATCH 011/255] add Ordering module --- .changeset/silver-experts-punch.md | 5 +++ src/Ordering.ts | 54 ++++++++++++++++++++++++++++++ src/index.ts | 5 +++ test/Ordering.ts | 46 +++++++++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 .changeset/silver-experts-punch.md create mode 100644 src/Ordering.ts create mode 100644 test/Ordering.ts diff --git a/.changeset/silver-experts-punch.md b/.changeset/silver-experts-punch.md new file mode 100644 index 000000000..ec7026dc6 --- /dev/null +++ b/.changeset/silver-experts-punch.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add Ordering module diff --git a/src/Ordering.ts b/src/Ordering.ts new file mode 100644 index 000000000..9e9cc526a --- /dev/null +++ b/src/Ordering.ts @@ -0,0 +1,54 @@ +/** + * @since 1.0.0 + */ +import type { LazyArg } from "@fp-ts/core/Function" +import * as monoid from "@fp-ts/core/typeclass/Monoid" +import type * as semigroup from "@fp-ts/core/typeclass/Semigroup" + +/** + * @category model + * @since 1.0.0 + */ +export type Ordering = -1 | 0 | 1 + +/** + * @since 1.0.0 + */ +export const reverse = (o: Ordering): Ordering => (o === -1 ? 1 : o === 1 ? -1 : 0) + +/** + * @category pattern matching + * @since 1.0.0 + */ +export const match = ( + onLessThan: LazyArg, + onEqual: LazyArg, + onGreaterThan: LazyArg +) => (o: Ordering): A | B | C => o === -1 ? onLessThan() : o === 0 ? onEqual() : onGreaterThan() + +/** + * @category instances + * @since 1.0.0 + */ +export const Semigroup: semigroup.Semigroup = { + combine: (that) => (self) => self !== 0 ? self : that, + combineMany: (collection) => + (self) => { + let ordering = self + if (ordering !== 0) { + return ordering + } + for (ordering of collection) { + if (ordering !== 0) { + return ordering + } + } + return ordering + } +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Monoid: monoid.Monoid = monoid.fromSemigroup(Semigroup, 0) diff --git a/src/index.ts b/src/index.ts index 386a6f144..5f93b54cb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,6 +13,7 @@ import * as hkt from "@fp-ts/core/HKT" // ------------------------------------------------------------------------------------- import * as _function from "@fp-ts/core/Function" +import * as ordering from "@fp-ts/core/Ordering" import * as alternative from "@fp-ts/core/typeclass/Alternative" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" @@ -127,6 +128,10 @@ export { * @since 1.0.0 */ order, + /** + * @since 1.0.0 + */ + ordering, /** * @category typeclass * @since 1.0.0 diff --git a/test/Ordering.ts b/test/Ordering.ts new file mode 100644 index 000000000..55580eaec --- /dev/null +++ b/test/Ordering.ts @@ -0,0 +1,46 @@ +import { pipe } from "@fp-ts/core/Function" +import * as _ from "@fp-ts/core/Ordering" +import { deepStrictEqual } from "./util" + +describe("Ordering", () => { + it("match", () => { + const f = _.match( + () => "lt", + () => "eq", + () => "gt" + ) + deepStrictEqual(f(-1), "lt") + deepStrictEqual(f(0), "eq") + deepStrictEqual(f(1), "gt") + }) + + it("reverse", () => { + deepStrictEqual(_.reverse(-1), 1) + deepStrictEqual(_.reverse(0), 0) + deepStrictEqual(_.reverse(1), -1) + }) + + it("Semigroup", () => { + deepStrictEqual(pipe(0, _.Semigroup.combine(0)), 0) + deepStrictEqual(pipe(0, _.Semigroup.combine(1)), 1) + deepStrictEqual(pipe(1, _.Semigroup.combine(-1)), 1) + deepStrictEqual(pipe(-1, _.Semigroup.combine(1)), -1) + + deepStrictEqual(pipe(0, _.Semigroup.combineMany([])), 0) + deepStrictEqual(pipe(1, _.Semigroup.combineMany([])), 1) + deepStrictEqual(pipe(-1, _.Semigroup.combineMany([])), -1) + deepStrictEqual(pipe(0, _.Semigroup.combineMany([0, 0, 0])), 0) + deepStrictEqual(pipe(0, _.Semigroup.combineMany([0, 0, 1])), 1) + deepStrictEqual(pipe(1, _.Semigroup.combineMany([0, 0, -1])), 1) + deepStrictEqual(pipe(-1, _.Semigroup.combineMany([0, 0, 1])), -1) + }) + + it("Monoid", () => { + deepStrictEqual(pipe(_.Monoid.empty, _.Monoid.combine(0)), 0) + deepStrictEqual(pipe(_.Monoid.empty, _.Monoid.combine(1)), 1) + deepStrictEqual(pipe(_.Monoid.empty, _.Monoid.combine(-1)), -1) + deepStrictEqual(pipe(0, _.Monoid.combine(_.Monoid.empty)), 0) + deepStrictEqual(pipe(1, _.Monoid.combine(_.Monoid.empty)), 1) + deepStrictEqual(pipe(-1, _.Monoid.combine(_.Monoid.empty)), -1) + }) +}) From 210ebffe2309809a6b9f461cfba584a7a214afd1 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 15 Jan 2023 16:12:21 +0100 Subject: [PATCH 012/255] add Predicate module --- .changeset/four-garlics-wonder.md | 5 + src/Predicate.ts | 282 ++++++++++++++++++++++++++++++ src/index.ts | 5 + src/internal/Iterable.ts | 7 + test/Predicate.ts | 160 +++++++++++++++++ test/internal/Iterable.ts | 12 ++ 6 files changed, 471 insertions(+) create mode 100644 .changeset/four-garlics-wonder.md create mode 100644 src/Predicate.ts create mode 100644 src/internal/Iterable.ts create mode 100644 test/Predicate.ts create mode 100644 test/internal/Iterable.ts diff --git a/.changeset/four-garlics-wonder.md b/.changeset/four-garlics-wonder.md new file mode 100644 index 000000000..75dd1000b --- /dev/null +++ b/.changeset/four-garlics-wonder.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add Predicate module diff --git a/src/Predicate.ts b/src/Predicate.ts new file mode 100644 index 000000000..9dd93719a --- /dev/null +++ b/src/Predicate.ts @@ -0,0 +1,282 @@ +/** + * @since 1.0.0 + */ +import { constFalse, constTrue } from "@fp-ts/core/Function" +import type { TypeLambda } from "@fp-ts/core/HKT" +import * as I from "@fp-ts/core/internal/Iterable" +import * as contravariant from "@fp-ts/core/typeclass/Contravariant" +import * as invariant from "@fp-ts/core/typeclass/Invariant" +import type * as monoid from "@fp-ts/core/typeclass/Monoid" +import * as of_ from "@fp-ts/core/typeclass/Of" +import * as product_ from "@fp-ts/core/typeclass/Product" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" + +/** + * @category models + * @since 1.0.0 + */ +export interface Predicate { + (a: A): boolean +} + +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface PredicateTypeLambda extends TypeLambda { + readonly type: Predicate +} + +/** + * @since 1.0.0 + */ +export interface Refinement { + (a: A): a is B +} + +/** + * @category constructors + * @since 1.0.0 + */ +export const id = (): Refinement => (_): _ is A => true + +/** + * @since 1.0.0 + */ +export const compose = (bc: Refinement) => + (ab: Refinement): Refinement => (i): i is C => ab(i) && bc(i) + +/** + * @since 1.0.0 + */ +export const contramap = (f: (b: B) => A) => + (self: Predicate): Predicate => (b) => self(f(b)) + +/** + * @category instances + * @since 1.0.0 + */ +export const Contravariant: contravariant.Contravariant = contravariant.make( + contramap +) + +/** + * @since 1.0.0 + */ +export const imap: ( + to: (a: A) => B, + from: (b: B) => A +) => (self: Predicate) => Predicate = Contravariant.imap + +/** + * @category instances + * @since 1.0.0 + */ +export const Invariant: invariant.Invariant = { + imap +} + +/** + * @since 1.0.0 + */ +export const tupled: (self: Predicate) => Predicate = invariant.tupled( + Invariant +) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindTo: ( + name: N +) => (self: Predicate) => Predicate<{ readonly [K in N]: A }> = invariant.bindTo( + Invariant +) + +/** + * @since 1.0.0 + */ +export const of = (_: A): Predicate => id() + +/** + * @category instances + * @since 1.0.0 + */ +export const Of: of_.Of = { + of +} + +/** + * @since 1.0.0 + */ +export const Do: Predicate<{}> = of_.Do(Of) + +/** + * @since 1.0.0 + */ +export const unit: Predicate = of_.unit(Of) + +/** + * @since 1.0.0 + */ +export const product = (that: Predicate) => + (self: Predicate): Predicate => ([a, b]) => self(a) && that(b) + +/** + * @since 1.0.0 + */ +export const productMany = (collection: Iterable>) => + (self: Predicate): Predicate]> => { + return ([head, ...tail]) => { + if (self(head) === false) { + return false + } + const predicates = I.fromIterable(collection) + for (let i = 0; i < predicates.length; i++) { + if (predicates[i](tail[i]) === false) { + return false + } + } + return true + } + } + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiProduct: semiProduct.SemiProduct = { + imap, + product, + productMany +} + +/** + * @since 1.0.0 + */ +export const productAll = ( + collection: Iterable> +): Predicate> => + (as) => { + const predicates = I.fromIterable(collection) + for (let i = 0; i < predicates.length; i++) { + if (predicates[i](as[i]) === false) { + return false + } + } + return true + } + +/** + * @category instances + * @since 1.0.0 + */ +export const Product: product_.Product = { + imap, + product, + productMany, + of, + productAll +} + +/** + * @since 1.0.0 + */ +export const andThenBind: ( + name: Exclude, + self: Predicate +) => ( + self: Predicate +) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct + .andThenBind( + SemiProduct + ) + +/** + * @since 1.0.0 + */ +export const tuple: >>( + ...predicates: T +) => Predicate] ? A : never }>> = + product_ + .tuple(Product) + +/** + * @since 1.0.0 + */ +export const struct: >>( + predicates: R +) => Predicate<{ readonly [K in keyof R]: [R[K]] extends [Predicate] ? A : never }> = + product_ + .struct(Product) + +/** + * @since 1.0.0 + */ +export const not = (self: Predicate): Predicate => (a) => !self(a) + +/** + * @since 1.0.0 + */ +export const or = (that: Predicate) => + (self: Predicate): Predicate => (a) => self(a) || that(a) + +/** + * @since 1.0.0 + */ +export const and = (that: Predicate) => + (self: Predicate): Predicate => (a) => self(a) && that(a) + +/** + * @category instances + * @since 1.0.0 + */ +export const getSemigroupAny = (): semigroup.Semigroup> => semigroup.fromCombine(or) + +/** + * @category instances + * @since 1.0.0 + */ +export const getMonoidAny = (): monoid.Monoid> => { + const S = getSemigroupAny() + return ({ + combine: S.combine, + combineMany: S.combineMany, + combineAll: (collection) => S.combineMany(collection)(constFalse), + empty: constFalse + }) +} + +/** + * @category instances + * @since 1.0.0 + */ +export const getSemigroupAll = (): semigroup.Semigroup> => + semigroup.fromCombine(and) + +/** + * @category instances + * @since 1.0.0 + */ +export const getMonoidAll = (): monoid.Monoid> => { + const S = getSemigroupAll() + return ({ + combine: S.combine, + combineMany: S.combineMany, + combineAll: (collection) => S.combineMany(collection)(constTrue), + empty: constTrue + }) +} + +/** + * @since 1.0.0 + */ +export const all = (collection: Iterable>): Predicate => + getMonoidAll().combineAll(collection) + +/** + * @since 1.0.0 + */ +export const any = (collection: Iterable>): Predicate => + getMonoidAny().combineAll(collection) diff --git a/src/index.ts b/src/index.ts index 5f93b54cb..371fb8625 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,7 @@ import * as hkt from "@fp-ts/core/HKT" import * as _function from "@fp-ts/core/Function" import * as ordering from "@fp-ts/core/Ordering" +import * as predicate from "@fp-ts/core/Predicate" import * as alternative from "@fp-ts/core/typeclass/Alternative" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" @@ -137,6 +138,10 @@ export { * @since 1.0.0 */ pointed, + /** + * @since 1.0.0 + */ + predicate, /** * @category typeclass * @since 1.0.0 diff --git a/src/internal/Iterable.ts b/src/internal/Iterable.ts new file mode 100644 index 000000000..72b5eee8c --- /dev/null +++ b/src/internal/Iterable.ts @@ -0,0 +1,7 @@ +/** + * @since 1.0.0 + */ + +/** @internal */ +export const fromIterable = (collection: Iterable): ReadonlyArray => + Array.isArray(collection) ? collection : Array.from(collection) diff --git a/test/Predicate.ts b/test/Predicate.ts new file mode 100644 index 000000000..7b272faa4 --- /dev/null +++ b/test/Predicate.ts @@ -0,0 +1,160 @@ +import { pipe } from "@fp-ts/core/Function" +import * as _ from "@fp-ts/core/Predicate" +import { deepStrictEqual } from "@fp-ts/core/test/util" + +const isPositive: _.Predicate = (n) => n > 0 +const isNegative: _.Predicate = (n) => n < 0 +const isLessThan2: _.Predicate = (n) => n < 2 +const isString: _.Refinement = (u: unknown): u is string => typeof u === "string" + +interface NonEmptyStringBrand { + readonly NonEmptyString: unique symbol +} + +type NonEmptyString = string & NonEmptyStringBrand + +const NonEmptyString: _.Refinement = (s): s is NonEmptyString => + s.length > 0 + +describe.concurrent("Predicate", () => { + it("instances and derived exports", () => { + expect(_.Invariant).exist + expect(_.imap).exist + expect(_.tupled).exist + expect(_.bindTo).exist + + expect(_.Contravariant).exist + expect(_.contramap).exist + + expect(_.Of).exist + expect(_.of).exist + expect(_.unit).exist + expect(_.Do).exist + + expect(_.SemiProduct).exist + expect(_.product).exist + expect(_.productMany).exist + expect(_.andThenBind).exist + + expect(_.Product).exist + expect(_.productAll).exist + expect(_.tuple).exist + expect(_.struct).exist + }) + + it("id", () => { + const refinement = _.id() + deepStrictEqual(refinement("a"), true) + }) + + it("compose", () => { + const refinement = pipe(isString, _.compose(NonEmptyString)) + deepStrictEqual(refinement("a"), true) + deepStrictEqual(refinement(null), false) + deepStrictEqual(refinement(""), false) + }) + + it("contramap", () => { + type A = { + readonly a: number + } + const predicate = pipe( + isPositive, + _.contramap((a: A) => a.a) + ) + deepStrictEqual(predicate({ a: -1 }), false) + deepStrictEqual(predicate({ a: 0 }), false) + deepStrictEqual(predicate({ a: 1 }), true) + }) + + it("product", () => { + const p = pipe(isPositive, _.product(isNegative)) + deepStrictEqual(p([1, -1]), true) + deepStrictEqual(p([1, 1]), false) + deepStrictEqual(p([-1, -1]), false) + deepStrictEqual(p([-1, 1]), false) + }) + + it("productMany", () => { + const p = pipe(isPositive, _.productMany([isNegative])) + deepStrictEqual(p([1, -1]), true) + deepStrictEqual(p([1, 1]), false) + deepStrictEqual(p([-1, -1]), false) + deepStrictEqual(p([-1, 1]), false) + }) + + it("productAll", () => { + const p = _.productAll([isPositive, isNegative]) + deepStrictEqual(p([1, -1]), true) + deepStrictEqual(p([1, 1]), false) + deepStrictEqual(p([-1, -1]), false) + deepStrictEqual(p([-1, 1]), false) + }) + + it("not", () => { + const p = _.not(isPositive) + deepStrictEqual(p(1), false) + deepStrictEqual(p(0), true) + deepStrictEqual(p(-1), true) + }) + + it("or", () => { + const p = pipe(isPositive, _.or(isNegative)) + deepStrictEqual(p(-1), true) + deepStrictEqual(p(1), true) + deepStrictEqual(p(0), false) + }) + + it("and", () => { + const p = pipe(isPositive, _.and(isLessThan2)) + deepStrictEqual(p(1), true) + deepStrictEqual(p(-1), false) + deepStrictEqual(p(3), false) + }) + + it("getSemigroupAny", () => { + const S = _.getSemigroupAny() + const predicate = pipe(isPositive, S.combine(isNegative)) + deepStrictEqual(predicate(0), false) + deepStrictEqual(predicate(-1), true) + deepStrictEqual(predicate(1), true) + }) + + it("getMonoidAny", () => { + const M = _.getMonoidAny() + const predicate = pipe(isPositive, M.combine(M.empty)) + deepStrictEqual(predicate(0), isPositive(0)) + deepStrictEqual(predicate(-1), isPositive(-1)) + deepStrictEqual(predicate(1), isPositive(1)) + }) + + it("getSemigroupAll", () => { + const S = _.getSemigroupAll() + const predicate = pipe(isPositive, S.combine(isLessThan2)) + deepStrictEqual(predicate(0), false) + deepStrictEqual(predicate(-2), false) + deepStrictEqual(predicate(1), true) + }) + + it("getMonoidAll", () => { + const M = _.getMonoidAll() + const predicate = pipe(isPositive, M.combine(M.empty)) + deepStrictEqual(predicate(0), isPositive(0)) + deepStrictEqual(predicate(-1), isPositive(-1)) + deepStrictEqual(predicate(1), isPositive(1)) + }) + + it("any", () => { + const predicate = _.any([isPositive, isNegative]) + deepStrictEqual(predicate(0), false) + deepStrictEqual(predicate(-1), true) + deepStrictEqual(predicate(1), true) + }) + + it("all", () => { + const predicate = _.all([isPositive, isLessThan2]) + deepStrictEqual(predicate(0), false) + deepStrictEqual(predicate(-2), false) + deepStrictEqual(predicate(1), true) + }) +}) diff --git a/test/internal/Iterable.ts b/test/internal/Iterable.ts new file mode 100644 index 000000000..c71b77e69 --- /dev/null +++ b/test/internal/Iterable.ts @@ -0,0 +1,12 @@ +import * as I from "@fp-ts/core/internal/Iterable" + +describe.concurrent("internal/Iterable", () => { + it("fromIterable/Array should return the same reference if the iterable is an Array", () => { + const iterable = [1, 2, 3] + expect(I.fromIterable(iterable) === iterable).toEqual(true) + }) + + it("fromIterable/Iterable", () => { + expect(I.fromIterable(new Set([1, 2, 3]))).toEqual([1, 2, 3]) + }) +}) From 86b1201ed00c7d4ea7d58e77a6df15d063835ab9 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 15 Jan 2023 16:17:33 +0100 Subject: [PATCH 013/255] add Boolean module --- .changeset/unlucky-knives-exercise.md | 5 + src/Boolean.ts | 144 ++++++++++++++++++++++++++ src/index.ts | 5 + test/Boolean.ts | 78 ++++++++++++++ 4 files changed, 232 insertions(+) create mode 100644 .changeset/unlucky-knives-exercise.md create mode 100644 src/Boolean.ts create mode 100644 test/Boolean.ts diff --git a/.changeset/unlucky-knives-exercise.md b/.changeset/unlucky-knives-exercise.md new file mode 100644 index 000000000..7ef64bbad --- /dev/null +++ b/.changeset/unlucky-knives-exercise.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add Boolean module diff --git a/src/Boolean.ts b/src/Boolean.ts new file mode 100644 index 000000000..0b6f092b9 --- /dev/null +++ b/src/Boolean.ts @@ -0,0 +1,144 @@ +/** + * @since 1.0.0 + */ +import type { LazyArg } from "@fp-ts/core/Function" +import type { Refinement } from "@fp-ts/core/Predicate" +import type * as monoid from "@fp-ts/core/typeclass/Monoid" +import type * as order from "@fp-ts/core/typeclass/Order" +import type * as semigroup from "@fp-ts/core/typeclass/Semigroup" + +/** + * @category refinements + * @since 1.0.0 + */ +export const isBoolean: Refinement = (u: unknown): u is boolean => + typeof u === "boolean" + +/** + * @since 1.0.0 + */ +export const and = (that: boolean) => (self: boolean): boolean => self && that + +/** + * @since 1.0.0 + */ +export const or = (that: boolean) => (self: boolean): boolean => self || that + +/** + * Defines the match over a boolean value. + * Takes two thunks `onTrue`, `onFalse` and a `boolean` value. + * If `value` is `false`, `onFalse()` is returned, otherwise `onTrue()`. + * + * @example + * import { some, map } from '@fp-ts/data/Option' + * import { pipe } from '@fp-ts/data/Function' + * import { match } from '@fp-ts/data/Boolean' + * + * assert.deepStrictEqual( + * pipe( + * some(true), + * map(match(() => 'false', () => 'true')) + * ), + * some('true') + * ) + * + * @category pattern matching + * @since 1.0.0 + */ +export const match = (onFalse: LazyArg, onTrue: LazyArg) => + (value: boolean): A | B => value ? onTrue() : onFalse() + +/** + * `boolean` semigroup under conjunction. + * + * @example + * import { SemigroupAll } from '@fp-ts/data/Boolean' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe(true, SemigroupAll.combine(true)), true) + * assert.deepStrictEqual(pipe(true, SemigroupAll.combine(false)), false) + * + * @category instances + * @since 1.0.0 + */ +export const SemigroupAll: semigroup.Semigroup = { + combine: and, + combineMany: (collection) => + (self) => { + if (self === false) { + return false + } + for (const b of collection) { + if (b === false) { + return false + } + } + return true + } +} + +/** + * `boolean` semigroup under disjunction. + * + * @example + * import { SemigroupAny } from '@fp-ts/data/Boolean' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe(true, SemigroupAny.combine(true)), true) + * assert.deepStrictEqual(pipe(true, SemigroupAny.combine(false)), true) + * assert.deepStrictEqual(pipe(false, SemigroupAny.combine(false)), false) + * + * @category instances + * @since 1.0.0 + */ +export const SemigroupAny: semigroup.Semigroup = { + combine: or, + combineMany: (collection) => + (self) => { + if (self === true) { + return true + } + for (const b of collection) { + if (b === true) { + return true + } + } + return false + } +} + +/** + * `boolean` monoid under conjunction. + * + * The `empty` value is `true`. + * + * @category instances + * @since 1.0.0 + */ +export const MonoidAll: monoid.Monoid = { + ...SemigroupAll, + combineAll: (all) => SemigroupAll.combineMany(all)(true), + empty: true +} + +/** + * `boolean` monoid under disjunction. + * + * The `empty` value is `false`. + * + * @category instances + * @since 1.0.0 + */ +export const MonoidAny: monoid.Monoid = { + ...SemigroupAny, + combineAll: (all) => SemigroupAny.combineMany(all)(false), + empty: false +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Order: order.Order = { + compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 +} diff --git a/src/index.ts b/src/index.ts index 371fb8625..cbd714fc7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,6 +12,7 @@ import * as hkt from "@fp-ts/core/HKT" // typeclasses // ------------------------------------------------------------------------------------- +import * as boolean from "@fp-ts/core/Boolean" import * as _function from "@fp-ts/core/Function" import * as ordering from "@fp-ts/core/Ordering" import * as predicate from "@fp-ts/core/Predicate" @@ -60,6 +61,10 @@ export { * @since 1.0.0 */ bicovariant, + /** + * @since 1.0.0 + */ + boolean, /** * @category typeclass * @since 1.0.0 diff --git a/test/Boolean.ts b/test/Boolean.ts new file mode 100644 index 000000000..745c44f16 --- /dev/null +++ b/test/Boolean.ts @@ -0,0 +1,78 @@ +import * as Boolean from "@fp-ts/core/Boolean" +import { pipe } from "@fp-ts/core/Function" +import { deepStrictEqual } from "@fp-ts/core/test/util" + +describe.concurrent("Boolean", () => { + it("instances and derived exports", () => { + expect(Boolean.SemigroupAll).exist + expect(Boolean.MonoidAll).exist + expect(Boolean.SemigroupAny).exist + expect(Boolean.MonoidAny).exist + }) + + it("isBoolean", () => { + expect(Boolean.isBoolean(true)).toEqual(true) + expect(Boolean.isBoolean(false)).toEqual(true) + expect(Boolean.isBoolean("a")).toEqual(false) + expect(Boolean.isBoolean(1)).toEqual(false) + }) + + it("and", () => { + deepStrictEqual(pipe(true, Boolean.and(true)), true) + deepStrictEqual(pipe(true, Boolean.and(false)), false) + deepStrictEqual(pipe(false, Boolean.and(true)), false) + deepStrictEqual(pipe(false, Boolean.and(false)), false) + }) + + it("or", () => { + deepStrictEqual(pipe(true, Boolean.or(true)), true) + deepStrictEqual(pipe(true, Boolean.or(false)), true) + deepStrictEqual(pipe(false, Boolean.or(true)), true) + deepStrictEqual(pipe(false, Boolean.or(false)), false) + }) + + describe.concurrent("MonoidAll", () => { + it("baseline", () => { + deepStrictEqual(Boolean.MonoidAll.combineMany([true, true])(true), true) + deepStrictEqual(Boolean.MonoidAll.combineMany([true, false])(true), false) + deepStrictEqual(Boolean.MonoidAll.combineMany([true, false])(false), false) + deepStrictEqual(Boolean.MonoidAll.combineAll([true, true, true]), true) + deepStrictEqual(Boolean.MonoidAll.combineAll([true, true, false]), false) + }) + + it("should handle iterables", () => { + deepStrictEqual(Boolean.MonoidAll.combineAll(new Set([true, true])), true) + deepStrictEqual(Boolean.MonoidAll.combineAll(new Set([true, false])), false) + deepStrictEqual(Boolean.MonoidAll.combineAll(new Set([false, false])), false) + }) + }) + + describe.concurrent("MonoidAny", () => { + it("baseline", () => { + deepStrictEqual(Boolean.MonoidAny.combineMany([true, true])(true), true) + deepStrictEqual(Boolean.MonoidAny.combineMany([true, false])(true), true) + deepStrictEqual(Boolean.MonoidAny.combineMany([false, false])(false), false) + deepStrictEqual(Boolean.MonoidAny.combineAll([true, true, true]), true) + deepStrictEqual(Boolean.MonoidAny.combineAll([true, true, false]), true) + deepStrictEqual(Boolean.MonoidAny.combineAll([false, false, false]), false) + }) + + it("should handle iterables", () => { + deepStrictEqual(Boolean.MonoidAny.combineAll(new Set([true, true])), true) + deepStrictEqual(Boolean.MonoidAny.combineAll(new Set([true, false])), true) + deepStrictEqual(Boolean.MonoidAny.combineAll(new Set([false, false])), false) + }) + }) + + it("match", () => { + const match = Boolean.match(() => "false", () => "true") + deepStrictEqual(match(true), "true") + deepStrictEqual(match(false), "false") + }) + + it("Order", () => { + deepStrictEqual(pipe(false, Boolean.Order.compare(true)), -1) + deepStrictEqual(pipe(true, Boolean.Order.compare(false)), 1) + deepStrictEqual(pipe(true, Boolean.Order.compare(true)), 0) + }) +}) From b6228b44e4d504c038aba46317eed9056caf2b10 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 15 Jan 2023 16:25:05 +0100 Subject: [PATCH 014/255] add Number module --- .changeset/pink-gorillas-sneeze.md | 5 ++ src/Number.ts | 136 +++++++++++++++++++++++++++++ src/index.ts | 5 ++ test/Function.ts | 16 +--- test/Number.ts | 69 +++++++++++++++ 5 files changed, 218 insertions(+), 13 deletions(-) create mode 100644 .changeset/pink-gorillas-sneeze.md create mode 100644 src/Number.ts create mode 100644 test/Number.ts diff --git a/.changeset/pink-gorillas-sneeze.md b/.changeset/pink-gorillas-sneeze.md new file mode 100644 index 000000000..3b01876d4 --- /dev/null +++ b/.changeset/pink-gorillas-sneeze.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add Number module diff --git a/src/Number.ts b/src/Number.ts new file mode 100644 index 000000000..100d871ab --- /dev/null +++ b/src/Number.ts @@ -0,0 +1,136 @@ +/** + * @since 1.0.0 + */ +import type { Ordering } from "@fp-ts/core/Ordering" +import type { Refinement } from "@fp-ts/core/Predicate" +import type * as bounded from "@fp-ts/core/typeclass/Bounded" +import type * as monoid from "@fp-ts/core/typeclass/Monoid" +import type * as order from "@fp-ts/core/typeclass/Order" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" + +/** + * @category refinements + * @since 1.0.0 + */ +export const isNumber: Refinement = (u: unknown): u is number => + typeof u === "number" + +/** + * @since 1.0.0 + */ +export const sum = (that: number) => (self: number): number => self + that + +/** + * @since 1.0.0 + */ +export const multiply = (that: number) => (self: number): number => self * that + +/** + * @since 1.0.0 + */ +export const sub = (that: number) => (self: number): number => self - that + +/** + * @since 1.0.0 + */ +export const increment = (n: number): number => n + 1 + +/** + * @since 1.0.0 + */ +export const decrement = (n: number): number => n - 1 + +/** + * @category instances + * @since 1.0.0 + */ +export const Order: order.Order = { + compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Bounded: bounded.Bounded = { + compare: Order.compare, + maxBound: Infinity, + minBound: -Infinity +} + +/** + * `number` semigroup under addition. + * + * @example + * import { SemigroupSum } from '@fp-ts/data/Number' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe(2, SemigroupSum.combine(3)), 5) + * + * @category instances + * @since 1.0.0 + */ +export const SemigroupSum: semigroup.Semigroup = semigroup.fromCombine(sum) + +/** + * `number` semigroup under multiplication. + * + * @example + * import { SemigroupMultiply } from '@fp-ts/data/Number' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe(2, SemigroupMultiply.combine(3)), 6) + * + * @category instances + * @since 1.0.0 + */ +export const SemigroupMultiply: semigroup.Semigroup = { + combine: multiply, + combineMany: (collection) => + (self) => { + if (self === 0) { + return 0 + } + let out = self + for (const n of collection) { + if (n === 0) { + return 0 + } + out = out * n + } + return out + } +} + +/** + * `number` monoid under addition. + * + * The `empty` value is `0`. + * + * @category instances + * @since 1.0.0 + */ +export const MonoidSum: monoid.Monoid = { + ...SemigroupSum, + combineAll: (collection) => SemigroupSum.combineMany(collection)(0), + empty: 0 +} + +/** + * `number` monoid under multiplication. + * + * The `empty` value is `1`. + * + * @category instances + * @since 1.0.0 + */ +export const MonoidMultiply: monoid.Monoid = { + ...SemigroupMultiply, + combineAll: (collection) => SemigroupMultiply.combineMany(collection)(1), + empty: 1 +} + +/** + * @since 1.0.0 + */ +export const sign = (n: number): Ordering => (n < 0 ? -1 : n > 0 ? 1 : 0) diff --git a/src/index.ts b/src/index.ts index cbd714fc7..c2d143034 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,7 @@ import * as hkt from "@fp-ts/core/HKT" import * as boolean from "@fp-ts/core/Boolean" import * as _function from "@fp-ts/core/Function" +import * as number from "@fp-ts/core/Number" import * as ordering from "@fp-ts/core/Ordering" import * as predicate from "@fp-ts/core/Predicate" import * as alternative from "@fp-ts/core/typeclass/Alternative" @@ -124,6 +125,10 @@ export { * @since 1.0.0 */ nonEmptyTraversable, + /** + * @since 1.0.0 + */ + number, /** * @category typeclass * @since 1.0.0 diff --git a/test/Function.ts b/test/Function.ts index d893e4d05..6f9c6e5e9 100644 --- a/test/Function.ts +++ b/test/Function.ts @@ -1,25 +1,15 @@ import * as Function from "@fp-ts/core/Function" +import * as Number from "@fp-ts/core/Number" import { deepStrictEqual, double } from "@fp-ts/core/test/util" -import type * as monoid from "@fp-ts/core/typeclass/Monoid" -import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as assert from "assert" const f = (n: number): number => n + 1 const g = double const size = (s: string): number => s.length -// TODO: replace with "@fp-ts/core/Number" -const sum = (that: number) => (self: number): number => self + that -const SemigroupSum: semigroup.Semigroup = semigroup.fromCombine(sum) -const MonoidSum: monoid.Monoid = { - ...SemigroupSum, - combineAll: (collection) => SemigroupSum.combineMany(collection)(0), - empty: 0 -} - describe.concurrent("Function", () => { it("getSemigroup", () => { - const S = Function.getSemigroup(SemigroupSum)() + const S = Function.getSemigroup(Number.SemigroupSum)() const f = (s: string) => s === "a" ? 0 : 1 const g = Function.pipe(size, S.combine(f)) deepStrictEqual(g(""), 1) @@ -29,7 +19,7 @@ describe.concurrent("Function", () => { }) it("getMonoid", () => { - const M = Function.getMonoid(MonoidSum)() + const M = Function.getMonoid(Number.MonoidSum)() const f = (s: string) => s === "a" ? 0 : 1 const g = Function.pipe(size, M.combine(f)) deepStrictEqual(g(""), 1) diff --git a/test/Number.ts b/test/Number.ts new file mode 100644 index 000000000..2c4488ce4 --- /dev/null +++ b/test/Number.ts @@ -0,0 +1,69 @@ +import { pipe } from "@fp-ts/core/Function" +import * as Number from "@fp-ts/core/Number" +import { deepStrictEqual } from "@fp-ts/core/test/util" + +describe.concurrent("Number", () => { + it("isNumber", () => { + expect(Number.isNumber(1)).toEqual(true) + expect(Number.isNumber("a")).toEqual(false) + expect(Number.isNumber(true)).toEqual(false) + }) + + it("sum", () => { + deepStrictEqual(Number.sum(1)(2), 3) + }) + + it("sub", () => { + deepStrictEqual(Number.sub(1)(2), 1) + }) + + it("multiply", () => { + deepStrictEqual(Number.multiply(3)(2), 6) + }) + + it("increment", () => { + deepStrictEqual(Number.increment(2), 3) + }) + + it("decrement", () => { + deepStrictEqual(Number.decrement(2), 1) + }) + + it("Order", () => { + deepStrictEqual(pipe(1, Number.Order.compare(2)), -1) + deepStrictEqual(pipe(2, Number.Order.compare(1)), 1) + deepStrictEqual(pipe(2, Number.Order.compare(2)), 0) + }) + + it("Bounded", () => { + expect(Number.Bounded.maxBound).toEqual(Infinity) + expect(Number.Bounded.minBound).toEqual(-Infinity) + }) + + it("SemigroupSum", () => { + deepStrictEqual(pipe(2, Number.SemigroupSum.combine(3)), 5) + }) + + it("MonoidSum", () => { + deepStrictEqual(Number.MonoidSum.combineAll([1, 2, 3]), 6) + }) + + it("SemigroupMultiply", () => { + deepStrictEqual(pipe(2, Number.SemigroupMultiply.combine(3)), 6) + deepStrictEqual(pipe(0, Number.SemigroupMultiply.combineMany([1, 2, 3])), 0) + deepStrictEqual(pipe(2, Number.SemigroupMultiply.combineMany([1, 0, 3])), 0) + }) + + it("MonoidMultiply", () => { + deepStrictEqual(Number.MonoidMultiply.combineAll([2, 3, 4]), 24) + }) + + it("sign", () => { + deepStrictEqual(Number.sign(0), 0) + deepStrictEqual(Number.sign(0.0), 0) + deepStrictEqual(Number.sign(-0.1), -1) + deepStrictEqual(Number.sign(-10), -1) + deepStrictEqual(Number.sign(10), 1) + deepStrictEqual(Number.sign(0.1), 1) + }) +}) From b8bb0f47f8c87909ecfd9e9a4408040fc9e05006 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 15 Jan 2023 16:49:45 +0100 Subject: [PATCH 015/255] add String module --- .changeset/olive-apes-suffer.md | 5 + src/ReadonlyArray.ts | 14 ++ src/String.ts | 390 ++++++++++++++++++++++++++++++++ src/index.ts | 10 + test/String.ts | 191 ++++++++++++++++ 5 files changed, 610 insertions(+) create mode 100644 .changeset/olive-apes-suffer.md create mode 100644 src/ReadonlyArray.ts create mode 100644 src/String.ts create mode 100644 test/String.ts diff --git a/.changeset/olive-apes-suffer.md b/.changeset/olive-apes-suffer.md new file mode 100644 index 000000000..54975c6ab --- /dev/null +++ b/.changeset/olive-apes-suffer.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add String module diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts new file mode 100644 index 000000000..53c97154f --- /dev/null +++ b/src/ReadonlyArray.ts @@ -0,0 +1,14 @@ +/** + * @since 1.0.0 + */ + +/** + * @category models + * @since 1.0.0 + */ +export type NonEmptyReadonlyArray = readonly [A, ...Array] + +/** + * @since 1.0.0 + */ +export const isNonEmpty = (as: ReadonlyArray): as is NonEmptyReadonlyArray => as.length > 0 diff --git a/src/String.ts b/src/String.ts new file mode 100644 index 000000000..e78ed8cc1 --- /dev/null +++ b/src/String.ts @@ -0,0 +1,390 @@ +/** + * @since 1.0.0 + */ + +import type { Refinement } from "@fp-ts/core/Predicate" +import { isNonEmpty } from "@fp-ts/core/ReadonlyArray" +import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" +import type * as monoid from "@fp-ts/core/typeclass/Monoid" +import type * as order from "@fp-ts/core/typeclass/Order" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" + +/** + * @since 1.0.0 + */ +export const concat = (that: string) => (self: string): string => self + that + +/** + * `string` semigroup under concatenation. + * + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('a', S.Semigroup.combine('b')), 'ab') + * + * @category instances + * @since 1.0.0 + */ +export const Semigroup: semigroup.Semigroup = semigroup.fromCombine(concat) + +/** + * An empty `string`. + * + * @since 1.0.0 + */ +export const empty: "" = "" as const + +/** + * `string` monoid under concatenation. + * + * The `empty` value is `''`. + * + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('a', S.Monoid.combine('b')), 'ab') + * assert.deepStrictEqual(pipe('a', S.Monoid.combine(S.Monoid.empty)), 'a') + * + * @category instances + * @since 1.0.0 + */ +export const Monoid: monoid.Monoid = { + ...Semigroup, + combineAll: (collection) => Semigroup.combineMany(collection)(empty), + empty +} + +/** + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('a', S.Order.compare('a')), 0) + * assert.deepStrictEqual(pipe('a', S.Order.compare('b')), -1) + * assert.deepStrictEqual(pipe('b', S.Order.compare('a')), 1) + * + * @category instances + * @since 1.0.0 + */ +export const Order: order.Order = { + compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 +} + +/** + * @example + * import * as S from '@fp-ts/data/String' + * + * assert.deepStrictEqual(S.isString('a'), true) + * assert.deepStrictEqual(S.isString(1), false) + * + * @category refinements + * @since 1.0.0 + */ +export const isString: Refinement = (u: unknown): u is string => + typeof u === "string" + +/** + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('a', S.toUpperCase), 'A') + * + * @since 1.0.0 + */ +export const toUpperCase = (s: string): string => s.toUpperCase() + +/** + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('A', S.toLowerCase), 'a') + * + * @since 1.0.0 + */ +export const toLowerCase = (s: string): string => s.toLowerCase() + +/** + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('abc', S.replace('b', 'd')), 'adc') + * + * @since 1.0.0 + */ +export const replace = (searchValue: string | RegExp, replaceValue: string) => + (s: string): string => s.replace(searchValue, replaceValue) + +/** + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe(' a ', S.trim), 'a') + * + * @since 1.0.0 + */ +export const trim = (s: string): string => s.trim() + +/** + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe(' a ', S.trimLeft), 'a ') + * + * @since 1.0.0 + */ +export const trimLeft = (s: string): string => s.trimLeft() + +/** + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe(' a ', S.trimRight), ' a') + * + * @since 1.0.0 + */ +export const trimRight = (s: string): string => s.trimRight() + +/** + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('abcd', S.slice(1, 3)), 'bc') + * + * @since 1.0.0 + */ +export const slice = (start: number, end: number) => (s: string): string => s.slice(start, end) + +/** + * Test whether a `string` is empty. + * + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('', S.isEmpty), true) + * assert.deepStrictEqual(pipe('a', S.isEmpty), false) + * + * @since 1.0.0 + */ +export const isEmpty = (s: string): boolean => s.length === 0 + +/** + * Calculate the number of characters in a `string`. + * + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('abc', S.size), 3) + * + * @since 1.0.0 + */ +export const size = (s: string): number => s.length + +/** + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('abc', S.split('')), ['a', 'b', 'c']) + * assert.deepStrictEqual(pipe('', S.split('')), ['']) + * + * @since 1.0.0 + */ +export const split = (separator: string | RegExp) => + (s: string): NonEmptyReadonlyArray => { + const out = s.split(separator) + return isNonEmpty(out) ? out : [s] + } + +/** + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('abc', S.includes('b')), true) + * assert.deepStrictEqual(pipe('abc', S.includes('d')), false) + * + * @since 1.0.0 + */ +export const includes = (searchString: string, position?: number) => + (s: string): boolean => s.includes(searchString, position) + +/** + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('abc', S.startsWith('a')), true) + * assert.deepStrictEqual(pipe('bc', S.startsWith('a')), false) + * + * @since 1.0.0 + */ +export const startsWith = (searchString: string, position?: number) => + (s: string): boolean => s.startsWith(searchString, position) + +/** + * @example + * import * as S from '@fp-ts/data/String' + * import { pipe } from '@fp-ts/data/Function' + * + * assert.deepStrictEqual(pipe('abc', S.endsWith('c')), true) + * assert.deepStrictEqual(pipe('ab', S.endsWith('c')), false) + * + * @since 1.0.0 + */ +export const endsWith = (searchString: string, position?: number) => + (s: string): boolean => s.endsWith(searchString, position) + +/** + * Keep the specified number of characters from the start of a string. + * + * If `n` is larger than the available number of characters, the string will + * be returned whole. + * + * If `n` is not a positive number, an empty string will be returned. + * + * If `n` is a float, it will be rounded down to the nearest integer. + * + * @since 1.0.0 + */ +export const takeLeft = (n: number) => (self: string): string => self.slice(0, Math.max(n, 0)) + +/** + * Keep the specified number of characters from the end of a string. + * + * If `n` is larger than the available number of characters, the string will + * be returned whole. + * + * If `n` is not a positive number, an empty string will be returned. + * + * If `n` is a float, it will be rounded down to the nearest integer. + * + * @since 1.0.0 + */ +export const takeRight = (n: number) => + (s: string): string => s.slice(Math.max(0, s.length - Math.floor(n)), Infinity) + +// TODO: 100% coverage tests (ask Max) +// const CR = 0x0d +// const LF = 0x0a + +// /** +// * Returns an `IterableIterator` which yields each line contained within the +// * string, trimming off the trailing newline character. +// * +// * @since 1.0.0 +// */ +// // export const linesIterator = (self: string): LinesIterator => linesSeparated(self, true) + +// /** +// * Returns an `IterableIterator` which yields each line contained within the +// * string as well as the trailing newline character. +// * +// * @since 1.0.0 +// */ +// export const linesWithSeparators = (s: string): LinesIterator => linesSeparated(s, false) + +// /** +// * For every line in this string, strip a leading prefix consisting of blanks +// * or control characters followed by the character specified by `marginChar` +// * from the line. +// * +// * @since 1.0.0 +// */ +// export const stripMarginWith = (marginChar: string) => +// (self: string): string => { +// let out = "" + +// for (const line of linesWithSeparators(self)) { +// let index = 0 + +// while (index < line.length && line.charAt(index) <= " ") { +// index = index + 1 +// } + +// const stripped = index < line.length && line.charAt(index) === marginChar +// ? line.substring(index + 1) +// : line + +// out = out + stripped +// } + +// return out +// } + +// /** +// * For every line in this string, strip a leading prefix consisting of blanks +// * or control characters followed by the `"|"` character from the line. +// * +// * @since 1.0.0 +// */ +// export const stripMargin = (self: string): string => stripMarginWith("|")(self) + +// class LinesIterator implements IterableIterator { +// private index: number +// private readonly length: number + +// constructor(readonly s: string, readonly stripped: boolean = false) { +// this.index = 0 +// this.length = s.length +// } + +// next(): IteratorResult { +// if (this.done) { +// return { done: true, value: undefined } +// } +// const start = this.index +// while (!this.done && !isLineBreak(this.s[this.index]!)) { +// this.index = this.index + 1 +// } +// let end = this.index +// if (!this.done) { +// const char = this.s[this.index]! +// this.index = this.index + 1 +// if (!this.done && isLineBreak2(char, this.s[this.index]!)) { +// this.index = this.index + 1 +// } +// if (!this.stripped) { +// end = this.index +// } +// } +// return { done: false, value: this.s.substring(start, end) } +// } + +// [Symbol.iterator](): IterableIterator { +// return new LinesIterator(this.s, this.stripped) +// } + +// private get done(): boolean { +// return this.index >= this.length +// } +// } + +// /** +// * Test if the provided character is a line break character (i.e. either `"\r"` +// * or `"\n"`). +// */ +// const isLineBreak = (char: string): boolean => { +// const code = char.charCodeAt(0) +// return code === CR || code === LF +// } + +// /** +// * Test if the provided characters combine to form a carriage return/line-feed +// * (i.e. `"\r\n"`). +// */ +// const isLineBreak2 = (char0: string, char1: string): boolean => +// char0.charCodeAt(0) === CR && char1.charCodeAt(0) === LF + +// const linesSeparated = (self: string, stripped: boolean): LinesIterator => +// new LinesIterator(self, stripped) diff --git a/src/index.ts b/src/index.ts index c2d143034..184afd3a6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,6 +17,8 @@ import * as _function from "@fp-ts/core/Function" import * as number from "@fp-ts/core/Number" import * as ordering from "@fp-ts/core/Ordering" import * as predicate from "@fp-ts/core/Predicate" +import * as readonlyArray from "@fp-ts/core/ReadonlyArray" +import * as string from "@fp-ts/core/String" import * as alternative from "@fp-ts/core/typeclass/Alternative" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" @@ -157,6 +159,10 @@ export { * @since 1.0.0 */ product, + /** + * @since 1.0.0 + */ + readonlyArray, /** * @category typeclass * @since 1.0.0 @@ -182,6 +188,10 @@ export { * @since 1.0.0 */ semiProduct, + /** + * @since 1.0.0 + */ + string, /** * @category typeclass * @since 1.0.0 diff --git a/test/String.ts b/test/String.ts new file mode 100644 index 000000000..033124f35 --- /dev/null +++ b/test/String.ts @@ -0,0 +1,191 @@ +import { pipe } from "@fp-ts/core/Function" +import * as String from "@fp-ts/core/String" +import { deepStrictEqual } from "@fp-ts/core/test/util" +import * as Order from "@fp-ts/core/typeclass/Order" + +describe.concurrent("String", () => { + it("isString", () => { + expect(String.isString("a")).toEqual(true) + expect(String.isString(1)).toEqual(false) + expect(String.isString(true)).toEqual(false) + }) + + it("empty", () => { + expect(String.empty).toEqual("") + }) + + it("Semigroup", () => { + expect(String.Semigroup.combine("b")("a")).toEqual("ab") + expect(String.Semigroup.combineMany(["b", "c"])("a")).toEqual("abc") + expect(String.Semigroup.combineMany([])("a")).toEqual("a") + }) + + it("Monoid", () => { + expect(String.Monoid.combineAll([])).toEqual("") + }) + + it("Order", () => { + const lessThan = Order.lessThan(String.Order) + const lessThanOrEqualTo = Order.lessThanOrEqualTo(String.Order) + expect(pipe("a", lessThan("b"))).toEqual(true) + expect(pipe("a", lessThan("a"))).toEqual(false) + expect(pipe("a", lessThanOrEqualTo("a"))).toEqual(true) + expect(pipe("b", lessThan("a"))).toEqual(false) + expect(pipe("b", lessThanOrEqualTo("a"))).toEqual(false) + }) + + it("concat", () => { + deepStrictEqual(pipe("a", String.concat("b")), "ab") + }) + + it("isEmpty", () => { + deepStrictEqual(String.isEmpty(String.empty), true) + deepStrictEqual(String.isEmpty(""), true) + deepStrictEqual(String.isEmpty("a"), false) + }) + + it("size", () => { + deepStrictEqual(String.size(String.empty), 0) + deepStrictEqual(String.size(""), 0) + deepStrictEqual(String.size("a"), 1) + }) + + it("toUpperCase", () => { + deepStrictEqual(String.toUpperCase("a"), "A") + }) + + it("toLowerCase", () => { + deepStrictEqual(String.toLowerCase("A"), "a") + }) + + it("replace", () => { + deepStrictEqual(pipe("abc", String.replace("b", "d")), "adc") + }) + + it("split", () => { + deepStrictEqual(pipe("abc", String.split("")), ["a", "b", "c"]) + deepStrictEqual(pipe("", String.split("")), [""]) + }) + + it("trim", () => { + deepStrictEqual(pipe(" a ", String.trim), "a") + }) + + it("trimLeft", () => { + deepStrictEqual(pipe(" a ", String.trimLeft), "a ") + }) + + it("trimRight", () => { + deepStrictEqual(pipe(" a ", String.trimRight), " a") + }) + + it("includes", () => { + deepStrictEqual(pipe("abc", String.includes("b")), true) + deepStrictEqual(pipe("abc", String.includes("b", 2)), false) + }) + + it("startsWith", () => { + deepStrictEqual(pipe("abc", String.startsWith("a")), true) + }) + + it("endsWith", () => { + deepStrictEqual(pipe("abc", String.endsWith("c")), true) + }) + + it("slice", () => { + deepStrictEqual(pipe("abcd", String.slice(1, 3)), "bc") + }) + + describe.concurrent("takeLeft", () => { + it("should take the specified number of characters from the left side of a string", () => { + const string = "Hello, World!" + + const result = pipe(string, String.takeLeft(7)) + + assert.strictEqual(result, "Hello, ") + }) + + it("should return the string for `n` larger than the string length", () => { + const string = "Hello, World!" + + const result = pipe(string, String.takeLeft(100)) + + assert.strictEqual(result, string) + }) + + it("should return the empty string for a negative `n`", () => { + const string = "Hello, World!" + + const result = pipe(string, String.takeLeft(-1)) + + assert.strictEqual(result, "") + }) + + it("should round down if `n` is a float", () => { + const string = "Hello, World!" + + const result = pipe(string, String.takeLeft(5.5)) + + assert.strictEqual(result, "Hello") + }) + }) + + describe.concurrent("takeRight", () => { + it("should take the specified number of characters from the right side of a string", () => { + const string = "Hello, World!" + + const result = pipe(string, String.takeRight(7)) + + assert.strictEqual(result, " World!") + }) + + it("should return the string for `n` larger than the string length", () => { + const string = "Hello, World!" + + const result = pipe(string, String.takeRight(100)) + + assert.strictEqual(result, string) + }) + + it("should return the empty string for a negative `n`", () => { + const string = "Hello, World!" + + const result = pipe(string, String.takeRight(-1)) + + assert.strictEqual(result, "") + }) + + it("should round down if `n` is a float", () => { + const string = "Hello, World!" + + const result = pipe(string, String.takeRight(6.5)) + + assert.strictEqual(result, "World!") + }) + }) + + // TODO: 100% coverage tests (ask Max) + // describe.concurrent("stripMargin", () => { + // it("should strip a leading prefix from each line", () => { + // const string = `| + // |Hello, + // |World! + // |` + + // const result = pipe(string, String.stripMargin) + + // assert.strictEqual(result, "\nHello,\nWorld!\n") + // }) + + // it("should strip a leading prefix from each line using a margin character", () => { + // const string = `$ + // $Hello, + // $World! + // $` + + // const result = pipe(string, String.stripMarginWith("$")) + + // assert.strictEqual(result, "\nHello,\nWorld!\n") + // }) + // }) +}) From e1050e9e304ec39fd632695900cbcc7fd6247450 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 15 Jan 2023 17:45:04 +0100 Subject: [PATCH 016/255] add Identity module --- .changeset/cyan-melons-own.md | 5 + src/Identity.ts | 534 ++++++++++++++++++++++++++++++++++ src/Predicate.ts | 6 +- src/index.ts | 5 + test/Identity.ts | 136 +++++++++ test/internal/Iterable.ts | 8 +- 6 files changed, 687 insertions(+), 7 deletions(-) create mode 100644 .changeset/cyan-melons-own.md create mode 100644 src/Identity.ts create mode 100644 test/Identity.ts diff --git a/.changeset/cyan-melons-own.md b/.changeset/cyan-melons-own.md new file mode 100644 index 000000000..7665266f3 --- /dev/null +++ b/.changeset/cyan-melons-own.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add Identity module diff --git a/src/Identity.ts b/src/Identity.ts new file mode 100644 index 000000000..0f759d7f6 --- /dev/null +++ b/src/Identity.ts @@ -0,0 +1,534 @@ +/** + * @since 1.0.0 + */ +import { identity } from "@fp-ts/core/Function" +import type { Kind, TypeLambda } from "@fp-ts/core/HKT" +import * as iterable from "@fp-ts/core/internal/Iterable" +import * as applicative from "@fp-ts/core/typeclass/Applicative" +import * as chainable from "@fp-ts/core/typeclass/Chainable" +import type * as coproduct_ from "@fp-ts/core/typeclass/Coproduct" +import * as covariant from "@fp-ts/core/typeclass/Covariant" +import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" +import * as foldable from "@fp-ts/core/typeclass/Foldable" +import * as invariant from "@fp-ts/core/typeclass/Invariant" +import type * as monad from "@fp-ts/core/typeclass/Monad" +import type { Monoid } from "@fp-ts/core/typeclass/Monoid" +import * as of_ from "@fp-ts/core/typeclass/Of" +import type * as pointed from "@fp-ts/core/typeclass/Pointed" +import * as product_ from "@fp-ts/core/typeclass/Product" +import type * as semiAlternative from "@fp-ts/core/typeclass/SemiAlternative" +import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" +import type * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" +import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import * as traversable from "@fp-ts/core/typeclass/Traversable" + +/** + * @category models + * @since 1.0.0 + */ +export type Identity = A + +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface IdentityTypeLambda extends TypeLambda { + readonly type: Identity +} + +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface IdentityTypeLambdaFix extends TypeLambda { + readonly type: Identity +} + +/** + * @since 1.0.0 + */ +export const map = (f: (a: A) => B) => (self: Identity): Identity => f(self) + +/** + * @since 1.0.0 + */ +export const imap: ( + to: (a: A) => B, + from: (b: B) => A +) => (self: Identity) => Identity = covariant + .imap(map) + +/** + * @category instances + * @since 1.0.0 + */ +export const Invariant: invariant.Invariant = { + imap +} + +/** + * @since 1.0.0 + */ +export const tupled: (self: Identity) => Identity = invariant.tupled(Invariant) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindTo: ( + name: N +) => (self: Identity) => Identity<{ readonly [K in N]: A }> = invariant.bindTo(Invariant) + +/** + * @category instances + * @since 1.0.0 + */ +export const Covariant: covariant.Covariant = { + ...Invariant, + map +} + +const let_: ( + name: Exclude, + f: (a: A) => B +) => ( + self: Identity +) => Identity<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant.let( + Covariant +) + +export { + /** + * @category do notation + * @since 1.0.0 + */ + let_ as let +} + +/** + * @category mapping + * @since 1.0.0 + */ +export const flap: (a: A) => (fab: Identity<(a: A) => B>) => Identity = covariant.flap( + Covariant +) + +/** + * Maps the success value of this effect to the specified constant value. + * + * @category mapping + * @since 1.0.0 + */ +export const as: (b: B) => <_>(self: Identity<_>) => Identity = covariant.as(Covariant) + +/** + * Returns the effect resulting from mapping the success of this effect to unit. + * + * @category mapping + * @since 1.0.0 + */ +export const asUnit: <_>(self: Identity<_>) => Identity = covariant.asUnit(Covariant) + +/** + * @category constructors + * @since 1.0.0 + */ +export const of: (a: A) => Identity = identity + +/** + * @category instances + * @since 1.0.0 + */ +export const Of: of_.Of = { + of +} + +/** + * @since 1.0.0 + */ +export const unit: Identity = of_.unit(Of) + +/** + * @category do notation + * @since 1.0.0 + */ +export const Do: Identity<{}> = of_.Do(Of) + +/** + * @category instances + * @since 1.0.0 + */ +export const Pointed: pointed.Pointed = { + ...Of, + ...Covariant +} + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMap = (f: (a: A) => Identity) => + (self: Identity): Identity => f(self) + +/** + * @category instances + * @since 1.0.0 + */ +export const FlatMap: flatMap_.FlatMap = { + flatMap +} + +/** + * @since 1.0.0 + */ +export const flatten: (self: Identity>) => Identity = flatMap_ + .flatten(FlatMap) + +/** + * @since 1.0.0 + */ +export const andThen: (that: Identity) => <_>(self: Identity<_>) => Identity = flatMap_ + .andThen(FlatMap) + +/** + * @since 1.0.0 + */ +export const composeKleisliArrow: ( + bfc: (b: B) => Identity +) => (afb: (a: A) => Identity) => (a: A) => Identity = flatMap_ + .composeKleisliArrow(FlatMap) + +/** + * @category instances + * @since 1.0.0 + */ +export const Chainable: chainable.Chainable = { + ...FlatMap, + ...Covariant +} + +/** + * @category do notation + * @since 1.0.0 + */ +export const bind: ( + name: Exclude, + f: (a: A) => Identity +) => ( + self: Identity +) => Identity<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable.bind( + Chainable +) + +/** + * Returns an effect that effectfully "peeks" at the success of this effect. + * + * @since 1.0.0 + */ +export const tap: (f: (a: A) => Identity<_>) => (self: Identity) => Identity = chainable + .tap( + Chainable + ) + +/** + * Sequences the specified effect after this effect, but ignores the value + * produced by the effect. + * + * @category sequencing + * @since 1.0.0 + */ +export const andThenDiscard: <_>(that: Identity<_>) => (self: Identity) => Identity = + chainable + .andThenDiscard(Chainable) + +/** + * @category instances + * @since 1.0.0 + */ +export const Monad: monad.Monad = { + ...Pointed, + ...FlatMap +} + +/** + * @since 1.0.0 + */ +export const product = ( + that: Identity +) => (self: Identity): Identity => [self, that] + +/** + * @since 1.0.0 + */ +export const productMany = (collection: Iterable>) => + (self: Identity): Identity]> => [self, ...collection] + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiProduct: semiProduct.SemiProduct = { + ...Invariant, + product, + productMany +} + +/** + * A variant of `bind` that sequentially ignores the scope. + * + * @category do notation + * @since 1.0.0 + */ +export const andThenBind: ( + name: Exclude, + fb: Identity +) => ( + self: Identity +) => Identity<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct + .andThenBind(SemiProduct) + +/** + * @since 1.0.0 + */ +export const productFlatten: ( + fb: Identity +) => >(self: Identity) => Identity = + semiProduct + .productFlatten(SemiProduct) + +/** + * @since 1.0.0 + */ +export const productAll = (collection: Iterable>): Identity> => + iterable.fromIterable(collection) + +/** + * @category instances + * @since 1.0.0 + */ +export const Product: product_.Product = { + ...Of, + ...SemiProduct, + productAll +} + +/** + * @since 1.0.0 + */ +export const tuple: >>( + ...tuple: T +) => Identity] ? A : never }>> = + product_ + .tuple(Product) + +/** + * @since 1.0.0 + */ +export const struct: >>( + r: R +) => Identity<{ readonly [K in keyof R]: [R[K]] extends [Identity] ? A : never }> = + product_ + .struct(Product) + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiApplicative: semiApplicative.SemiApplicative = { + ...SemiProduct, + ...Covariant +} + +/** + * @category instances + * @since 1.0.0 + */ +export const liftSemigroup: (S: Semigroup) => Semigroup> = semiApplicative + .liftSemigroup(SemiApplicative) + +/** + * Lifts a binary function into `Identity`. + * + * @category lifting + * @since 1.0.0 + */ +export const lift2: ( + f: (a: A, b: B) => C +) => (fa: Identity, fb: Identity) => Identity = semiApplicative.lift2( + SemiApplicative +) + +/** + * Lifts a ternary function into `Identity`. + * + * @category lifting + * @since 1.0.0 + */ +export const lift3: ( + f: (a: A, b: B, c: C) => D +) => (fa: Identity, fb: Identity, fc: Identity) => Identity = semiApplicative.lift3( + SemiApplicative +) + +/** + * @since 1.0.0 + */ +export const ap: ( + fa: Identity +) => (self: Identity<(a: A) => B>) => Identity = semiApplicative.ap( + SemiApplicative +) + +/** + * @category instances + * @since 1.0.0 + */ +export const Applicative: applicative.Applicative = { + ...SemiApplicative, + ...Product +} + +/** + * @since 1.0.0 + */ +export const liftMonoid: (M: Monoid) => Monoid> = applicative.liftMonoid( + Applicative +) + +/** + * @category instances + * @since 1.0.0 + */ +export const getSemiCoproduct = ( + S: Semigroup +): semiCoproduct.SemiCoproduct> => ({ + imap: Invariant.imap, + coproduct: S.combine, + coproductMany: S.combineMany +}) + +/** + * @category instances + * @since 1.0.0 + */ +export const getSemiAlternative = ( + S: Semigroup +): semiAlternative.SemiAlternative> => ({ + ...getSemiCoproduct(S), + map: Covariant.map +}) + +/** + * @category folding + * @since 1.0.0 + */ +export const reduce = (b: B, f: (b: B, a: A) => B) => (self: Identity): B => f(b, self) + +/** + * @category folding + * @since 1.0.0 + */ +export const reduceRight = (b: B, f: (b: B, a: A) => B) => + (self: Identity): B => f(b, self) + +/** + * @category instances + * @since 1.0.0 + */ +export const Foldable: foldable.Foldable = { + reduce +} + +/** + * @category folding + * @since 1.0.0 + */ +export const foldMap: (M: Monoid) => (f: (a: A) => M) => (self: Identity) => M = + foldable + .foldMap(Foldable) + +/** + * @category conversions + * @since 1.0.0 + */ +export const toArray: (self: Identity) => Array = foldable.toArray(Foldable) + +/** + * @category conversions + * @since 1.0.0 + */ +export const toArrayWith: (f: (a: A) => B) => (self: Identity) => Array = foldable + .toArrayWith(Foldable) + +/** + * @category folding + * @since 1.0.0 + */ +export const reduceKind: ( + G: monad.Monad +) => ( + b: B, + f: (b: B, a: A) => Kind +) => (self: Identity) => Kind = foldable.reduceKind(Foldable) + +/** + * @category folding + * @since 1.0.0 + */ +export const reduceRightKind: ( + G: monad.Monad +) => ( + b: B, + f: (b: B, a: A) => Kind +) => (self: Identity) => Kind = foldable.reduceRightKind(Foldable) + +/** + * @category folding + * @since 1.0.0 + */ +export const foldMapKind: ( + G: coproduct_.Coproduct +) => ( + f: (a: A) => Kind +) => (self: Identity) => Kind = foldable.foldMapKind(Foldable) + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverse = ( + F: applicative.Applicative +) => + ( + f: (a: A) => Kind + ) => (self: Identity): Kind> => f(self) + +/** + * @category traversing + * @since 1.0.0 + */ +export const sequence: ( + F: applicative.Applicative +) => (fas: Identity>) => Kind> = traversable + .sequence(traverse) + +/** + * @category instances + * @since 1.0.0 + */ +export const Traversable: traversable.Traversable = { + traverse, + sequence +} + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverseTap: ( + F: applicative.Applicative +) => ( + f: (a: A) => Kind +) => (self: Identity) => Kind> = traversable + .traverseTap(Traversable) diff --git a/src/Predicate.ts b/src/Predicate.ts index 9dd93719a..641ba2169 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -3,7 +3,7 @@ */ import { constFalse, constTrue } from "@fp-ts/core/Function" import type { TypeLambda } from "@fp-ts/core/HKT" -import * as I from "@fp-ts/core/internal/Iterable" +import * as iterable from "@fp-ts/core/internal/Iterable" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monoid from "@fp-ts/core/typeclass/Monoid" @@ -132,7 +132,7 @@ export const productMany = (collection: Iterable>) => if (self(head) === false) { return false } - const predicates = I.fromIterable(collection) + const predicates = iterable.fromIterable(collection) for (let i = 0; i < predicates.length; i++) { if (predicates[i](tail[i]) === false) { return false @@ -159,7 +159,7 @@ export const productAll = ( collection: Iterable> ): Predicate> => (as) => { - const predicates = I.fromIterable(collection) + const predicates = iterable.fromIterable(collection) for (let i = 0; i < predicates.length; i++) { if (predicates[i](as[i]) === false) { return false diff --git a/src/index.ts b/src/index.ts index 184afd3a6..251fb5e74 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,7 @@ import * as hkt from "@fp-ts/core/HKT" import * as boolean from "@fp-ts/core/Boolean" import * as _function from "@fp-ts/core/Function" +import * as identity from "@fp-ts/core/Identity" import * as number from "@fp-ts/core/Number" import * as ordering from "@fp-ts/core/Ordering" import * as predicate from "@fp-ts/core/Predicate" @@ -107,6 +108,10 @@ export { * @since 1.0.0 */ hkt, + /** + * @since 1.0.0 + */ + identity, /** * @category typeclass * @since 1.0.0 diff --git a/test/Identity.ts b/test/Identity.ts new file mode 100644 index 000000000..1de2992f9 --- /dev/null +++ b/test/Identity.ts @@ -0,0 +1,136 @@ +import { pipe } from "@fp-ts/core/Function" +import * as _ from "@fp-ts/core/Identity" +// import * as O from "@fp-ts/core/Option" +import * as String from "@fp-ts/core/String" +import * as U from "./util" + +describe.concurrent("Identity", () => { + it("instances and derived exports", () => { + expect(_.Invariant).exist + expect(_.imap).exist + expect(_.tupled).exist + expect(_.bindTo).exist + + expect(_.Covariant).exist + expect(_.map).exist + expect(_.let).exist + expect(_.flap).exist + expect(_.as).exist + expect(_.asUnit).exist + + expect(_.Of).exist + expect(_.of).exist + expect(_.Do).exist + + expect(_.Pointed).exist + + expect(_.FlatMap).exist + expect(_.flatMap).exist + expect(_.flatten).exist + expect(_.andThen).exist + expect(_.composeKleisliArrow).exist + + expect(_.Chainable).exist + expect(_.bind).exist + expect(_.tap).exist + expect(_.andThenDiscard).exist + + expect(_.Monad).exist + + expect(_.SemiProduct).exist + expect(_.product).exist + expect(_.productMany).exist + expect(_.andThenBind).exist + expect(_.productFlatten).exist + + expect(_.Product).exist + expect(_.productAll).exist + expect(_.tuple).exist + expect(_.struct).exist + + expect(_.SemiApplicative).exist + expect(_.liftSemigroup).exist + expect(_.lift2).exist + expect(_.lift3).exist + expect(_.ap).exist + expect(_.andThenDiscard).exist + expect(_.andThen).exist + + expect(_.Applicative).exist + expect(_.liftMonoid).exist + + expect(_.Foldable).exist + expect(_.reduce).exist + expect(_.reduceRight).exist + expect(_.foldMap).exist + expect(_.toArray).exist + expect(_.toArrayWith).exist + expect(_.reduceKind).exist + expect(_.reduceRightKind).exist + expect(_.foldMapKind).exist + + expect(_.Traversable).exist + expect(_.traverse).exist + expect(_.sequence).exist + expect(_.traverseTap).exist + }) + + it("unit", () => { + U.deepStrictEqual(_.unit, undefined) + }) + + it("of", () => { + U.deepStrictEqual(_.of("a"), "a") + }) + + it("SemiProduct", () => { + U.deepStrictEqual(pipe("a", _.SemiProduct.productMany(["b", "c"])), ["a", "b", "c"]) + }) + + it("Product", () => { + U.deepStrictEqual(_.Product.productAll([]), []) + U.deepStrictEqual(_.Product.productAll(["a", "b", "c"]), ["a", "b", "c"]) + }) + + it("flatMap", () => { + U.deepStrictEqual( + pipe("a", _.flatMap((a) => a + "b")), + "ab" + ) + }) + + it("product", () => { + U.deepStrictEqual(pipe("a", _.product("b")), ["a", "b"]) + }) + + it("getSemiCoproduct", () => { + const F = _.getSemiCoproduct(String.Semigroup) + U.deepStrictEqual(pipe("a", F.coproduct("b")), "ab") + U.deepStrictEqual(pipe("a", F.coproductMany(["b", "c"])), "abc") + }) + + it("getSemiAlternative", () => { + const F = _.getSemiAlternative(String.Semigroup) + U.deepStrictEqual(pipe("a", F.coproduct("b")), "ab") + U.deepStrictEqual(pipe("a", F.coproductMany(["b", "c"])), "abc") + }) + + it("reduce", () => { + U.deepStrictEqual(pipe("b", _.reduce("a", (b, a) => b + a)), "ab") + U.deepStrictEqual(pipe("b", _.Foldable.reduce("a", (b, a) => b + a)), "ab") + }) + + it("reduceRight", () => { + const f = (a: string, acc: string) => acc + a + U.deepStrictEqual(pipe("a", _.reduceRight("", f)), "a") + }) + + // TODO + // it("traverse", () => { + // U.deepStrictEqual(pipe(1, _.traverse(O.Applicative)(O.some)), O.some(1)) + // U.deepStrictEqual(pipe(1, _.traverse(O.Applicative)(() => O.none)), O.none) + + // U.deepStrictEqual(pipe(1, _.Traversable.traverse(O.Applicative)(O.some)), O.some(1)) + // U.deepStrictEqual(pipe(1, _.Traversable.traverse(O.Applicative)(() => O.none)), O.none) + // }) +}) diff --git a/test/internal/Iterable.ts b/test/internal/Iterable.ts index c71b77e69..7ee04a196 100644 --- a/test/internal/Iterable.ts +++ b/test/internal/Iterable.ts @@ -1,12 +1,12 @@ -import * as I from "@fp-ts/core/internal/Iterable" +import * as iterable from "@fp-ts/core/internal/Iterable" describe.concurrent("internal/Iterable", () => { it("fromIterable/Array should return the same reference if the iterable is an Array", () => { - const iterable = [1, 2, 3] - expect(I.fromIterable(iterable) === iterable).toEqual(true) + const i = [1, 2, 3] + expect(iterable.fromIterable(i) === i).toEqual(true) }) it("fromIterable/Iterable", () => { - expect(I.fromIterable(new Set([1, 2, 3]))).toEqual([1, 2, 3]) + expect(iterable.fromIterable(new Set([1, 2, 3]))).toEqual([1, 2, 3]) }) }) From 3ac3256c56ba5496d832f7b3033dc6dd9db1916a Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 06:46:33 +0100 Subject: [PATCH 017/255] add Equivalence module --- .changeset/polite-mice-begin.md | 5 + src/Boolean.ts | 9 ++ src/Number.ts | 7 ++ src/String.ts | 9 +- src/index.ts | 6 + src/typeclass/Equivalence.ts | 209 ++++++++++++++++++++++++++++++++ src/typeclass/Product.ts | 2 +- src/typeclass/SemiProduct.ts | 4 +- test/Boolean.ts | 7 ++ test/Number.ts | 5 + test/String.ts | 5 + test/typeclass/Equivalence.ts | 168 +++++++++++++++++++++++++ 12 files changed, 432 insertions(+), 4 deletions(-) create mode 100644 .changeset/polite-mice-begin.md create mode 100644 src/typeclass/Equivalence.ts create mode 100644 test/typeclass/Equivalence.ts diff --git a/.changeset/polite-mice-begin.md b/.changeset/polite-mice-begin.md new file mode 100644 index 000000000..a4b66a2e5 --- /dev/null +++ b/.changeset/polite-mice-begin.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add Equivalence module diff --git a/src/Boolean.ts b/src/Boolean.ts index 0b6f092b9..7db4ed1d3 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -3,6 +3,7 @@ */ import type { LazyArg } from "@fp-ts/core/Function" import type { Refinement } from "@fp-ts/core/Predicate" +import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import type * as monoid from "@fp-ts/core/typeclass/Monoid" import type * as order from "@fp-ts/core/typeclass/Order" import type * as semigroup from "@fp-ts/core/typeclass/Semigroup" @@ -15,11 +16,13 @@ export const isBoolean: Refinement = (u: unknown): u is boolea typeof u === "boolean" /** + * @category combinators * @since 1.0.0 */ export const and = (that: boolean) => (self: boolean): boolean => self && that /** + * @category combinators * @since 1.0.0 */ export const or = (that: boolean) => (self: boolean): boolean => self || that @@ -135,6 +138,12 @@ export const MonoidAny: monoid.Monoid = { empty: false } +/** + * @category instances + * @since 1.0.0 + */ +export const Equivalence: equivalence.Equivalence = equivalence.boolean + /** * @category instances * @since 1.0.0 diff --git a/src/Number.ts b/src/Number.ts index 100d871ab..83080a28f 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -4,6 +4,7 @@ import type { Ordering } from "@fp-ts/core/Ordering" import type { Refinement } from "@fp-ts/core/Predicate" import type * as bounded from "@fp-ts/core/typeclass/Bounded" +import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import type * as monoid from "@fp-ts/core/typeclass/Monoid" import type * as order from "@fp-ts/core/typeclass/Order" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" @@ -40,6 +41,12 @@ export const increment = (n: number): number => n + 1 */ export const decrement = (n: number): number => n - 1 +/** + * @category instances + * @since 1.0.0 + */ +export const Equivalence: equivalence.Equivalence = equivalence.number + /** * @category instances * @since 1.0.0 diff --git a/src/String.ts b/src/String.ts index e78ed8cc1..98921c6de 100644 --- a/src/String.ts +++ b/src/String.ts @@ -5,6 +5,7 @@ import type { Refinement } from "@fp-ts/core/Predicate" import { isNonEmpty } from "@fp-ts/core/ReadonlyArray" import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" +import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import type * as monoid from "@fp-ts/core/typeclass/Monoid" import type * as order from "@fp-ts/core/typeclass/Order" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" @@ -56,6 +57,12 @@ export const Monoid: monoid.Monoid = { empty } +/** + * @category instances + * @since 1.0.0 + */ +export const Equivalence: equivalence.Equivalence = equivalence.string + /** * @example * import * as S from '@fp-ts/data/String' @@ -175,7 +182,7 @@ export const slice = (start: number, end: number) => (s: string): string => s.sl * * @since 1.0.0 */ -export const isEmpty = (s: string): boolean => s.length === 0 +export const isEmpty = (s: string): s is "" => s.length === 0 /** * Calculate the number of characters in a `string`. diff --git a/src/index.ts b/src/index.ts index 251fb5e74..7830f9c29 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,6 +28,7 @@ import * as chainable from "@fp-ts/core/typeclass/Chainable" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import * as coproduct from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" +import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as flatMap from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" @@ -94,6 +95,11 @@ export { * @since 1.0.0 */ covariant, + /** + * @category typeclass + * @since 1.0.0 + */ + equivalence, /** * @category typeclass * @since 1.0.0 diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts new file mode 100644 index 000000000..762f7790c --- /dev/null +++ b/src/typeclass/Equivalence.ts @@ -0,0 +1,209 @@ +/** + * This module provides an implementation of the `Equivalence` type class. + * An `Equivalence` is a binary relation that is reflexive, symmetric and transitive. + * + * @since 1.0.0 + */ +import type { TypeLambda } from "@fp-ts/core/HKT" +import * as contravariant from "@fp-ts/core/typeclass/Contravariant" +import type * as invariant from "@fp-ts/core/typeclass/Invariant" +import type { Monoid } from "@fp-ts/core/typeclass/Monoid" +import * as monoid from "@fp-ts/core/typeclass/Monoid" +import type * as product from "@fp-ts/core/typeclass/Product" +import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" +import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" + +/** + * @category type class + * @since 1.0.0 + */ +export interface Equivalence { + (x: A, y: A): boolean +} + +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface EquivalenceTypeLambda extends TypeLambda { + readonly type: Equivalence +} + +/** + * Return an `Equivalence` that uses strict equality (===) to compare values + * + * @since 1.0.0 + * @category constructors + */ +export const strict: () => Equivalence = () => (x, y) => x === y + +/** + * @category instances + * @since 1.0.0 + */ +export const string: Equivalence = strict() + +/** + * @category instances + * @since 1.0.0 + */ +export const number: Equivalence = strict() + +/** + * @category instances + * @since 1.0.0 + */ +export const boolean: Equivalence = strict() + +/** + * @category instances + * @since 1.0.0 + */ +export const bigint: Equivalence = strict() + +/** + * @category instances + * @since 1.0.0 + */ +export const symbol: Equivalence = strict() + +/** + * Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple + * by applying each `Equivalence` to the corresponding element of the tuple. + * + * @category constructors + * @since 1.0.0 + */ +export const tuple = >( + ...equivalences: { readonly [K in keyof A]: Equivalence } +): Equivalence> => + (x, y) => equivalences.every((equivalence, i) => equivalence(x[i], y[i])) + +/** + * Given an `Equivalence` of type `A`, returns a new `Equivalence` of type `ReadonlyArray`. + * The returned `Equivalence` compares arrays by first checking their length and then applying the provided `Equivalence` to each element. + * If all comparisons return true, the arrays are considered equal. + * + * @category constructors + * @since 1.0.0 + */ +export const array = ( + equivalence: Equivalence +): Equivalence> => + (x, y) => x.length === y.length && x.every((a, i) => equivalence(a, y[i])) + +/** + * Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct + * by applying each `Equivalence` to the corresponding property of the struct. + * + * @category constructors + * @since 1.0.0 + */ +export const struct = ( + equivalences: { [K in keyof A]: Equivalence } +): Equivalence<{ readonly [K in keyof A]: A[K] }> => + (x, y) => { + for (const key in equivalences) { + if (!equivalences[key](x[key], y[key])) { + return false + } + } + return true + } + +/** + * Given an `Equivalence` of type `A`, returns a new `Equivalence` of type `{ readonly [x: string]: A }`. + * The returned `Equivalence` compares records by first checking their number of keys and then applying the provided `Equivalence` to each value. + * If all comparisons return true, the records are considered equal. + * + * @category constructors + * @since 1.0.0 + */ +export const record = ( + equivalence: Equivalence +): Equivalence<{ readonly [x: string]: A }> => + (x, y) => { + const keys = Object.keys(x) + if (Object.keys(y).length !== keys.length) { + return false + } + for (const key of keys) { + if (!equivalence(x[key], y[key])) { + return false + } + } + return true + } + +/** + * @category instances + * @since 2.10.0 + */ +export const getSemigroup = (): Semigroup> => ({ + combine: (that) => (self) => (x, y) => self(x, y) && that(x, y), + combineMany: (collection) => + self => + (x, y) => { + if (!self(x, y)) { + return false + } + for (const equivalence of collection) { + if (!equivalence(x, y)) { + return false + } + } + return true + } +}) + +const empty: Equivalence = () => true + +/** + * @category instances + * @since 2.6.0 + */ +export const getMonoid = (): Monoid> => + monoid.fromSemigroup(getSemigroup(), empty) + +/** + * @category combinators + * @since 1.0.0 + */ +export const contramap = (f: (b: B) => A) => + (self: Equivalence): Equivalence => (x, y) => self(f(x), f(y)) + +/** + * @category instances + * @since 1.0.0 + */ +export const Contravariant: contravariant.Contravariant = contravariant.make( + contramap +) + +/** + * @category instances + * @since 1.0.0 + */ +export const Invariant: invariant.Invariant = { + imap: Contravariant.imap +} + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiProduct: semiProduct.SemiProduct = { + imap: Contravariant.imap, + product: that => self => tuple(self, that), + productMany: collection => self => tuple(self, ...collection) +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Product: product.Product = { + ...SemiProduct, + of: () => empty, + productAll: (collection: Iterable>) => tuple>(...collection) +} diff --git a/src/typeclass/Product.ts b/src/typeclass/Product.ts index 675d7c733..e6129ea94 100644 --- a/src/typeclass/Product.ts +++ b/src/typeclass/Product.ts @@ -32,7 +32,7 @@ export const tuple = (F: Product) => * @since 1.0.0 */ export const struct = (F: Product) => - }>(fields: R): Kind< + }>(fields: R): Kind< F, ([R[keyof R]] extends [Kind] ? R : never), ([R[keyof R]] extends [Kind] ? O : never), diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 9bc244c14..833aa743c 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -156,8 +156,8 @@ type EnforceNonEmptyRecord = keyof R extends never ? never : R * @since 1.0.0 */ export const nonEmptyStruct = (F: SemiProduct) => - }>( - fields: EnforceNonEmptyRecord & { readonly [x: PropertyKey]: Kind } + }>( + fields: EnforceNonEmptyRecord & { readonly [x: string]: Kind } ): Kind< F, ([R[keyof R]] extends [Kind] ? R : never), diff --git a/test/Boolean.ts b/test/Boolean.ts index 745c44f16..d9d7a3aae 100644 --- a/test/Boolean.ts +++ b/test/Boolean.ts @@ -70,6 +70,13 @@ describe.concurrent("Boolean", () => { deepStrictEqual(match(false), "false") }) + it("Equivalence", () => { + expect(Boolean.Equivalence(true, true)).toBe(true) + expect(Boolean.Equivalence(false, false)).toBe(true) + expect(Boolean.Equivalence(true, false)).toBe(false) + expect(Boolean.Equivalence(false, true)).toBe(false) + }) + it("Order", () => { deepStrictEqual(pipe(false, Boolean.Order.compare(true)), -1) deepStrictEqual(pipe(true, Boolean.Order.compare(false)), 1) diff --git a/test/Number.ts b/test/Number.ts index 2c4488ce4..a68aa5692 100644 --- a/test/Number.ts +++ b/test/Number.ts @@ -29,6 +29,11 @@ describe.concurrent("Number", () => { deepStrictEqual(Number.decrement(2), 1) }) + it("Equivalence", () => { + expect(Number.Equivalence(1, 1)).toBe(true) + expect(Number.Equivalence(1, 2)).toBe(false) + }) + it("Order", () => { deepStrictEqual(pipe(1, Number.Order.compare(2)), -1) deepStrictEqual(pipe(2, Number.Order.compare(1)), 1) diff --git a/test/String.ts b/test/String.ts index 033124f35..31f099c75 100644 --- a/test/String.ts +++ b/test/String.ts @@ -24,6 +24,11 @@ describe.concurrent("String", () => { expect(String.Monoid.combineAll([])).toEqual("") }) + it("Equivalence", () => { + expect(String.Equivalence("a", "a")).toBe(true) + expect(String.Equivalence("a", "b")).toBe(false) + }) + it("Order", () => { const lessThan = Order.lessThan(String.Order) const lessThanOrEqualTo = Order.lessThanOrEqualTo(String.Order) diff --git a/test/typeclass/Equivalence.ts b/test/typeclass/Equivalence.ts new file mode 100644 index 000000000..6411c8247 --- /dev/null +++ b/test/typeclass/Equivalence.ts @@ -0,0 +1,168 @@ +import { pipe } from "@fp-ts/core/Function" +import * as _ from "@fp-ts/core/typeclass/Equivalence" + +describe("Equivalence", () => { + it("exports", () => { + expect(_.Contravariant).exists + }) + + test("strict returns an Equivalence that uses strict equality (===) to compare values", () => { + const eq = _.strict<{ a: number }>() + const a = { a: 1 } + expect(eq(a, a)).toBe(true) + expect(eq({ a: 1 }, { a: 1 })).toBe(false) + }) + + it("bigint", () => { + const eq = _.bigint + expect(eq(1n, 1n)).toBe(true) + expect(eq(1n, 2n)).toBe(false) + }) + + it("symbol", () => { + const eq = _.symbol + expect(eq(Symbol.for("@fp-ts/core/test/a"), Symbol.for("@fp-ts/core/test/a"))).toBe(true) + expect(eq(Symbol.for("@fp-ts/core/test/a"), Symbol.for("@fp-ts/core/test/b"))).toBe(false) + }) + + it("tuple", () => { + const eqTuple = _.tuple(_.string, _.number, _.boolean) + expect(eqTuple(["a", 1, true], ["a", 1, true])).toEqual(true) + expect(eqTuple(["a", 1, true], ["b", 1, true])).toEqual(false) + expect(eqTuple(["a", 1, true], ["a", 2, true])).toEqual(false) + expect(eqTuple(["a", 1, true], ["a", 1, false])).toEqual(false) + }) + + describe("array", () => { + it("returns true when all the elements of the arrays are equal according to the provided Equivalence", () => { + const eqA = _.string + const eqArray = _.array(eqA) + expect(eqArray(["a", "b"], ["a", "b"])).toBe(true) + }) + + it("returns false when at least one element of the arrays is not equal according to the provided Equivalence", () => { + const eqA = _.string + const eqArray = _.array(eqA) + expect(eqArray(["a", "b"], ["b", "b"])).toBe(false) + expect(eqArray(["a", "b"], ["a", "c"])).toBe(false) + }) + + it("returns false when comparing arrays of different length", () => { + const eqA = _.string + const eqArray = _.array(eqA) + expect(eqArray(["a"], ["a", "b"])).toBe(false) + expect(eqArray(["a", "b"], ["a"])).toBe(false) + }) + }) + + describe("record", () => { + it("returns true when all the values of the records are equal according to the provided Equivalence", () => { + const eqA = _.string + const eqRecord = _.record(eqA) + expect(eqRecord({ a: "a", b: "b" }, { a: "a", b: "b" })).toBe(true) + }) + + it("returns false when at least one value of the records is not equal according to the provided Equivalence", () => { + const eqA = _.string + const eqRecord = _.record(eqA) + expect(eqRecord({ a: "a", b: "b" }, { a: "b", b: "b" })).toBe(false) + expect(eqRecord({ a: "a", b: "b" }, { a: "a", b: "c" })).toBe(false) + }) + + it("returns false when comparing records with a different number of keys", () => { + const eqA = _.string + const eqRecord = _.record(eqA) + expect(eqRecord({ a: "a" }, { a: "a", b: "b" })).toBe(false) + expect(eqRecord({ a: "a", b: "b" }, { a: "a" })).toBe(false) + }) + }) + + it("struct", () => { + const eqStruct = _.struct({ a: _.string, b: _.number, c: _.boolean }) + expect(eqStruct({ a: "a", b: 1, c: true }, { a: "a", b: 1, c: true })).toEqual(true) + expect(eqStruct({ a: "a", b: 1, c: true }, { a: "b", b: 1, c: true })).toEqual(false) + expect(eqStruct({ a: "a", b: 1, c: true }, { a: "a", b: 2, c: true })).toEqual(false) + expect(eqStruct({ a: "a", b: 1, c: true }, { a: "a", b: 1, c: false })).toEqual(false) + }) + + it("contramap", () => { + interface Person { + readonly name: string + readonly age: number + } + const eqPerson = pipe(_.string, _.contramap((p: Person) => p.name)) + expect(eqPerson({ name: "a", age: 1 }, { name: "a", age: 2 })).toEqual(true) + expect(eqPerson({ name: "a", age: 1 }, { name: "a", age: 1 })).toEqual(true) + expect(eqPerson({ name: "a", age: 1 }, { name: "b", age: 1 })).toEqual(false) + expect(eqPerson({ name: "a", age: 1 }, { name: "b", age: 2 })).toEqual(false) + }) + + it("getSemigroup", () => { + type T = readonly [string, number, boolean] + const S = _.getSemigroup() + const E0: _.Equivalence = _.contramap((x: T) => x[0])(_.string) + const E1: _.Equivalence = _.contramap((x: T) => x[1])(_.number) + const eqE0E1 = pipe(E0, S.combine(E1)) + expect(eqE0E1(["a", 1, true], ["a", 1, true])).toEqual(true) + expect(eqE0E1(["a", 1, true], ["a", 1, false])).toEqual(true) + expect(eqE0E1(["a", 1, true], ["b", 1, true])).toEqual(false) + expect(eqE0E1(["a", 1, true], ["a", 2, false])).toEqual(false) + const E2: _.Equivalence = _.contramap((x: T) => x[2])(_.boolean) + const eqE0E1E2 = S.combineMany([E1, E2])(E0) + expect(eqE0E1E2(["a", 1, true], ["a", 1, true])).toEqual(true) + expect(eqE0E1E2(["a", 1, true], ["b", 1, true])).toEqual(false) + expect(eqE0E1E2(["a", 1, true], ["a", 2, true])).toEqual(false) + expect(eqE0E1E2(["a", 1, true], ["a", 1, false])).toEqual(false) + }) + + it("getMonoid", () => { + type T = readonly [string, number, boolean] + const M = _.getMonoid() + const E0: _.Equivalence = _.contramap((x: T) => x[0])(_.string) + const E1: _.Equivalence = _.contramap((x: T) => x[1])(_.number) + const E2: _.Equivalence = _.contramap((x: T) => x[2])(_.boolean) + const eqE0E1E2 = M.combineAll([E0, E1, E2]) + expect(eqE0E1E2(["a", 1, true], ["a", 1, true])).toEqual(true) + expect(eqE0E1E2(["a", 1, true], ["b", 1, true])).toEqual(false) + expect(eqE0E1E2(["a", 1, true], ["a", 2, true])).toEqual(false) + expect(eqE0E1E2(["a", 1, true], ["a", 1, false])).toEqual(false) + }) + + it("Invariant", () => { + const eq = _.Invariant.imap((s: string) => [s], ([s]) => s)( + _.string + ) + expect(eq(["a"], ["a"])).toEqual(true) + expect(eq(["a"], ["b"])).toEqual(false) + }) + + it("SemiProduct/product", () => { + const eq = pipe( + _.string, + _.SemiProduct.product(_.string) + ) + expect(eq(["a", "b"], ["a", "b"])).toEqual(true) + expect(eq(["a", "b"], ["a", "c"])).toEqual(false) + }) + + it("SemiProduct/productMany", () => { + const eq = pipe( + _.string, + _.SemiProduct.productMany([_.string]) + ) + expect(eq(["a"], ["a"])).toEqual(true) + expect(eq(["a"], ["b"])).toEqual(false) + expect(eq(["a"], ["a", "b"])).toEqual(false) + expect(eq(["a", "b"], ["a", "b"])).toEqual(true) + expect(eq(["a", "b"], ["a", "b", "d"])).toEqual(true) + expect(eq(["a", "b", "c"], ["a", "b", "d"])).toEqual(true) + }) + + it("SemiProduct/productAll", () => { + const eq = _.Product.productAll([_.Product.of(""), _.string, _.string]) + expect(eq(["a"], ["a"])).toEqual(true) + expect(eq(["a"], ["b"])).toEqual(true) + expect(eq(["a", "c"], ["b", "c"])).toEqual(true) + expect(eq(["a", "c"], ["b", "d"])).toEqual(false) + }) +}) From 03c390c39ac9a8f4bf3323f95b0cd027ad5d8c92 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 08:10:47 +0100 Subject: [PATCH 018/255] add Option module --- .changeset/brave-poems-appear.md | 5 + src/Either.ts | 59 ++ src/Option.ts | 1216 ++++++++++++++++++++++++++++++ src/ReadonlyArray.ts | 169 +++++ src/index.ts | 22 + src/internal/Either.ts | 33 + src/internal/Option.ts | 27 + src/typeclass/Compactable.ts | 46 ++ src/typeclass/Filterable.ts | 89 +++ test/Identity.ts | 15 +- test/Option.ts | 563 ++++++++++++++ 11 files changed, 2236 insertions(+), 8 deletions(-) create mode 100644 .changeset/brave-poems-appear.md create mode 100644 src/Either.ts create mode 100644 src/Option.ts create mode 100644 src/internal/Either.ts create mode 100644 src/internal/Option.ts create mode 100644 src/typeclass/Compactable.ts create mode 100644 src/typeclass/Filterable.ts create mode 100644 test/Option.ts diff --git a/.changeset/brave-poems-appear.md b/.changeset/brave-poems-appear.md new file mode 100644 index 000000000..e0dd1b389 --- /dev/null +++ b/.changeset/brave-poems-appear.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add Option module diff --git a/src/Either.ts b/src/Either.ts new file mode 100644 index 000000000..ba1185b3a --- /dev/null +++ b/src/Either.ts @@ -0,0 +1,59 @@ +/** + * ```ts + * type Either = Left | Right + * ``` + * + * Represents a value of one of two possible types (a disjoint union). + * + * An instance of `Either` is either an instance of `Left` or `Right`. + * + * A common use of `Either` is as an alternative to `Option` for dealing with possible missing values. In this usage, + * `None` is replaced with a `Left` which can contain useful information. `Right` takes the place of `Some`. Convention + * dictates that `Left` is used for failure and `Right` is used for success. + * + * @since 1.0.0 + */ + +import * as either from "@fp-ts/core/internal/Either" + +/** + * @category models + * @since 1.0.0 + */ +export type Left = { + readonly _tag: "Left" + readonly left: E +} + +/** + * @category models + * @since 1.0.0 + */ +export type Right = { + readonly _tag: "Right" + readonly right: A +} + +/** + * @category models + * @since 1.0.0 + */ +export type Either = Left | Right + +/** + * Constructs a new `Either` holding a `Right` value. This usually represents a successful value due to the right bias + * of this structure. + * + * @category constructors + * @since 1.0.0 + */ +export const right: (a: A) => Either = either.right + +/** + * Constructs a new `Either` holding a `Left` value. This usually represents a failure, due to the right-bias of this + * structure. + * + * @category constructors + * @since 1.0.0 + */ +export const left: (e: E) => Either = either.left diff --git a/src/Option.ts b/src/Option.ts new file mode 100644 index 000000000..13736839a --- /dev/null +++ b/src/Option.ts @@ -0,0 +1,1216 @@ +/** + * ```ts + * type Option = None | Some + * ``` + * + * `Option` is a container for an optional value of type `A`. If the value of type `A` is present, the `Option` is + * an instance of `Some`, containing the present value of type `A`. If the value is absent, the `Option` is an + * instance of `None`. + * + * An option could be looked at as a collection or foldable structure with either one or zero elements. + * Another way to look at `Option` is: it represents the effect of a possibly failing computation. + * + * @since 1.0.0 + */ +import type { Either } from "@fp-ts/core/Either" +import type { LazyArg } from "@fp-ts/core/Function" +import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" +import type { Kind, TypeLambda } from "@fp-ts/core/HKT" +import * as either from "@fp-ts/core/internal/Either" +import * as iterable from "@fp-ts/core/internal/Iterable" +import * as option from "@fp-ts/core/internal/Option" +import type { Predicate, Refinement } from "@fp-ts/core/Predicate" +import type * as alternative from "@fp-ts/core/typeclass/Alternative" +import * as applicative from "@fp-ts/core/typeclass/Applicative" +import * as chainable from "@fp-ts/core/typeclass/Chainable" +import * as compactable from "@fp-ts/core/typeclass/Compactable" +import type * as coproduct_ from "@fp-ts/core/typeclass/Coproduct" +import * as covariant from "@fp-ts/core/typeclass/Covariant" +import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" +import * as filterable from "@fp-ts/core/typeclass/Filterable" +import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" +import * as foldable from "@fp-ts/core/typeclass/Foldable" +import * as invariant from "@fp-ts/core/typeclass/Invariant" +import type * as monad from "@fp-ts/core/typeclass/Monad" +import type { Monoid } from "@fp-ts/core/typeclass/Monoid" +import * as of_ from "@fp-ts/core/typeclass/Of" +import type { Order } from "@fp-ts/core/typeclass/Order" +import * as order from "@fp-ts/core/typeclass/Order" +import type * as pointed from "@fp-ts/core/typeclass/Pointed" +import * as product_ from "@fp-ts/core/typeclass/Product" +import type * as semiAlternative from "@fp-ts/core/typeclass/SemiAlternative" +import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" +import * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" +import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import * as traversable from "@fp-ts/core/typeclass/Traversable" + +/** + * @category models + * @since 1.0.0 + */ +export type None = { + readonly _tag: "None" +} + +/** + * @category models + * @since 1.0.0 + */ +export type Some = { + readonly _tag: "Some" + readonly value: A +} + +/** + * @category models + * @since 1.0.0 + */ +export type Option = None | Some + +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface OptionTypeLambda extends TypeLambda { + readonly type: Option +} + +/** + * @category constructors + * @since 1.0.0 + */ +export const none = (): Option => option.none + +/** + * @category constructors + * @since 1.0.0 + */ +export const some: (a: A) => Option = option.some + +/** + * Returns `true` if the specified value is an instance of `Option`, `false` + * otherwise. + * + * @example + * import { some, none, isOption } from '@fp-ts/core/Option' + * + * assert.strictEqual(isOption(some(1)), true) + * assert.strictEqual(isOption(none), true) + * assert.strictEqual(isOption({}), false) + * + * @category guards + * @since 1.0.0 + */ +export const isOption: (u: unknown) => u is Option = option.isOption + +/** + * Constructs a new `Option` from a nullable type. If the value is `null` or `undefined`, returns `None`, otherwise + * returns the value wrapped in a `Some`. + * + * @example + * import { none, some, fromNullable } from '@fp-ts/core/Option' + * + * assert.deepStrictEqual(fromNullable(undefined), none) + * assert.deepStrictEqual(fromNullable(null), none) + * assert.deepStrictEqual(fromNullable(1), some(1)) + * + * @category conversions + * @since 1.0.0 + */ +export const fromNullable: (a: A) => Option> = option.fromNullable + +/** + * Returns a `Refinement` from a `Option` returning function. + * This function ensures that a `Refinement` definition is type-safe. + * + * @category conversions + * @since 1.0.0 + */ +export const toRefinement = (f: (a: A) => Option): Refinement => + (a: A): a is B => isSome(f(a)) + +/** + * Converts an exception into an `Option`. If `f` throws, returns `None`, otherwise returns the output wrapped in a + * `Some`. + * + * @example + * import { none, some, fromThrowable } from '@fp-ts/core/Option' + * + * assert.deepStrictEqual( + * fromThrowable(() => { + * throw new Error() + * }), + * none + * ) + * assert.deepStrictEqual(fromThrowable(() => 1), some(1)) + * + * @category interop + * @since 1.0.0 + */ +export const fromThrowable = (f: () => A): Option => { + try { + return some(f()) + } catch (e) { + return option.none + } +} + +/** + * Lifts a function that may throw to one returning a `Option`. + * + * @category interop + * @since 1.0.0 + */ +export const liftThrowable = , B>( + f: (...a: A) => B +): ((...a: A) => Option) => (...a) => fromThrowable(() => f(...a)) + +/** + * @category interop + * @since 1.0.0 + */ +export const getOrThrow = (onError: LazyArg) => + (self: Option): A => { + if (isSome(self)) { + return self.value + } + throw onError() + } + +/** + * Returns an effect whose success is mapped by the specified `f` function. + * + * @category mapping + * @since 1.0.0 + */ +export const map = (f: (a: A) => B) => + (self: Option): Option => isNone(self) ? option.none : some(f(self.value)) + +/** + * @category mapping + * @since 1.0.0 + */ +export const imap = covariant.imap(map) + +/** + * @category instances + * @since 1.0.0 + */ +export const Invariant: invariant.Invariant = { + imap +} + +/** + * @since 1.0.0 + */ +export const tupled: (self: Option) => Option = invariant.tupled(Invariant) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindTo: ( + name: N +) => (self: Option) => Option<{ readonly [K in N]: A }> = invariant.bindTo(Invariant) + +/** + * @category instances + * @since 1.0.0 + */ +export const Covariant: covariant.Covariant = { + ...Invariant, + map +} + +const let_: ( + name: Exclude, + f: (a: A) => B +) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = + covariant.let(Covariant) + +export { + /** + * @category do notation + * @since 1.0.0 + */ + let_ as let +} + +/** + * @category mapping + * @since 1.0.0 + */ +export const flap: (a: A) => (fab: Option<(a: A) => B>) => Option = covariant.flap( + Covariant +) + +/** + * Maps the success value of this effect to the specified constant value. + * + * @category mapping + * @since 1.0.0 + */ +export const as: (b: B) => <_>(self: Option<_>) => Option = covariant.as(Covariant) + +/** + * Returns the effect resulting from mapping the success of this effect to unit. + * + * @category mapping + * @since 1.0.0 + */ +export const asUnit: <_>(self: Option<_>) => Option = covariant.asUnit(Covariant) + +/** + * @category constructors + * @since 1.0.0 + */ +export const of: (a: A) => Option = some + +/** + * @category instances + * @since 1.0.0 + */ +export const Of: of_.Of = { + of: some +} + +/** + * @since 1.0.0 + */ +export const unit: Option = of_.unit(Of) + +/** + * @category do notation + * @since 1.0.0 + */ +export const Do: Option<{}> = of_.Do(Of) + +/** + * @category instances + * @since 1.0.0 + */ +export const Pointed: pointed.Pointed = { + ...Of, + ...Covariant +} + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMap = (f: (a: A) => Option) => + (self: Option): Option => isNone(self) ? option.none : f(self.value) + +/** + * @category instances + * @since 1.0.0 + */ +export const FlatMap: flatMap_.FlatMap = { + flatMap +} + +/** + * @since 1.0.0 + */ +export const flatten: (self: Option>) => Option = flatMap_ + .flatten(FlatMap) + +/** + * @since 1.0.0 + */ +export const andThen: (that: Option) => <_>(self: Option<_>) => Option = flatMap_ + .andThen(FlatMap) + +/** + * @since 1.0.0 + */ +export const composeKleisliArrow: ( + bfc: (b: B) => Option +) => (afb: (a: A) => Option) => (a: A) => Option = flatMap_ + .composeKleisliArrow(FlatMap) + +/** + * @category instances + * @since 1.0.0 + */ +export const Chainable: chainable.Chainable = { + ...FlatMap, + ...Covariant +} + +/** + * @category do notation + * @since 1.0.0 + */ +export const bind: ( + name: Exclude, + f: (a: A) => Option +) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = + chainable.bind(Chainable) + +/** + * Returns an effect that effectfully "peeks" at the success of this effect. + * + * @since 1.0.0 + */ +export const tap: (f: (a: A) => Option<_>) => (self: Option) => Option = chainable.tap( + Chainable +) + +/** + * @category debugging + * @since 1.0.0 + */ +export const inspectSome = ( + onSome: (a: A) => void +) => + (self: Option): Option => { + if (isSome(self)) { + onSome(self.value) + } + return self + } + +/** + * @category debugging + * @since 1.0.0 + */ +export const inspectNone = ( + onNone: () => void +) => + (self: Option): Option => { + if (isNone(self)) { + onNone() + } + return self + } + +/** + * Sequences the specified effect after this effect, but ignores the value + * produced by the effect. + * + * @category sequencing + * @since 1.0.0 + */ +export const andThenDiscard: <_>(that: Option<_>) => (self: Option) => Option = chainable + .andThenDiscard(Chainable) + +/** + * @category instances + * @since 1.0.0 + */ +export const Monad: monad.Monad = { + ...Pointed, + ...FlatMap +} + +/** + * @since 1.0.0 + */ +export const product = ( + that: Option +) => + (self: Option): Option => + isSome(self) && isSome(that) ? some([self.value, that.value]) : option.none + +/** + * @since 1.0.0 + */ +export const productMany = (collection: Iterable>) => + (self: Option): Option]> => { + if (isNone(self)) { + return option.none + } + const out: [A, ...Array] = [self.value] + for (const o of collection) { + if (isNone(o)) { + return option.none + } + out.push(o.value) + } + return some(out) + } + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiProduct: semiProduct.SemiProduct = { + ...Invariant, + product, + productMany +} + +/** + * A variant of `bind` that sequentially ignores the scope. + * + * @category do notation + * @since 1.0.0 + */ +export const andThenBind: ( + name: Exclude, + fb: Option +) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = + semiProduct.andThenBind(SemiProduct) + +/** + * @since 1.0.0 + */ +export const productFlatten: ( + fb: Option +) => >(self: Option) => Option = semiProduct + .productFlatten(SemiProduct) + +/** + * @since 1.0.0 + */ +export const productAll = (collection: Iterable>): Option> => { + const out: Array = [] + for (const o of collection) { + if (isNone(o)) { + return option.none + } + out.push(o.value) + } + return some(out) +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Product: product_.Product = { + ...Of, + ...SemiProduct, + productAll +} + +/** + * @since 1.0.0 + */ +export const tuple: >>( + ...tuple: T +) => Option] ? A : never }>> = product_ + .tuple(Product) + +/** + * @since 1.0.0 + */ +export const struct: >>( + r: R +) => Option<{ readonly [K in keyof R]: [R[K]] extends [Option] ? A : never }> = product_ + .struct(Product) + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiApplicative: semiApplicative.SemiApplicative = { + ...SemiProduct, + ...Covariant +} + +/** + * Monoid returning the left-most non-`None` value. If both operands are `Some`s then the inner values are + * combined using the provided `Semigroup` + * + * | x | y | combine(y)(x) | + * | ------- | ------- | ------------------- | + * | none | none | none | + * | some(a) | none | some(a) | + * | none | some(a) | some(a) | + * | some(a) | some(b) | some(combine(b)(a)) | + * + * @example + * import { getMonoid, some, none } from '@fp-ts/core/Option' + * import * as N from '@fp-ts/core/Number' + * import { pipe } from '@fp-ts/core/Function' + * + * const M = getMonoid(N.SemigroupSum) + * assert.deepStrictEqual(pipe(none, M.combine(none)), none) + * assert.deepStrictEqual(pipe(some(1), M.combine(none)), some(1)) + * assert.deepStrictEqual(pipe(none, M.combine(some(1))), some(1)) + * assert.deepStrictEqual(pipe(some(1), M.combine(some(2))), some(3)) + * + * @category lifting + * @since 1.0.0 + */ +export const getMonoid = ( + Semigroup: Semigroup +): Monoid> => { + const combine = (that: Option) => + (self: Option): Option => + isNone(self) ? that : isNone(that) ? self : some(Semigroup.combine(that.value)(self.value)) + return ({ + combine, + combineMany: (others) => + (start) => { + let c = start + for (const o of others) { + c = combine(o)(c) + } + return c + }, + combineAll: (collection: Iterable>): Option => { + let c: Option = option.none + for (const o of collection) { + c = combine(o)(c) + } + return c + }, + empty: option.none + }) +} + +/** + * Lifts a binary function into `Option`. + * + * @category lifting + * @since 1.0.0 + */ +export const lift2: (f: (a: A, b: B) => C) => (fa: Option, fb: Option) => Option = + semiApplicative.lift2(SemiApplicative) + +/** + * Lifts a ternary function into `Option`. + * + * @category lifting + * @since 1.0.0 + */ +export const lift3: ( + f: (a: A, b: B, c: C) => D +) => (fa: Option, fb: Option, fc: Option) => Option = semiApplicative.lift3( + SemiApplicative +) + +/** + * @since 1.0.0 + */ +export const ap: ( + fa: Option +) => (self: Option<(a: A) => B>) => Option = semiApplicative.ap( + SemiApplicative +) + +/** + * Semigroup returning the left-most `None` value. If both operands are `Right`s then the inner values + * are concatenated using the provided `Semigroup`. + * + * @category combining + * @since 1.0.0 + */ +export const getFirstNoneSemigroup: (S: Semigroup) => Semigroup> = semiApplicative + .liftSemigroup(SemiApplicative) + +/** + * @category instances + * @since 1.0.0 + */ +export const Applicative: applicative.Applicative = { + ...SemiApplicative, + ...Product +} + +/** + * Monoid returning the left-most `None` value. If both operands are `Right`s then the inner values + * are concatenated using the provided `Monoid`. + * + * The `empty` value is `some(M.empty)`. + * + * @category combining + * @since 1.0.0 + */ +export const getFirstNoneMonoid: (M: Monoid) => Monoid> = applicative.liftMonoid( + Applicative +) + +/** + * @since 1.0.0 + */ +export const coproduct = (that: Option) => + (self: Option): Option => isSome(self) ? self : that + +/** + * @category error handling + * @since 1.0.0 + */ +export const firstSomeOf = (collection: Iterable>) => + (self: Option): Option => { + let out = self + if (isSome(out)) { + return out + } + for (out of collection) { + if (isSome(out)) { + return out + } + } + return out + } + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiCoproduct: semiCoproduct.SemiCoproduct = { + ...Invariant, + coproduct, + coproductMany: firstSomeOf +} + +/** + * Semigroup returning the left-most `Some` value. + * + * @category combining + * @since 1.0.0 + */ +export const getFirstSomeSemigroup: () => Semigroup> = semiCoproduct + .getSemigroup( + SemiCoproduct + ) + +/** + * @since 1.0.0 + */ +export const coproductEither = (that: Option) => + (self: Option): Option> => + isNone(self) ? pipe(that, map(either.right)) : pipe(self, map(either.left)) + +/** + * @since 1.0.0 + */ +export const coproductAll = (collection: Iterable>): Option => { + const options = iterable.fromIterable(collection) + return options.length > 0 ? + SemiCoproduct.coproductMany(options.slice(1))(options[0]) : + option.none +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Coproduct: coproduct_.Coproduct = { + ...SemiCoproduct, + zero: none, + coproductAll +} + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiAlternative: semiAlternative.SemiAlternative = { + ...Covariant, + ...SemiCoproduct +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Alternative: alternative.Alternative = { + ...SemiAlternative, + ...Coproduct +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Foldable: foldable.Foldable = { + reduce: (b, f) => (self) => isNone(self) ? b : f(b, self.value) +} + +/** + * @since 1.0.0 + */ +export const toArray: (self: Option) => Array = foldable.toArray(Foldable) + +/** + * Alias of `flatten`. + * + * @category filtering + * @since 1.0.0 + */ +export const compact: (self: Option>) => Option = flatten + +/** + * @category instances + * @since 1.0.0 + */ +export const Compactable: compactable.Compactable = { + compact +} + +/** + * @category filtering + * @since 1.0.0 + */ +export const separate: (self: Option>) => readonly [Option, Option] = + compactable.separate({ ...Covariant, ...Compactable }) + +/** + * @category filtering + * @since 1.0.0 + */ +export const filterMap = (f: (a: A) => Option) => + (self: Option): Option => isNone(self) ? option.none : f(self.value) + +/** + * @category instances + * @since 1.0.0 + */ +export const Filterable: filterable.Filterable = { + filterMap +} + +/** + * @category filtering + * @since 1.0.0 + */ +export const filter: { + (refinement: Refinement): (fc: Option) => Option + (predicate: Predicate): (fb: Option) => Option +} = filterable.filter(Filterable) + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverse = ( + F: applicative.Applicative +) => + ( + f: (a: A) => Kind + ) => + (self: Option): Kind> => + isNone(self) ? F.of>(option.none) : pipe(f(self.value), F.map(some)) + +/** + * @category traversing + * @since 1.0.0 + */ +export const sequence: ( + F: applicative.Applicative +) => (fas: Option>) => Kind> = traversable + .sequence(traverse) + +/** + * @category instances + * @since 1.0.0 + */ +export const Traversable: traversable.Traversable = { + traverse, + sequence +} + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverseTap: ( + F: applicative.Applicative +) => ( + f: (a: A) => Kind +) => (self: Option) => Kind> = traversable + .traverseTap(Traversable) + +/** + * Returns `true` if the option is `None`, `false` otherwise. + * + * @example + * import { some, none, isNone } from '@fp-ts/core/Option' + * + * assert.strictEqual(isNone(some(1)), false) + * assert.strictEqual(isNone(none), true) + * + * @category guards + * @since 1.0.0 + */ +export const isNone: (self: Option) => self is None = option.isNone + +/** + * Returns `true` if the option is an instance of `Some`, `false` otherwise. + * + * @example + * import { some, none, isSome } from '@fp-ts/core/Option' + * + * assert.strictEqual(isSome(some(1)), true) + * assert.strictEqual(isSome(none), false) + * + * @category guards + * @since 1.0.0 + */ +export const isSome: (self: Option) => self is Some = option.isSome + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromIterable = (collection: Iterable): Option => { + for (const a of collection) { + return some(a) + } + return option.none +} + +/** + * Converts a `Either` to an `Option` discarding the error. + * + * @example + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(O.fromEither(E.right(1)), O.some(1)) + * assert.deepStrictEqual(O.fromEither(E.left('a')), O.none) + * + * @category conversions + * @since 1.0.0 + */ +export const fromEither: (self: Either) => Option = either.getRight + +/** + * @category conversions + * @since 1.0.0 + */ +export const toEither: (onNone: LazyArg) => (self: Option) => Either = + either.fromOption + +/** + * Takes a (lazy) default value, a function, and an `Option` value, if the `Option` value is `None` the default value is + * returned, otherwise the function is applied to the value inside the `Some` and the result is returned. + * + * @example + * import { some, none, match } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.strictEqual( + * pipe( + * some(1), + * match(() => 'a none', a => `a some containing ${a}`) + * ), + * 'a some containing 1' + * ) + * + * assert.strictEqual( + * pipe( + * none, + * match(() => 'a none', a => `a some containing ${a}`) + * ), + * 'a none' + * ) + * + * @category pattern matching + * @since 1.0.0 + */ +export const match = (onNone: LazyArg, onSome: (a: A) => C) => + (self: Option): B | C => isNone(self) ? onNone() : onSome(self.value) + +/** + * Extracts the value out of the structure, if it exists. Otherwise returns the given default value + * + * @example + * import { some, none, getOrElse } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.strictEqual(pipe(some(1), getOrElse(() => 0)), 1) + * assert.strictEqual(pipe(none, getOrElse(() => 0)), 0) + * + * @category error handling + * @since 1.0.0 + */ +export const getOrElse = (onNone: LazyArg) => + (self: Option): A | B => isNone(self) ? onNone() : self.value + +/** + * Returns a *smart constructor* from a function that returns a nullable value. + * + * @example + * import { liftNullable, none, some } from '@fp-ts/core/Option' + * + * const f = (s: string): number | undefined => { + * const n = parseFloat(s) + * return isNaN(n) ? undefined : n + * } + * + * const g = liftNullable(f) + * + * assert.deepStrictEqual(g('1'), some(1)) + * assert.deepStrictEqual(g('a'), none) + * + * @category lifting + * @since 1.0.0 + */ +export const liftNullable = , B>( + f: (...a: A) => B | null | undefined +): ((...a: A) => Option>) => (...a) => fromNullable(f(...a)) + +/** + * This is `flatMap` + `fromNullable`, useful when working with optional values. + * + * @example + * import { some, none, fromNullable, flatMapNullable } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * interface Employee { + * company?: { + * address?: { + * street?: { + * name?: string + * } + * } + * } + * } + * + * const employee1: Employee = { company: { address: { street: { name: 'high street' } } } } + * + * assert.deepStrictEqual( + * pipe( + * fromNullable(employee1.company), + * flatMapNullable(company => company.address), + * flatMapNullable(address => address.street), + * flatMapNullable(street => street.name) + * ), + * some('high street') + * ) + * + * const employee2: Employee = { company: { address: { street: {} } } } + * + * assert.deepStrictEqual( + * pipe( + * fromNullable(employee2.company), + * flatMapNullable(company => company.address), + * flatMapNullable(address => address.street), + * flatMapNullable(street => street.name) + * ), + * none + * ) + * + * @category sequencing + * @since 1.0.0 + */ +export const flatMapNullable = (f: (a: A) => B | null | undefined) => + (self: Option): Option> => + isNone(self) ? option.none : fromNullable(f(self.value)) + +/** + * Extracts the value out of the structure, if it exists. Otherwise returns `null`. + * + * @example + * import { some, none, getOrNull } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.strictEqual(pipe(some(1), getOrNull), 1) + * assert.strictEqual(pipe(none, getOrNull), null) + * + * @category conversions + * @since 1.0.0 + */ +export const getOrNull: (self: Option) => A | null = getOrElse(constNull) + +/** + * Extracts the value out of the structure, if it exists. Otherwise returns `undefined`. + * + * @example + * import { some, none, getOrUndefined } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.strictEqual(pipe(some(1), getOrUndefined), 1) + * assert.strictEqual(pipe(none, getOrUndefined), undefined) + * + * @category conversions + * @since 1.0.0 + */ +export const getOrUndefined: (self: Option) => A | undefined = getOrElse(constUndefined) + +/** + * Lazy version of `orElse`. + * + * @category error handling + * @since 1.0.0 + */ +export const catchAll = (that: LazyArg>) => + (self: Option): Option => isNone(self) ? that() : self + +/** + * Identifies an associative operation on a type constructor. It is similar to `Semigroup`, except that it applies to + * types of kind `* -> *`. + * + * In case of `Option` returns the left-most non-`None` value. + * + * | x | y | pipe(x, orElse(y) | + * | ------- | ------- | ------------------| + * | none | none | none | + * | some(a) | none | some(a) | + * | none | some(b) | some(b) | + * | some(a) | some(b) | some(a) | + * + * @example + * import * as O from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.deepStrictEqual( + * pipe( + * O.none, + * O.orElse(O.none) + * ), + * O.none + * ) + * assert.deepStrictEqual( + * pipe( + * O.some('a'), + * O.orElse(O.none) + * ), + * O.some('a') + * ) + * assert.deepStrictEqual( + * pipe( + * O.none, + * O.orElse(O.some('b')) + * ), + * O.some('b') + * ) + * assert.deepStrictEqual( + * pipe( + * O.some('a'), + * O.orElse(O.some('b')) + * ), + * O.some('a') + * ) + * + * @category error handling + * @since 1.0.0 + */ +export const orElse = (that: Option): ((self: Option) => Option) => + catchAll(() => that) + +/** + * Returns an effect that will produce the value of this effect, unless it + * fails, in which case, it will produce the value of the specified effect. + * + * @category error handling + * @since 1.0.0 + */ +export const orElseEither = ( + that: Option +) => + (self: Option): Option> => + isNone(self) ? + pipe(that, map(either.right)) : + pipe, Option>>(self, map(either.left)) + +/** + * Executes this effect and returns its value, if it succeeds, but otherwise + * succeeds with the specified value. + * + * @category error handling + * @since 1.0.0 + */ +export const orElseSucceed = ( + onNone: () => B +): (self: Option) => Option => catchAll(() => some(onNone())) + +/** + * The `Order` instance allows `Option` values to be compared with + * `compare`, whenever there is an `Order` instance for + * the type the `Option` contains. + * + * `None` is considered to be less than any `Some` value. + * + * @example + * import { none, some, liftOrder } from '@fp-ts/core/Option' + * import * as N from '@fp-ts/core/Number' + * import { pipe } from '@fp-ts/core/Function' + * + * const O = liftOrder(N.Order) + * assert.strictEqual(pipe(none, O.compare(none)), 0) + * assert.strictEqual(pipe(none, O.compare(some(1))), -1) + * assert.strictEqual(pipe(some(1), O.compare(none)), 1) + * assert.strictEqual(pipe(some(1), O.compare(some(2))), -1) + * assert.strictEqual(pipe(some(1), O.compare(some(1))), 0) + * + * @category sorting + * @since 1.0.0 + */ +export const liftOrder = (O: Order): Order> => + order.fromCompare((that) => + (self) => isSome(self) ? (isSome(that) ? O.compare(that.value)(self.value) : 1) : -1 + ) + +/** + * Returns a *smart constructor* based on the given predicate. + * + * @example + * import * as O from '@fp-ts/core/Option' + * + * const getOption = O.liftPredicate((n: number) => n >= 0) + * + * assert.deepStrictEqual(getOption(-1), O.none) + * assert.deepStrictEqual(getOption(1), O.some(1)) + * + * @category lifting + * @since 1.0.0 + */ +export const liftPredicate: { + (refinement: Refinement): (c: C) => Option + (predicate: Predicate): (b: B) => Option +} = (predicate: Predicate) => (b: B) => predicate(b) ? some(b) : option.none + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftEither = , E, B>( + f: (...a: A) => Either +) => (...a: A): Option => fromEither(f(...a)) + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMapEither = (f: (a: A) => Either) => + (self: Option): Option => pipe(self, flatMap(liftEither(f))) + +/** + * Returns a function that checks if an `Option` contains a given value using a provided `equivalence` function. + * + * @since 1.0.0 + */ +export const contains = (equivalence: Equivalence) => + (a: A) => (self: Option): boolean => isNone(self) ? false : equivalence(self.value, a) + +/** + * Returns `true` if the predicate is satisfied by the wrapped value + * + * @example + * import { some, none, exists } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.strictEqual( + * pipe( + * some(1), + * exists(n => n > 0) + * ), + * true + * ) + * assert.strictEqual( + * pipe( + * some(1), + * exists(n => n > 1) + * ), + * false + * ) + * assert.strictEqual( + * pipe( + * none, + * exists(n => n > 0) + * ), + * false + * ) + * + * @since 1.0.0 + */ +export const exists = (predicate: Predicate) => + (self: Option): boolean => isNone(self) ? false : predicate(self.value) diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 53c97154f..367a320a5 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -2,13 +2,182 @@ * @since 1.0.0 */ +import type { TypeLambda } from "@fp-ts/core/HKT" +import type * as applicative from "@fp-ts/core/typeclass/Applicative" +import * as covariant from "@fp-ts/core/typeclass/Covariant" +import type * as invariant from "@fp-ts/core/typeclass/Invariant" +import type * as of_ from "@fp-ts/core/typeclass/Of" +import type * as product_ from "@fp-ts/core/typeclass/Product" +import type * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" + +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface ReadonlyArrayTypeLambda extends TypeLambda { + readonly type: ReadonlyArray +} + /** * @category models * @since 1.0.0 */ export type NonEmptyReadonlyArray = readonly [A, ...Array] +/** + * @category models + * @since 1.0.0 + */ +export type NonEmptyArray = [A, ...Array] + /** * @since 1.0.0 */ export const isNonEmpty = (as: ReadonlyArray): as is NonEmptyReadonlyArray => as.length > 0 + +/** + * @category constructors + * @since 1.0.0 + */ +export const empty: () => Array = () => [] + +/** + * Test whether a `ReadonlyArray` is empty narrowing down the type to `[]`. + * + * @category predicates + * @since 1.0.0 + */ +export const isEmpty = (self: ReadonlyArray): self is readonly [] => self.length === 0 + +/** + * @since 1.0.0 + */ +export const product = ( + that: ReadonlyArray +) => + (self: ReadonlyArray): Array<[A, B]> => { + if (isEmpty(self) || isEmpty(that)) { + return empty() + } + const out: Array<[A, B]> = [] + for (let i = 0; i < self.length; i++) { + for (let j = 0; j < that.length; j++) { + out.push([self[i], that[j]]) + } + } + return out + } + +/** + * @category mapping + * @since 1.0.0 + */ +export const map = (f: (a: A) => B): (self: ReadonlyArray) => Array => + mapWithIndex((a) => f(a)) + +/** + * @category mapping + * @since 1.0.0 + */ +export const mapWithIndex = ( + f: (a: A, i: number) => B +) => (self: ReadonlyArray): Array => self.map((a, i) => f(a, i)) + +/** + * @category instances + * @since 1.0.0 + */ +export const Covariant: covariant.Covariant = covariant.make(map) + +/** + * @since 1.0.0 + */ +export const productMany: ( + collection: Iterable> +) => (self: ReadonlyArray) => ReadonlyArray> = semiProduct + .productMany( + Covariant, + product + ) + +/** + * @since 1.0.0 + */ +export const productAll = ( + collection: Iterable> +): ReadonlyArray> => { + const arrays = Array.from(collection) + if (isEmpty(arrays)) { + return empty() + } + return productMany(arrays.slice(1))(arrays[0]) +} + +/** + * @category mapping + * @since 1.0.0 + */ +export const imap: ( + to: (a: A) => B, + from: (b: B) => A +) => (self: ReadonlyArray) => ReadonlyArray = covariant.imap(map) + +/** + * @category instances + * @since 1.0.0 + */ +export const Invariant: invariant.Invariant = { + imap +} + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiProduct: semiProduct.SemiProduct = { + ...Invariant, + product, + productMany +} + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiApplicative: semiApplicative.SemiApplicative = { + ...SemiProduct, + ...Covariant +} + +/** + * @category constructors + * @since 1.0.0 + */ +export const of = (a: A): NonEmptyArray => [a] + +/** + * @category instances + * @since 1.0.0 + */ +export const Of: of_.Of = { + of +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Product: product_.Product = { + ...Of, + ...SemiProduct, + productAll +} +/** + * @category instances + * @since 1.0.0 + */ +export const Applicative: applicative.Applicative = { + ...SemiApplicative, + ...Product +} diff --git a/src/index.ts b/src/index.ts index 7830f9c29..18842e414 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,9 +13,11 @@ import * as hkt from "@fp-ts/core/HKT" // ------------------------------------------------------------------------------------- import * as boolean from "@fp-ts/core/Boolean" +import * as either from "@fp-ts/core/Either" import * as _function from "@fp-ts/core/Function" import * as identity from "@fp-ts/core/Identity" import * as number from "@fp-ts/core/Number" +import * as option from "@fp-ts/core/Option" import * as ordering from "@fp-ts/core/Ordering" import * as predicate from "@fp-ts/core/Predicate" import * as readonlyArray from "@fp-ts/core/ReadonlyArray" @@ -25,10 +27,12 @@ import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" import * as bounded from "@fp-ts/core/typeclass/Bounded" import * as chainable from "@fp-ts/core/typeclass/Chainable" +import * as compactable from "@fp-ts/core/typeclass/Compactable" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import * as coproduct from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" +import * as filterable from "@fp-ts/core/typeclass/Filterable" import * as flatMap from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" @@ -80,6 +84,11 @@ export { * @since 1.0.0 */ chainable, + /** + * @category typeclass + * @since 1.0.0 + */ + compactable, /** * @category typeclass * @since 1.0.0 @@ -95,11 +104,20 @@ export { * @since 1.0.0 */ covariant, + /** + * @since 1.0.0 + */ + either, /** * @category typeclass * @since 1.0.0 */ equivalence, + /** + * @category typeclass + * @since 1.0.0 + */ + filterable, /** * @category typeclass * @since 1.0.0 @@ -147,6 +165,10 @@ export { * @since 1.0.0 */ of, + /** + * @since 1.0.0 + */ + option, /** * @category typeclass * @since 1.0.0 diff --git a/src/internal/Either.ts b/src/internal/Either.ts new file mode 100644 index 000000000..215be4841 --- /dev/null +++ b/src/internal/Either.ts @@ -0,0 +1,33 @@ +/** + * @since 1.0.0 + */ + +import type { Either, Left, Right } from "@fp-ts/core/Either" +import * as option from "@fp-ts/core/internal/Option" +import type { Option } from "@fp-ts/core/Option" + +/** @internal */ +export const isLeft = (ma: Either): ma is Left => ma._tag === "Left" + +/** @internal */ +export const isRight = (ma: Either): ma is Right => ma._tag === "Right" + +/** @internal */ +export const left = (e: E): Either => ({ _tag: "Left", left: e }) + +/** @internal */ +export const right = (a: A): Either => ({ _tag: "Right", right: a }) + +/** @internal */ +export const getLeft = ( + self: Either +): Option => (isRight(self) ? option.none : option.some(self.left)) + +/** @internal */ +export const getRight = ( + self: Either +): Option => (isLeft(self) ? option.none : option.some(self.right)) + +/** @internal */ +export const fromOption = (onNone: () => E) => + (fa: Option): Either => option.isNone(fa) ? left(onNone()) : right(fa.value) diff --git a/src/internal/Option.ts b/src/internal/Option.ts new file mode 100644 index 000000000..c3a101ea6 --- /dev/null +++ b/src/internal/Option.ts @@ -0,0 +1,27 @@ +/** + * @since 1.0.0 + */ + +import type { None, Option, Some } from "@fp-ts/core/Option" + +/** @internal */ +export const isOption = (u: unknown): u is Option => + typeof u === "object" && u != null && "_tag" in u && + (u["_tag"] === "None" || u["_tag"] === "Some") + +/** @internal */ +export const isNone = (fa: Option): fa is None => fa._tag === "None" + +/** @internal */ +export const isSome = (fa: Option): fa is Some => fa._tag === "Some" + +/** @internal */ +export const none: Option = { _tag: "None" } + +/** @internal */ +export const some = (a: A): Option => ({ _tag: "Some", value: a }) + +/** @internal */ +export const fromNullable = ( + a: A +): Option> => (a == null ? none : some(a as NonNullable)) diff --git a/src/typeclass/Compactable.ts b/src/typeclass/Compactable.ts new file mode 100644 index 000000000..ef0c79de7 --- /dev/null +++ b/src/typeclass/Compactable.ts @@ -0,0 +1,46 @@ +/** + * `Compactable` represents data structures which can be _compacted_/_separated_. + * + * @since 1.0.0 + */ +import type { Either } from "@fp-ts/core/Either" +import { pipe } from "@fp-ts/core/Function" +import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" +import * as either from "@fp-ts/core/internal/Either" +import type { Option } from "@fp-ts/core/Option" +import type { Covariant } from "@fp-ts/core/typeclass/Covariant" + +/** + * @category models + * @since 1.0.0 + */ +export interface Compactable extends TypeClass { + readonly compact: (self: Kind>) => Kind +} + +/** + * Returns a default `compact` composition. + * + * @since 1.0.0 + */ +export const compactComposition = ( + F: Covariant, + G: Compactable +): (( + self: Kind>> +) => Kind>) => F.map(G.compact) + +/** + * @since 1.0.0 + */ +export const separate = ( + F: Covariant & Compactable +) => + ( + self: Kind> + ): readonly [Kind, Kind] => { + return [ + pipe(self, F.map(either.getLeft), F.compact), + pipe(self, F.map(either.getRight), F.compact) + ] + } diff --git a/src/typeclass/Filterable.ts b/src/typeclass/Filterable.ts new file mode 100644 index 000000000..03c5befeb --- /dev/null +++ b/src/typeclass/Filterable.ts @@ -0,0 +1,89 @@ +/** + * `Filterable` represents data structures which can be _partitioned_/_filtered_. + * + * @since 1.0.0 + */ +import type { Either } from "@fp-ts/core/Either" +import { pipe } from "@fp-ts/core/Function" +import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" +import * as either from "@fp-ts/core/internal/Either" +import * as option from "@fp-ts/core/internal/Option" +import type { Option } from "@fp-ts/core/Option" +import type { Covariant } from "@fp-ts/core/typeclass/Covariant" + +/** + * @category models + * @since 1.0.0 + */ +export interface Filterable extends TypeClass { + readonly filterMap: ( + f: (a: A) => Option + ) => (self: Kind) => Kind +} + +/** + * Returns a default `filterMap` composition. + * + * @since 1.0.0 + */ +export const filterMapComposition = ( + F: Covariant, + G: Filterable +) => + ( + f: (a: A) => Option + ): ( + self: Kind> + ) => Kind> => F.map(G.filterMap(f)) + +/** + * @since 1.0.0 + */ +export const filter: ( + F: Filterable +) => { + (refinement: (a: A) => a is B): ( + self: Kind + ) => Kind + ( + predicate: (a: A) => boolean + ): (self: Kind) => Kind +} = (Filterable: Filterable) => + ( + predicate: (a: A) => boolean + ): ((self: Kind) => Kind) => + Filterable.filterMap((b) => (predicate(b) ? option.some(b) : option.none)) + +/** + * @since 1.0.0 + */ +export const partitionMap = (F: Filterable) => + (f: (a: A) => Either) => + ( + self: Kind + ): readonly [Kind, Kind] => { + return [ + pipe(self, F.filterMap((a) => either.getLeft(f(a)))), + pipe(self, F.filterMap((a) => either.getRight(f(a)))) + ] + } + +/** + * @since 1.0.0 + */ +export const partition: ( + F: Filterable +) => { + (refinement: (a: A) => a is B): ( + self: Kind + ) => readonly [Kind, Kind] + (predicate: (a: A) => boolean): ( + self: Kind + ) => readonly [Kind, Kind] +} = (Filterable: Filterable) => + ( + predicate: (a: A) => boolean + ): (( + self: Kind + ) => readonly [Kind, Kind]) => + partitionMap(Filterable)((b) => (predicate(b) ? either.right(b) : either.left(b))) diff --git a/test/Identity.ts b/test/Identity.ts index 1de2992f9..f840be294 100644 --- a/test/Identity.ts +++ b/test/Identity.ts @@ -1,6 +1,6 @@ import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/Identity" -// import * as O from "@fp-ts/core/Option" +import * as O from "@fp-ts/core/Option" import * as String from "@fp-ts/core/String" import * as U from "./util" @@ -125,12 +125,11 @@ describe.concurrent("Identity", () => { U.deepStrictEqual(pipe("a", _.reduceRight("", f)), "a") }) - // TODO - // it("traverse", () => { - // U.deepStrictEqual(pipe(1, _.traverse(O.Applicative)(O.some)), O.some(1)) - // U.deepStrictEqual(pipe(1, _.traverse(O.Applicative)(() => O.none)), O.none) + it("traverse", () => { + U.deepStrictEqual(pipe(1, _.traverse(O.Applicative)(O.some)), O.some(1)) + U.deepStrictEqual(pipe(1, _.traverse(O.Applicative)(() => O.none())), O.none()) - // U.deepStrictEqual(pipe(1, _.Traversable.traverse(O.Applicative)(O.some)), O.some(1)) - // U.deepStrictEqual(pipe(1, _.Traversable.traverse(O.Applicative)(() => O.none)), O.none) - // }) + U.deepStrictEqual(pipe(1, _.Traversable.traverse(O.Applicative)(O.some)), O.some(1)) + U.deepStrictEqual(pipe(1, _.Traversable.traverse(O.Applicative)(() => O.none())), O.none()) + }) }) diff --git a/test/Option.ts b/test/Option.ts new file mode 100644 index 000000000..f0c9f641a --- /dev/null +++ b/test/Option.ts @@ -0,0 +1,563 @@ +import { equivalence } from "@fp-ts/core" +import * as E from "@fp-ts/core/Either" +import { pipe } from "@fp-ts/core/Function" +import * as _ from "@fp-ts/core/Option" +import * as ReadonlyArray from "@fp-ts/core/ReadonlyArray" +import * as S from "@fp-ts/core/String" +import { deepStrictEqual, double } from "@fp-ts/core/test/util" + +const p = (n: number): boolean => n > 2 + +describe.concurrent("Option", () => { + it("instances and derived exports", () => { + expect(_.Invariant).exist + expect(_.imap).exist + expect(_.tupled).exist + expect(_.bindTo).exist + + expect(_.Covariant).exist + expect(_.map).exist + expect(_.let).exist + expect(_.flap).exist + expect(_.as).exist + expect(_.asUnit).exist + + expect(_.Of).exist + expect(_.of).exist + expect(_.Do).exist + + expect(_.Pointed).exist + + expect(_.FlatMap).exist + expect(_.flatMap).exist + expect(_.flatten).exist + expect(_.andThen).exist + expect(_.composeKleisliArrow).exist + + expect(_.Chainable).exist + expect(_.bind).exist + expect(_.tap).exist + expect(_.andThenDiscard).exist + + expect(_.Monad).exist + + expect(_.SemiProduct).exist + expect(_.product).exist + expect(_.productMany).exist + + expect(_.Product).exist + expect(_.productAll).exist + expect(_.tuple).exist + expect(_.struct).exist + + expect(_.SemiApplicative).exist + expect(_.getFirstNoneSemigroup).exist // liftSemigroup + expect(_.lift2).exist + expect(_.lift3).exist + expect(_.ap).exist + expect(_.andThenDiscard).exist + expect(_.andThen).exist + + expect(_.Applicative).exist + expect(_.getFirstNoneMonoid).exist // liftMonoid + + expect(_.SemiCoproduct).exist + expect(_.getFirstSomeSemigroup).exist // getSemigroup + expect(_.coproduct).exist + + expect(_.Coproduct).exist + expect(_.coproductAll).exist + + expect(_.SemiAlternative).exist + + expect(_.Alternative).exist + + expect(_.Foldable).exist + expect(_.toArray).exist + + expect(_.Traversable).exist + expect(_.traverse).exist + expect(_.sequence).exist + expect(_.traverseTap).exist + + expect(_.Compactable).exist + expect(_.compact).exist + expect(_.separate).exist + + expect(_.Filterable).exist + expect(_.filterMap).exist + expect(_.filter).exist + }) + + it("toRefinement", () => { + const f = ( + s: string | number + ): _.Option => (typeof s === "string" ? _.some(s) : _.none()) + const isString = _.toRefinement(f) + deepStrictEqual(isString("s"), true) + deepStrictEqual(isString(1), false) + type A = { readonly type: "A" } + type B = { readonly type: "B" } + type C = A | B + const isA = _.toRefinement((c) => (c.type === "A" ? _.some(c) : _.none())) + deepStrictEqual(isA({ type: "A" }), true) + deepStrictEqual(isA({ type: "B" }), false) + }) + + it("isOption", () => { + deepStrictEqual(pipe(_.some(1), _.isOption), true) + deepStrictEqual(pipe(_.none(), _.isOption), true) + deepStrictEqual(pipe(E.right(1), _.isOption), false) + }) + + it("coproductEither", () => { + deepStrictEqual(pipe(_.none(), _.coproductEither(_.none())), _.none()) + deepStrictEqual(pipe(_.none(), _.coproductEither(_.some("a"))), _.some(E.right("a"))) + deepStrictEqual(pipe(_.some(1), _.coproductEither(_.none())), _.some(E.left(1))) + deepStrictEqual(pipe(_.some(1), _.coproductEither(_.some("a"))), _.some(E.left(1))) + }) + + it("firstSomeOf", () => { + deepStrictEqual(pipe(_.some(1), _.firstSomeOf([])), _.some(1)) + deepStrictEqual(pipe(_.none(), _.firstSomeOf([])), _.none()) + deepStrictEqual( + pipe(_.none(), _.firstSomeOf([_.none(), _.none(), _.none(), _.some(1)])), + _.some(1) + ) + deepStrictEqual( + pipe(_.none(), _.firstSomeOf([_.none(), _.none(), _.none()])), + _.none() + ) + }) + + it("catchAll", () => { + deepStrictEqual(pipe(_.some(1), _.catchAll(() => _.some(2))), _.some(1)) + deepStrictEqual(pipe(_.some(1), _.catchAll(() => _.none())), _.some(1)) + deepStrictEqual(pipe(_.none(), _.catchAll(() => _.some(1))), _.some(1)) + deepStrictEqual(pipe(_.none(), _.catchAll(() => _.none())), _.none()) + }) + + it("orElseEither", () => { + expect(pipe(_.some(1), _.orElseEither(_.some(2)))).toEqual(_.some(E.left(1))) + expect(pipe(_.some(1), _.orElseEither(_.none()))).toEqual(_.some(E.left(1))) + expect(pipe(_.none(), _.orElseEither(_.some(2)))).toEqual(_.some(E.right(2))) + expect(pipe(_.none(), _.orElseEither(_.none()))).toEqual(_.none()) + }) + + it("orElseSucceed", () => { + deepStrictEqual(pipe(_.some(1), _.orElseSucceed(() => 2)), _.some(1)) + deepStrictEqual(pipe(_.none(), _.orElseSucceed(() => 2)), _.some(2)) + }) + + it("inspectSome", () => { + const log: Array = [] + pipe( + _.some(1), + _.inspectSome(() => log.push(1)) + ) + pipe( + _.none(), + _.inspectSome(() => log.push(2)) + ) + deepStrictEqual( + log, + [1] + ) + }) + + it("inspectNone", () => { + const log: Array = [] + pipe( + _.some(1), + _.inspectNone(() => log.push(1)) + ) + pipe( + _.none(), + _.inspectNone(() => log.push(2)) + ) + deepStrictEqual( + log, + [2] + ) + }) + + it("getOrThrow", () => { + expect(pipe(_.some(1), _.getOrThrow(() => new Error("e")))).toEqual(1) + expect(() => pipe(_.none(), _.getOrThrow(() => new Error("e")))).toThrow( + new Error("e") + ) + }) + + it("of", () => { + deepStrictEqual(_.of(1), _.some(1)) + }) + + it("Foldable", () => { + expect(pipe(_.none(), _.Foldable.reduce("a", (s, n: number) => s + String(n)))).toEqual("a") + expect(pipe(_.some(1), _.Foldable.reduce("a", (s, n: number) => s + String(n)))).toEqual( + "a1" + ) + }) + + it("coproductAll", () => { + deepStrictEqual(_.coproductAll([]), _.none()) + deepStrictEqual(_.coproductAll([_.some(1)]), _.some(1)) + deepStrictEqual(_.coproductAll([_.none(), _.some(1)]), _.some(1)) + deepStrictEqual(_.coproductAll([_.some(1), _.some(2)]), _.some(1)) + }) + + it("unit", () => { + deepStrictEqual(_.unit, _.some(undefined)) + }) + + it("product", () => { + deepStrictEqual(pipe(_.none(), _.product(_.none())), _.none()) + deepStrictEqual(pipe(_.some(1), _.product(_.none())), _.none()) + deepStrictEqual(pipe(_.none(), _.product(_.some("a"))), _.none()) + deepStrictEqual( + pipe(_.some(1), _.product(_.some("a"))), + _.some([1, "a"] as const) + ) + }) + + it("productMany", () => { + deepStrictEqual(pipe(_.none(), _.SemiProduct.productMany([])), _.none()) + deepStrictEqual(pipe(_.some(1), _.SemiProduct.productMany([])), _.some([1] as const)) + deepStrictEqual( + pipe(_.some(1), _.SemiProduct.productMany([_.none() as _.Option])), + _.none() + ) + deepStrictEqual( + pipe(_.some(1), _.SemiProduct.productMany([_.some(2)])), + _.some([1, 2] as const) + ) + }) + + it("productAll", () => { + const productAll = _.Applicative.productAll + deepStrictEqual(productAll([]), _.some([])) + deepStrictEqual(productAll([_.none()]), _.none()) + deepStrictEqual(productAll([_.some(1), _.some(2)]), _.some([1, 2])) + deepStrictEqual(productAll([_.some(1), _.none()]), _.none()) + }) + + it("SemiCoproduct", () => { + const coproduct = _.SemiCoproduct.coproduct + deepStrictEqual(pipe(_.none(), coproduct(_.none())), _.none()) + deepStrictEqual(pipe(_.none(), coproduct(_.some(2))), _.some(2)) + deepStrictEqual(pipe(_.some(1), coproduct(_.none())), _.some(1)) + deepStrictEqual(pipe(_.some(1), coproduct(_.some(2))), _.some(1)) + + const coproductMany = _.SemiCoproduct.coproductMany + deepStrictEqual(pipe(_.none(), coproductMany([])), _.none()) + deepStrictEqual(pipe(_.none(), coproductMany([_.none()])), _.none()) + deepStrictEqual(pipe(_.none(), coproductMany([_.some(2)])), _.some(2)) + deepStrictEqual(pipe(_.some(1), coproductMany([])), _.some(1)) + deepStrictEqual(pipe(_.some(1), coproductMany([_.none() as _.Option])), _.some(1)) + deepStrictEqual(pipe(_.some(1), coproductMany([_.some(2)])), _.some(1)) + }) + + it("fromIterable", () => { + deepStrictEqual(_.fromIterable([]), _.none()) + deepStrictEqual(_.fromIterable(["a"]), _.some("a")) + }) + + it("map", () => { + deepStrictEqual(pipe(_.some(2), _.map(double)), _.some(4)) + deepStrictEqual(pipe(_.none(), _.map(double)), _.none()) + }) + + it("flatMap", () => { + const f = (n: number) => _.some(n * 2) + const g = () => _.none() + deepStrictEqual(pipe(_.some(1), _.flatMap(f)), _.some(2)) + deepStrictEqual(pipe(_.none(), _.flatMap(f)), _.none()) + deepStrictEqual(pipe(_.some(1), _.flatMap(g)), _.none()) + deepStrictEqual(pipe(_.none(), _.flatMap(g)), _.none()) + }) + + it("orElse", () => { + const assertAlt = ( + a: _.Option, + b: _.Option, + expected: _.Option + ) => { + deepStrictEqual(pipe(a, _.orElse(b)), expected) + } + assertAlt(_.some(1), _.some(2), _.some(1)) + assertAlt(_.some(1), _.none(), _.some(1)) + assertAlt(_.none(), _.some(2), _.some(2)) + assertAlt(_.none(), _.none(), _.none()) + }) + + it("compact", () => { + deepStrictEqual(_.compact(_.none()), _.none()) + deepStrictEqual(_.compact(_.some(_.none())), _.none()) + deepStrictEqual(_.compact(_.some(_.some("123"))), _.some("123")) + }) + + it("filterMap", () => { + const f = (n: number) => (p(n) ? _.some(n + 1) : _.none()) + deepStrictEqual(pipe(_.none(), _.filterMap(f)), _.none()) + deepStrictEqual(pipe(_.some(1), _.filterMap(f)), _.none()) + deepStrictEqual(pipe(_.some(3), _.filterMap(f)), _.some(4)) + }) + + it("traverse", () => { + deepStrictEqual( + pipe( + _.some("hello"), + _.traverse(ReadonlyArray.Applicative)(() => []) + ), + [] + ) + deepStrictEqual( + pipe( + _.some("hello"), + _.traverse(ReadonlyArray.Applicative)((s) => [s.length]) + ), + [_.some(5)] + ) + deepStrictEqual( + pipe( + _.none(), + _.traverse(ReadonlyArray.Applicative)((s) => [s]) + ), + [_.none()] + ) + }) + + it("toEither", () => { + deepStrictEqual(pipe(_.none(), _.toEither(() => "e")), E.left("e")) + deepStrictEqual(pipe(_.some(1), _.toEither(() => "e")), E.right(1)) + }) + + it("match", () => { + const f = () => "none" + const g = (s: string) => `some${s.length}` + const match = _.match(f, g) + deepStrictEqual(match(_.none()), "none") + deepStrictEqual(match(_.some("abc")), "some3") + }) + + it("getOrElse", () => { + deepStrictEqual(pipe(_.some(1), _.getOrElse(() => 0)), 1) + deepStrictEqual(pipe(_.none(), _.getOrElse(() => 0)), 0) + }) + + it("getOrNull", () => { + deepStrictEqual(_.getOrNull(_.none()), null) + deepStrictEqual(_.getOrNull(_.some(1)), 1) + }) + + it("getOrUndefined", () => { + deepStrictEqual(_.getOrUndefined(_.none()), undefined) + deepStrictEqual(_.getOrUndefined(_.some(1)), 1) + }) + + it("liftOrder", () => { + const OS = _.liftOrder(S.Order) + deepStrictEqual(pipe(_.none(), OS.compare(_.none())), 0) + deepStrictEqual(pipe(_.some("a"), OS.compare(_.none())), 1) + deepStrictEqual(pipe(_.none(), OS.compare(_.some("a"))), -1) + deepStrictEqual(pipe(_.some("a"), OS.compare(_.some("a"))), 0) + deepStrictEqual(pipe(_.some("a"), OS.compare(_.some("b"))), -1) + deepStrictEqual(pipe(_.some("b"), OS.compare(_.some("a"))), 1) + }) + + it("flatMapNullable", () => { + interface X { + readonly a?: { + readonly b?: { + readonly c?: { + readonly d: number + } + } + } + } + const x1: X = { a: {} } + const x2: X = { a: { b: {} } } + const x3: X = { a: { b: { c: { d: 1 } } } } + deepStrictEqual( + pipe( + _.fromNullable(x1.a), + _.flatMapNullable((x) => x.b), + _.flatMapNullable((x) => x.c), + _.flatMapNullable((x) => x.d) + ), + _.none() + ) + deepStrictEqual( + pipe( + _.fromNullable(x2.a), + _.flatMapNullable((x) => x.b), + _.flatMapNullable((x) => x.c), + _.flatMapNullable((x) => x.d) + ), + _.none() + ) + deepStrictEqual( + pipe( + _.fromNullable(x3.a), + _.flatMapNullable((x) => x.b), + _.flatMapNullable((x) => x.c), + _.flatMapNullable((x) => x.d) + ), + _.some(1) + ) + }) + + it("getMonoid", () => { + const M = _.getMonoid(S.Semigroup) + deepStrictEqual(pipe(_.none(), M.combine(_.none())), _.none()) + deepStrictEqual(pipe(_.none(), M.combine(_.some("a"))), _.some("a")) + deepStrictEqual(pipe(_.some("a"), M.combine(_.none())), _.some("a")) + deepStrictEqual(pipe(_.some("b"), M.combine(_.some("a"))), _.some("ba")) + deepStrictEqual(pipe(_.some("a"), M.combine(_.some("b"))), _.some("ab")) + + deepStrictEqual(pipe(_.some("a"), M.combineMany([_.some("b")])), _.some("ab")) + deepStrictEqual(pipe(_.none(), M.combineMany([_.some("b")])), _.some("b")) + deepStrictEqual(pipe(_.some("a"), M.combineMany([_.none()])), _.some("a")) + + deepStrictEqual(pipe(M.combineAll([])), _.none()) + deepStrictEqual(pipe(M.combineAll([_.some("a")])), _.some("a")) + deepStrictEqual(pipe(M.combineAll([_.some("a"), _.some("b")])), _.some("ab")) + deepStrictEqual(pipe(M.combineAll([_.some("a"), _.none()])), _.some("a")) + }) + + it("fromNullable", () => { + deepStrictEqual(_.fromNullable(2), _.some(2)) + deepStrictEqual(_.fromNullable(null), _.none()) + deepStrictEqual(_.fromNullable(undefined), _.none()) + }) + + it("liftPredicate", () => { + const f = _.liftPredicate(p) + deepStrictEqual(f(1), _.none()) + deepStrictEqual(f(3), _.some(3)) + + type Direction = "asc" | "desc" + const parseDirection = _.liftPredicate((s: string): s is Direction => + s === "asc" || s === "desc" + ) + deepStrictEqual(parseDirection("asc"), _.some("asc")) + deepStrictEqual(parseDirection("foo"), _.none()) + }) + + it("contains", () => { + const contains = _.contains(equivalence.number) + deepStrictEqual(pipe(_.none(), contains(2)), false) + deepStrictEqual(pipe(_.some(2), contains(2)), true) + deepStrictEqual(pipe(_.some(2), contains(1)), false) + }) + + it("isNone", () => { + deepStrictEqual(_.isNone(_.none()), true) + deepStrictEqual(_.isNone(_.some(1)), false) + }) + + it("isSome", () => { + deepStrictEqual(_.isSome(_.none()), false) + deepStrictEqual(_.isSome(_.some(1)), true) + }) + + it("exists", () => { + const predicate = (a: number) => a === 2 + deepStrictEqual(pipe(_.none(), _.exists(predicate)), false) + deepStrictEqual(pipe(_.some(1), _.exists(predicate)), false) + deepStrictEqual(pipe(_.some(2), _.exists(predicate)), true) + }) + + it("fromThrowable", () => { + deepStrictEqual( + _.fromThrowable(() => JSON.parse("2")), + _.some(2) + ) + deepStrictEqual( + _.fromThrowable(() => JSON.parse("(")), + _.none() + ) + }) + + it("fromEither", () => { + deepStrictEqual(_.fromEither(E.right(1)), _.some(1)) + deepStrictEqual(_.fromEither(E.left("e")), _.none()) + }) + + it("do notation", () => { + deepStrictEqual( + pipe( + _.some(1), + _.bindTo("a"), + _.bind("b", () => _.some("b")) + ), + _.some({ a: 1, b: "b" }) + ) + }) + + it("andThenBind", () => { + deepStrictEqual( + pipe(_.some(1), _.bindTo("a"), _.andThenBind("b", _.some("b"))), + _.some({ a: 1, b: "b" }) + ) + }) + + it("productFlatten", () => { + deepStrictEqual( + pipe(_.some(1), _.tupled, _.productFlatten(_.some("b"))), + _.some([1, "b"] as const) + ) + }) + + it("liftNullable", () => { + const f = _.liftNullable((n: number) => (n > 0 ? n : null)) + deepStrictEqual(f(1), _.some(1)) + deepStrictEqual(f(-1), _.none()) + }) + + it("liftThrowable", () => { + const f = _.liftThrowable((s: string) => { + const len = s.length + if (len > 0) { + return len + } + throw new Error("empty string") + }) + deepStrictEqual(f("a"), _.some(1)) + deepStrictEqual(f(""), _.none()) + }) + + it("liftEither", () => { + const f = _.liftEither((n: number) => (n > 0 ? E.right(n) : E.left("e"))) + deepStrictEqual(f(1), _.some(1)) + deepStrictEqual(f(-1), _.none()) + }) + + it("flatMapEither", () => { + const f = _.flatMapEither((n: number) => (n > 0 ? E.right(n) : E.left("e"))) + deepStrictEqual(pipe(_.none(), f), _.none()) + deepStrictEqual(pipe(_.some(0), f), _.none()) + deepStrictEqual(pipe(_.some(1), f), _.some(1)) + }) + + it("guard", () => { + deepStrictEqual( + pipe( + _.Do, + _.bind("x", () => _.some("a")), + _.bind("y", () => _.some("a")), + _.filter(({ x, y }) => x === y) + ), + _.some({ x: "a", y: "a" }) + ) + deepStrictEqual( + pipe( + _.Do, + _.bind("x", () => _.some("a")), + _.bind("y", () => _.some("b")), + _.filter(({ x, y }) => x === y) + ), + _.none() + ) + }) +}) From f85856d096a7a57aae3f5c790e9b21937dc87cc3 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 08:17:24 +0100 Subject: [PATCH 019/255] add Either module --- .changeset/afraid-cars-lay.md | 5 + src/Either.ts | 1087 ++++++++++++++++++++++++++++++++- src/internal/Either.ts | 11 + test/Either.ts | 483 +++++++++++++++ 4 files changed, 1585 insertions(+), 1 deletion(-) create mode 100644 .changeset/afraid-cars-lay.md create mode 100644 test/Either.ts diff --git a/.changeset/afraid-cars-lay.md b/.changeset/afraid-cars-lay.md new file mode 100644 index 000000000..ea1e3c0ad --- /dev/null +++ b/.changeset/afraid-cars-lay.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add Either module diff --git a/src/Either.ts b/src/Either.ts index ba1185b3a..421875f7a 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -13,8 +13,32 @@ * * @since 1.0.0 */ - +import type { LazyArg } from "@fp-ts/core/Function" +import { constNull, constUndefined, identity, pipe } from "@fp-ts/core/Function" +import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as either from "@fp-ts/core/internal/Either" +import * as option from "@fp-ts/core/internal/Option" +import type { Option } from "@fp-ts/core/Option" +import type { Predicate, Refinement } from "@fp-ts/core/Predicate" +import * as applicative from "@fp-ts/core/typeclass/Applicative" +import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" +import * as chainable from "@fp-ts/core/typeclass/Chainable" +import * as covariant from "@fp-ts/core/typeclass/Covariant" +import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" +import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" +import type * as foldable from "@fp-ts/core/typeclass/Foldable" +import * as invariant from "@fp-ts/core/typeclass/Invariant" +import type * as monad from "@fp-ts/core/typeclass/Monad" +import type { Monoid } from "@fp-ts/core/typeclass/Monoid" +import * as of_ from "@fp-ts/core/typeclass/Of" +import type * as pointed from "@fp-ts/core/typeclass/Pointed" +import * as product_ from "@fp-ts/core/typeclass/Product" +import type * as semiAlternative from "@fp-ts/core/typeclass/SemiAlternative" +import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" +import * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" +import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import * as traversable from "@fp-ts/core/typeclass/Traversable" /** * @category models @@ -40,6 +64,14 @@ export type Right = { */ export type Either = Left | Right +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface EitherTypeLambda extends TypeLambda { + readonly type: Either +} + /** * Constructs a new `Either` holding a `Right` value. This usually represents a successful value due to the right bias * of this structure. @@ -57,3 +89,1056 @@ export const right: (a: A) => Either = either.right * @since 1.0.0 */ export const left: (e: E) => Either = either.left + +/** + * Alias of `right`. + * + * @category constructors + * @since 1.0.0 + */ +export const of: (a: A) => Either = right + +/** + * Returns `true` if the specified value is an instance of `Either`, `false` + * otherwise. + * + * @category guards + * @since 1.0.0 + */ +export const isEither: (u: unknown) => u is Either = either.isEither + +/** + * Returns `true` if the either is an instance of `Left`, `false` otherwise. + * + * @category guards + * @since 1.0.0 + */ +export const isLeft: (self: Either) => self is Left = either.isLeft + +/** + * Returns `true` if the either is an instance of `Right`, `false` otherwise. + * + * @category guards + * @since 1.0.0 + */ +export const isRight: (self: Either) => self is Right = either.isRight + +/** + * Returns an effect whose Right is mapped by the specified `f` function. + * + * @category mapping + * @since 1.0.0 + */ +export const map = (f: (a: A) => B) => + (self: Either): Either => isRight(self) ? right(f(self.right)) : self + +/** + * @category mapping + * @since 1.0.0 + */ +export const imap: ( + to: (a: A) => B, + from: (b: B) => A +) => (self: Either) => Either = covariant.imap(map) + +/** + * @category instances + * @since 1.0.0 + */ +export const Invariant: invariant.Invariant = { + imap +} + +/** + * @category mapping + * @since 1.0.0 + */ +export const tupled: (self: Either) => Either = invariant.tupled( + Invariant +) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindTo: ( + name: N +) => (self: Either) => Either = invariant.bindTo(Invariant) + +/** + * @category instances + * @since 1.0.0 + */ +export const Covariant: covariant.Covariant = { + ...Invariant, + map +} + +/** + * @category mapping + * @since 1.0.0 + */ +export const flap: (a: A) => (self: Either B>) => Either = covariant + .flap( + Covariant + ) + +/** + * Maps the Right value of this effect to the specified constant value. + * + * @category mapping + * @since 1.0.0 + */ +export const as: (b: B) => (self: Either) => Either = covariant.as( + Covariant +) + +/** + * Returns the effect Eithering from mapping the Right of this effect to unit. + * + * @category mapping + * @since 1.0.0 + */ +export const asUnit: (self: Either) => Either = covariant.asUnit( + Covariant +) + +const let_: ( + name: Exclude, + f: (a: A) => B +) => ( + self: Either +) => Either = covariant.let( + Covariant +) + +export { + /** + * @category do notation + * @since 1.0.0 + */ + let_ as let +} + +/** + * Returns an effect whose Left and Right channels have been mapped by + * the specified pair of functions, `f` and `g`. + * + * @category mapping + * @since 1.0.0 + */ +export const bimap = ( + f: (e: E) => G, + g: (a: A) => B +) => (self: Either): Either => isLeft(self) ? left(f(self.left)) : right(g(self.right)) + +/** + * @category instances + * @since 1.0.0 + */ +export const Bicovariant: bicovariant.Bicovariant = { + bimap +} + +/** + * Returns an effect with its error channel mapped using the specified + * function. This can be used to lift a "smaller" error into a "larger" error. + * + * @category error handling + * @since 1.0.0 + */ +export const mapLeft: (f: (e: E) => G) => (self: Either) => Either = + bicovariant + .mapLeft(Bicovariant) + +/** + * @category instances + * @since 1.0.0 + */ +export const Of: of_.Of = { + of +} + +/** + * @since 1.0.0 + */ +export const unit: Either = of_.unit(Of) + +/** + * @category do notation + * @since 1.0.0 + */ +export const Do: Either = of_.Do(Of) + +/** + * @category instances + * @since 1.0.0 + */ +export const Pointed: pointed.Pointed = { + ...Of, + ...Covariant +} + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMap = ( + f: (a: A) => Either +) => (self: Either): Either => isLeft(self) ? self : f(self.right) + +/** + * @category instances + * @since 1.0.0 + */ +export const FlatMap: flatMap_.FlatMap = { + flatMap +} + +/** + * @since 1.0.0 + */ +export const flatten: (self: Either>) => Either = flatMap_ + .flatten(FlatMap) + +/** + * @since 1.0.0 + */ +export const andThen: ( + that: Either +) => (self: Either) => Either = flatMap_ + .andThen(FlatMap) + +/** + * @since 1.0.0 + */ +export const composeKleisliArrow: ( + bfc: (b: B) => Either +) => (afb: (a: A) => Either) => (a: A) => Either = flatMap_ + .composeKleisliArrow(FlatMap) + +/** + * @category instances + * @since 1.0.0 + */ +export const Chainable: chainable.Chainable = { + ...FlatMap, + ...Covariant +} + +/** + * @category do notation + * @since 1.0.0 + */ +export const bind: ( + name: Exclude, + f: (a: A) => Either +) => ( + self: Either +) => Either = chainable + .bind(Chainable) + +/** + * Sequences the specified effect after this effect, but ignores the value + * produced by the effect. + * + * @category sequencing + * @since 1.0.0 + */ +export const andThenDiscard: ( + that: Either +) => (self: Either) => Either = chainable + .andThenDiscard(Chainable) + +/** + * @category instances + * @since 1.0.0 + */ +export const Monad: monad.Monad = { + ...Pointed, + ...FlatMap +} + +/** + * @since 1.0.0 + */ +export const product = ( + that: Either +) => + (self: Either): Either => + isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self + +/** + * @category error handling + * @since 1.0.0 + */ +export const productMany = ( + collection: Iterable> +) => + (self: Either): Either]> => { + if (isLeft(self)) { + return self + } + const out: [A, ...Array] = [self.right] + for (const e of collection) { + if (isLeft(e)) { + return e + } + out.push(e.right) + } + return right(out) + } + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiProduct: semiProduct.SemiProduct = { + ...Invariant, + product, + productMany +} + +/** + * A variant of `bind` that sequentially ignores the scope. + * + * @category do notation + * @since 1.0.0 + */ +export const andThenBind: ( + name: Exclude, + fb: Either +) => ( + self: Either +) => Either = semiProduct + .andThenBind(SemiProduct) + +/** + * @since 1.0.0 + */ +export const productFlatten: ( + that: Either +) => >( + self: Either +) => Either = semiProduct + .productFlatten(SemiProduct) + +/** + * @since 1.0.0 + */ +export const productAll = ( + collection: Iterable> +): Either> => { + const out: Array = [] + for (const e of collection) { + if (isLeft(e)) { + return e + } + out.push(e.right) + } + return right(out) +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Product: product_.Product = { + ...Of, + ...SemiProduct, + productAll +} + +/** + * @since 1.0.0 + */ +export const tuple: >>( + ...tuple: T +) => Either< + [T[number]] extends [Either] ? E : never, + Readonly<{ [I in keyof T]: [T[I]] extends [Either] ? A : never }> +> = product_ + .tuple(Product) + +/** + * @since 1.0.0 + */ +export const struct: >>( + r: R +) => Either< + [R[keyof R]] extends [Either] ? E : never, + { readonly [K in keyof R]: [R[K]] extends [Either] ? A : never } +> = product_ + .struct(Product) + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiApplicative: semiApplicative.SemiApplicative = { + ...SemiProduct, + ...Covariant +} + +/** + * Semigroup returning the left-most `Left` value. If both operands are `Right`s then the inner values + * are concatenated using the provided `Semigroup`. + * + * | x | y | x |> combine(y) | + * | ---------| ---------| -----------------------| + * | left(a) | left(b) | left(a) | + * | left(a) | right(2) | left(a) | + * | right(1) | left(b) | left(b) | + * | right(1) | right(2) | right(1 |> combine(2)) | + * + * @category combining + * @since 1.0.0 + */ +export const getFirstLeftSemigroup: (S: Semigroup) => Semigroup> = + semiApplicative + .liftSemigroup(SemiApplicative) + +/** + * @category lifting + * @since 1.0.0 + */ +export const lift2: ( + f: (a: A, b: B) => C +) => (fa: Either, fb: Either) => Either = semiApplicative + .lift2(SemiApplicative) + +/** + * @category lifting + * @since 1.0.0 + */ +export const lift3: ( + f: (a: A, b: B, c: C) => D +) => ( + fa: Either, + fb: Either, + fc: Either +) => Either = semiApplicative.lift3( + SemiApplicative +) + +/** + * @since 1.0.0 + */ +export const ap: ( + fa: Either +) => (self: Either B>) => Either = semiApplicative.ap( + SemiApplicative +) + +/** + * @category instances + * @since 1.0.0 + */ +export const Applicative: applicative.Applicative = { + ...SemiApplicative, + ...Product +} + +/** + * Monoid returning the left-most `Left` value. If both operands are `Right`s then the inner values + * are concatenated using the provided `Monoid`. + * + * The `empty` value is `right(M.empty)`. + * + * @category combining + * @since 1.0.0 + */ +export const getFirstLeftMonoid: (M: Monoid) => Monoid> = applicative + .liftMonoid( + Applicative + ) + +/** + * @category error handling + * @since 1.0.0 + */ +export const firstSuccessOf = (collection: Iterable>) => + (self: Either): Either => { + let out = self + if (isRight(out)) { + return out + } + for (out of collection) { + if (isRight(out)) { + return out + } + } + return out + } + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiCoproduct: semiCoproduct.SemiCoproduct = { + ...Invariant, + coproduct: (that) => (self) => isRight(self) ? self : that, + coproductMany: firstSuccessOf +} + +/** + * Semigroup returning the left-most `Right` value. + * + * | x | y | x |> combine(y) | + * | ---------| ---------| ----------------| + * | left(a) | left(b) | left(b) | + * | left(a) | right(2) | right(2) | + * | right(1) | left(b) | right(1) | + * | right(1) | right(2) | right(1) | + * + * @category combining + * @since 1.0.0 + */ +export const getFirstRightSemigroup: () => Semigroup> = semiCoproduct + .getSemigroup(SemiCoproduct) + +/** + * Returns the wrapped value if it's a `Right` or a default value if is a `Left`. + * + * @example + * import * as E from '@fp-ts/core/Either' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.deepStrictEqual( + * pipe( + * E.right(1), + * E.getOrElse(() => 0) + * ), + * 1 + * ) + * assert.deepStrictEqual( + * pipe( + * E.left('error'), + * E.getOrElse(() => 0) + * ), + * 0 + * ) + * + * @category getters + * @since 1.0.0 + */ +export const getOrElse = (onLeft: LazyArg) => + (self: Either): A | B => isLeft(self) ? onLeft() : self.right + +/** + * Recovers from all errors. + * + * @category error handling + * @since 1.0.0 + */ +export const catchAll = ( + onLeft: (e: E1) => Either +) => (self: Either): Either => isLeft(self) ? onLeft(self.left) : self + +/** + * Executes this effect and returns its value, if it succeeds, but otherwise + * executes the specified effect. + * + * | x | y | x |> orElse(y) | + * | ---------- | ---------- | ---------------| + * | left(a) | left(b) | left(b) | + * | left(a) | right(2) | right(2) | + * | right(1) | left(b) | right(1) | + * | right(1) | right(2) | right(1) | + * + * @category error handling + * @since 1.0.0 + */ +export const orElse = ( + that: Either +) => (self: Either): Either => isLeft(self) ? that : self + +/** + * Returns an effect that will produce the value of this effect, unless it + * fails, in which case, it will produce the value of the specified effect. + * + * @category error handling + * @since 1.0.0 + */ +export const orElseEither = ( + that: Either +) => + (self: Either): Either> => + isLeft(self) ? + pipe(that, map(right)) : + pipe, Either>>(self, map(left)) + +/** + * Executes this effect and returns its value, if it succeeds, but otherwise + * fails with the specified error. + * + * @category error handling + * @since 1.0.0 + */ +export const orElseFail = ( + onLeft: LazyArg +): (self: Either) => Either => catchAll(() => left(onLeft())) + +/** + * Executes this effect and returns its value, if it succeeds, but otherwise + * succeeds with the specified value. + * + * @category error handling + * @since 1.0.0 + */ +export const orElseSucceed = ( + onLeft: LazyArg +): (self: Either) => Either => catchAll(() => right(onLeft())) + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiAlternative: semiAlternative.SemiAlternative = { + ...Covariant, + ...SemiCoproduct +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Foldable: foldable.Foldable = { + reduce: (b, f) => (self) => isLeft(self) ? b : f(b, self.right) +} + +/** + * Takes two functions and an `Either` value, if the value is a `Left` the inner value is applied to the first function, + * if the value is a `Right` the inner value is applied to the second function. + * + * @example + * import * as E from '@fp-ts/core/Either' + * import { pipe } from '@fp-ts/core/Function' + * + * const onLeft = (errors: ReadonlyArray): string => `Errors: ${errors.join(', ')}` + * + * const onRight = (value: number): string => `Ok: ${value}` + * + * assert.strictEqual( + * pipe( + * E.right(1), + * E.match(onLeft , onRight) + * ), + * 'Ok: 1' + * ) + * assert.strictEqual( + * pipe( + * E.left(['error 1', 'error 2']), + * E.match(onLeft , onRight) + * ), + * 'Errors: error 1, error 2' + * ) + * + * @category pattern matching + * @since 1.0.0 + */ +export const match = (onLeft: (e: E) => B, onRight: (a: A) => C) => + (self: Either): B | C => isLeft(self) ? onLeft(self.left) : onRight(self.right) + +/** + * Takes a lazy default and a nullable value, if the value is not nully, turn it into a `Right`, if the value is nully use + * the provided default as a `Left`. + * + * @example + * import * as E from '@fp-ts/core/Either' + * + * const parse = E.fromNullable(() => 'nullable') + * + * assert.deepStrictEqual(parse(1), E.right(1)) + * assert.deepStrictEqual(parse(null), E.left('nullable')) + * + * @category conversions + * @since 1.0.0 + */ +export const fromNullable: (onNullable: LazyArg) => (a: A) => Either> = + either.fromNullable + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftNullable = , B, E>( + f: (...a: A) => B | null | undefined, + onNullable: (...a: A) => E +) => (...a: A): Either> => fromNullable(() => onNullable(...a))(f(...a)) + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMapNullable = ( + f: (a: A) => B | null | undefined, + onNullable: (a: A) => E2 +): ((self: Either) => Either>) => + flatMap(liftNullable(f, onNullable)) + +/** + * Returns a `Refinement` from a `Either` returning function. + * This function ensures that a `Refinement` definition is type-safe. + * + * @category conversions + * @since 1.0.0 + */ +export const toRefinement = (f: (a: A) => Either): Refinement => + (a: A): a is B => isRight(f(a)) + +/** + * Constructs a new `Either` from a function that might throw. + * + * @example + * import * as E from '@fp-ts/core/Either' + * import { identity } from '@fp-ts/core/Function' + * + * const unsafeHead = (as: ReadonlyArray): A => { + * if (as.length > 0) { + * return as[0] + * } else { + * throw new Error('empty array') + * } + * } + * + * const head = (as: ReadonlyArray): E.Either => + * E.fromThrowable(() => unsafeHead(as), identity) + * + * assert.deepStrictEqual(head([]), E.left(new Error('empty array'))) + * assert.deepStrictEqual(head([1, 2, 3]), E.right(1)) + * + * @category interop + * @since 1.0.0 + */ +export const fromThrowable = ( + f: () => A, + onThrow: (error: unknown) => E +): Either => { + try { + return right(f()) + } catch (e) { + return left(onThrow(e)) + } +} + +/** + * @category interop + * @since 1.0.0 + */ +export const getOrThrow = (onLeft: (e: E) => unknown) => + (self: Either): A => { + if (isRight(self)) { + return self.right + } + throw onLeft(self.left) + } + +/** + * Lifts a function that may throw to one returning a `Either`. + * + * @category interop + * @since 1.0.0 + */ +export const liftThrowable = , B, E>( + f: (...a: A) => B, + onThrow: (error: unknown) => E +): ((...a: A) => Either) => (...a) => fromThrowable(() => f(...a), onThrow) + +/** + * @category getters + * @since 1.0.0 + */ +export const merge: (self: Either) => E | A = match(identity, identity) + +/** + * @category mutations + * @since 1.0.0 + */ +export const reverse = (self: Either): Either => + isLeft(self) ? right(self.left) : left(self.right) + +/** + * @category filtering + * @since 1.0.0 + */ +export const compact = (onNone: LazyArg) => + (self: Either>): Either => + isLeft(self) ? self : option.isNone(self.right) ? left(onNone()) : right(self.right.value) + +/** + * @category filtering + * @since 1.0.0 + */ +export const filter: { + (refinement: Refinement, onFalse: LazyArg): ( + self: Either + ) => Either + ( + predicate: Predicate, + onFalse: LazyArg + ): (self: Either) => Either +} = ( + predicate: Predicate, + onFalse: LazyArg +) => + (self: Either): Either => + isLeft(self) ? self : predicate(self.right) ? self : left(onFalse()) + +/** + * @category filtering + * @since 1.0.0 + */ +export const filterMap = ( + f: (a: A) => Option, + onNone: LazyArg +) => + (self: Either): Either => + pipe( + self, + flatMap((a) => { + const ob = f(a) + return option.isNone(ob) ? left(onNone()) : right(ob.value) + }) + ) + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverse = (F: applicative.Applicative) => + (f: (a: A) => Kind) => + (self: Either): Kind> => + isLeft(self) ? + F.of>(left(self.left)) : + pipe(f(self.right), F.map>(right)) + +/** + * @category traversing + * @since 1.0.0 + */ +export const sequence: ( + F: applicative.Applicative +) => ( + self: Either> +) => Kind> = traversable.sequence(traverse) + +/** + * @category instances + * @since 1.0.0 + */ +export const Traversable: traversable.Traversable = { + traverse, + sequence +} + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverseTap: ( + F: applicative.Applicative +) => ( + f: (a: A) => Kind +) => (self: Either) => Kind> = traversable + .traverseTap(Traversable) + +/** + * Returns an effect that effectfully "peeks" at the success of this effect. + * + * @since 1.0.0 + */ +export const tap: ( + f: (a: A) => Either +) => (self: Either) => Either = chainable.tap( + Chainable +) + +/** + * @category debugging + * @since 1.0.0 + */ +export const inspectRight = ( + onRight: (a: A) => void +) => + (self: Either): Either => { + if (isRight(self)) { + onRight(self.right) + } + return self + } + +/** + * Returns an effect that effectfully "peeks" at the failure of this effect. + * + * @category error handling + * @since 1.0.0 + */ +export const tapError = ( + onLeft: (e: E1) => Either +) => + (self: Either): Either => { + if (isRight(self)) { + return self + } + const out = onLeft(self.left) + return isLeft(out) ? out : self + } + +/** + * @category debugging + * @since 1.0.0 + */ +export const inspectLeft = ( + onLeft: (e: E) => void +) => + (self: Either): Either => { + if (isLeft(self)) { + onLeft(self.left) + } + return self + } + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromIterable = (onEmpty: LazyArg) => + (collection: Iterable): Either => { + for (const a of collection) { + return right(a) + } + return left(onEmpty()) + } + +/** + * @example + * import * as E from '@fp-ts/core/Either' + * import { pipe } from '@fp-ts/core/Function' + * import * as O from '@fp-ts/core/Option' + * + * assert.deepStrictEqual(pipe(O.some(1), E.fromOption(() => 'error')), E.right(1)) + * assert.deepStrictEqual(pipe(O.none, E.fromOption(() => 'error')), E.left('error')) + * + * @category conversions + * @since 1.0.0 + */ +export const fromOption: (onNone: LazyArg) => (self: Option) => Either = + either.fromOption + +/** + * Converts a `Either` to an `Option` discarding the Right. + * + * @example + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(E.getLeft(E.right('ok')), O.none) + * assert.deepStrictEqual(E.getLeft(E.left('err')), O.some('err')) + * + * @category getters + * @since 1.0.0 + */ +export const getLeft: (self: Either) => Option = either.getLeft + +/** + * Converts a `Either` to an `Option` discarding the error. + * + * @example + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(E.getRight(E.right('ok')), O.some('ok')) + * assert.deepStrictEqual(E.getRight(E.left('err')), O.none) + * + * @category getters + * @since 1.0.0 + */ +export const getRight: (self: Either) => Option = either.getRight + +/** + * @category getters + * @since 1.0.0 + */ +export const getOrNull: (self: Either) => A | null = getOrElse(constNull) + +/** + * @category getters + * @since 1.0.0 + */ +export const getOrUndefined: (self: Either) => A | undefined = getOrElse(constUndefined) + +/** + * @example + * import { liftPredicate, left, right } from '@fp-ts/core/Either' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.deepStrictEqual( + * pipe( + * 1, + * liftPredicate((n) => n > 0, () => 'error') + * ), + * right(1) + * ) + * assert.deepStrictEqual( + * pipe( + * -1, + * liftPredicate((n) => n > 0, () => 'error') + * ), + * left('error') + * ) + * + * @category lifting + * @since 1.0.0 + */ +export const liftPredicate: { + ( + refinement: Refinement, + onFalse: LazyArg + ): (c: C) => Either + (predicate: Predicate, onFalse: LazyArg): (b: B) => Either +} = (predicate: Predicate, onFalse: LazyArg) => + (b: B) => predicate(b) ? right(b) : left(onFalse()) + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftOption = , B, E>( + f: (...a: A) => Option, + onNone: (...a: A) => E +) => (...a: A): Either => fromOption(() => onNone(...a))(f(...a)) + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMapOption = ( + f: (a: A) => Option, + onNone: (a: A) => E2 +) => (self: Either): Either => pipe(self, flatMap(liftOption(f, onNone))) + +/** + * Returns a function that checks if an `Either` contains a given value using a provided `equivalence` function. + * + * @since 1.0.0 + */ +export const contains = (equivalence: Equivalence) => + (a: A) => (self: Either): boolean => isLeft(self) ? false : equivalence(self.right, a) + +/** + * Returns `false` if `Left` or returns the Either of the application of the given predicate to the `Right` value. + * + * @example + * import * as E from '@fp-ts/core/Either' + * + * const f = E.exists((n: number) => n > 2) + * + * assert.strictEqual(f(E.left('a')), false) + * assert.strictEqual(f(E.right(1)), false) + * assert.strictEqual(f(E.right(3)), true) + * + * @since 1.0.0 + */ +export const exists = (predicate: Predicate) => + (self: Either): boolean => isLeft(self) ? false : predicate(self.right) diff --git a/src/internal/Either.ts b/src/internal/Either.ts index 215be4841..fbc5bce28 100644 --- a/src/internal/Either.ts +++ b/src/internal/Either.ts @@ -3,9 +3,15 @@ */ import type { Either, Left, Right } from "@fp-ts/core/Either" +import type { LazyArg } from "@fp-ts/core/Function" import * as option from "@fp-ts/core/internal/Option" import type { Option } from "@fp-ts/core/Option" +/** @internal */ +export const isEither = (u: unknown): u is Either => + typeof u === "object" && u != null && "_tag" in u && + (u["_tag"] === "Left" || u["_tag"] === "Right") + /** @internal */ export const isLeft = (ma: Either): ma is Left => ma._tag === "Left" @@ -28,6 +34,11 @@ export const getRight = ( self: Either ): Option => (isLeft(self) ? option.none : option.some(self.right)) +/** @internal */ +export const fromNullable = (onNullable: LazyArg) => + (a: A): Either> => + a == null ? left(onNullable()) : right(a as NonNullable) + /** @internal */ export const fromOption = (onNone: () => E) => (fa: Option): Either => option.isNone(fa) ? left(onNone()) : right(fa.value) diff --git a/test/Either.ts b/test/Either.ts new file mode 100644 index 000000000..83e429746 --- /dev/null +++ b/test/Either.ts @@ -0,0 +1,483 @@ +import * as _ from "@fp-ts/core/Either" +import { flow, identity, pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" +import * as String from "@fp-ts/core/String" +import { deepStrictEqual, double } from "@fp-ts/core/test/util" +import { number } from "@fp-ts/core/typeclass/Equivalence" + +describe.concurrent("Either", () => { + it("instances and derived exports", () => { + expect(_.Invariant).exist + expect(_.imap).exist + expect(_.tupled).exist + expect(_.bindTo).exist + + expect(_.Covariant).exist + expect(_.map).exist + expect(_.let).exist + expect(_.flap).exist + expect(_.as).exist + expect(_.asUnit).exist + + expect(_.Bicovariant).exist + expect(_.bimap).exist + expect(_.mapLeft).exist + + expect(_.Of).exist + expect(_.of).exist + expect(_.unit).exist + expect(_.Do).exist + + expect(_.Pointed).exist + + expect(_.FlatMap).exist + expect(_.flatMap).exist + expect(_.flatten).exist + expect(_.andThen).exist + expect(_.composeKleisliArrow).exist + + expect(_.Chainable).exist + expect(_.bind).exist + expect(_.tap).exist + expect(_.andThenDiscard).exist + + expect(_.Monad).exist + + expect(_.SemiProduct).exist + expect(_.product).exist + + expect(_.Product).exist + expect(_.productAll).exist + expect(_.tuple).exist + expect(_.struct).exist + + expect(_.SemiApplicative).exist + expect(_.getFirstLeftSemigroup).exist // liftSemigroup + expect(_.lift2).exist + expect(_.lift3).exist + expect(_.ap).exist + expect(_.andThenDiscard).exist + expect(_.andThen).exist + + expect(_.Applicative).exist + expect(_.getFirstLeftMonoid).exist // liftMonoid + + expect(_.SemiCoproduct).exist + expect(_.getFirstRightSemigroup).exist // getSemigroup + expect(_.firstSuccessOf).exist + + expect(_.SemiAlternative).exist + + expect(_.Foldable).exist + + expect(_.Traversable).exist + expect(_.traverse).exist + expect(_.sequence).exist + expect(_.traverseTap).exist + }) + + it("toRefinement", () => { + const f = (s: string | number): _.Either => + typeof s === "string" ? _.right(s) : _.left("not a string") + const isString = _.toRefinement(f) + deepStrictEqual(isString("s"), true) + deepStrictEqual(isString(1), false) + type A = { readonly type: "A" } + type B = { readonly type: "B" } + type C = A | B + const isA = _.toRefinement(( + c: C + ) => (c.type === "A" ? _.right(c) : _.left("not as A"))) + deepStrictEqual(isA({ type: "A" }), true) + deepStrictEqual(isA({ type: "B" }), false) + }) + + it("isEither", () => { + deepStrictEqual(pipe(_.right(1), _.isEither), true) + deepStrictEqual(pipe(_.left("e"), _.isEither), true) + deepStrictEqual(pipe(O.some(1), _.isEither), false) + }) + + it("orElseFail", () => { + deepStrictEqual(pipe(_.right(1), _.orElseFail(() => "e2")), _.right(1)) + deepStrictEqual(pipe(_.left("e1"), _.orElseFail(() => "e2")), _.left("e2")) + }) + + it("orElseSucceed", () => { + deepStrictEqual(pipe(_.right(1), _.orElseSucceed(() => 2)), _.right(1)) + deepStrictEqual(pipe(_.left("e"), _.orElseSucceed(() => 2)), _.right(2)) + }) + + it("reduce", () => { + deepStrictEqual(pipe(_.right("bar"), _.Foldable.reduce("foo", (b, a) => b + a)), "foobar") + deepStrictEqual(pipe(_.left("bar"), _.Foldable.reduce("foo", (b, a) => b + a)), "foo") + }) + + it("getRight", () => { + deepStrictEqual(pipe(_.right(1), _.getRight), O.some(1)) + deepStrictEqual(pipe(_.left("a"), _.getRight), O.none()) + }) + + it("getLeft", () => { + deepStrictEqual(pipe(_.right(1), _.getLeft), O.none()) + deepStrictEqual(pipe(_.left("e"), _.getLeft), O.some("e")) + }) + + it("getOrNull", () => { + deepStrictEqual(pipe(_.right(1), _.getOrNull), 1) + deepStrictEqual(pipe(_.left("a"), _.getOrNull), null) + }) + + it("getOrUndefined", () => { + deepStrictEqual(pipe(_.right(1), _.getOrUndefined), 1) + deepStrictEqual(pipe(_.left("a"), _.getOrUndefined), undefined) + }) + + it("compact", () => { + deepStrictEqual(pipe(_.right(O.some(1)), _.compact(() => "e2")), _.right(1)) + deepStrictEqual(pipe(_.right(O.none()), _.compact(() => "e2")), _.left("e2")) + deepStrictEqual(pipe(_.left("e1"), _.compact(() => "e2")), _.left("e1")) + }) + + it("inspectRight", () => { + const log: Array = [] + pipe(_.right(1), _.inspectRight((e) => log.push(e))) + pipe(_.left("e"), _.inspectRight((e) => log.push(e))) + deepStrictEqual(log, [1]) + }) + + it("tapError", () => { + deepStrictEqual(pipe(_.right(1), _.tapError(() => _.right(2))), _.right(1)) + deepStrictEqual(pipe(_.left("a"), _.tapError(() => _.right(2))), _.left("a")) + deepStrictEqual(pipe(_.left("a"), _.tapError(() => _.left("b"))), _.left("b")) + }) + + it("inspectLeft", () => { + const log: Array = [] + pipe(_.right(1), _.inspectLeft((e) => log.push(e))) + pipe(_.left("e"), _.inspectLeft((e) => log.push(e))) + deepStrictEqual(log, ["e"]) + }) + + it("getOrThrow", () => { + expect(pipe(_.right(1), _.getOrThrow((e: string) => new Error(e)))).toEqual(1) + expect(() => pipe(_.left("e"), _.getOrThrow((e: string) => new Error(e)))).toThrow( + new Error("e") + ) + }) + + it("andThenDiscard", () => { + deepStrictEqual(pipe(_.right(1), _.andThenDiscard(_.right("a"))), _.right(1)) + deepStrictEqual(pipe(_.right(1), _.andThenDiscard(_.left(true))), _.left(true)) + deepStrictEqual(pipe(_.left(1), _.andThenDiscard(_.right("a"))), _.left(1)) + deepStrictEqual(pipe(_.left(1), _.andThenDiscard(_.left(true))), _.left(1)) + }) + + it("andThen", () => { + deepStrictEqual(pipe(_.right(1), _.andThen(_.right("a"))), _.right("a")) + deepStrictEqual(pipe(_.right(1), _.andThen(_.left(true))), _.left(true)) + deepStrictEqual(pipe(_.left(1), _.andThen(_.right("a"))), _.left(1)) + deepStrictEqual(pipe(_.left(1), _.andThen(_.left(true))), _.left(1)) + }) + + it("orElse", () => { + deepStrictEqual(pipe(_.right(1), _.orElse(_.right(2))), _.right(1)) + deepStrictEqual(pipe(_.right(1), _.orElse(_.left("b"))), _.right(1)) + deepStrictEqual(pipe(_.left("a"), _.orElse(_.right(2))), _.right(2)) + deepStrictEqual(pipe(_.left("a"), _.orElse(_.left("b"))), _.left("b")) + }) + + it("orElseEither", () => { + expect(pipe(_.right(1), _.orElseEither(_.right(2)))).toEqual(_.right(_.left(1))) + expect(pipe(_.right(1), _.orElseEither(_.left("b")))).toEqual(_.right(_.left(1))) + expect(pipe(_.left("a"), _.orElseEither(_.right(2)))).toEqual(_.right(_.right(2))) + expect(pipe(_.left("a"), _.orElseEither(_.left("b")))).toEqual(_.left("b")) + }) + + it("map", () => { + const f = _.map(String.size) + deepStrictEqual(pipe(_.right("abc"), f), _.right(3)) + deepStrictEqual(pipe(_.left("s"), f), _.left("s")) + }) + + it("flatMap", () => { + const f = _.flatMap(flow(String.size, _.right)) + deepStrictEqual(pipe(_.right("abc"), f), _.right(3)) + deepStrictEqual(pipe(_.left("maError"), f), _.left("maError")) + }) + + it("bimap", () => { + const f = _.bimap(String.size, (n: number) => n > 2) + deepStrictEqual(pipe(_.right(1), f), _.right(false)) + }) + + it("mapLeft", () => { + const f = _.mapLeft(double) + deepStrictEqual(pipe(_.right("a"), f), _.right("a")) + deepStrictEqual(pipe(_.left(1), f), _.left(2)) + }) + + it("traverse", () => { + const traverse = _.traverse(O.Applicative)(( + n: number + ) => (n >= 2 ? O.some(n) : O.none())) + deepStrictEqual(pipe(_.left("a"), traverse), O.some(_.left("a"))) + deepStrictEqual(pipe(_.right(1), traverse), O.none()) + deepStrictEqual(pipe(_.right(3), traverse), O.some(_.right(3))) + }) + + it("sequence", () => { + const sequence = _.sequence(O.Applicative) + deepStrictEqual(sequence(_.right(O.some(1))), O.some(_.right(1))) + deepStrictEqual(sequence(_.left("a")), O.some(_.left("a"))) + deepStrictEqual(sequence(_.right(O.none())), O.none()) + }) + + it("match", () => { + const f = (s: string) => `left${s.length}` + const g = (s: string) => `right${s.length}` + const match = _.match(f, g) + deepStrictEqual(match(_.left("abc")), "left3") + deepStrictEqual(match(_.right("abc")), "right3") + }) + + it("getOrElse", () => { + deepStrictEqual(pipe(_.right(12), _.getOrElse(() => 17)), 12) + deepStrictEqual(pipe(_.left("a"), _.getOrElse(() => 17)), 17) + }) + + it("contains", () => { + const contains = _.contains(number) + deepStrictEqual(pipe(_.left("a"), contains(2)), false) + deepStrictEqual(pipe(_.right(2), contains(2)), true) + deepStrictEqual(pipe(_.right(2), contains(1)), false) + }) + + it("filter", () => { + const predicate = (n: number) => n > 10 + deepStrictEqual(pipe(_.right(12), _.filter(predicate, () => -1)), _.right(12)) + deepStrictEqual(pipe(_.right(7), _.filter(predicate, () => -1)), _.left(-1)) + deepStrictEqual(pipe(_.left(12), _.filter(predicate, () => -1)), _.left(12)) + }) + + it("isLeft", () => { + deepStrictEqual(_.isLeft(_.right(1)), false) + deepStrictEqual(_.isLeft(_.left(1)), true) + }) + + it("isRight", () => { + deepStrictEqual(_.isRight(_.right(1)), true) + deepStrictEqual(_.isRight(_.left(1)), false) + }) + + it("catchAll", () => { + deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.right(2))), _.right(1)) + deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.left("foo"))), _.right(1)) + deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.right(1))), _.right(1)) + deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.left("b"))), _.left("b")) + }) + + it("swap", () => { + deepStrictEqual(_.reverse(_.right("a")), _.left("a")) + deepStrictEqual(_.reverse(_.left("b")), _.right("b")) + }) + + it("liftPredicate", () => { + const f = _.liftPredicate((n: number) => n >= 2, () => "e") + deepStrictEqual(f(3), _.right(3)) + deepStrictEqual(f(1), _.left("e")) + }) + + it("fromNullable", () => { + deepStrictEqual(_.fromNullable(() => "default")(null), _.left("default")) + deepStrictEqual(_.fromNullable(() => "default")(undefined), _.left("default")) + deepStrictEqual(_.fromNullable(() => "default")(1), _.right(1)) + }) + + it("fromThrowable", () => { + deepStrictEqual( + _.fromThrowable(() => { + return 1 + }, identity), + _.right(1) + ) + + deepStrictEqual( + _.fromThrowable(() => { + throw "string error" + }, identity), + _.left("string error") + ) + }) + + it("filterMap", () => { + const p = (n: number) => n > 2 + const f = (n: number) => (p(n) ? O.some(n + 1) : O.none()) + deepStrictEqual(pipe(_.left("123"), _.filterMap(f, () => "")), _.left("123")) + deepStrictEqual(pipe(_.right(1), _.filterMap(f, () => "")), _.left(String.Monoid.empty)) + deepStrictEqual(pipe(_.right(3), _.filterMap(f, () => "")), _.right(4)) + }) + + it("fromIterable", () => { + deepStrictEqual(_.fromIterable(() => "e")([]), _.left("e")) + deepStrictEqual(_.fromIterable(() => "e")(["a"]), _.right("a")) + }) + + it("firstSuccessOf", () => { + deepStrictEqual(pipe(_.right(1), _.firstSuccessOf([])), _.right(1)) + deepStrictEqual(pipe(_.left("e"), _.firstSuccessOf([])), _.left("e")) + deepStrictEqual( + pipe(_.left("e1"), _.firstSuccessOf([_.left("e2"), _.left("e3"), _.left("e4"), _.right(1)])), + _.right(1) + ) + deepStrictEqual( + pipe(_.left("e1"), _.firstSuccessOf([_.left("e2"), _.left("e3"), _.left("e4")])), + _.left("e4") + ) + }) + + it("fromOption", () => { + deepStrictEqual(_.fromOption(() => "none")(O.none()), _.left("none")) + deepStrictEqual(_.fromOption(() => "none")(O.some(1)), _.right(1)) + }) + + it("liftOption", () => { + const f = _.liftOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "a") + deepStrictEqual(f(1), _.right(1)) + deepStrictEqual(f(-1), _.left("a")) + }) + + it("flatMapOption", () => { + const f = _.flatMapOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "a") + deepStrictEqual(f(_.right(1)), _.right(1)) + deepStrictEqual(f(_.right(-1)), _.left("a")) + deepStrictEqual(f(_.left("b")), _.left("b")) + }) + + it("exists", () => { + const gt2 = _.exists((n: number) => n > 2) + deepStrictEqual(gt2(_.left("a")), false) + deepStrictEqual(gt2(_.right(1)), false) + deepStrictEqual(gt2(_.right(3)), true) + }) + + it("do notation", () => { + deepStrictEqual( + pipe( + _.right(1), + _.bindTo("a"), + _.bind("b", () => _.right("b")), + _.let("c", ({ a, b }) => [a, b]) + ), + _.right({ a: 1, b: "b", c: [1, "b"] }) + ) + }) + + it("andThenBind", () => { + deepStrictEqual( + pipe(_.right(1), _.bindTo("a"), _.andThenBind("b", _.right("b"))), + _.right({ a: 1, b: "b" }) + ) + }) + + it("product", () => { + deepStrictEqual(pipe(_.right(1), _.product(_.right("a"))), _.right([1, "a"] as const)) + deepStrictEqual(pipe(_.right(1), _.product(_.left("e2"))), _.left("e2")) + deepStrictEqual(pipe(_.left("e1"), _.product(_.right("a"))), _.left("e1")) + deepStrictEqual(pipe(_.left("e1"), _.product(_.left("2"))), _.left("e1")) + }) + + it("productMany", () => { + deepStrictEqual(pipe(_.right(1), _.productMany([])), _.right([1] as const)) + deepStrictEqual( + pipe(_.right(1), _.productMany([_.right(2), _.right(3)])), + _.right([1, 2, 3] as const) + ) + deepStrictEqual( + pipe(_.right(1), _.productMany([_.left("e"), _.right(3)])), + _.left("e") + ) + deepStrictEqual( + pipe(_.left("e"), _.productMany([_.right(2), _.right(3)])), + _.left("e") + ) + }) + + it("productAll", () => { + deepStrictEqual(_.productAll([]), _.right([])) + deepStrictEqual( + _.productAll([_.right(1), _.right(2), _.right(3)]), + _.right([1, 2, 3]) + ) + deepStrictEqual( + _.productAll([_.left("e"), _.right(2), _.right(3)]), + _.left("e") + ) + }) + + it("coproduct", () => { + deepStrictEqual(pipe(_.right(1), _.SemiCoproduct.coproduct(_.right(2))), _.right(1)) + deepStrictEqual(pipe(_.right(1), _.SemiCoproduct.coproduct(_.left("e2"))), _.right(1)) + deepStrictEqual(pipe(_.left("e1"), _.SemiCoproduct.coproduct(_.right(2))), _.right(2)) + deepStrictEqual(pipe(_.left("e1"), _.SemiCoproduct.coproduct(_.left("e2"))), _.left("e2")) + }) + + it("coproductMany", () => { + deepStrictEqual(pipe(_.right(1), _.SemiCoproduct.coproductMany([_.right(2)])), _.right(1)) + deepStrictEqual( + pipe( + _.right(1) as _.Either, + _.SemiCoproduct.coproductMany([_.left("e2") as _.Either]) + ), + _.right(1) + ) + deepStrictEqual( + pipe( + _.left("e1") as _.Either, + _.SemiCoproduct.coproductMany([_.right(2) as _.Either]) + ), + _.right(2) + ) + deepStrictEqual( + pipe(_.left("e1"), _.SemiCoproduct.coproductMany([_.left("e2")])), + _.left("e2") + ) + }) + + it("productFlatten", () => { + deepStrictEqual( + pipe(_.right(1), _.tupled, _.productFlatten(_.right("b"))), + _.right([1, "b"] as const) + ) + }) + + it("liftNullable", () => { + const f = _.liftNullable((n: number) => (n > 0 ? n : null), () => "error") + deepStrictEqual(f(1), _.right(1)) + deepStrictEqual(f(-1), _.left("error")) + }) + + it("flatMapNullable", () => { + const f = _.flatMapNullable((n: number) => (n > 0 ? n : null), () => "error") + deepStrictEqual(f(_.right(1)), _.right(1)) + deepStrictEqual(f(_.right(-1)), _.left("error")) + deepStrictEqual(f(_.left("a")), _.left("a")) + }) + + it("merge", () => { + deepStrictEqual(_.merge(_.right(1)), 1) + deepStrictEqual(_.merge(_.left("a")), "a") + }) + + it("liftThrowable", () => { + const f = _.liftThrowable((s: string) => { + const len = s.length + if (len > 0) { + return len + } + throw new Error("empty string") + }, identity) + deepStrictEqual(f("a"), _.right(1)) + deepStrictEqual(f(""), _.left(new Error("empty string"))) + }) +}) From 4f3e6cfebc921063e1e7d2d631c58a69d13976a0 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 08:28:37 +0100 Subject: [PATCH 020/255] add These module --- .changeset/heavy-suns-buy.md | 5 + src/Boolean.ts | 2 +- src/Number.ts | 2 +- src/ReadonlyArray.ts | 30 + src/String.ts | 2 +- src/These.ts | 1321 ++++++++++++++++++++++++++++++++++ src/index.ts | 5 + test/These.ts | 816 +++++++++++++++++++++ 8 files changed, 2180 insertions(+), 3 deletions(-) create mode 100644 .changeset/heavy-suns-buy.md create mode 100644 src/These.ts create mode 100644 test/These.ts diff --git a/.changeset/heavy-suns-buy.md b/.changeset/heavy-suns-buy.md new file mode 100644 index 000000000..8c5199636 --- /dev/null +++ b/.changeset/heavy-suns-buy.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add These module diff --git a/src/Boolean.ts b/src/Boolean.ts index 7db4ed1d3..f10ed523f 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -9,7 +9,7 @@ import type * as order from "@fp-ts/core/typeclass/Order" import type * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** - * @category refinements + * @category guards * @since 1.0.0 */ export const isBoolean: Refinement = (u: unknown): u is boolean => diff --git a/src/Number.ts b/src/Number.ts index 83080a28f..ba33b56db 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -10,7 +10,7 @@ import type * as order from "@fp-ts/core/typeclass/Order" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** - * @category refinements + * @category guards * @since 1.0.0 */ export const isNumber: Refinement = (u: unknown): u is number => diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 367a320a5..509507fa2 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -3,6 +3,7 @@ */ import type { TypeLambda } from "@fp-ts/core/HKT" +import * as iterable from "@fp-ts/core/internal/Iterable" import type * as applicative from "@fp-ts/core/typeclass/Applicative" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type * as invariant from "@fp-ts/core/typeclass/Invariant" @@ -181,3 +182,32 @@ export const Applicative: applicative.Applicative = { ...SemiApplicative, ...Product } + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromIterable: (collection: Iterable) => ReadonlyArray = iterable.fromIterable + +/** + * @category mutations + * @since 1.0.0 + */ +export const appendAll = (that: Iterable) => + (self: Iterable): Array => fromIterable(self).concat(fromIterable(that)) + +/** + * @category mutations + * @since 1.0.0 + */ +export function appendAllNonEmpty( + that: NonEmptyReadonlyArray +): (self: Iterable) => NonEmptyArray +export function appendAllNonEmpty( + that: Iterable +): (self: NonEmptyReadonlyArray) => NonEmptyArray +export function appendAllNonEmpty( + that: Iterable +): (self: NonEmptyReadonlyArray) => Array { + return appendAll(that) +} diff --git a/src/String.ts b/src/String.ts index 98921c6de..9700222b8 100644 --- a/src/String.ts +++ b/src/String.ts @@ -86,7 +86,7 @@ export const Order: order.Order = { * assert.deepStrictEqual(S.isString('a'), true) * assert.deepStrictEqual(S.isString(1), false) * - * @category refinements + * @category guards * @since 1.0.0 */ export const isString: Refinement = (u: unknown): u is string => diff --git a/src/These.ts b/src/These.ts new file mode 100644 index 000000000..61a16d21d --- /dev/null +++ b/src/These.ts @@ -0,0 +1,1321 @@ +/** + * A data structure providing "inclusive-or" as opposed to `Either`'s "exclusive-or". + * + * If you interpret `Either` as suggesting the computation may either fail or of (exclusively), then + * `These` may fail, of, or do both at the same time. + * + * There are a few ways to interpret the both case: + * + * - You can think of a computation that has a non-fatal error. + * - You can think of a computation that went as far as it could before erroring. + * - You can think of a computation that keeps track of errors as it completes. + * + * Another way you can think of `These` is saying that we want to handle `E` kind of data, `A` kind of data, or + * both `E` and `A` kind of data at the same time. This is particularly useful when it comes to displaying UI's. + * + * (description adapted from https://package.elm-lang.org/packages/joneshf/elm-these) + * + * Adapted from https://github.com/purescript-contrib/purescript-these + * + * @since 1.0.0 + */ +import type { Either, Left, Right } from "@fp-ts/core/Either" +import type { LazyArg } from "@fp-ts/core/Function" +import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" +import type { Kind, TypeLambda } from "@fp-ts/core/HKT" +import * as either from "@fp-ts/core/internal/Either" +import * as option from "@fp-ts/core/internal/Option" +import type { Option } from "@fp-ts/core/Option" +import type { Predicate, Refinement } from "@fp-ts/core/Predicate" +import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" +import * as RA from "@fp-ts/core/ReadonlyArray" +import * as applicative from "@fp-ts/core/typeclass/Applicative" +import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" +import * as chainable from "@fp-ts/core/typeclass/Chainable" +import * as covariant from "@fp-ts/core/typeclass/Covariant" +import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" +import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" +import type * as foldable from "@fp-ts/core/typeclass/Foldable" +import * as invariant from "@fp-ts/core/typeclass/Invariant" +import type * as monad from "@fp-ts/core/typeclass/Monad" +import type { Monoid } from "@fp-ts/core/typeclass/Monoid" +import * as of_ from "@fp-ts/core/typeclass/Of" +import type * as pointed from "@fp-ts/core/typeclass/Pointed" +import * as product_ from "@fp-ts/core/typeclass/Product" +import type * as semiAlternative from "@fp-ts/core/typeclass/SemiAlternative" +import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" +import * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" +import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import * as traversable from "@fp-ts/core/typeclass/Traversable" + +/** + * @category model + * @since 1.0.0 + */ +export type Both = { + readonly _tag: "Both" + readonly left: E + readonly right: A +} + +/** + * @category model + * @since 1.0.0 + */ +export type These = Either | Both + +/** + * @category model + * @since 1.0.0 + */ +export type Validated = These, A> + +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface TheseTypeLambda extends TypeLambda { + readonly type: These +} + +/** + * @category type lambdas + * @since 3.0.0 + */ +export interface ValidatedTypeLambda extends TypeLambda { + readonly type: Validated +} + +/** + * @category constructors + * @since 1.0.0 + */ +export const left = (left: E): These => ({ _tag: "Left", left }) + +/** + * @category constructors + * @since 1.0.0 + */ +export const right = (right: A): These => ({ _tag: "Right", right }) + +/** + * Alias of `right`. + * + * @category constructors + * @since 1.0.0 + */ +export const of = right + +/** + * @category constructors + * @since 1.0.0 + */ +export const both = (left: E, right: A): These => ({ + _tag: "Both", + left, + right +}) + +/** + * @category constructors + * @since 1.0.0 + */ +export const fail = (e: E): Validated => left([e]) + +/** + * Alias of `right`. + * + * @category constructors + * @since 1.0.0 + */ +export const succeed: (a: A) => Validated = right + +/** + * @category constructors + * @since 1.0.0 + */ +export const warn = (e: E, a: A): Validated => both([e], a) + +/** + * @category constructors + * @since 1.0.0 + */ +export const leftOrBoth = (e: LazyArg) => + (self: Option): These => option.isNone(self) ? left(e()) : both(e(), self.value) + +/** + * @category constructors + * @since 1.0.0 + */ +export const rightOrBoth = (a: () => A) => + (self: Option): These => option.isNone(self) ? right(a()) : both(self.value, a()) + +/** + * @category pattern matching + * @since 1.0.0 + */ +export const match = ( + onLeft: (e: E) => B, + onRight: (a: A) => C, + onBoth: (e: E, a: A) => D +) => + (self: These): B | C | D => { + switch (self._tag) { + case "Left": + return onLeft(self.left) + case "Right": + return onRight(self.right) + case "Both": + return onBoth(self.left, self.right) + } + } + +/** + * @since 1.0.0 + */ +export const reverse: (self: These) => These = match( + right, + left, + (e, a) => both(a, e) +) + +/** + * Returns `true` if the these is an instance of `Left`, `false` otherwise + * + * @category guards + * @since 1.0.0 + */ +export const isLeft = (self: These): self is Left => self._tag === "Left" + +/** + * @category guards + * @since 1.0.0 + */ +export const isLeftOrBoth = (self: These): self is Left | Both => + self._tag !== "Right" + +/** + * Returns `true` if the these is an instance of `Right`, `false` otherwise + * + * @category guards + * @since 1.0.0 + */ +export const isRight = (self: These): self is Right => self._tag === "Right" + +/** + * @category guards + * @since 1.0.0 + */ +export const isRightOrBoth = (self: These): self is Right | Both => + self._tag !== "Left" + +/** + * Returns `true` if the these is an instance of `Both`, `false` otherwise + * + * @category guards + * @since 1.0.0 + */ +export const isBoth = (self: These): self is Both => self._tag === "Both" + +/** + * Returns `true` if the specified value is an instance of `These`, `false` + * otherwise. + * + * @category guards + * @since 1.0.0 + */ +export const isThese = (u: unknown): u is These => + typeof u === "object" && + u != null && "_tag" in u && + (u["_tag"] === "Left" || u["_tag"] === "Right" || u["_tag"] === "Both") + +/** + * Constructs a new `These` from a function that might throw. + * + * @category interop + * @since 1.0.0 + */ +export const fromThrowable = ( + f: () => A, + onThrow: (error: unknown) => E +): These => { + try { + return right(f()) + } catch (e) { + return left(onThrow(e)) + } +} + +/** + * Lifts a function that may throw to one returning a `These`. + * + * @category interop + * @since 1.0.0 + */ +export const liftThrowable = , B, E>( + f: (...a: A) => B, + onThrow: (error: unknown) => E +): ((...a: A) => These) => (...a) => fromThrowable(() => f(...a), onThrow) + +/** + * @category interop + * @since 1.0.0 + */ +export const getOrThrow = (onLeft: (e: E) => unknown) => + (self: These): A => { + if (isRightOrBoth(self)) { + return self.right + } + throw onLeft(self.left) + } + +/** + * @category interop + * @since 1.0.0 + */ +export const getRightOnlyOrThrow = (onLeft: (e: E) => unknown) => + (self: These): A => { + if (isRight(self)) { + return self.right + } + throw onLeft(self.left) + } + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromNullable = (onNullable: LazyArg) => + (a: A): These> => a == null ? left(onNullable()) : right(a as NonNullable) + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromEither = (self: Either): Validated => + either.isLeft(self) ? left([self.left]) : self + +/** + * @category conversions + * @since 1.0.0 + */ +export const toEither = ( + onBoth: (e: E, a: A) => Either +) => (self: These): Either => isBoth(self) ? onBoth(self.left, self.right) : self + +/** + * @category conversions + * @since 1.0.0 + */ +export const absolve: (self: These) => Either = toEither(( + _, + a +) => either.right(a)) + +/** + * @category conversions + * @since 1.0.0 + */ +export const condemn: (self: These) => Either = toEither(( + e, + _ +) => either.left(e)) + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftNullable = , B, E>( + f: (...a: A) => B | null | undefined, + onNullable: (...a: A) => E +) => (...a: A): These> => fromNullable(() => onNullable(...a))(f(...a)) + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMapNullable = ( + f: (a: A) => B | null | undefined, + onNullable: (a: A) => E2 +): ((self: Validated) => Validated>) => + flatMap(liftNullable(f, (a) => [onNullable(a)])) + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftPredicate: { + ( + refinement: Refinement, + onFalse: LazyArg + ): (c: C) => These + (predicate: Predicate, onFalse: LazyArg): (b: B) => These +} = (predicate: Predicate, onFalse: LazyArg) => + (b: B) => predicate(b) ? right(b) : left(onFalse()) + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromIterable = (onEmpty: LazyArg) => + (collection: Iterable): These => { + for (const a of collection) { + return right(a) + } + return left(onEmpty()) + } + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromOption = (onNone: LazyArg) => + (self: Option): These => option.isNone(self) ? left(onNone()) : right(self.value) + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromTuple = (self: readonly [E, A]): These => both(self[0], self[1]) + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftOption = , B, E>( + f: (...a: A) => Option, + onNone: (...a: A) => E +) => (...a: A): These => fromOption(() => onNone(...a))(f(...a)) + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftEither = , E, B>( + f: (...a: A) => Either +) => (...a: A): Validated => fromEither(f(...a)) + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftThese = , E, B>( + f: (...a: A) => These +) => (...a: A): Validated => fromThese(f(...a)) + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMapOption = ( + f: (a: A) => Option, + onNone: (a: A) => E2 +) => + (self: Validated): Validated => + pipe(self, flatMap(liftOption(f, (a) => [onNone(a)]))) + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMapEither = ( + f: (a: A) => Either +) => (self: Validated): Validated => pipe(self, flatMap(liftEither(f))) + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMapThese = ( + f: (a: A) => These +) => (self: Validated): Validated => pipe(self, flatMap(liftThese(f))) + +/** + * @category getters + * @since 1.0.0 + */ +export const getRight = ( + self: These +): Option => isLeft(self) ? option.none : option.some(self.right) + +/** + * Returns the `A` value if and only if the value is constructed with `Right` + * + * @category getters + * @since 1.0.0 + */ +export const getRightOnly = ( + self: These +): Option => isRight(self) ? option.some(self.right) : option.none + +/** + * @category getters + * @since 1.0.0 + */ +export const getLeft = ( + self: These +): Option => isRight(self) ? option.none : option.some(self.left) + +/** + * Returns the `E` value if and only if the value is constructed with `Left` + * + * @category getters + * @since 1.0.0 + */ +export const getLeftOnly = ( + self: These +): Option => isLeft(self) ? option.some(self.left) : option.none + +/** + * @category getters + * @since 1.0.0 + */ +export const getBoth = ( + self: These +): Option => isBoth(self) ? option.some([self.left, self.right]) : option.none + +/** + * @category getters + * @since 1.0.0 + */ +export const getBothOrElse = (e: LazyArg, a: LazyArg) => + ( + self: These + ): readonly [E, A] => + isLeft(self) ? + [self.left, a()] : + isRight(self) ? + [e(), self.right] : + [self.left, self.right] + +/** + * @category getters + * @since 1.0.0 + */ +export const getOrElse = (onLeft: LazyArg) => + (self: These): A | B => isLeft(self) ? onLeft() : self.right + +/** + * @category getters + * @since 1.0.0 + */ +export const getOrNull: (self: These) => A | null = getOrElse(constNull) + +/** + * @category getters + * @since 1.0.0 + */ +export const getOrUndefined: (self: These) => A | undefined = getOrElse(constUndefined) + +/** + * @category debugging + * @since 1.0.0 + */ +export const inspectRight = ( + onRight: (a: A) => void +) => + (self: These): These => { + if (isRight(self)) { + onRight(self.right) + } + return self + } + +/** + * @category debugging + * @since 1.0.0 + */ +export const inspectRightOrBoth = ( + onRightOrBoth: (a: A) => void +) => + (self: These): These => { + if (isRightOrBoth(self)) { + onRightOrBoth(self.right) + } + return self + } + +/** + * @category debugging + * @since 1.0.0 + */ +export const inspectLeft = ( + onLeft: (e: E) => void +) => + (self: These): These => { + if (isLeft(self)) { + onLeft(self.left) + } + return self + } + +/** + * @category debugging + * @since 1.0.0 + */ +export const inspectBoth = ( + onBoth: (e: E, a: A) => void +) => + (self: These): These => { + if (isBoth(self)) { + onBoth(self.left, self.right) + } + return self + } + +/** + * Returns an effect whose left and right channels have been mapped by + * the specified pair of functions, `f` and `g`. + * + * @category mapping + * @since 1.0.0 + */ +export const bimap: ( + f: (e: E) => G, + g: (a: A) => B +) => (self: These) => These = (f, g) => + (fa) => + isLeft(fa) ? + left(f(fa.left)) : + isRight(fa) ? + right(g(fa.right)) : + both(f(fa.left), g(fa.right)) + +/** + * @category instances + * @since 1.0.0 + */ +export const Bicovariant: bicovariant.Bicovariant = { + bimap +} + +/** + * Returns an effect with its error channel mapped using the specified + * function. This can be used to lift a "smaller" error into a "larger" error. + * + * @category error handling + * @since 1.0.0 + */ +export const mapLeft: (f: (e: E) => G) => (self: These) => These = bicovariant + .mapLeft(Bicovariant) + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromThese: (self: These) => Validated = mapLeft((e) => [e]) + +/** + * Returns an effect whose right is mapped by the specified `f` function. + * + * @category mapping + * @since 1.0.0 + */ +export const map: (f: (a: A) => B) => (self: These) => These = bicovariant.map( + Bicovariant +) + +/** + * @category instances + * @since 1.0.0 + */ +export const Covariant: covariant.Covariant = covariant.make(map) + +/** + * @category mapping + * @since 1.0.0 + */ +export const imap: ( + to: (a: A) => B, + from: (b: B) => A +) => (self: These) => These = Covariant.imap + +/** + * @category instances + * @since 1.0.0 + */ +export const Invariant: invariant.Invariant = { + imap +} + +/** + * @category mapping + * @since 1.0.0 + */ +export const tupled: (self: These) => These = invariant.tupled( + Invariant +) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindTo: ( + name: N +) => (self: These) => These = invariant.bindTo(Invariant) + +/** + * @category mapping + * @since 1.0.0 + */ +export const flap: (a: A) => (self: These B>) => These = covariant + .flap( + Covariant + ) + +/** + * Maps the right value of this effect to the specified constant value. + * + * @category mapping + * @since 1.0.0 + */ +export const as: (b: B) => (self: These) => These = covariant.as( + Covariant +) + +/** + * Returns the effect resulting from mapping the right of this effect to unit. + * + * @category mapping + * @since 1.0.0 + */ +export const asUnit: (self: These) => These = covariant.asUnit(Covariant) + +const let_: ( + name: Exclude, + f: (a: A) => B +) => ( + self: These +) => These = covariant.let( + Covariant +) + +export { + /** + * @category do notation + * @since 1.0.0 + */ + let_ as let +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Of: of_.Of = { + of +} + +/** + * @since 1.0.0 + */ +export const unit: These = of_.unit(Of) + +/** + * @category do notation + * @since 1.0.0 + */ +export const Do: These = of_.Do(Of) + +/** + * @category instances + * @since 1.0.0 + */ +export const Pointed: pointed.Pointed = { + ...Of, + ...Covariant +} + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverse = ( + F: applicative.Applicative +) => + ( + f: (a: A) => Kind + ) => + (self: These): Kind> => + isLeft(self) + ? F.of>(self) + : isRight(self) + ? pipe(f(self.right), F.map>(right)) + : pipe( + f(self.right), + F.map((b) => both(self.left, b)) + ) + +/** + * @category traversing + * @since 1.0.0 + */ +export const sequence: ( + F: applicative.Applicative +) => ( + self: These> +) => Kind> = traversable.sequence(traverse) + +/** + * @category instances + * @since 1.0.0 + */ +export const Traversable: traversable.Traversable = { + traverse, + sequence +} + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverseTap: ( + F: applicative.Applicative +) => ( + f: (a: A) => Kind +) => (self: These) => Kind> = traversable + .traverseTap(Traversable) + +/** + * Returns a function that checks if a `These` contains a given value using a provided `equivalence` function. + * + * @since 1.0.0 + */ +export const contains = (equivalence: Equivalence) => + (a: A) => (self: These): boolean => isLeft(self) ? false : equivalence(self.right, a) + +/** + * @category predicates + * @since 1.0.0 + */ +export const exists = (predicate: Predicate) => + (self: These): boolean => isLeft(self) ? false : predicate(self.right) + +/** + * @category instances + * @since 1.0.0 + */ +export const Foldable: foldable.Foldable = { + reduce: (b, f) => (self) => isLeft(self) ? b : f(b, self.right) +} + +/** + * Recovers from all errors. + * + * @category error handling + * @since 1.0.0 + */ +export const catchAll = ( + onLeft: (e: E1) => These +) => (self: These): These => isLeft(self) ? onLeft(self.left) : self + +/** + * Executes this effect and returns its value, if it succeeds, but otherwise + * executes the specified effect. + * + * @category error handling + * @since 1.0.0 + */ +export const orElse = ( + that: These +) => (self: These): These => isLeft(self) ? that : self + +/** + * Returns an effect that will produce the value of this effect, unless it + * fails, in which case, it will produce the value of the specified effect. + * + * @category error handling + * @since 1.0.0 + */ +export const orElseEither = ( + that: These +) => + (self: These): These> => + isLeft(self) ? + pipe(that, map(either.right)) : + pipe(self, map(either.left)) + +/** + * Executes this effect and returns its value, if it succeeds, but otherwise + * fails with the specified error. + * + * @category error handling + * @since 1.0.0 + */ +export const orElseFail = ( + onLeft: LazyArg +): (self: These) => These => catchAll(() => left(onLeft())) + +/** + * Executes this effect and returns its value, if it succeeds, but otherwise + * succeeds with the specified value. + * + * @category error handling + * @since 1.0.0 + */ +export const orElseSucceed = ( + onLeft: LazyArg +): (self: These) => These => catchAll(() => right(onLeft())) + +/** + * @category error handling + * @since 1.0.0 + */ +export const firstRightOrBothOf = (collection: Iterable>) => + (self: These): These => { + let out = self + if (isRightOrBoth(out)) { + return out + } + for (out of collection) { + if (isRightOrBoth(out)) { + return out + } + } + return out + } + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiCoproduct: semiCoproduct.SemiCoproduct = { + ...Invariant, + coproduct: (that) => (self) => isRightOrBoth(self) ? self : that, + coproductMany: firstRightOrBothOf +} + +/** + * @category combining + * @since 1.0.0 + */ +export const getFirstRightOrBothSemigroup: () => Semigroup> = semiCoproduct + .getSemigroup(SemiCoproduct) + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiAlternative: semiAlternative.SemiAlternative = { + ...Covariant, + ...SemiCoproduct +} + +/** + * @category filtering + * @since 1.0.0 + */ +export const compact = (onNone: LazyArg) => + (self: These>): These => + isLeft(self) ? + self : + option.isNone(self.right) ? + left(onNone()) : + isBoth(self) ? + both(self.left, self.right.value) : + right(self.right.value) + +/** + * @category filtering + * @since 1.0.0 + */ +export const filter: { + (refinement: Refinement, onFalse: LazyArg): ( + self: These + ) => These + ( + predicate: Predicate, + onFalse: LazyArg + ): (self: These) => These +} = ( + predicate: Predicate, + onFalse: LazyArg +) => + (self: These): These => + isLeft(self) ? self : predicate(self.right) ? self : left(onFalse()) + +/** + * @category filtering + * @since 1.0.0 + */ +export const filterMap = ( + f: (a: A) => Option, + onNone: LazyArg +) => + (self: These): These => { + if (isLeft(self)) { + return self + } + if (isRight(self)) { + const ob = f(self.right) + return option.isNone(ob) ? left(onNone()) : right(ob.value) + } + const ob = f(self.right) + return option.isNone(ob) ? left(onNone()) : both(self.left, ob.value) + } + +/** + * @since 1.0.0 + */ +export const product = (that: Validated) => + ( + self: Validated + ): Validated => { + if (isLeft(self)) { + return self + } + if (isRight(self)) { + if (isLeft(that)) { + return that + } + if (isRight(that)) { + return right([self.right, that.right]) + } + return both(that.left, [self.right, that.right]) + } + if (isLeft(that)) { + return left(RA.appendAllNonEmpty(that.left)(self.left)) + } + if (isRight(that)) { + return both(self.left, [self.right, that.right]) + } + return both(RA.appendAllNonEmpty(that.left)(self.left), [self.right, that.right]) + } + +/** + * @since 1.0.0 + */ +export const productMany = ( + collection: Iterable> +) => + ( + self: Validated + ): Validated]> => + pipe(self, product(productAll(collection)), map(([a, as]) => [a, ...as])) + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiProduct: semiProduct.SemiProduct = { + imap, + product, + productMany +} + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiApplicative: semiApplicative.SemiApplicative = { + map, + ...SemiProduct +} + +/** + * @category lifting + * @since 1.0.0 + */ +export const lift2: ( + f: (a: A, b: B) => C +) => ( + fa: Validated, + fb: Validated +) => Validated = semiApplicative + .lift2(SemiApplicative) + +/** + * @category lifting + * @since 1.0.0 + */ +export const lift3: ( + f: (a: A, b: B, c: C) => D +) => ( + fa: Validated, + fb: Validated, + fc: Validated +) => Validated = semiApplicative.lift3( + SemiApplicative +) + +/** + * @since 1.0.0 + */ +export const ap: ( + fa: Validated +) => (self: Validated B>) => Validated = semiApplicative.ap( + SemiApplicative +) + +/** + * @category combining + * @since 1.0.0 + */ +export const getFirstLeftSemigroup: ( + S: Semigroup +) => Semigroup> = semiApplicative + .liftSemigroup(SemiApplicative) + +/** + * @since 1.0.0 + */ +export const productAll = ( + collection: Iterable> +): Validated> => { + const rights: Array = [] + const lefts: Array = [] + let isFatal = false + for (const t of collection) { + if (isLeft(t)) { + lefts.push(...t.left) + isFatal = true + break + } else if (isRight(t)) { + rights.push(t.right) + } else { + lefts.push(...t.left) + rights.push(t.right) + } + } + if (RA.isNonEmpty(lefts)) { + return isFatal ? left(lefts) : both(lefts, rights) + } + return right(rights) +} + +/** + * @category do notation + * @since 1.0.0 + */ +export const andThenBind: ( + name: Exclude, + fb: Validated +) => ( + self: Validated +) => Validated = semiProduct + .andThenBind(SemiProduct) + +/** + * @category do notation + * @since 1.0.0 + */ +export const andThenBindEither = ( + name: Exclude, + fb: Either +): ( + self: Validated +) => Validated => + andThenBind(name, fromEither(fb)) + +/** + * @category do notation + * @since 1.0.0 + */ +export const andThenBindThese = ( + name: Exclude, + fb: These +): ( + self: Validated +) => Validated => + andThenBind(name, fromThese(fb)) + +/** + * @since 1.0.0 + */ +export const productFlatten: ( + that: Validated +) => >( + self: Validated +) => Validated = semiProduct + .productFlatten(SemiProduct) + +/** + * @category instances + * @since 1.0.0 + */ +export const Product: product_.Product = { + ...SemiProduct, + of, + productAll +} + +/** + * @since 1.0.0 + */ +export const tuple: >>( + ...tuple: T +) => Validated< + [T[number]] extends [Validated] ? E : never, + Readonly<{ [I in keyof T]: [T[I]] extends [Validated] ? A : never }> +> = product_ + .tuple(Product) + +/** + * @since 1.0.0 + */ +export const struct: >>( + r: R +) => Validated< + [R[keyof R]] extends [Validated] ? E : never, + { readonly [K in keyof R]: [R[K]] extends [Validated] ? A : never } +> = product_ + .struct(Product) + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMap = ( + f: (a: A) => Validated +) => + (self: Validated): Validated => { + if (isLeft(self)) { + return self + } + if (isRight(self)) { + return f(self.right) + } + const that = f(self.right) + if (isLeft(that)) { + return left(RA.appendAllNonEmpty(that.left)(self.left)) + } + if (isRight(that)) { + return both(self.left, that.right) + } + return both(RA.appendAllNonEmpty(that.left)(self.left), that.right) + } + +/** + * @category instances + * @since 1.0.0 + */ +export const Applicative: applicative.Applicative = { + ...SemiApplicative, + ...Product +} + +/** + * @category combining + * @since 1.0.0 + */ +export const getFirstLeftMonoid: (M: Monoid) => Monoid> = applicative + .liftMonoid( + Applicative + ) + +/** + * @category instances + * @since 1.0.0 + */ +export const FlatMap: flatMap_.FlatMap = { + flatMap +} + +/** + * @since 1.0.0 + */ +export const flatten: ( + self: Validated> +) => Validated = flatMap_ + .flatten(FlatMap) + +/** + * @since 1.0.0 + */ +export const andThen: ( + that: Validated +) => ( + self: Validated +) => Validated = flatMap_ + .andThen(FlatMap) + +/** + * @since 1.0.0 + */ +export const composeKleisliArrow: ( + bfc: (b: B) => Validated +) => ( + afb: (a: A) => Validated +) => (a: A) => Validated = flatMap_ + .composeKleisliArrow(FlatMap) + +/** + * @category instances + * @since 1.0.0 + */ +export const Chainable: chainable.Chainable = { + imap, + map, + flatMap +} + +/** + * @category do notation + * @since 1.0.0 + */ +export const bind: ( + name: Exclude, + f: (a: A) => Validated +) => ( + self: Validated +) => Validated = chainable + .bind(Chainable) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindEither = ( + name: Exclude, + f: (a: A) => Either +): ( + self: Validated +) => Validated => + bind(name, (a) => fromEither(f(a))) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindThese = ( + name: Exclude, + f: (a: A) => These +): ( + self: Validated +) => Validated => + bind(name, (a) => fromThese(f(a))) + +/** + * Sequences the specified effect after this effect, but ignores the value + * produced by the effect. + * + * @category sequencing + * @since 1.0.0 + */ +export const andThenDiscard: ( + that: Validated +) => (self: Validated) => Validated = chainable + .andThenDiscard(Chainable) + +/** + * Returns an effect that effectfully "peeks" at the success of this effect. + * + * @since 1.0.0 + */ +export const tap: ( + f: (a: A) => Validated +) => (self: Validated) => Validated = chainable.tap( + Chainable +) + +/** + * @category instances + * @since 1.0.0 + */ +export const Monad: monad.Monad = { + imap, + map, + of, + flatMap +} diff --git a/src/index.ts b/src/index.ts index 18842e414..f4a28145d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,6 +22,7 @@ import * as ordering from "@fp-ts/core/Ordering" import * as predicate from "@fp-ts/core/Predicate" import * as readonlyArray from "@fp-ts/core/ReadonlyArray" import * as string from "@fp-ts/core/String" +import * as these from "@fp-ts/core/These" import * as alternative from "@fp-ts/core/typeclass/Alternative" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" @@ -225,6 +226,10 @@ export { * @since 1.0.0 */ string, + /** + * @since 1.0.0 + */ + these, /** * @category typeclass * @since 1.0.0 diff --git a/test/These.ts b/test/These.ts new file mode 100644 index 000000000..5dcd2eddb --- /dev/null +++ b/test/These.ts @@ -0,0 +1,816 @@ +import * as E from "@fp-ts/core/Either" +import { identity, pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" +import * as S from "@fp-ts/core/String" +import * as _ from "@fp-ts/core/These" +import { number } from "@fp-ts/core/typeclass/Equivalence" +import * as U from "./util" + +describe("These", () => { + it("instances and derived exports", () => { + expect(_.Invariant).exist + expect(_.imap).exist + expect(_.tupled).exist + expect(_.bindTo).exist + + expect(_.Bicovariant).exist + expect(_.mapLeft).exist + + expect(_.Covariant).exist + expect(_.map).exist + expect(_.let).exist + expect(_.flap).exist + expect(_.as).exist + expect(_.asUnit).exist + + expect(_.Of).exist + expect(_.of).exist + expect(_.unit).exist + expect(_.Do).exist + + expect(_.Pointed).exist + + expect(_.FlatMap).exist + expect(_.flatMap).exist + expect(_.flatten).exist + expect(_.andThen).exist + expect(_.composeKleisliArrow).exist + + expect(_.Chainable).exist + expect(_.bind).exist + expect(_.tap).exist + expect(_.andThenDiscard).exist + + expect(_.Monad).exist + + expect(_.SemiProduct).exist + expect(_.product).exist + expect(_.productMany).exist + expect(_.andThenBind).exist + expect(_.productFlatten).exist + + expect(_.Product).exist + expect(_.productAll).exist + expect(_.tuple).exist + expect(_.struct).exist + + expect(_.SemiApplicative).exist + expect(_.getFirstLeftSemigroup).exist // liftSemigroup + expect(_.lift2).exist + expect(_.lift3).exist + expect(_.ap).exist + expect(_.andThenDiscard).exist + expect(_.andThen).exist + + expect(_.Applicative).exist + expect(_.getFirstLeftMonoid).exist // liftMonoid + + expect(_.SemiCoproduct).exist + // expect(_.coproduct).exist + expect(_.firstRightOrBothOf).exist // coproductMany + expect(_.getFirstRightOrBothSemigroup).exist // getSemigroup + // expect(_.coproductEither).exist // orElseEither + + expect(_.SemiAlternative).exist + + expect(_.Foldable).exist + + expect(_.Traversable).exist + expect(_.traverse).exist + expect(_.sequence).exist + expect(_.traverseTap).exist + }) + + it("reduce", () => { + U.deepStrictEqual(pipe(_.right("a"), _.Foldable.reduce("-", (b, a) => b + a)), "-a") + U.deepStrictEqual(pipe(_.left("e"), _.Foldable.reduce("-", (b, a) => b + a)), "-") + U.deepStrictEqual(pipe(_.both("e", "a"), _.Foldable.reduce("-", (b, a) => b + a)), "-a") + }) + + it("map", () => { + U.deepStrictEqual(pipe(_.left("e"), _.map(U.double)), _.left("e")) + U.deepStrictEqual(pipe(_.right(2), _.map(U.double)), _.right(4)) + U.deepStrictEqual(pipe(_.both("e", 2), _.map(U.double)), _.both("e", 4)) + }) + + it("bimap", () => { + const f = _.bimap(S.size, U.double) + U.deepStrictEqual(pipe(_.left("e"), f), _.left(1)) + U.deepStrictEqual(pipe(_.right(2), f), _.right(4)) + U.deepStrictEqual(pipe(_.both("eee", 1), f), _.both(3, 2)) + }) + + it("mapLeft", () => { + const f = _.mapLeft(S.size) + U.deepStrictEqual(pipe(_.left("e"), f), _.left(1)) + U.deepStrictEqual(pipe(_.right(2), f), _.right(2)) + U.deepStrictEqual(pipe(_.both("eee", 1), f), _.both(3, 1)) + }) + + it("traverse", () => { + const traverse = _.traverse(O.Applicative)((n: number) => (n > 1 ? O.some(n) : O.none())) + U.deepStrictEqual(pipe(_.left("a"), traverse), O.some(_.left("a"))) + U.deepStrictEqual(pipe(_.right(2), traverse), O.some(_.right(2))) + U.deepStrictEqual(pipe(_.right(1), traverse), O.none()) + U.deepStrictEqual(pipe(_.both("a", 2), traverse), O.some(_.both("a", 2))) + U.deepStrictEqual( + pipe( + _.both("a", 1), + _.traverse(O.Applicative)((n) => (n >= 2 ? O.some(n) : O.none())) + ), + O.none() + ) + }) + + it("andThenBindEither", () => { + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindEither("b", E.right(2))), + _.succeed({ a: 1, b: 2 }) + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindEither("b", E.left("e2"))), + _.fail("e2") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindEither("b", E.right(2))), + _.fail("e1") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindEither("b", E.left("e2"))), + _.fail("e1") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.andThenBindEither("b", E.right(2))), + _.warn("e1", { a: 1, b: 2 }) + ) + expect( + pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.andThenBindEither("b", E.left("e2"))) + ).toEqual( + _.left(["e1", "e2"]) + ) + }) + + it("andThenBindThese", () => { + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindThese("b", _.right(2))), + _.succeed({ a: 1, b: 2 }) + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindThese("b", _.left("e2"))), + _.fail("e2") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindThese("b", _.both("e2", 2))), + _.warn("e2", { a: 1, b: 2 }) + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindThese("b", _.right(2))), + _.fail("e1") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindThese("b", _.left("e2"))), + _.fail("e1") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindThese("b", _.both("e2", 2))), + _.fail("e1") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.andThenBindThese("b", _.right(2))), + _.warn("e1", { a: 1, b: 2 }) + ) + expect( + pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.andThenBindThese("b", _.left("e2"))) + ).toEqual( + _.left(["e1", "e2"]) + ) + expect( + pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.andThenBindThese("b", _.both("e2", 2))) + ).toEqual( + _.both(["e1", "e2"], { a: 1, b: 2 }) + ) + }) + + it("andThenBind", () => { + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindEither("b", () => E.right(2))), + _.succeed({ a: 1, b: 2 }) + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindEither("b", () => E.left("e2"))), + _.fail("e2") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.fail("e1")), _.bindEither("b", () => E.right(2))), + _.fail("e1") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.fail("e1")), _.bindEither("b", () => E.left("e2"))), + _.fail("e1") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.bindEither("b", () => E.right(2))), + _.warn("e1", { a: 1, b: 2 }) + ) + expect( + pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.bindEither("b", () => E.left("e2"))) + ).toEqual( + _.left(["e1", "e2"]) + ) + }) + + it("andThenBind", () => { + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindThese("b", () => _.right(2))), + _.succeed({ a: 1, b: 2 }) + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindThese("b", () => _.left("e2"))), + _.fail("e2") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindThese("b", () => _.both("e2", 2))), + _.warn("e2", { a: 1, b: 2 }) + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.fail("e1")), _.bindThese("b", () => _.right(2))), + _.fail("e1") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.fail("e1")), _.bindThese("b", () => _.left("e2"))), + _.fail("e1") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.fail("e1")), _.bindThese("b", () => _.both("e2", 2))), + _.fail("e1") + ) + U.deepStrictEqual( + pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.bindThese("b", () => _.right(2))), + _.warn("e1", { a: 1, b: 2 }) + ) + expect( + pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.bindThese("b", () => _.left("e2"))) + ).toEqual( + _.left(["e1", "e2"]) + ) + expect( + pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.bindThese("b", () => _.both("e2", 2))) + ).toEqual( + _.both(["e1", "e2"], { a: 1, b: 2 }) + ) + }) + + it("sequence", () => { + const sequence = _.sequence(O.Applicative) + U.deepStrictEqual(sequence(_.left("a")), O.some(_.left("a"))) + U.deepStrictEqual(sequence(_.right(O.some(1))), O.some(_.right(1))) + U.deepStrictEqual(sequence(_.right(O.none())), O.none()) + U.deepStrictEqual(sequence(_.both("a", O.some(1))), O.some(_.both("a", 1))) + U.deepStrictEqual(sequence(_.both("a", O.none())), O.none()) + }) + + it("product", () => { + const a = ["a"] as const + const b = ["b"] as const + const ab = ["a", "b"] as const + + U.deepStrictEqual(pipe(_.right(1), _.product(_.right(2))), _.right([1, 2] as const)) + U.deepStrictEqual(pipe(_.right(1), _.product(_.left(b))), _.left(b)) + U.deepStrictEqual(pipe(_.right(1), _.product(_.both(b, 2))), _.both(b, [1, 2] as const)) + + U.deepStrictEqual(pipe(_.left(a), _.product(_.right(2))), _.left(a)) + U.deepStrictEqual(pipe(_.left(a), _.product(_.left(b))), _.left(a)) + U.deepStrictEqual(pipe(_.left(a), _.product(_.both(b, 2))), _.left(a)) + + U.deepStrictEqual(pipe(_.both(a, 1), _.product(_.right(2))), _.both(a, [1, 2] as const)) + expect(pipe(_.both(a, 1), _.product(_.left(b)))).toEqual(_.left(ab)) + expect(pipe(_.both(a, 1), _.product(_.both(b, 2)))).toEqual(_.both(ab, [1, 2])) + }) + + it("productMany", () => { + const a = ["a"] as const + const b = ["b"] as const + const ab = ["a", "b"] as const + + U.deepStrictEqual(pipe(_.right(1), _.productMany([_.right(2)])), _.right([1, 2] as const)) + U.deepStrictEqual( + pipe(_.right(1), _.productMany([_.left(b)])), + _.left(b) + ) + U.deepStrictEqual( + pipe(_.right(1), _.productMany([_.both(b, 2)])), + _.both(b, [1, 2] as const) + ) + + U.deepStrictEqual(pipe(_.left(a), _.productMany([_.right(2)])), _.left(a)) + U.deepStrictEqual(pipe(_.left(a), _.productMany([_.left(b)])), _.left(a)) + U.deepStrictEqual( + pipe(_.left(a), _.productMany([_.both(b, 2)])), + _.left(a) + ) + + U.deepStrictEqual(pipe(_.both(a, 1), _.productMany([_.right(2)])), _.both(a, [1, 2] as const)) + expect(pipe(_.both(a, 1), _.productMany([_.left(b)]))).toEqual(_.left(ab)) + expect(pipe(_.both(a, 1), _.productMany([_.both(b, 2)]))).toEqual( + _.both(ab, [1, 2]) + ) + }) + + it("productAll", () => { + const a = ["a"] as const + const b = ["b"] as const + const ab = ["a", "b"] as const + + U.deepStrictEqual(_.productAll([_.right(1), _.right(2)]), _.right([1, 2] as const)) + U.deepStrictEqual(_.productAll([_.right(1), _.left(b)]), _.left(b)) + U.deepStrictEqual(_.productAll([_.right(1), _.both(b, 2)]), _.both(b, [1, 2] as const)) + + U.deepStrictEqual(_.productAll([_.left(a), _.right(2)]), _.left(a)) + U.deepStrictEqual(_.productAll([_.left(a), _.left(b)]), _.left(a)) + U.deepStrictEqual(_.productAll([_.left(a), _.both(b, 2)]), _.left(a)) + + U.deepStrictEqual(_.productAll([_.both(a, 1), _.right(2)]), _.both(a, [1, 2])) + expect(_.productAll([_.both(a, 1), _.left(b)])).toEqual(_.left(ab)) + expect(_.productAll([_.both(a, 1), _.both(b, 2)])).toEqual(_.both(ab, [1, 2])) + }) + + it("flatMap", () => { + const f = ( + n: number + ) => (n >= 2 ? + (n <= 5 ? _.succeed(n * 2) : _.warn("e2", n)) : + _.fail("e3")) + U.deepStrictEqual( + pipe(_.fail("e1"), _.flatMap(f)), + _.fail("e1") + ) + U.deepStrictEqual(pipe(_.succeed(2), _.flatMap(f)), _.succeed(4)) + U.deepStrictEqual(pipe(_.succeed(1), _.flatMap(f)), _.fail("e3")) + U.deepStrictEqual(pipe(_.succeed(6), _.flatMap(f)), _.warn("e2", 6)) + U.deepStrictEqual( + pipe(_.warn("e1", 2), _.flatMap(f)), + _.warn("e1", 4) + ) + U.deepStrictEqual( + pipe( + _.warn("e1", 1), + _.flatMap(f) + ), + _.left(["e1", "e3"] as const) + ) + U.deepStrictEqual( + pipe( + _.warn("e1", 6), + _.flatMap(f) + ), + _.both(["e1", "e2"] as const, 6) + ) + }) + + it("flatMapNullable", () => { + const f = _.flatMapNullable((n: number) => (n > 0 ? n : null), () => "e2") + U.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) + U.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) + U.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) + U.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) + expect(f(_.warn("e1", -1))).toEqual(_.left(["e1", "e2"])) + }) + + it("flatMapOption", () => { + const f = _.flatMapOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "e2") + U.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) + U.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) + U.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) + U.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) + expect(f(_.warn("e1", -1))).toEqual(_.left(["e1", "e2"])) + }) + + it("flatMapEither", () => { + const f = _.flatMapEither((n: number) => (n > 0 ? E.right(n) : E.left("e2"))) + U.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) + U.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) + U.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) + U.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) + expect(f(_.warn("e1", -1))).toEqual(_.left(["e1", "e2"])) + }) + + it("flatMapThese", () => { + const f = _.flatMapThese(( + n: number + ) => (n > 10 ? _.both("e3", n) : n > 0 ? _.right(n) : _.left("e2"))) + U.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) + U.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) + U.deepStrictEqual(f(_.succeed(11)), _.warn("e3", 11)) + U.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) + U.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) + expect(f(_.warn("e1", -1))).toEqual(_.left(["e1", "e2"])) + expect(f(_.warn("e1", 11))).toEqual(_.both(["e1", "e3"], 11)) + }) + + it("leftOrBoth", () => { + U.deepStrictEqual(_.leftOrBoth(() => "a")(O.none()), _.left("a")) + U.deepStrictEqual(_.leftOrBoth(() => "a")(O.some(1)), _.both("a", 1)) + }) + + it("rightOrBoth", () => { + U.deepStrictEqual(_.rightOrBoth(() => 1)(O.none()), _.right(1)) + U.deepStrictEqual(_.rightOrBoth(() => 1)(O.some("a")), _.both("a", 1)) + }) + + it("match", () => { + const f = (s: string, n: number) => S.size(s) + U.double(n) + const match = _.match(S.size, U.double, f) + U.deepStrictEqual(match(_.left("foo")), 3) + U.deepStrictEqual(match(_.right(1)), 2) + U.deepStrictEqual(match(_.both("foo", 1)), 5) + }) + + it("getBothOrElse", () => { + const f = _.getBothOrElse(() => "a", () => 1) + U.deepStrictEqual(pipe(_.left("b"), f), ["b", 1]) + U.deepStrictEqual(pipe(_.right(2), f), ["a", 2]) + U.deepStrictEqual(pipe(_.both("b", 2), f), ["b", 2]) + }) + + it("getBoth", () => { + U.deepStrictEqual(pipe(_.left("e"), _.getBoth), O.none()) + U.deepStrictEqual(pipe(_.right(1), _.getBoth), O.none()) + U.deepStrictEqual(pipe(_.both("e", 1), _.getBoth), O.some(["e", 1] as const)) + }) + + it("getLeft", () => { + U.deepStrictEqual(_.getLeft(_.left("e")), O.some("e")) + U.deepStrictEqual(_.getLeft(_.right(1)), O.none()) + U.deepStrictEqual(_.getLeft(_.both("e", 1)), O.some("e")) + }) + + it("getRight", () => { + U.deepStrictEqual(_.getRight(_.left("e")), O.none()) + U.deepStrictEqual(_.getRight(_.right(1)), O.some(1)) + U.deepStrictEqual(_.getRight(_.both("e", 1)), O.some(1)) + }) + + it("getLeftOnly", () => { + U.deepStrictEqual(_.getLeftOnly(_.left("e")), O.some("e")) + U.deepStrictEqual(_.getLeftOnly(_.right(1)), O.none()) + U.deepStrictEqual(_.getLeftOnly(_.both("e", 1)), O.none()) + }) + + it("getRightOnly", () => { + U.deepStrictEqual(_.getRightOnly(_.left("e")), O.none()) + U.deepStrictEqual(_.getRightOnly(_.right(1)), O.some(1)) + U.deepStrictEqual(_.getRightOnly(_.both("e", 1)), O.none()) + }) + + it("isLeft", () => { + U.deepStrictEqual(_.isLeft(_.left("e")), true) + U.deepStrictEqual(_.isLeft(_.right(1)), false) + U.deepStrictEqual(_.isLeft(_.both("e", 1)), false) + }) + + it("isLeftOrBoth", () => { + U.deepStrictEqual(_.isLeftOrBoth(_.left("e")), true) + U.deepStrictEqual(_.isLeftOrBoth(_.right(1)), false) + U.deepStrictEqual(_.isLeftOrBoth(_.both("e", 1)), true) + }) + + it("isRight", () => { + U.deepStrictEqual(_.isRight(_.left("e")), false) + U.deepStrictEqual(_.isRight(_.right(1)), true) + U.deepStrictEqual(_.isRight(_.both("", 1)), false) + }) + + it("isRightOrBoth", () => { + U.deepStrictEqual(_.isRightOrBoth(_.left("e")), false) + U.deepStrictEqual(_.isRightOrBoth(_.right(1)), true) + U.deepStrictEqual(_.isRightOrBoth(_.both("e", 1)), true) + }) + + it("isThese", () => { + U.deepStrictEqual(_.isThese(_.left("e")), true) + U.deepStrictEqual(_.isThese(_.right(1)), true) + U.deepStrictEqual(_.isThese(_.both("e", 1)), true) + U.deepStrictEqual(_.isThese(E.left("e")), true) + U.deepStrictEqual(_.isThese(E.right(1)), true) + U.deepStrictEqual(_.isThese(O.some(1)), false) + }) + + it("isBoth", () => { + U.deepStrictEqual(_.isBoth(_.left("e")), false) + U.deepStrictEqual(_.isBoth(_.right(1)), false) + U.deepStrictEqual(_.isBoth(_.both("e", 1)), true) + }) + + it("fromThrowable", () => { + U.deepStrictEqual( + _.fromThrowable(() => { + return 1 + }, identity), + _.right(1) + ) + + U.deepStrictEqual( + _.fromThrowable(() => { + throw "string error" + }, identity), + _.left("string error") + ) + }) + + it("liftThrowable", () => { + const f = _.liftThrowable((s: string) => { + const len = s.length + if (len > 0) { + return len + } + throw new Error("empty string") + }, identity) + U.deepStrictEqual(f("a"), _.right(1)) + U.deepStrictEqual(f(""), _.left(new Error("empty string"))) + }) + + it("inspectRight", () => { + const log: Array = [] + pipe(_.right(1), _.inspectRight((a) => log.push(a))) + pipe(_.left("e1"), _.inspectRight((a) => log.push(a))) + pipe(_.both("e2", 1), _.inspectRight((a) => log.push(a))) + U.deepStrictEqual(log, [1]) + }) + + it("inspectRightOrBoth", () => { + const log: Array = [] + pipe(_.right(1), _.inspectRightOrBoth((a) => log.push(a))) + pipe(_.left("e1"), _.inspectRightOrBoth((a) => log.push(a))) + pipe(_.both("e2", 2), _.inspectRightOrBoth((a) => log.push(a))) + U.deepStrictEqual(log, [1, 2]) + }) + + it("inspectBoth", () => { + const log: Array = [] + pipe(_.right(1), _.inspectBoth((e, a) => log.push(e, a))) + pipe(_.left("e1"), _.inspectBoth((e, a) => log.push(e, a))) + pipe(_.both("e2", 2), _.inspectBoth((e, a) => log.push(e, a))) + U.deepStrictEqual(log, ["e2", 2]) + }) + + it("inspectLeft", () => { + const log: Array = [] + pipe(_.right(1), _.inspectLeft((e) => log.push(e))) + pipe(_.left("e1"), _.inspectLeft((e) => log.push(e))) + pipe(_.both("e2", 1), _.inspectLeft((e) => log.push(e))) + U.deepStrictEqual(log, ["e1"]) + }) + + it("getOrThrow", () => { + expect(pipe(_.right(1), _.getOrThrow((e: string) => new Error(e)))).toEqual(1) + expect(() => pipe(_.left("e"), _.getOrThrow((e: string) => new Error(e)))).toThrow( + new Error("e") + ) + expect(pipe(_.both("e", 1), _.getOrThrow((e: string) => new Error(e)))).toEqual(1) + }) + + it("getRightOnlyOrThrow", () => { + expect(pipe(_.right(1), _.getRightOnlyOrThrow((e: string) => new Error(e)))).toEqual(1) + expect(() => pipe(_.left("e"), _.getRightOnlyOrThrow((e: string) => new Error(e)))).toThrow( + new Error("e") + ) + expect(() => pipe(_.both("e", 1), _.getRightOnlyOrThrow((e: string) => new Error(e)))).toThrow( + new Error("e") + ) + }) + + it("getOrElse", () => { + U.deepStrictEqual(pipe(_.right(1), _.getOrElse(() => 2)), 1) + U.deepStrictEqual(pipe(_.left("e"), _.getOrElse(() => 2)), 2) + U.deepStrictEqual(pipe(_.both("e", 1), _.getOrElse(() => 2)), 1) + }) + + it("getOrNull", () => { + U.deepStrictEqual(pipe(_.right(1), _.getOrNull), 1) + U.deepStrictEqual(pipe(_.left("e"), _.getOrNull), null) + U.deepStrictEqual(pipe(_.both("e", 1), _.getOrNull), 1) + }) + + it("getOrUndefined", () => { + U.deepStrictEqual(pipe(_.right(1), _.getOrUndefined), 1) + U.deepStrictEqual(pipe(_.left("e"), _.getOrUndefined), undefined) + U.deepStrictEqual(pipe(_.both("e", 1), _.getOrUndefined), 1) + }) + + it("fromNullable", () => { + U.deepStrictEqual(_.fromNullable(() => "default")(null), _.left("default")) + U.deepStrictEqual(_.fromNullable(() => "default")(undefined), _.left("default")) + U.deepStrictEqual(_.fromNullable(() => "default")(1), _.right(1)) + }) + + it("liftNullable", () => { + const f = _.liftNullable((n: number) => (n > 0 ? n : null), () => "error") + U.deepStrictEqual(f(1), _.right(1)) + U.deepStrictEqual(f(-1), _.left("error")) + }) + + it("liftPredicate", () => { + const f = _.liftPredicate((n: number) => n >= 2, () => "e") + U.deepStrictEqual(f(3), _.right(3)) + U.deepStrictEqual(f(1), _.left("e")) + }) + + it("fromIterable", () => { + U.deepStrictEqual(_.fromIterable(() => "e")([]), _.left("e")) + U.deepStrictEqual(_.fromIterable(() => "e")(["a"]), _.right("a")) + }) + + it("fromOption", () => { + U.deepStrictEqual(_.fromOption(() => "e")(O.none()), _.left("e")) + U.deepStrictEqual(_.fromOption(() => "e")(O.some(1)), _.right(1)) + }) + + it("fromEither", () => { + U.deepStrictEqual(_.fromEither(E.right(1)), _.right(1)) + U.deepStrictEqual(_.fromEither(E.left("e")), _.left(["e"] as const)) + }) + + it("fromThese", () => { + U.deepStrictEqual(_.fromThese(_.right(1)), _.succeed(1)) + U.deepStrictEqual(_.fromThese(_.left("e")), _.fail("e")) + U.deepStrictEqual(_.fromThese(_.both("e", 1)), _.warn("e", 1)) + }) + + it("toEither", () => { + expect(_.toEither).exist + }) + + it("absolve", () => { + U.deepStrictEqual(_.absolve(_.right(1)), E.right(1)) + U.deepStrictEqual(_.absolve(_.left("e")), E.left("e")) + U.deepStrictEqual(_.absolve(_.both("e", 1)), E.right(1)) + }) + + it("condemn", () => { + U.deepStrictEqual(_.condemn(_.right(1)), E.right(1)) + U.deepStrictEqual(_.condemn(_.left("e")), E.left("e")) + U.deepStrictEqual(_.condemn(_.both("e", 1)), E.left("e")) + }) + + it("liftOption", () => { + const f = _.liftOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "e") + U.deepStrictEqual(f(1), _.right(1)) + U.deepStrictEqual(f(-1), _.left("e")) + }) + + it("liftEither", () => { + const f = _.liftEither((n: number) => (n > 0 ? E.right(n) : E.left("e"))) + U.deepStrictEqual(f(1), _.succeed(1)) + U.deepStrictEqual(f(-1), _.fail("e")) + }) + + it("liftThese", () => { + const f = _.liftThese((n: number) => (n > 0 ? _.right(n) : _.left("e"))) + U.deepStrictEqual(f(1), _.succeed(1)) + U.deepStrictEqual(f(-1), _.fail("e")) + }) + + it("fromTuple", () => { + U.deepStrictEqual(pipe(["e", 1] as const, _.fromTuple), _.both("e", 1)) + }) + + it("reverse", () => { + U.deepStrictEqual(_.reverse(_.left("e")), _.right("e")) + U.deepStrictEqual(_.reverse(_.right(1)), _.left(1)) + U.deepStrictEqual(_.reverse(_.both("e", 1)), _.both(1, "e")) + }) + + it("exists", () => { + const gt2 = _.exists((n: number) => n > 2) + U.deepStrictEqual(gt2(_.left("a")), false) + U.deepStrictEqual(gt2(_.right(1)), false) + U.deepStrictEqual(gt2(_.right(3)), true) + U.deepStrictEqual(gt2(_.both("a", 1)), false) + U.deepStrictEqual(gt2(_.both("a", 3)), true) + }) + + it("contains", () => { + const contains = _.contains(number) + U.deepStrictEqual(contains(2)(_.left("a")), false) + U.deepStrictEqual(contains(2)(_.right(2)), true) + U.deepStrictEqual(contains(1)(_.right(2)), false) + U.deepStrictEqual(contains(2)(_.both("a", 2)), true) + U.deepStrictEqual(contains(1)(_.both("a", 2)), false) + }) + + it("of", () => { + U.deepStrictEqual(_.of(1), _.right(1)) + }) + + it("catchAll", () => { + U.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.right(2))), _.right(1)) + U.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.left("b"))), _.right(1)) + U.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.both("b", 2))), _.right(1)) + U.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.right(2))), _.right(2)) + U.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.left("b"))), _.left("b")) + U.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.both("b", 2))), _.both("b", 2)) + U.deepStrictEqual(pipe(_.both("a", 1), _.catchAll(() => _.right(2))), _.both("a", 1)) + U.deepStrictEqual(pipe(_.both("a", 1), _.catchAll(() => _.left("b"))), _.both("a", 1)) + U.deepStrictEqual(pipe(_.both("a", 1), _.catchAll(() => _.both("b", 2))), _.both("a", 1)) + }) + + it("orElse", () => { + U.deepStrictEqual(pipe(_.right(1), _.orElse(_.right(2))), _.right(1)) + U.deepStrictEqual(pipe(_.right(1), _.orElse(_.left("b"))), _.right(1)) + U.deepStrictEqual(pipe(_.right(1), _.orElse(_.both("b", 2))), _.right(1)) + U.deepStrictEqual(pipe(_.left("a"), _.orElse(_.right(2))), _.right(2)) + U.deepStrictEqual(pipe(_.left("a"), _.orElse(_.left("b"))), _.left("b")) + U.deepStrictEqual(pipe(_.left("a"), _.orElse(_.both("b", 2))), _.both("b", 2)) + U.deepStrictEqual(pipe(_.both("a", 1), _.orElse(_.right(2))), _.both("a", 1)) + U.deepStrictEqual(pipe(_.both("a", 1), _.orElse(_.left("b"))), _.both("a", 1)) + U.deepStrictEqual(pipe(_.both("a", 1), _.orElse(_.both("b", 2))), _.both("a", 1)) + }) + + it("orElseEither", () => { + expect(pipe(_.right(1), _.orElseEither(_.right(2)))).toEqual(_.right(E.left(1))) + expect(pipe(_.right(1), _.orElseEither(_.left("b")))).toEqual(_.right(E.left(1))) + expect(pipe(_.right(1), _.orElseEither(_.both("b", 2)))).toEqual(_.right(E.left(1))) + expect(pipe(_.left("a"), _.orElseEither(_.right(2)))).toEqual(_.right(E.right(2))) + expect(pipe(_.left("a"), _.orElseEither(_.left("b")))).toEqual(_.left("b")) + expect(pipe(_.left("a"), _.orElseEither(_.both("b", 2)))).toEqual(_.both("b", E.right(2))) + expect(pipe(_.both("a", 1), _.orElseEither(_.right(2)))).toEqual(_.both("a", E.left(1))) + expect(pipe(_.both("a", 1), _.orElseEither(_.left("b")))).toEqual(_.both("a", E.left(1))) + expect(pipe(_.both("a", 1), _.orElseEither(_.both("b", 2)))).toEqual(_.both("a", E.left(1))) + }) + + it("orElseFail", () => { + U.deepStrictEqual(pipe(_.right(1), _.orElseFail(() => "e2")), _.right(1)) + U.deepStrictEqual(pipe(_.left("e1"), _.orElseFail(() => "e2")), _.left("e2")) + U.deepStrictEqual(pipe(_.both("e1", 1), _.orElseFail(() => "e2")), _.both("e1", 1)) + }) + + it("orElseSucceed", () => { + U.deepStrictEqual(pipe(_.right(1), _.orElseSucceed(() => 2)), _.right(1)) + U.deepStrictEqual(pipe(_.left("e"), _.orElseSucceed(() => 2)), _.right(2)) + U.deepStrictEqual(pipe(_.both("e", 1), _.orElseSucceed(() => 2)), _.both("e", 1)) + }) + + it("firstSuccessOf", () => { + U.deepStrictEqual(pipe(_.right(1), _.firstRightOrBothOf([])), _.right(1)) + U.deepStrictEqual(pipe(_.left("e"), _.firstRightOrBothOf([])), _.left("e")) + U.deepStrictEqual( + pipe( + _.left("e1"), + _.firstRightOrBothOf([_.left("e2"), _.left("e3"), _.left("e4"), _.right(1)]) + ), + _.right(1) + ) + U.deepStrictEqual( + pipe( + _.left("e1"), + _.firstRightOrBothOf([_.left("e2"), _.left("e3"), _.left("e4"), _.both("e5", 1)]) + ), + _.both("e5", 1) + ) + U.deepStrictEqual( + pipe(_.left("e1"), _.firstRightOrBothOf([_.left("e2"), _.left("e3"), _.left("e4")])), + _.left("e4") + ) + }) + + it("coproduct", () => { + U.deepStrictEqual(pipe(_.right(1), _.SemiCoproduct.coproduct(_.right(2))), _.right(1)) + U.deepStrictEqual(pipe(_.right(1), _.SemiCoproduct.coproduct(_.left("e2"))), _.right(1)) + U.deepStrictEqual(pipe(_.left("e1"), _.SemiCoproduct.coproduct(_.right(2))), _.right(2)) + U.deepStrictEqual(pipe(_.left("e1"), _.SemiCoproduct.coproduct(_.left("e2"))), _.left("e2")) + U.deepStrictEqual( + pipe(_.both("e1", 1), _.SemiCoproduct.coproduct(_.right(2))), + _.both("e1", 1) + ) + U.deepStrictEqual( + pipe(_.both("e1", 1), _.SemiCoproduct.coproduct(_.left("e2"))), + _.both("e1", 1) + ) + }) + + it("compact", () => { + U.deepStrictEqual(pipe(_.right(O.some(1)), _.compact(() => "e2")), _.right(1)) + U.deepStrictEqual(pipe(_.right(O.none()), _.compact(() => "e2")), _.left("e2")) + U.deepStrictEqual(pipe(_.left("e1"), _.compact(() => "e2")), _.left("e1")) + U.deepStrictEqual(pipe(_.both("e1", O.some(1)), _.compact(() => "e2")), _.both("e1", 1)) + U.deepStrictEqual(pipe(_.both("e1", O.none()), _.compact(() => "e2")), _.left("e2")) + }) + + it("filter", () => { + const predicate = (n: number) => n > 10 + U.deepStrictEqual(pipe(_.right(12), _.filter(predicate, () => "e2")), _.right(12)) + U.deepStrictEqual(pipe(_.right(7), _.filter(predicate, () => "e2")), _.left("e2")) + U.deepStrictEqual(pipe(_.left("e1"), _.filter(predicate, () => "e2")), _.left("e1")) + U.deepStrictEqual(pipe(_.both("e1", 12), _.filter(predicate, () => "e2")), _.both("e1", 12)) + U.deepStrictEqual(pipe(_.both("e1", 7), _.filter(predicate, () => "e2")), _.left("e2")) + }) + + it("filterMap", () => { + const f = (n: number) => (n > 2 ? O.some(n + 1) : O.none()) + U.deepStrictEqual(pipe(_.left("e1"), _.filterMap(f, () => "e2")), _.left("e1")) + U.deepStrictEqual(pipe(_.right(1), _.filterMap(f, () => "e2")), _.left("e2")) + U.deepStrictEqual(pipe(_.right(3), _.filterMap(f, () => "e2")), _.right(4)) + U.deepStrictEqual(pipe(_.both("e1", 1), _.filterMap(f, () => "e2")), _.left("e2")) + U.deepStrictEqual(pipe(_.both("e1", 3), _.filterMap(f, () => "e2")), _.both("e1", 4)) + }) +}) From eb14d83ff5c7d736d538403defc6f18c94ce181a Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 08:39:20 +0100 Subject: [PATCH 021/255] add CovariantWithIndex, FilterableWithIndex, TraversableFilterable modules --- .changeset/purple-meals-explode.md | 5 ++ src/index.ts | 20 ++++- src/typeclass/CovariantWithIndex.ts | 40 +++++++++ src/typeclass/FilterableWithIndex.ts | 104 ++++++++++++++++++++++++ src/typeclass/TraversableFilterable.ts | 107 +++++++++++++++++++++++++ 5 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 .changeset/purple-meals-explode.md create mode 100644 src/typeclass/CovariantWithIndex.ts create mode 100644 src/typeclass/FilterableWithIndex.ts create mode 100644 src/typeclass/TraversableFilterable.ts diff --git a/.changeset/purple-meals-explode.md b/.changeset/purple-meals-explode.md new file mode 100644 index 000000000..3af08023c --- /dev/null +++ b/.changeset/purple-meals-explode.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add CovariantWithIndex, FilterableWithIndex, TraversableFilterable modules diff --git a/src/index.ts b/src/index.ts index f4a28145d..97ddb8daf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,8 +32,10 @@ import * as compactable from "@fp-ts/core/typeclass/Compactable" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import * as coproduct from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" +import * as covariantWithIndex from "@fp-ts/core/typeclass/CovariantWithIndex" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as filterable from "@fp-ts/core/typeclass/Filterable" +import * as filterableWithIndex from "@fp-ts/core/typeclass/FilterableWithIndex" import * as flatMap from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" @@ -50,6 +52,7 @@ import * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" +import * as traversableFilterable from "@fp-ts/core/typeclass/TraversableFilterable" export { /** @@ -105,6 +108,11 @@ export { * @since 1.0.0 */ covariant, + /** + * @category typeclass + * @since 1.0.0 + */ + covariantWithIndex, /** * @since 1.0.0 */ @@ -119,6 +127,11 @@ export { * @since 1.0.0 */ filterable, + /** + * @category typeclass + * @since 1.0.0 + */ + filterableWithIndex, /** * @category typeclass * @since 1.0.0 @@ -234,5 +247,10 @@ export { * @category typeclass * @since 1.0.0 */ - traversable + traversable, + /** + * @category typeclass + * @since 1.0.0 + */ + traversableFilterable } diff --git a/src/typeclass/CovariantWithIndex.ts b/src/typeclass/CovariantWithIndex.ts new file mode 100644 index 000000000..d9e8fb7ec --- /dev/null +++ b/src/typeclass/CovariantWithIndex.ts @@ -0,0 +1,40 @@ +/** + * @since 1.0.0 + */ +import { pipe } from "@fp-ts/core/Function" +import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" +import type { Covariant } from "@fp-ts/core/typeclass/Covariant" + +/** + * @category type class + * @since 1.0.0 + */ +export interface CovariantWithIndex extends TypeClass { + readonly mapWithIndex: ( + f: (a: A, i: I) => B + ) => (self: Kind) => Kind +} + +/** + * Returns a default `mapWithIndex` composition. + * + * @since 1.0.0 + */ +export const mapWithIndexComposition = ( + F: CovariantWithIndex, + G: CovariantWithIndex +): (( + f: (a: A, ij: readonly [I, J]) => B +) => ( + self: Kind> +) => Kind>) => + (f) => F.mapWithIndex((ga, i) => pipe(ga, G.mapWithIndex((a, j) => f(a, [i, j])))) + +/** + * Returns a default `map` implementation. + * + * @since 1.0.0 + */ +export const map = ( + F: CovariantWithIndex +): Covariant["map"] => (f) => F.mapWithIndex(f) diff --git a/src/typeclass/FilterableWithIndex.ts b/src/typeclass/FilterableWithIndex.ts new file mode 100644 index 000000000..7525a7a4a --- /dev/null +++ b/src/typeclass/FilterableWithIndex.ts @@ -0,0 +1,104 @@ +/** + * @since 1.0.0 + */ +import type { Either } from "@fp-ts/core/Either" +import * as E from "@fp-ts/core/Either" +import { pipe } from "@fp-ts/core/Function" +import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" +import * as O from "@fp-ts/core/Option" +import type { Option } from "@fp-ts/core/Option" +import type { Covariant } from "@fp-ts/core/typeclass/Covariant" +import type { Filterable } from "@fp-ts/core/typeclass/Filterable" + +/** + * @category models + * @since 1.0.0 + */ +export interface FilterableWithIndex extends TypeClass { + readonly filterMapWithIndex: ( + f: (a: A, i: I) => Option + ) => (self: Kind) => Kind +} + +/** + * Returns a default `filterMapWithIndex` composition. + * + * @since 1.0.0 + */ +export const filterMapWithIndexComposition = ( + F: Covariant, + G: FilterableWithIndex +) => + ( + f: (a: A, i: I) => Option + ): ( + self: Kind> + ) => Kind> => F.map(G.filterMapWithIndex(f)) + +/** + * Returns a default `filterMap` implementation. + * + * @since 1.0.0 + */ +export const filterMap = ( + F: FilterableWithIndex +): Filterable["filterMap"] => (f) => F.filterMapWithIndex(f) + +/** + * @since 1.0.0 + */ +export const filterWithIndex: ( + F: FilterableWithIndex +) => { + (refinement: (a: A, i: I) => a is B): ( + self: Kind + ) => Kind + ( + predicate: (a: A, i: I) => boolean + ): (self: Kind) => Kind +} = (FilterableWithIndex: FilterableWithIndex) => + ( + predicate: (a: A, i: I) => boolean + ): ((self: Kind) => Kind) => + FilterableWithIndex.filterMapWithIndex(( + b, + i + ) => (predicate(b, i) ? O.some(b) : O.none())) + +/** + * @since 1.0.0 + */ +export const partitionMapWithIndex = ( + F: FilterableWithIndex +) => + (f: (a: A, i: I) => Either) => + ( + self: Kind + ): readonly [Kind, Kind] => { + return [ + pipe(self, F.filterMapWithIndex((a, i) => E.getLeft(f(a, i)))), + pipe(self, F.filterMapWithIndex((a, i) => E.getRight(f(a, i)))) + ] + } + +/** + * @since 1.0.0 + */ +export const partitionWithIndex: ( + F: FilterableWithIndex +) => { + (refinement: (a: A, i: I) => a is B): ( + self: Kind + ) => readonly [Kind, Kind] + (predicate: (a: A, i: I) => boolean): ( + self: Kind + ) => readonly [Kind, Kind] +} = (FilterableWithIndex: FilterableWithIndex) => { + const partitionMapWithIndex_ = partitionMapWithIndex(FilterableWithIndex) + return ( + predicate: (a: A, i: I) => boolean + ): (( + self: Kind + ) => readonly [Kind, Kind]) => + partitionMapWithIndex_((b, i) => (predicate(b, i) ? E.right(b) : E.left(b))) +} diff --git a/src/typeclass/TraversableFilterable.ts b/src/typeclass/TraversableFilterable.ts new file mode 100644 index 000000000..2afc083c7 --- /dev/null +++ b/src/typeclass/TraversableFilterable.ts @@ -0,0 +1,107 @@ +/** + * `TraversableFilterable` represents data structures which can be _partitioned_ with effects in some `Applicative` functor. + * + * @since 1.0.0 + */ +import type { Either } from "@fp-ts/core/Either" +import * as E from "@fp-ts/core/Either" +import { pipe } from "@fp-ts/core/Function" +import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" +import type { Option } from "@fp-ts/core/Option" +import * as O from "@fp-ts/core/Option" +import type { Applicative } from "@fp-ts/core/typeclass/Applicative" +import * as compactable from "@fp-ts/core/typeclass/Compactable" +import type { Compactable } from "@fp-ts/core/typeclass/Compactable" +import type { Covariant } from "@fp-ts/core/typeclass/Covariant" +import type { Traversable } from "@fp-ts/core/typeclass/Traversable" + +/** + * @category models + * @since 1.0.0 + */ +export interface TraversableFilterable extends TypeClass { + readonly traversePartitionMap: ( + F: Applicative + ) => ( + f: (a: A) => Kind> + ) => ( + self: Kind + ) => Kind, Kind]> + + readonly traverseFilterMap: ( + F: Applicative + ) => ( + f: (a: A) => Kind> + ) => ( + self: Kind + ) => Kind> +} + +/** + * Returns a default `traversePartitionMap` implementation. + * + * @since 1.0.0 + */ +export const traversePartitionMap = ( + T: Traversable & Covariant & Compactable +): TraversableFilterable["traversePartitionMap"] => + (F) => + (f) => + (ta) => + pipe( + ta, + T.traverse(F)(f), + F.map(compactable.separate(T)) + ) + +/** + * Returns a default `traverseFilterMap` implementation. + * + * @since 1.0.0 + */ +export const traverseFilterMap = ( + T: Traversable & Compactable +): TraversableFilterable["traverseFilterMap"] => + (F) => (f) => (ta) => pipe(ta, T.traverse(F)(f), F.map(T.compact)) + +/** + * @since 1.0.0 + */ +export const traverseFilter = ( + T: TraversableFilterable +) => + ( + F: Applicative + ): (( + predicate: (a: A) => Kind + ) => ( + self: Kind + ) => Kind>) => + (predicate) => + T.traverseFilterMap(F)((b) => + pipe( + predicate(b), + F.map((keep) => (keep ? O.some(b) : O.none())) + ) + ) + +/** + * @since 1.0.0 + */ +export const traversePartition = ( + T: TraversableFilterable +) => + ( + F: Applicative + ): (( + predicate: (a: A) => Kind + ) => ( + self: Kind + ) => Kind, Kind]>) => + (predicate) => + T.traversePartitionMap(F)((b) => + pipe( + predicate(b), + F.map((keep) => (keep ? E.right(b) : E.left(b))) + ) + ) From aadd01a35d910754e6eefe5588035e303fca8433 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 15:02:42 +0100 Subject: [PATCH 022/255] add ReadonlyArray module --- .changeset/clean-goats-learn.md | 5 + src/Identity.ts | 4 +- src/Option.ts | 4 +- src/Predicate.ts | 6 +- src/ReadonlyArray.ts | 2240 +++++++++++++++++++++++++++++-- src/String.ts | 4 +- src/internal/Iterable.ts | 7 - src/internal/ReadonlyArray.ts | 11 + test/ReadonlyArray.ts | 1670 +++++++++++++++++++++++ test/internal/Iterable.ts | 12 - 10 files changed, 3841 insertions(+), 122 deletions(-) create mode 100644 .changeset/clean-goats-learn.md delete mode 100644 src/internal/Iterable.ts create mode 100644 src/internal/ReadonlyArray.ts create mode 100644 test/ReadonlyArray.ts delete mode 100644 test/internal/Iterable.ts diff --git a/.changeset/clean-goats-learn.md b/.changeset/clean-goats-learn.md new file mode 100644 index 000000000..2f4981c7f --- /dev/null +++ b/.changeset/clean-goats-learn.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add ReadonlyArray module diff --git a/src/Identity.ts b/src/Identity.ts index 0f759d7f6..41ba1275d 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -3,7 +3,7 @@ */ import { identity } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import * as iterable from "@fp-ts/core/internal/Iterable" +import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as chainable from "@fp-ts/core/typeclass/Chainable" import type * as coproduct_ from "@fp-ts/core/typeclass/Coproduct" @@ -301,7 +301,7 @@ export const productFlatten: ( * @since 1.0.0 */ export const productAll = (collection: Iterable>): Identity> => - iterable.fromIterable(collection) + readonlyArray.fromIterable(collection) /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index 13736839a..819f08f3a 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -17,8 +17,8 @@ import type { LazyArg } from "@fp-ts/core/Function" import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as either from "@fp-ts/core/internal/Either" -import * as iterable from "@fp-ts/core/internal/Iterable" import * as option from "@fp-ts/core/internal/Option" +import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type { Predicate, Refinement } from "@fp-ts/core/Predicate" import type * as alternative from "@fp-ts/core/typeclass/Alternative" import * as applicative from "@fp-ts/core/typeclass/Applicative" @@ -681,7 +681,7 @@ export const coproductEither = (that: Option) => * @since 1.0.0 */ export const coproductAll = (collection: Iterable>): Option => { - const options = iterable.fromIterable(collection) + const options = readonlyArray.fromIterable(collection) return options.length > 0 ? SemiCoproduct.coproductMany(options.slice(1))(options[0]) : option.none diff --git a/src/Predicate.ts b/src/Predicate.ts index 641ba2169..dce414810 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -3,7 +3,7 @@ */ import { constFalse, constTrue } from "@fp-ts/core/Function" import type { TypeLambda } from "@fp-ts/core/HKT" -import * as iterable from "@fp-ts/core/internal/Iterable" +import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monoid from "@fp-ts/core/typeclass/Monoid" @@ -132,7 +132,7 @@ export const productMany = (collection: Iterable>) => if (self(head) === false) { return false } - const predicates = iterable.fromIterable(collection) + const predicates = readonlyArray.fromIterable(collection) for (let i = 0; i < predicates.length; i++) { if (predicates[i](tail[i]) === false) { return false @@ -159,7 +159,7 @@ export const productAll = ( collection: Iterable> ): Predicate> => (as) => { - const predicates = iterable.fromIterable(collection) + const predicates = readonlyArray.fromIterable(collection) for (let i = 0; i < predicates.length; i++) { if (predicates[i](as[i]) === false) { return false diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 509507fa2..b299f7ce3 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1,16 +1,42 @@ /** * @since 1.0.0 */ - -import type { TypeLambda } from "@fp-ts/core/HKT" -import * as iterable from "@fp-ts/core/internal/Iterable" -import type * as applicative from "@fp-ts/core/typeclass/Applicative" +import type { Either } from "@fp-ts/core/Either" +import { identity, pipe } from "@fp-ts/core/Function" +import type { LazyArg } from "@fp-ts/core/Function" +import type { Kind, TypeLambda } from "@fp-ts/core/HKT" +import * as either from "@fp-ts/core/internal/Either" +import * as option from "@fp-ts/core/internal/Option" +import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" +import * as number from "@fp-ts/core/Number" +import type { Option } from "@fp-ts/core/Option" +import * as O from "@fp-ts/core/Option" +import type { Predicate, Refinement } from "@fp-ts/core/Predicate" +import * as string from "@fp-ts/core/String" +import * as applicative from "@fp-ts/core/typeclass/Applicative" +import * as chainable from "@fp-ts/core/typeclass/Chainable" +import type * as compactable from "@fp-ts/core/typeclass/Compactable" +import type { Coproduct } from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" +import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" +import * as filterable from "@fp-ts/core/typeclass/Filterable" +import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" +import * as foldable from "@fp-ts/core/typeclass/Foldable" import type * as invariant from "@fp-ts/core/typeclass/Invariant" -import type * as of_ from "@fp-ts/core/typeclass/Of" +import type * as monad from "@fp-ts/core/typeclass/Monad" +import type { Monoid } from "@fp-ts/core/typeclass/Monoid" +import * as of_ from "@fp-ts/core/typeclass/Of" +import * as order from "@fp-ts/core/typeclass/Order" +import type { Order } from "@fp-ts/core/typeclass/Order" +import type * as pointed from "@fp-ts/core/typeclass/Pointed" import type * as product_ from "@fp-ts/core/typeclass/Product" -import type * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" +import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" +import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" +import { fromCombine } from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import * as traversable from "@fp-ts/core/typeclass/Traversable" +import * as traversableFilterable from "@fp-ts/core/typeclass/TraversableFilterable" /** * @category type lambdas @@ -33,181 +59,2207 @@ export type NonEmptyReadonlyArray = readonly [A, ...Array] export type NonEmptyArray = [A, ...Array] /** + * Builds a `NonEmptyArray` from an non-empty collection of elements. + * + * @category constructors * @since 1.0.0 */ -export const isNonEmpty = (as: ReadonlyArray): as is NonEmptyReadonlyArray => as.length > 0 +export const make = >( + ...elements: Elements +): NonEmptyArray => elements /** + * Return a `NonEmptyArray` of length `n` with element `i` initialized with `f(i)`. + * + * **Note**. `n` is normalized to an integer >= 1. + * * @category constructors * @since 1.0.0 */ -export const empty: () => Array = () => [] +export const makeBy = (f: (i: number) => A) => + (n: number): NonEmptyArray => { + const max = Math.max(1, Math.floor(n)) + const out: NonEmptyArray = [f(0)] + for (let i = 1; i < max; i++) { + out.push(f(i)) + } + return out + } /** - * Test whether a `ReadonlyArray` is empty narrowing down the type to `[]`. + * Return a `NonEmptyArray` containing a range of integers, including both endpoints. * - * @category predicates + * @category constructors * @since 1.0.0 */ -export const isEmpty = (self: ReadonlyArray): self is readonly [] => self.length === 0 +export const range = (start: number, end: number): NonEmptyArray => + start <= end ? makeBy((i) => start + i)(end - start + 1) : [start] + +/** + * Return a `NonEmptyArray` containing a value repeated the specified number of times. + * + * **Note**. `n` is normalized to an integer >= 1. + * + * @category constructors + * @since 1.0.0 + */ +export const replicate = (a: A): ((n: number) => NonEmptyArray) => makeBy(() => a) /** + * @category conversions * @since 1.0.0 */ -export const product = ( - that: ReadonlyArray +export const fromIterable: (collection: Iterable) => Array = readonlyArray.fromIterable + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromOption = ( + self: Option +): Array => (option.isNone(self) ? [] : [self.value]) + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromEither = ( + self: Either +): Array => (either.isLeft(self) ? [] : [self.right]) + +/** + * @category pattern matching + * @since 1.0.0 + */ +export const match = ( + onEmpty: LazyArg, + onNonEmpty: (head: A, tail: Array) => C ) => - (self: ReadonlyArray): Array<[A, B]> => { - if (isEmpty(self) || isEmpty(that)) { - return empty() + (self: ReadonlyArray): B | C => + isNonEmpty(self) ? onNonEmpty(headNonEmpty(self), tailNonEmpty(self)) : onEmpty() + +/** + * @category pattern matching + * @since 1.0.0 + */ +export const matchRight = ( + onEmpty: LazyArg, + onNonEmpty: (init: Array, last: A) => C +) => + (self: ReadonlyArray): B | C => + isNonEmpty(self) ? + onNonEmpty(initNonEmpty(self), lastNonEmpty(self)) : + onEmpty() + +/** + * Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray`. + * + * @category mutations + * @since 1.0.0 + */ +export const prepend = ( + head: B +) => (self: Iterable): NonEmptyArray => [head, ...self] + +/** + * @category mutations + * @since 1.0.0 + */ +export const prependAll = (that: Iterable) => + (self: Iterable): Array => fromIterable(that).concat(fromIterable(self)) + +/** + * @category mutations + * @since 1.0.0 + */ +export function prependAllNonEmpty( + that: NonEmptyReadonlyArray +): (self: Iterable) => NonEmptyArray +export function prependAllNonEmpty( + that: Iterable +): (self: NonEmptyReadonlyArray) => NonEmptyArray +export function prependAllNonEmpty( + that: Iterable +): (self: NonEmptyReadonlyArray) => Array { + return prependAll(that) +} + +/** + * Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`. + * + * @category mutations + * @since 1.0.0 + */ +export const append = ( + last: B +) => (self: Iterable): NonEmptyArray => [...self, last] as any + +/** + * @category mutations + * @since 1.0.0 + */ +export const appendAll = (that: Iterable) => + (self: Iterable): Array => fromIterable(self).concat(fromIterable(that)) + +/** + * @category mutations + * @since 1.0.0 + */ +export function appendAllNonEmpty( + that: NonEmptyReadonlyArray +): (self: Iterable) => NonEmptyArray +export function appendAllNonEmpty( + that: Iterable +): (self: NonEmptyReadonlyArray) => NonEmptyArray +export function appendAllNonEmpty( + that: Iterable +): (self: NonEmptyReadonlyArray) => Array { + return appendAll(that) +} + +/** + * Fold an `Iterable` from the left, keeping all intermediate results instead of only the final result. + * + * @category folding + * @since 1.0.0 + */ +export const scan = (b: B, f: (b: B, a: A) => B) => + (self: Iterable): NonEmptyArray => { + const out: NonEmptyArray = [b] + let i = 0 + for (const a of self) { + out[i + 1] = f(out[i], a) + i++ } - const out: Array<[A, B]> = [] - for (let i = 0; i < self.length; i++) { - for (let j = 0; j < that.length; j++) { - out.push([self[i], that[j]]) - } + return out + } + +/** + * Fold an `Iterable` from the right, keeping all intermediate results instead of only the final result. + * + * @category folding + * @since 1.0.0 + */ +export const scanRight = (b: B, f: (b: B, a: A) => B) => + (self: Iterable): NonEmptyArray => { + const input = fromIterable(self) + const out: NonEmptyArray = new Array(input.length + 1) as any + out[input.length] = b + for (let i = input.length - 1; i >= 0; i--) { + out[i] = f(out[i + 1], input[i]) } return out } /** - * @category mapping + * Test whether a `ReadonlyArray` is empty narrowing down the type to `[]`. + * + * @category predicates * @since 1.0.0 */ -export const map = (f: (a: A) => B): (self: ReadonlyArray) => Array => - mapWithIndex((a) => f(a)) +export const isEmpty = (self: ReadonlyArray): self is readonly [] => self.length === 0 /** - * @category mapping + * Test whether a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyReadonlyArray`. + * + * @category predicates * @since 1.0.0 */ -export const mapWithIndex = ( - f: (a: A, i: number) => B -) => (self: ReadonlyArray): Array => self.map((a, i) => f(a, i)) +export const isNonEmpty: (self: ReadonlyArray) => self is NonEmptyReadonlyArray = + readonlyArray.isNonEmpty /** - * @category instances + * Return the number of elements in a `ReadonlyArray`. + * + * @category getters * @since 1.0.0 */ -export const Covariant: covariant.Covariant = covariant.make(map) +export const size = (self: ReadonlyArray): number => self.length + +const isOutOfBound = (i: number, as: ReadonlyArray): boolean => i < 0 || i >= as.length + +const clamp = (i: number, as: ReadonlyArray): number => + Math.floor(Math.min(Math.max(0, i), as.length)) /** + * This function provides a safe way to read a value at a particular index from a `ReadonlyArray`. + * + * @category getters * @since 1.0.0 */ -export const productMany: ( - collection: Iterable> -) => (self: ReadonlyArray) => ReadonlyArray> = semiProduct - .productMany( - Covariant, - product - ) +export const get = (index: number) => + (self: ReadonlyArray): Option => { + const i = Math.floor(index) + return isOutOfBound(i, self) ? option.none : option.some(self[i]) + } /** + * Return a tuple containing the first element, and a new `Array` of the remaining elements, if any. + * + * @category getters * @since 1.0.0 */ -export const productAll = ( - collection: Iterable> -): ReadonlyArray> => { - const arrays = Array.from(collection) - if (isEmpty(arrays)) { - return empty() +export const unprepend = ( + self: NonEmptyReadonlyArray +): [A, Array] => [headNonEmpty(self), tailNonEmpty(self)] + +/** + * Return a tuple containing a copy of the `NonEmptyReadonlyArray` without its last element, and that last element. + * + * @category getters + * @since 1.0.0 + */ +export const unappend = ( + self: NonEmptyReadonlyArray +): [Array, A] => [initNonEmpty(self), lastNonEmpty(self)] + +/** + * Get the first element of a `ReadonlyArray`, or `None` if the `ReadonlyArray` is empty. + * + * @category getters + * @since 1.0.0 + */ +export const head: (self: ReadonlyArray) => Option = get(0) + +/** + * Gets an element unsafely, will throw on out of bounds. + * + * @since 1.0.0 + * @category unsafe + */ +export const unsafeGet = (index: number) => + (self: ReadonlyArray): A => { + const i = Math.floor(index) + if (isOutOfBound(i, self)) { + throw new Error(`Index ${i} out of bounds`) + } + return self[i] } - return productMany(arrays.slice(1))(arrays[0]) -} /** - * @category mapping + * @category getters * @since 1.0.0 */ -export const imap: ( - to: (a: A) => B, - from: (b: B) => A -) => (self: ReadonlyArray) => ReadonlyArray = covariant.imap(map) +export const headNonEmpty: (self: NonEmptyReadonlyArray) => A = unsafeGet(0) /** - * @category instances + * Get the last element in a `ReadonlyArray`, or `None` if the `ReadonlyArray` is empty. + * + * @category getters * @since 1.0.0 */ -export const Invariant: invariant.Invariant = { - imap -} +export const last = (self: ReadonlyArray): Option => + isNonEmpty(self) ? option.some(lastNonEmpty(self)) : option.none /** - * @category instances + * @category getters * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = { - ...Invariant, - product, - productMany -} +export const lastNonEmpty = (as: NonEmptyReadonlyArray): A => as[as.length - 1] /** - * @category instances + * Get all but the first element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty. + * + * @category getters * @since 1.0.0 */ -export const SemiApplicative: semiApplicative.SemiApplicative = { - ...SemiProduct, - ...Covariant +export const tail = (self: Iterable): Option> => { + const input = fromIterable(self) + return isNonEmpty(input) ? option.some(tailNonEmpty(input)) : option.none } /** - * @category constructors + * @category getters * @since 1.0.0 */ -export const of = (a: A): NonEmptyArray => [a] +export const tailNonEmpty = (self: NonEmptyReadonlyArray): Array => self.slice(1) /** - * @category instances + * Get all but the last element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty. + * + * @category getters * @since 1.0.0 */ -export const Of: of_.Of = { - of +export const init = (self: Iterable): Option> => { + const input = fromIterable(self) + return isNonEmpty(input) ? option.some(initNonEmpty(input)) : option.none } /** - * @category instances + * Get all but the last element of a non empty array, creating a new array. + * + * @category getters * @since 1.0.0 */ -export const Product: product_.Product = { - ...Of, - ...SemiProduct, - productAll +export const initNonEmpty = (self: NonEmptyReadonlyArray): Array => self.slice(0, -1) + +/** + * Keep only a max number of elements from the start of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * @category getters + * @since 1.0.0 + */ +export const take = (n: number) => + (self: Iterable): Array => { + const input = fromIterable(self) + return input.slice(0, clamp(n, input)) + } + +/** + * Keep only a max number of elements from the end of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * @category getters + * @since 1.0.0 + */ +export const takeRight = (n: number) => + (self: Iterable): Array => { + const input = fromIterable(self) + const i = clamp(n, input) + return i === 0 ? [] : input.slice(-i) + } + +/** + * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. + * + * @category getters + * @since 1.0.0 + */ +export function takeWhile( + refinement: Refinement +): (self: Iterable) => Array +export function takeWhile( + predicate: Predicate +): (self: Iterable) => Array +export function takeWhile( + predicate: Predicate +): (self: Iterable) => Array { + return (self: Iterable) => { + const out: Array = [] + for (const a of self) { + if (!predicate(a)) { + break + } + out.push(a) + } + return out + } +} + +const spanIndex = (self: Iterable, predicate: Predicate): number => { + let i = 0 + for (const a of self) { + if (!predicate(a)) { + break + } + i++ + } + return i } + /** - * @category instances + * Split an `Iterable` into two parts: + * + * 1. the longest initial subarray for which all elements satisfy the specified predicate + * 2. the remaining elements + * + * @category filtering * @since 1.0.0 */ -export const Applicative: applicative.Applicative = { - ...SemiApplicative, - ...Product +export function span( + refinement: Refinement +): (self: Iterable) => [init: Array, rest: Array] +export function span( + predicate: Predicate +): ( + self: Iterable +) => [init: Array, rest: Array] +export function span( + predicate: Predicate +): (self: Iterable) => [init: Array, rest: Array] +export function span( + predicate: Predicate +): (self: Iterable) => [init: Array, rest: Array] { + return (self) => splitAt(spanIndex(self, predicate))(self) } /** - * @category conversions + * Drop a max number of elements from the start of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * @category getters * @since 1.0.0 */ -export const fromIterable: (collection: Iterable) => ReadonlyArray = iterable.fromIterable +export const drop = (n: number) => + (self: Iterable): Array => { + const input = fromIterable(self) + return input.slice(clamp(n, input), input.length) + } /** - * @category mutations + * Drop a max number of elements from the end of an `Iterable`, creating a new `Array`. + * + * **Note**. `n` is normalized to a non negative integer. + * + * @category getters * @since 1.0.0 */ -export const appendAll = (that: Iterable) => - (self: Iterable): Array => fromIterable(self).concat(fromIterable(that)) +export const dropRight = (n: number) => + (self: Iterable): Array => { + const input = fromIterable(self) + return input.slice(0, input.length - clamp(n, input)) + } /** - * @category mutations + * Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. + * + * @category getters * @since 1.0.0 */ -export function appendAllNonEmpty( - that: NonEmptyReadonlyArray -): (self: Iterable) => NonEmptyArray -export function appendAllNonEmpty( - that: Iterable -): (self: NonEmptyReadonlyArray) => NonEmptyArray -export function appendAllNonEmpty( - that: Iterable -): (self: NonEmptyReadonlyArray) => Array { - return appendAll(that) +export function dropWhile( + refinement: Refinement +): (self: Iterable) => Array +export function dropWhile( + predicate: Predicate +): (self: Iterable) => Array +export function dropWhile( + predicate: Predicate +): (self: Iterable) => Array +export function dropWhile( + predicate: Predicate +): (self: Iterable) => Array { + return (self) => fromIterable(self).slice(spanIndex(self, predicate)) } + +/** + * Return the first index for which a predicate holds. + * + * @category getters + * @since 1.0.0 + */ +export const findFirstIndex = (predicate: Predicate) => + (self: Iterable): Option => { + let i = 0 + for (const a of self) { + if (predicate(a)) { + return option.some(i) + } + i++ + } + return option.none + } + +/** + * Return the last index for which a predicate holds. + * + * @category getters + * @since 1.0.0 + */ +export const findLastIndex = (predicate: Predicate) => + (self: Iterable): Option => { + const input = fromIterable(self) + for (let i = input.length - 1; i >= 0; i--) { + if (predicate(input[i])) { + return option.some(i) + } + } + return option.none + } + +/** + * Find the first element for which a predicate holds. + * + * @category getters + * @since 1.0.0 + */ +export function findFirst( + refinement: Refinement +): (self: Iterable) => Option +export function findFirst( + predicate: Predicate +): (self: Iterable) => Option +export function findFirst(predicate: Predicate): (self: Iterable) => Option +export function findFirst(predicate: Predicate): (self: Iterable) => Option { + return (self) => { + const input = fromIterable(self) + for (let i = 0; i < input.length; i++) { + if (predicate(input[i])) { + return option.some(input[i]) + } + } + return option.none + } +} + +/** + * Find the last element for which a predicate holds. + * + * @category getters + * @since 1.0.0 + */ +export function findLast( + refinement: Refinement +): (self: Iterable) => Option +export function findLast( + predicate: Predicate +): (self: Iterable) => Option +export function findLast(predicate: Predicate): (self: Iterable) => Option +export function findLast(predicate: Predicate): (self: Iterable) => Option { + return (self) => { + const input = fromIterable(self) + for (let i = input.length - 1; i >= 0; i--) { + if (predicate(input[i])) { + return option.some(input[i]) + } + } + return option.none + } +} + +/** + * Insert an element at the specified index, creating a new `NonEmptyArray`, + * or return `None` if the index is out of bounds. + * + * @category mutations + * @since 1.0.0 + */ +export const insertAt = (i: number, b: B) => + (self: Iterable): Option> => { + const out: Array = Array.from(self) + // v--- `= self.length` ok, it means inserting in last position + if (i < 0 || i > out.length) { + return option.none + } + out.splice(i, 0, b) + return option.some(out) as any + } + +/** + * Change the element at the specified index, creating a new `Array`, + * or return a copy of the input if the index is out of bounds. + * + * @category mutations + * @since 1.0.0 + */ +export const replace = ( + i: number, + b: B +): ((self: Iterable) => Array) => modify(i, () => b) + +/** + * @category mutations + * @since 1.0.0 + */ +export const replaceOption = ( + i: number, + b: B +): ((self: Iterable) => Option>) => modifyOption(i, () => b) + +/** + * Apply a function to the element at the specified index, creating a new `Array`, + * or return a copy of the input if the index is out of bounds. + * + * @category mutations + * @since 1.0.0 + */ +export const modify = (i: number, f: (a: A) => B) => + (self: Iterable): Array => + pipe(modifyOption(i, f)(self), O.getOrElse(() => Array.from(self))) + +/** + * Apply a function to the element at the specified index, creating a new `Array`, + * or return `None` if the index is out of bounds. + +* @category mutations + * @since 1.0.0 + */ +export const modifyOption = (i: number, f: (a: A) => B) => + (self: Iterable): Option> => { + const out = Array.from(self) + if (isOutOfBound(i, out)) { + return O.none() + } + const next = f(out[i]) + // @ts-expect-error + out[i] = next + return O.some(out) + } + +/** + * Delete the element at the specified index, creating a new `Array`, + * or return a copy of the input if the index is out of bounds. + * + * @category mutations + * @since 1.0.0 + */ +export const remove = (i: number) => + (self: Iterable): Array => { + const out = Array.from(self) + if (isOutOfBound(i, out)) { + return out + } + out.splice(i, 1) + return out + } + +/** + * Reverse an `Iterable`, creating a new `Array`. + * + * @category mutations + * @since 1.0.0 + */ +export const reverse = ( + self: Iterable +): Array => Array.from(self).reverse() + +/** + * @since 1.0.0 + */ +export const reverseNonEmpty = ( + self: NonEmptyReadonlyArray +): NonEmptyArray => [lastNonEmpty(self), ...self.slice(0, -1).reverse()] + +/** + * Return all the `Right` elements from an `Interable` of `Either`s. + * + * @category getters + * @since 1.0.0 + */ +export const rights = (self: Iterable>): Array => { + const out: Array = [] + for (const a of self) { + if (either.isRight(a)) { + out.push(a.right) + } + } + return out +} + +/** + * Return all the `Left` elements from an `Interable` of `Either`s. + * + * @category getters + * @since 1.0.0 + */ +export const lefts = (self: Iterable>): Array => { + const out: Array = [] + for (const a of self) { + if (either.isLeft(a)) { + out.push(a.left) + } + } + return out +} + +/** + * Sort the elements of an `Iterable` in increasing order, creating a new `Array`. + * + * @category sorting + * @since 1.0.0 + */ +export const sort = (O: Order) => + (self: Iterable): Array => { + const out = Array.from(self) + out.sort((self, that) => O.compare(that)(self)) + return out + } + +/** + * Sort the elements of a `NonEmptyReadonlyArray` in increasing order, creating a new `NonEmptyArray`. + * + * @category sorting + * @since 1.0.0 + */ +export const sortNonEmpty = (O: Order) => + (self: NonEmptyReadonlyArray): NonEmptyArray => sort(O)(self) as any + +/** + * Sort the elements of an `Iterable` in increasing order, where elements are compared + * using first `orders[0]`, then `orders[1]`, etc... + * + * @category sorting + * @since 1.0.0 + */ +export const sortBy = ( + ...orders: ReadonlyArray> +) => + ( + self: Iterable + ): Array => { + const input = fromIterable(self) + return (isNonEmpty(input) ? sortByNonEmpty(...orders)(input) : []) + } + +/** + * @category sorting + * @since 1.0.0 + */ +export const sortByNonEmpty = ( + ...orders: ReadonlyArray> +): ((as: NonEmptyReadonlyArray) => NonEmptyArray) => + sortNonEmpty(order.getMonoid().combineAll(orders)) + +/** + * Takes two `Iterable`s and returns an `Array` of corresponding pairs. + * If one input `Iterable` is short, excess elements of the + * longer `Iterable` are discarded. + * + * @category mutations + * @since 1.0.0 + */ +export const zip = ( + that: Iterable +): (self: Iterable) => Array<[A, B]> => zipWith(that, (a, b) => [a, b]) + +/** + * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results in a new `Array`. If one + * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. + * + * @category mutations + * @since 1.0.0 + */ +export const zipWith = (that: Iterable, f: (a: A, b: B) => C) => + (self: Iterable): Array => { + const as = fromIterable(self) + const bs = fromIterable(that) + return isNonEmpty(as) && isNonEmpty(bs) ? zipNonEmptyWith(bs, f)(as) : [] + } + +/** + * @category mutations + * @since 1.0.0 + */ +export const zipNonEmpty = (that: NonEmptyReadonlyArray) => + (self: NonEmptyReadonlyArray): NonEmptyArray<[A, B]> => + pipe( + self, + zipNonEmptyWith(that, (a, b) => [a, b]) + ) + +/** + * @category mutations + * @since 1.0.0 + */ +export const zipNonEmptyWith = (that: NonEmptyReadonlyArray, f: (a: A, b: B) => C) => + (self: NonEmptyReadonlyArray): NonEmptyArray => { + const cs: NonEmptyArray = [f(headNonEmpty(self), headNonEmpty(that))] + const len = Math.min(self.length, that.length) + for (let i = 1; i < len; i++) { + cs[i] = f(self[i], that[i]) + } + return cs + } + +/** + * This function is the inverse of `zip`. Takes an `Iterable` of pairs and return two corresponding `Array`s. + * + * @category mutations + * @since 1.0.0 + */ +export const unzip = ( + self: Iterable<[A, B]> +): [Array, Array] => { + const input = fromIterable(self) + return isNonEmpty(input) ? unzipNonEmpty(input) : [[], []] +} + +/** + * @category mutations + * @since 1.0.0 + */ +export const unzipNonEmpty = ( + self: NonEmptyReadonlyArray<[A, B]> +): [NonEmptyArray, NonEmptyArray] => { + const fa: NonEmptyArray = [self[0][0]] + const fb: NonEmptyArray = [self[0][1]] + for (let i = 1; i < self.length; i++) { + fa[i] = self[i][0] + fb[i] = self[i][1] + } + return [fa, fb] +} + +/** + * Places an element in between members of an `Iterable` + * + * @category mutations + * @since 1.0.0 + */ +export const intersperse = (middle: B) => + (self: Iterable): Array => { + const input = fromIterable(self) + return (isNonEmpty(input) ? intersperseNonEmpty(middle)(input) : []) + } + +/** + * Places an element in between members of a `NonEmptyReadonlyArray` + * + * @category mutations + * @since 1.0.0 + */ +export const intersperseNonEmpty = (middle: B) => + (self: NonEmptyReadonlyArray): NonEmptyArray => { + const out: NonEmptyArray = [headNonEmpty(self)] + const tail = tailNonEmpty(self) + for (let i = 0; i < tail.length; i++) { + if (i < tail.length) { + out.push(middle) + } + out.push(tail[i]) + } + return out + } + +/** + * Apply a function to the head, creating a new `NonEmptyReadonlyArray`. + * + * @category mutations + * @since 1.0.0 + */ +export const modifyNonEmptyHead = (f: (a: A) => B) => + ( + self: NonEmptyReadonlyArray + ): NonEmptyArray => [f(headNonEmpty(self)), ...tailNonEmpty(self)] + +/** + * Change the head, creating a new `NonEmptyReadonlyArray`. + * + * @category mutations + * @since 1.0.0 + */ +export const setNonEmptyHead = ( + b: B +): ((self: NonEmptyReadonlyArray) => NonEmptyArray) => modifyNonEmptyHead(() => b) + +/** + * Apply a function to the last element, creating a new `NonEmptyReadonlyArray`. + * + * @category mutations + * @since 1.0.0 + */ +export const modifyNonEmptyLast = (f: (a: A) => B) => + (self: NonEmptyReadonlyArray): NonEmptyArray => + pipe(initNonEmpty(self), append(f(lastNonEmpty(self)))) + +/** + * Change the last element, creating a new `NonEmptyReadonlyArray`. + * + * @category mutations + * @since 1.0.0 + */ +export const setNonEmptyLast = ( + b: B +): ((self: NonEmptyReadonlyArray) => NonEmptyArray) => modifyNonEmptyLast(() => b) + +/** + * Rotate an `Iterable` by `n` steps. + * + * @category mutations + * @since 1.0.0 + */ +export const rotate = (n: number) => + (self: Iterable): Array => { + const input = fromIterable(self) + return isNonEmpty(input) ? rotateNonEmpty(n)(input) : [] + } + +/** + * Rotate a `NonEmptyReadonlyArray` by `n` steps. + * + * @category mutations + * @since 1.0.0 + */ +export const rotateNonEmpty = (n: number) => + (self: NonEmptyReadonlyArray): NonEmptyArray => { + const len = self.length + const m = Math.round(n) % len + if (isOutOfBound(Math.abs(m), self) || m === 0) { + return copy(self) + } + if (m < 0) { + const [f, s] = splitNonEmptyAt(-m)(self) + return appendAllNonEmpty(f)(s) + } else { + return rotateNonEmpty(m - len)(self) + } + } + +/** + * Returns a function that checks if a `ReadonlyArray` contains a given value using a provided `equivalence` function. + * + * @category predicates + * @since 1.0.0 + */ +export const contains = (equivalence: Equivalence) => + (a: A) => + (self: Iterable): boolean => { + for (const i of self) { + if (equivalence(a, i)) { + return true + } + } + return false + } + +/** + * Remove duplicates from am `Iterable`, keeping the first occurrence of an element. + * + * @category mutations + * @since 1.0.0 + */ +export const uniq = (equivalence: Equivalence) => + (self: Iterable): Array => { + const input = fromIterable(self) + return isNonEmpty(input) ? uniqNonEmpty(equivalence)(input) : [] + } + +/** + * Remove duplicates from a `NonEmptyReadonlyArray`, keeping the first occurrence of an element. + * + * @category mutations + * @since 1.0.0 + */ +export const uniqNonEmpty = (equivalence: Equivalence) => + (self: NonEmptyReadonlyArray): NonEmptyArray => { + const out: NonEmptyArray = [headNonEmpty(self)] + const rest = tailNonEmpty(self) + for (const a of rest) { + if (out.every((o) => !equivalence(a, o))) { + out.push(a) + } + } + return out + } + +/** + * A useful recursion pattern for processing an `Iterable` to produce a new `Array`, often used for "chopping" up the input + * `Iterable`. Typically chop is called with some function that will consume an initial prefix of the `Iterable` and produce a + * value and the rest of the `Array`. + * + * @since 1.0.0 + */ +export const chop = ( + f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] +) => + (self: Iterable): Array => { + const input = fromIterable(self) + return isNonEmpty(input) ? chopNonEmpty(f)(input) : [] + } + +/** + * A useful recursion pattern for processing a `NonEmptyReadonlyArray` to produce a new `NonEmptyReadonlyArray`, often used for "chopping" up the input + * `NonEmptyReadonlyArray`. Typically `chop` is called with some function that will consume an initial prefix of the `NonEmptyReadonlyArray` and produce a + * value and the tail of the `NonEmptyReadonlyArray`. + * + * @since 1.0.0 + */ +export const chopNonEmpty = ( + f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] +) => + (self: NonEmptyReadonlyArray): NonEmptyArray => { + const [b, rest] = f(self) + const out: NonEmptyArray = [b] + let next: ReadonlyArray = rest + while (readonlyArray.isNonEmpty(next)) { + const [b, rest] = f(next) + out.push(b) + next = rest + } + return out + } + +/** + * Splits an `Iterable` into two pieces, the first piece has max `n` elements. + * + * @category getters + * @since 1.0.0 + */ +export const splitAt = (n: number) => + (self: Iterable): [Array, Array] => { + const input = Array.from(self) + return n >= 1 && isNonEmpty(input) ? + splitNonEmptyAt(n)(input) : + isEmpty(input) ? + [input, []] : + [[], input] + } + +/** + * @since 1.0.0 + */ +export function copy(self: NonEmptyReadonlyArray): NonEmptyArray +export function copy(self: ReadonlyArray): Array +export function copy(self: ReadonlyArray): Array { + return self.slice() +} + +/** + * Splits a `NonEmptyReadonlyArray` into two pieces, the first piece has max `n` elements. + * + * @category getters + * @since 1.0.0 + */ +export const splitNonEmptyAt = (n: number) => + (self: NonEmptyReadonlyArray): [NonEmptyArray, Array] => { + const m = Math.max(1, n) + return m >= self.length ? + [copy(self), []] : + [pipe(self.slice(1, m), prepend(headNonEmpty(self))), self.slice(m)] + } + +/** + * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of + * the `Iterable`. Note that `chunksOf(n)([])` is `[]`, not `[[]]`. This is intentional, and is consistent with a recursive + * definition of `chunksOf`; it satisfies the property that + * + * ```ts + * chunksOf(n)(xs).concat(chunksOf(n)(ys)) == chunksOf(n)(xs.concat(ys))) + * ``` + * + * whenever `n` evenly divides the length of `self`. + * + * @category getters + * @since 1.0.0 + */ +export const chunksOf = (n: number) => + (self: Iterable): Array> => { + const input = fromIterable(self) + return isNonEmpty(input) ? chunksOfNonEmpty(n)(input) : [] + } + +/** + * Splits a `NonEmptyReadonlyArray` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of + * the `NonEmptyReadonlyArray`. + * + * @category getters + * @since 1.0.0 + */ +export const chunksOfNonEmpty = ( + n: number +): ((self: NonEmptyReadonlyArray) => NonEmptyArray>) => + chopNonEmpty(splitNonEmptyAt(n)) + +/** + * Group equal, consecutive elements of a `NonEmptyReadonlyArray` into `NonEmptyArray`s. + * + * @category grouping + * @since 1.0.0 + */ +export const group = (equivalence: Equivalence) => + (self: NonEmptyReadonlyArray): NonEmptyArray> => + pipe( + self, + chopNonEmpty((as) => { + const h = headNonEmpty(as) + const out: NonEmptyArray = [h] + let i = 1 + for (; i < as.length; i++) { + const a = as[i] + if (equivalence(a, h)) { + out.push(a) + } else { + break + } + } + return [out, as.slice(i)] + }) + ) + +/** + * Splits an `Iterable` into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning + * function on each element, and grouping the results according to values returned + * + * @category grouping + * @since 1.0.0 + */ +export const groupBy = (f: (a: A) => string) => + (self: Iterable): Record> => { + const out: Record> = {} + for (const a of self) { + const k = f(a) + if (Object.prototype.hasOwnProperty.call(out, k)) { + out[k].push(a) + } else { + out[k] = [a] + } + } + return out + } + +/** + * @category mutations + * @since 1.0.0 + */ +export const union = (equivalence: Equivalence) => + (that: ReadonlyArray) => + (self: ReadonlyArray): Array => { + const a = Array.from(self) + const b = Array.from(that) + return isNonEmpty(a) && isNonEmpty(b) ? + unionNonEmpty(equivalence)(b)(a) : + isNonEmpty(a) ? + a : + b + } + +/** + * @category mutations + * @since 1.0.0 + */ +export const unionNonEmpty = (equivalence: Equivalence): { + (that: NonEmptyReadonlyArray): (self: ReadonlyArray) => NonEmptyArray + (that: ReadonlyArray): (self: NonEmptyReadonlyArray) => NonEmptyArray +} => + // @ts-expect-error + (that: ReadonlyArray) => + (self: NonEmptyReadonlyArray): NonEmptyArray => + uniqNonEmpty(equivalence)(appendAllNonEmpty(that)(self)) + +/** + * Creates an `Array` of unique values that are included in all given `Iterable`s. + * The order and references of result values are determined by the first `Iterable`. + * + * @category mutations + * @since 1.0.0 + */ +export const intersection = (equivalence: Equivalence) => + (that: Iterable) => + (self: Iterable): Array => + fromIterable(self).filter((a) => contains(equivalence)(a)(that)) + +/** + * Creates a `Array` of values not included in the other given `Iterable`. + * The order and references of result values are determined by the first `Iterable`. + * + * @category mutations + * @since 1.0.0 + */ +export const difference = (equivalence: Equivalence) => + (that: Iterable) => + (self: Iterable): Array => + fromIterable(self).filter((a) => !contains(equivalence)(a)(that)) + +/** + * @category constructors + * @since 1.0.0 + */ +export const of = (a: A): NonEmptyArray => [a] + +/** + * @category constructors + * @since 1.0.0 + */ +export const empty: () => Array = () => [] + +/** + * @category mapping + * @since 1.0.0 + */ +export const map = (f: (a: A) => B): (self: ReadonlyArray) => Array => + mapWithIndex((a) => f(a)) + +/** + * @category mapping + * @since 1.0.0 + */ +export const mapNonEmpty = ( + f: (a: A) => B +): (self: NonEmptyReadonlyArray) => NonEmptyArray => mapNonEmptyWithIndex(f) + +/** + * @category mapping + * @since 1.0.0 + */ +export const mapWithIndex = ( + f: (a: A, i: number) => B +) => (self: ReadonlyArray): Array => self.map((a, i) => f(a, i)) + +/** + * @category mapping + * @since 1.0.0 + */ +export const mapNonEmptyWithIndex = ( + f: (a: A, i: number) => B +) => + (self: NonEmptyReadonlyArray): NonEmptyArray => { + const out: NonEmptyArray = [f(headNonEmpty(self), 0)] + for (let i = 1; i < self.length; i++) { + out.push(f(self[i], i)) + } + return out + } + +/** + * @category instances + * @since 1.0.0 + */ +export const Of: of_.Of = { + of +} + +/** + * @category do notation + * @since 1.0.0 + */ +export const Do: ReadonlyArray<{}> = of_.Do(Of) + +/** + * @category mapping + * @since 1.0.0 + */ +export const imap: ( + to: (a: A) => B, + from: (b: B) => A +) => (self: ReadonlyArray) => ReadonlyArray = covariant.imap(map) + +/** + * @category instances + * @since 1.0.0 + */ +export const Invariant: invariant.Invariant = { + imap +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Covariant: covariant.Covariant = covariant.make(map) + +const let_: ( + name: Exclude, + f: (a: A) => B +) => ( + self: ReadonlyArray +) => ReadonlyArray<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant.let(Covariant) + +export { + /** + * @category do notation + * @since 1.0.0 + */ + let_ as let +} + +/** + * @category mapping + * @since 1.0.0 + */ +export const flap: (a: A) => ( + self: ReadonlyArray<(a: A) => B> +) => ReadonlyArray = covariant.flap(Covariant) + +/** + * Maps the success value of this effect to the specified constant value. + * + * @category mapping + * @since 1.0.0 + */ +export const as: (b: B) => (self: ReadonlyArray) => ReadonlyArray = covariant.as( + Covariant +) + +/** + * @category instances + * @since 1.0.0 + */ +export const Pointed: pointed.Pointed = { + ...Of, + ...Covariant +} + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMapWithIndex = (f: (a: A, i: number) => ReadonlyArray) => + (self: ReadonlyArray): Array => { + if (isEmpty(self)) { + return [] + } + const out: Array = [] + for (let i = 0; i < self.length; i++) { + out.push(...f(self[i], i)) + } + return out + } + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMap: ( + f: (a: A) => ReadonlyArray +) => (self: ReadonlyArray) => Array = (f) => flatMapWithIndex(f) + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMapNonEmptyWithIndex = (f: (a: A, i: number) => NonEmptyReadonlyArray) => + (self: NonEmptyReadonlyArray): NonEmptyArray => { + const out: NonEmptyArray = copy(f(headNonEmpty(self), 0)) + for (let i = 1; i < self.length; i++) { + out.push(...f(self[i], i)) + } + return out + } + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMapNonEmpty: ( + f: (a: A) => NonEmptyReadonlyArray +) => (self: NonEmptyReadonlyArray) => NonEmptyArray = (f) => flatMapNonEmptyWithIndex(f) + +/** + * @category instances + * @since 1.0.0 + */ +export const FlatMap: flatMap_.FlatMap = { + flatMap +} + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatten: (self: ReadonlyArray>) => ReadonlyArray = flatMap_ + .flatten(FlatMap) + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flattenNonEmpty: ( + self: NonEmptyReadonlyArray> +) => NonEmptyArray = flatMapNonEmpty(identity) + +/** + * @since 1.0.0 + */ +export const composeKleisliArrow: ( + bfc: (b: B) => ReadonlyArray +) => (afb: (a: A) => ReadonlyArray) => (a: A) => ReadonlyArray = flatMap_ + .composeKleisliArrow(FlatMap) + +/** + * @category instances + * @since 1.0.0 + */ +export const Chainable: chainable.Chainable = { + ...FlatMap, + ...Covariant +} + +/** + * @category do notation + * @since 1.0.0 + */ +export const bind: ( + name: Exclude, + f: (a: A) => ReadonlyArray +) => ( + self: ReadonlyArray +) => ReadonlyArray<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable.bind(Chainable) + +/** + * @category filtering + * @since 1.0.0 + */ +export const filterMapWithIndex = (f: (a: A, i: number) => Option) => + (self: Iterable): Array => { + const as = fromIterable(self) + const out: Array = [] + for (let i = 0; i < as.length; i++) { + const o = f(as[i], i) + if (option.isSome(o)) { + out.push(o.value) + } + } + return out + } + +/** + * @category filtering + * @since 1.0.0 + */ +export const filterMap: (f: (a: A) => Option) => (self: Iterable) => Array = (f) => + filterMapWithIndex(f) + +/** + * @category filtering + * @since 1.0.0 + */ +export const compact: (self: Iterable>) => Array = filterMap(identity) + +/** + * @category instances + * @since 1.0.0 + */ +export const Compactable: compactable.Compactable = { + compact +} + +/** + * @category filtering + * @since 1.0.0 + */ +export const separate = ( + self: ReadonlyArray> +): [Array, Array] => { + const left: Array = [] + const right: Array = [] + for (const e of self) { + if (either.isLeft(e)) { + left.push(e.left) + } else { + right.push(e.right) + } + } + return [left, right] +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Filterable: filterable.Filterable = { + filterMap +} + +/** + * @category filtering + * @since 1.0.0 + */ +export const filter: { + ( + refinement: Refinement + ): (self: ReadonlyArray) => ReadonlyArray + (predicate: Predicate): (self: ReadonlyArray) => ReadonlyArray +} = filterable.filter(Filterable) + +/** + * @category filtering + * @since 1.0.0 + */ +export const filterWithIndex: { + ( + refinement: (a: A, i: number) => a is B + ): (self: ReadonlyArray) => Array + ( + predicate: (a: A, i: number) => boolean + ): (self: ReadonlyArray) => Array +} = ( + predicate: (a: A, i: number) => boolean +): ((self: ReadonlyArray) => Array) => + filterMapWithIndex((b, i) => (predicate(b, i) ? option.some(b) : option.none)) + +/** + * @category filtering + * @since 1.0.0 + */ +export const partition: { + (refinement: Refinement): ( + self: ReadonlyArray + ) => readonly [ReadonlyArray, ReadonlyArray] + ( + predicate: Predicate + ): (self: ReadonlyArray) => readonly [ReadonlyArray, ReadonlyArray] +} = filterable.partition(Filterable) + +/** + * @category filtering + * @since 1.0.0 + */ +export const partitionWithIndex: { + (refinement: (a: A, i: number) => a is B): ( + self: ReadonlyArray + ) => [Array, Array] + (predicate: (a: A, i: number) => boolean): ( + self: ReadonlyArray + ) => [Array, Array] +} = ( + predicate: (a: A, i: number) => boolean +): ((self: ReadonlyArray) => [Array, Array]) => + partitionMapWithIndex((b, i) => (predicate(b, i) ? either.right(b) : either.left(b))) + +/** + * @category filtering + * @since 1.0.0 + */ +export const partitionMap: ( + f: (a: A) => Either +) => (self: ReadonlyArray) => [Array, Array] = (f) => partitionMapWithIndex(f) + +/** + * @category filtering + * @since 1.0.0 + */ +export const partitionMapWithIndex = (f: (a: A, i: number) => Either) => + (self: ReadonlyArray): [Array, Array] => { + const left: Array = [] + const right: Array = [] + for (let i = 0; i < self.length; i++) { + const e = f(self[i], i) + if (either.isLeft(e)) { + left.push(e.left) + } else { + right.push(e.right) + } + } + return [left, right] + } + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverse = (F: applicative.Applicative) => + ( + f: (a: A) => Kind + ): ((self: ReadonlyArray) => Kind>) => traverseWithIndex(F)(f) + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverseWithIndex = (F: applicative.Applicative) => + (f: (a: A, i: number) => Kind) => + (self: ReadonlyArray): Kind> => F.productAll(self.map(f)) + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverseNonEmpty = ( + F: semiApplicative.SemiApplicative +) => + ( + f: (a: A) => Kind + ): ((self: NonEmptyReadonlyArray) => Kind>) => + traverseNonEmptyWithIndex(F)(f) + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverseNonEmptyWithIndex = ( + F: semiApplicative.SemiApplicative +) => + (f: (a: A, i: number) => Kind) => + (self: NonEmptyReadonlyArray): Kind> => { + const fbs = pipe(self, mapNonEmptyWithIndex(f)) + return pipe(headNonEmpty(fbs), F.productMany(tailNonEmpty(fbs))) + } + +/** + * @category traversing + * @since 1.0.0 + */ +export const sequence: ( + F: applicative.Applicative +) => ( + self: ReadonlyArray> +) => Kind> = traversable.sequence(traverse) + +/** + * @category instances + * @since 1.0.0 + */ +export const Traversable: traversable.Traversable = { + traverse, + sequence +} + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverseTap: ( + F: applicative.Applicative +) => ( + f: (a: A) => Kind +) => (self: ReadonlyArray) => Kind> = traversable + .traverseTap( + Traversable + ) + +/** + * @category traversing + * @since 1.0.0 + */ +export const sequenceNonEmpty = ( + F: semiApplicative.SemiApplicative +): (( + self: NonEmptyReadonlyArray> +) => Kind>) => traverseNonEmpty(F)(identity) + +/** + * @since 1.0.0 + */ +export const product = ( + that: ReadonlyArray +) => + (self: ReadonlyArray): Array<[A, B]> => { + if (isEmpty(self) || isEmpty(that)) { + return empty() + } + const out: Array<[A, B]> = [] + for (let i = 0; i < self.length; i++) { + for (let j = 0; j < that.length; j++) { + out.push([self[i], that[j]]) + } + } + return out + } + +/** + * @since 1.0.0 + */ +export const productMany: ( + collection: Iterable> +) => (self: ReadonlyArray) => ReadonlyArray> = semiProduct + .productMany( + Covariant, + product + ) + +/** + * @since 1.0.0 + */ +export const productAll = ( + collection: Iterable> +): ReadonlyArray> => { + const arrays = Array.from(collection) + if (isEmpty(arrays)) { + return empty() + } + return productMany(arrays.slice(1))(arrays[0]) +} + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiProduct: semiProduct.SemiProduct = { + ...Invariant, + product, + productMany +} + +/** + * A variant of `bind` that sequentially ignores the scope. + * + * @category do notation + * @since 1.0.0 + */ +export const andThenBind: ( + name: Exclude, + fb: ReadonlyArray +) => ( + self: ReadonlyArray +) => ReadonlyArray<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct + .andThenBind(SemiProduct) + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiApplicative: semiApplicative.SemiApplicative = { + ...SemiProduct, + ...Covariant +} + +/** + * @since 1.0.0 + */ +export const ap: ( + fa: ReadonlyArray +) => (self: ReadonlyArray<(a: A) => B>) => ReadonlyArray = semiApplicative.ap( + SemiApplicative +) + +/** + * Lifts a binary function into `ReadonlyArray`. + * + * @category lifting + * @since 1.0.0 + */ +export const lift2: ( + f: (a: A, b: B) => C +) => (fa: ReadonlyArray, fb: ReadonlyArray) => ReadonlyArray = semiApplicative.lift2( + SemiApplicative +) + +/** + * Lifts a ternary function into `ReadonlyArray`. + * + * @category lifting + * @since 1.0.0 + */ +export const lift3: ( + f: (a: A, b: B, c: C) => D +) => (fa: ReadonlyArray, fb: ReadonlyArray, fc: ReadonlyArray) => ReadonlyArray = + semiApplicative.lift3(SemiApplicative) + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftSemigroup: (S: Semigroup) => Semigroup> = semiApplicative + .liftSemigroup( + SemiApplicative + ) + +/** + * @category instances + * @since 1.0.0 + */ +export const Product: product_.Product = { + ...Of, + ...SemiProduct, + productAll +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Applicative: applicative.Applicative = { + ...SemiApplicative, + ...Product +} + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftMonoid: (M: Monoid) => Monoid> = applicative + .liftMonoid( + Applicative + ) + +/** + * @category instances + * @since 1.0.0 + */ +export const Monad: monad.Monad = { + ...Pointed, + ...FlatMap +} + +/** + * @category folding + * @since 1.0.0 + */ +export const reduce = (b: B, f: (b: B, a: A) => B) => + (self: ReadonlyArray): B => self.reduce((b, a) => f(b, a), b) + +/** + * @category folding + * @since 1.0.0 + */ +export const reduceWithIndex = (b: B, f: (b: B, a: A, i: number) => B) => + (self: ReadonlyArray): B => self.reduce((b, a, i) => f(b, a, i), b) + +/** + * @category folding + * @since 1.0.0 + */ +export const reduceRight = (b: B, f: (b: B, a: A) => B) => + (self: ReadonlyArray): B => self.reduceRight((b, a) => f(b, a), b) + +/** + * @category folding + * @since 1.0.0 + */ +export const reduceRightWithIndex = (b: B, f: (b: B, a: A, i: number) => B) => + (self: ReadonlyArray): B => self.reduceRight((b, a, i) => f(b, a, i), b) + +/** + * @category instances + * @since 1.0.0 + */ +export const Foldable: foldable.Foldable = { + reduce +} + +/** + * @category folding + * @since 1.0.0 + */ +export const foldMap: ( + M: Monoid +) => (f: (a: A) => M) => (self: ReadonlyArray) => M = foldable.foldMap( + Foldable +) + +/** + * @category folding + * @since 1.0.0 + */ +export const foldMapWithIndex = (Monoid: Monoid) => + (f: (a: A, i: number) => M) => + (self: ReadonlyArray): M => + self.reduce((m, a, i) => Monoid.combine(f(a, i))(m), Monoid.empty) + +/** + * @category folding + * @since 1.0.0 + */ +export const foldMapNonEmpty = (S: Semigroup) => + (f: (a: A) => S): (self: NonEmptyReadonlyArray) => S => foldMapNonEmptyWithIndex(S)(f) + +/** + * @category folding + * @since 1.0.0 + */ +export const foldMapNonEmptyWithIndex = (S: Semigroup) => + (f: (a: A, i: number) => S) => + (self: NonEmptyReadonlyArray): S => + tailNonEmpty(self).reduce((s, a, i) => S.combine(f(a, i + 1))(s), f(headNonEmpty(self), 0)) + +/** + * @category folding + * @since 1.0.0 + */ +export const reduceKind: ( + F: monad.Monad +) => ( + b: B, + f: (b: B, a: A) => Kind +) => (self: ReadonlyArray) => Kind = foldable.reduceKind( + Foldable +) + +/** + * @category folding + * @since 1.0.0 + */ +export const reduceRightKind: ( + F: monad.Monad +) => ( + b: B, + f: (b: B, a: A) => Kind +) => (self: ReadonlyArray) => Kind = foldable + .reduceRightKind( + Foldable + ) + +/** + * @category folding + * @since 1.0.0 + */ +export const foldMapKind: ( + F: Coproduct +) => ( + f: (a: A) => Kind +) => (self: ReadonlyArray) => Kind = foldable.foldMapKind( + Foldable +) + +/** + * @category filtering + * @since 1.0.0 + */ +export const traverseFilterMap: ( + F: applicative.Applicative +) => ( + f: (a: A) => Kind> +) => (ta: ReadonlyArray) => Kind> = traversableFilterable + .traverseFilterMap({ ...Traversable, ...Compactable }) + +/** + * @category filtering + * @since 1.0.0 + */ +export const traversePartitionMap: ( + F: applicative.Applicative +) => ( + f: (a: A) => Kind> +) => (self: ReadonlyArray) => Kind, ReadonlyArray]> = + traversableFilterable + .traversePartitionMap({ ...Traversable, ...Covariant, ...Compactable }) + +/** + * @category instances + * @since 1.0.0 + */ +export const TraversableFilterable: traversableFilterable.TraversableFilterable< + ReadonlyArrayTypeLambda +> = { + traverseFilterMap, + traversePartitionMap +} + +/** + * Filter values inside a context. + * + * @since 1.0.0 + */ +export const traverseFilter: ( + F: applicative.Applicative +) => ( + predicate: (a: A) => Kind +) => (self: ReadonlyArray) => Kind> = traversableFilterable + .traverseFilter(TraversableFilterable) + +/** + * @since 1.0.0 + */ +export const traversePartition: ( + F: applicative.Applicative +) => ( + predicate: (a: A) => Kind +) => ( + self: ReadonlyArray +) => Kind, ReadonlyArray]> = traversableFilterable + .traversePartition(TraversableFilterable) + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftPredicate: { + (refinement: Refinement): (c: C) => Array + (predicate: Predicate): (b: B) => Array +} = (predicate: Predicate) => (b: B) => predicate(b) ? [b] : [] + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftOption = , B>( + f: (...a: A) => Option +) => (...a: A): Array => fromOption(f(...a)) + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromNullable = (a: A): Array> => + a == null ? empty() : [a as NonNullable] + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftNullable = , B>( + f: (...a: A) => B | null | undefined +): (...a: A) => Array> => (...a) => fromNullable(f(...a)) + +/** + * @category sequencing + * @since 1.0.0 + */ +export const flatMapNullable = ( + f: (a: A) => B | null | undefined +) => + (self: ReadonlyArray): Array> => + isNonEmpty(self) ? fromNullable(f(headNonEmpty(self))) : empty() + +/** + * @category lifting + * @since 1.0.0 + */ +export const liftEither = , E, B>( + f: (...a: A) => Either +) => + (...a: A): Array => { + const e = f(...a) + return either.isLeft(e) ? [] : [e.right] + } + +/** + * Check if a predicate holds true for every `ReadonlyArray` member. + * + * @category lifting + * @since 1.0.0 + */ +export function every( + refinement: Refinement +): Refinement, Array> +export function every(predicate: Predicate): Predicate> +export function every(predicate: Predicate): Predicate> { + return (self) => self.every(predicate) +} + +/** + * Check if a predicate holds true for any `ReadonlyArray` member. + * + * @category predicates + * @since 1.0.0 + */ +export const some = (predicate: Predicate) => + (self: ReadonlyArray): self is NonEmptyArray => self.some(predicate) + +/** + * Alias of [`some`](#some) + * + * @since 1.0.0 + */ +export const has = some + +/** + * Fold a data structure, accumulating values in some `Monoid`, combining adjacent elements + * using the specified separator. + * + * @since 1.0.0 + */ +export const intercalate = (M: Monoid) => + (middle: A) => + (self: ReadonlyArray): A => isNonEmpty(self) ? intercalateNonEmpty(M)(middle)(self) : M.empty + +/** + * Places an element in between members of a `NonEmptyReadonlyArray`, then folds the results using the provided `Semigroup`. + * + * @since 1.0.0 + */ +export const intercalateNonEmpty = ( + S: Semigroup +) => + (middle: A) => + (self: NonEmptyReadonlyArray): A => + semigroup.intercalate(middle)(S).combineMany(tailNonEmpty(self))(headNonEmpty(self)) + +/** + * @since 1.0.0 + */ +export const join: (sep: string) => (self: ReadonlyArray) => string = intercalate( + string.Monoid +) + +/** + * @since 1.0.0 + */ +export const productFlatten: ( + that: ReadonlyArray +) => >( + self: ReadonlyArray +) => ReadonlyArray = semiProduct.productFlatten(SemiProduct) + +/** + * @since 1.0.0 + */ +export const extend = ( + f: (as: ReadonlyArray) => B +) => (self: ReadonlyArray): Array => self.map((_, i, as) => f(as.slice(i))) + +/** + * @since 1.0.0 + */ +export const min = (O: Order): ((self: NonEmptyReadonlyArray) => A) => { + const S = semigroup.min(O) + return (self) => self.reduce((a, acc) => S.combine(acc)(a)) +} + +/** + * @since 1.0.0 + */ +export const max = (O: Order): ((self: NonEmptyReadonlyArray) => A) => { + const S = semigroup.max(O) + return (self) => self.reduce((a, acc) => S.combine(acc)(a)) +} + +/** + * @category constructors + * @since 1.0.0 + */ +export const unfold = (b: B, f: (b: B) => Option): Array => { + const out: Array = [] + let next: B = b + let o: Option + while (option.isSome(o = f(next))) { + const [a, b] = o.value + out.push(a) + next = b + } + return out +} + +/** + * @category instances + * @since 1.0.0 + */ +export const getUnionSemigroup = (equivalence: Equivalence): Semigroup> => + // @ts-expect-error + fromCombine(union(equivalence)) + +/** + * @category instances + * @since 1.0.0 + */ +export const getUnionMonoid = (equivalence: Equivalence): Monoid> => { + const S = getUnionSemigroup(equivalence) + return ({ + combine: S.combine, + combineMany: S.combineMany, + combineAll: (collection) => S.combineMany(collection)(empty()), + empty: empty() + }) +} + +/** + * @category instances + * @since 1.0.0 + */ +export const getIntersectionSemigroup = ( + equivalence: Equivalence +): Semigroup> => + // @ts-expect-error + fromCombine(intersection(equivalence)) + +/** + * Returns a `Semigroup` for `ReadonlyArray`. + * + * @category instances + * @since 1.0.0 + */ +export const getSemigroup = (): Semigroup> => fromCombine(appendAll) + +/** + * Returns a `Monoid` for `ReadonlyArray`. + * + * @category instances + * @since 1.0.0 + */ +export const getMonoid = (): Monoid> => { + const S = getSemigroup() + return ({ + combine: S.combine, + combineMany: S.combineMany, + combineAll: (collection) => S.combineMany(collection)(empty()), + empty: empty() + }) +} + +/** + * Derives an `Order` over the `ReadonlyArray` of a given element type from the `Order` of that type. The ordering between two such + * `ReadonlyArray`s is equal to: the first non equal comparison of each `ReadonlyArray`s elements taken pairwise in increasing order, in + * case of equality over all the pairwise elements; the longest `ReadonlyArray` is considered the greatest, if both `ReadonlyArray`s have + * the same length, the result is equality. + * + * @category lifting + * @since 1.0.0 + */ +export const liftOrder = (O: Order): Order> => + order.fromCompare((that) => + (self) => { + const aLen = self.length + const bLen = that.length + const len = Math.min(aLen, bLen) + for (let i = 0; i < len; i++) { + const o = O.compare(that[i])(self[i]) + if (o !== 0) { + return o + } + } + return number.Order.compare(bLen)(aLen) + } + ) diff --git a/src/String.ts b/src/String.ts index 9700222b8..74ecc7a96 100644 --- a/src/String.ts +++ b/src/String.ts @@ -2,8 +2,8 @@ * @since 1.0.0 */ +import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type { Refinement } from "@fp-ts/core/Predicate" -import { isNonEmpty } from "@fp-ts/core/ReadonlyArray" import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import type * as monoid from "@fp-ts/core/typeclass/Monoid" @@ -210,7 +210,7 @@ export const size = (s: string): number => s.length export const split = (separator: string | RegExp) => (s: string): NonEmptyReadonlyArray => { const out = s.split(separator) - return isNonEmpty(out) ? out : [s] + return readonlyArray.isNonEmpty(out) ? out : [s] } /** diff --git a/src/internal/Iterable.ts b/src/internal/Iterable.ts deleted file mode 100644 index 72b5eee8c..000000000 --- a/src/internal/Iterable.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @since 1.0.0 - */ - -/** @internal */ -export const fromIterable = (collection: Iterable): ReadonlyArray => - Array.isArray(collection) ? collection : Array.from(collection) diff --git a/src/internal/ReadonlyArray.ts b/src/internal/ReadonlyArray.ts new file mode 100644 index 000000000..0754a3224 --- /dev/null +++ b/src/internal/ReadonlyArray.ts @@ -0,0 +1,11 @@ +/** + * @since 1.0.0 + */ +import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" + +/** @internal */ +export const isNonEmpty = (as: ReadonlyArray): as is NonEmptyReadonlyArray => as.length > 0 + +/** @internal */ +export const fromIterable = (collection: Iterable): Array => + Array.isArray(collection) ? collection : Array.from(collection) diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts new file mode 100644 index 000000000..550933a4e --- /dev/null +++ b/test/ReadonlyArray.ts @@ -0,0 +1,1670 @@ +import * as E from "@fp-ts/core/Either" +import { identity, pipe } from "@fp-ts/core/Function" +import * as Number from "@fp-ts/core/Number" +import * as O from "@fp-ts/core/Option" +import type { Predicate } from "@fp-ts/core/Predicate" +import * as RA from "@fp-ts/core/ReadonlyArray" +import * as String from "@fp-ts/core/String" +import { deepStrictEqual, double, strictEqual } from "@fp-ts/core/test/util" +import * as Order from "@fp-ts/core/typeclass/Order" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import * as assert from "assert" +import * as fc from "fast-check" + +describe.concurrent("ReadonlyArray", () => { + it("instances and derived exports", () => { + expect(RA.Invariant).exist + expect(RA.imap).exist + + expect(RA.Covariant).exist + expect(RA.map).exist + expect(RA.let).exist + expect(RA.flap).exist + expect(RA.as).exist + + expect(RA.Of).exist + expect(RA.of).exist + expect(RA.Do).exist + + expect(RA.Pointed).exist + + expect(RA.FlatMap).exist + expect(RA.flatMap).exist + expect(RA.flatten).exist + expect(RA.composeKleisliArrow).exist + + expect(RA.Chainable).exist + expect(RA.bind).exist + + expect(RA.Monad).exist + + expect(RA.SemiProduct).exist + expect(RA.product).exist + expect(RA.productMany).exist + expect(RA.andThenBind).exist + expect(RA.productFlatten).exist + + expect(RA.Product).exist + expect(RA.productAll).exist + // expect(ReadonlyArray.tuple).exist + // expect(ReadonlyArray.struct).exist + + expect(RA.SemiApplicative).exist + expect(RA.liftSemigroup).exist + expect(RA.lift2).exist + expect(RA.lift3).exist + expect(RA.ap).exist + + expect(RA.Applicative).exist + expect(RA.liftMonoid).exist + + expect(RA.Foldable).exist + expect(RA.reduce).exist + expect(RA.reduceRight).exist + expect(RA.foldMap).exist + expect(RA.reduceKind).exist + expect(RA.reduceRightKind).exist + expect(RA.foldMapKind).exist + + expect(RA.Traversable).exist + expect(RA.traverse).exist + expect(RA.sequence).exist + expect(RA.traverseTap).exist + + expect(RA.Compactable).exist + expect(RA.compact).exist + expect(RA.separate).exist + + expect(RA.Filterable).exist + expect(RA.filterMap).exist + expect(RA.filter).exist + expect(RA.partition).exist + expect(RA.partitionMap).exist + + expect(RA.TraversableFilterable).exist + expect(RA.traverseFilterMap).exist + expect(RA.traversePartitionMap).exist + expect(RA.traverseFilter).exist + expect(RA.traversePartition).exist + + expect(RA.liftPredicate).exist + expect(RA.liftOption).exist + expect(RA.liftNullable).exist + expect(RA.flatMapNullable).exist + }) + + it("fromIterable/Array should return the same reference if the iterable is an Array", () => { + const i = [1, 2, 3] + expect(RA.fromIterable(i) === i).toEqual(true) + }) + + it("fromIterable/Iterable", () => { + expect(RA.fromIterable(new Set([1, 2, 3]))).toEqual([1, 2, 3]) + }) + + describe("iterable inputs", () => { + it("prepend", () => { + deepStrictEqual(pipe([1, 2, 3], RA.prepend(0)), [0, 1, 2, 3]) + deepStrictEqual(pipe([[2]], RA.prepend([1])), [[1], [2]]) + + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.prepend(0)), [0, 1, 2, 3]) + deepStrictEqual(pipe(new Set([[2]]), RA.prepend([1])), [[1], [2]]) + }) + + it("prependAll", () => { + deepStrictEqual(pipe([3, 4], RA.prependAll([1, 2])), [1, 2, 3, 4]) + + deepStrictEqual(pipe([3, 4], RA.prependAll(new Set([1, 2]))), [1, 2, 3, 4]) + deepStrictEqual(pipe(new Set([3, 4]), RA.prependAll([1, 2])), [1, 2, 3, 4]) + }) + + it("prependAllNonEmpty", () => { + deepStrictEqual(pipe([3, 4], RA.prependAllNonEmpty([1, 2])), [1, 2, 3, 4]) + + deepStrictEqual(pipe(RA.make(3, 4), RA.prependAllNonEmpty(new Set([1, 2]))), [1, 2, 3, 4]) + deepStrictEqual(pipe(new Set([3, 4]), RA.prependAllNonEmpty([1, 2])), [1, 2, 3, 4]) + }) + + it("append", () => { + deepStrictEqual(pipe([1, 2, 3], RA.append(4)), [1, 2, 3, 4]) + deepStrictEqual(pipe([[1]], RA.append([2])), [[1], [2]]) + + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.append(4)), [1, 2, 3, 4]) + deepStrictEqual(pipe(new Set([[1]]), RA.append([2])), [[1], [2]]) + }) + + it("appendAll", () => { + deepStrictEqual(pipe([1, 2], RA.appendAll([3, 4])), [1, 2, 3, 4]) + + deepStrictEqual(pipe([1, 2], RA.appendAll(new Set([3, 4]))), [1, 2, 3, 4]) + deepStrictEqual(pipe(new Set([1, 2]), RA.appendAll([3, 4])), [1, 2, 3, 4]) + }) + + it("appendAllNonEmpty", () => { + deepStrictEqual(pipe([1, 2], RA.appendAllNonEmpty([3, 4])), [1, 2, 3, 4]) + + deepStrictEqual(pipe(RA.make(1, 2), RA.appendAllNonEmpty(new Set([3, 4]))), [1, 2, 3, 4]) + deepStrictEqual(pipe(new Set([1, 2]), RA.appendAllNonEmpty([3, 4])), [1, 2, 3, 4]) + }) + + it("scan", () => { + const f = (b: number, a: number) => b - a + deepStrictEqual(pipe([1, 2, 3], RA.scan(10, f)), [10, 9, 7, 4]) + deepStrictEqual(pipe([0], RA.scan(10, f)), [10, 10]) + deepStrictEqual(pipe([], RA.scan(10, f)), [10]) + + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.scan(10, f)), [10, 9, 7, 4]) + deepStrictEqual(pipe(new Set([0]), RA.scan(10, f)), [10, 10]) + deepStrictEqual(pipe(new Set([]), RA.scan(10, f)), [10]) + }) + + it("scanRight", () => { + const f = (b: number, a: number) => a - b + deepStrictEqual(pipe([1, 2, 3], RA.scanRight(10, f)), [-8, 9, -7, 10]) + deepStrictEqual(pipe([0], RA.scanRight(10, f)), [-10, 10]) + deepStrictEqual(pipe([], RA.scanRight(10, f)), [10]) + + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.scanRight(10, f)), [-8, 9, -7, 10]) + deepStrictEqual(pipe(new Set([0]), RA.scanRight(10, f)), [-10, 10]) + deepStrictEqual(pipe(new Set([]), RA.scanRight(10, f)), [10]) + }) + + it("tail", () => { + deepStrictEqual(RA.tail([1, 2, 3]), O.some([2, 3])) + deepStrictEqual(RA.tail([]), O.none()) + + deepStrictEqual(RA.tail(new Set([1, 2, 3])), O.some([2, 3])) + deepStrictEqual(RA.tail(new Set([])), O.none()) + }) + + it("init", () => { + deepStrictEqual(RA.init([1, 2, 3]), O.some([1, 2])) + deepStrictEqual(RA.init([]), O.none()) + + deepStrictEqual(RA.init(new Set([1, 2, 3])), O.some([1, 2])) + deepStrictEqual(RA.init(new Set([])), O.none()) + }) + + it("take", () => { + expect(pipe([1, 2, 3, 4], RA.take(2))).toEqual([1, 2]) + expect(pipe([1, 2, 3, 4], RA.take(0))).toEqual([]) + // out of bounds + expect(pipe([1, 2, 3, 4], RA.take(-10))).toEqual([]) + expect(pipe([1, 2, 3, 4], RA.take(10))).toEqual([1, 2, 3, 4]) + + expect(pipe(new Set([1, 2, 3, 4]), RA.take(2))).toEqual([1, 2]) + expect(pipe(new Set([1, 2, 3, 4]), RA.take(0))).toEqual([]) + // out of bounds + expect(pipe(new Set([1, 2, 3, 4]), RA.take(-10))).toEqual([]) + expect(pipe(new Set([1, 2, 3, 4]), RA.take(10))).toEqual([1, 2, 3, 4]) + }) + + it("takeRight", () => { + deepStrictEqual(pipe(RA.empty(), RA.takeRight(0)), []) + deepStrictEqual(pipe([1, 2], RA.takeRight(0)), []) + deepStrictEqual(pipe([1, 2], RA.takeRight(1)), [2]) + deepStrictEqual(pipe([1, 2], RA.takeRight(2)), [1, 2]) + // out of bound + deepStrictEqual(pipe(RA.empty(), RA.takeRight(1)), []) + deepStrictEqual(pipe(RA.empty(), RA.takeRight(-1)), []) + deepStrictEqual(pipe([1, 2], RA.takeRight(3)), [1, 2]) + deepStrictEqual(pipe([1, 2], RA.takeRight(-1)), []) + + deepStrictEqual(pipe(new Set(), RA.takeRight(0)), []) + deepStrictEqual(pipe(new Set([1, 2]), RA.takeRight(0)), []) + deepStrictEqual(pipe(new Set([1, 2]), RA.takeRight(1)), [2]) + deepStrictEqual(pipe(new Set([1, 2]), RA.takeRight(2)), [1, 2]) + // out of bound + deepStrictEqual(pipe(new Set(), RA.takeRight(1)), []) + deepStrictEqual(pipe(new Set(), RA.takeRight(-1)), []) + deepStrictEqual(pipe(new Set([1, 2]), RA.takeRight(3)), [1, 2]) + deepStrictEqual(pipe(new Set([1, 2]), RA.takeRight(-1)), []) + }) + + it("takeWhile", () => { + const f = (n: number) => n % 2 === 0 + deepStrictEqual(pipe([2, 4, 3, 6], RA.takeWhile(f)), [2, 4]) + deepStrictEqual(pipe(RA.empty(), RA.takeWhile(f)), []) + deepStrictEqual(pipe([1, 2, 4], RA.takeWhile(f)), []) + deepStrictEqual(pipe([2, 4], RA.takeWhile(f)), [2, 4]) + + deepStrictEqual(pipe(new Set([2, 4, 3, 6]), RA.takeWhile(f)), [2, 4]) + deepStrictEqual(pipe(new Set(), RA.takeWhile(f)), []) + deepStrictEqual(pipe(new Set([1, 2, 4]), RA.takeWhile(f)), []) + deepStrictEqual(pipe(new Set([2, 4]), RA.takeWhile(f)), [2, 4]) + }) + + it("span", () => { + const f = RA.span((n: number) => n % 2 === 1) + const assertSpan = ( + input: Iterable, + expectedInit: ReadonlyArray, + expectedRest: ReadonlyArray + ) => { + const [init, rest] = f(input) + deepStrictEqual(init, expectedInit) + deepStrictEqual(rest, expectedRest) + } + assertSpan([1, 3, 2, 4, 5], [1, 3], [2, 4, 5]) + assertSpan(RA.empty(), RA.empty(), RA.empty()) + assertSpan([1, 3], [1, 3], RA.empty()) + assertSpan([2, 4], RA.empty(), [2, 4]) + + assertSpan(new Set([1, 3, 2, 4, 5]), [1, 3], [2, 4, 5]) + assertSpan(new Set(), RA.empty(), RA.empty()) + assertSpan(new Set([1, 3]), [1, 3], RA.empty()) + assertSpan(new Set([2, 4]), RA.empty(), [2, 4]) + }) + + it("drop", () => { + deepStrictEqual(pipe(RA.empty(), RA.drop(0)), []) + deepStrictEqual(pipe([1, 2], RA.drop(0)), [1, 2]) + deepStrictEqual(pipe([1, 2], RA.drop(1)), [2]) + deepStrictEqual(pipe([1, 2], RA.drop(2)), []) + // out of bound + deepStrictEqual(pipe(RA.empty(), RA.drop(1)), []) + deepStrictEqual(pipe(RA.empty(), RA.drop(-1)), []) + deepStrictEqual(pipe([1, 2], RA.drop(3)), []) + deepStrictEqual(pipe([1, 2], RA.drop(-1)), [1, 2]) + + deepStrictEqual(pipe(new Set(), RA.drop(0)), []) + deepStrictEqual(pipe(new Set([1, 2]), RA.drop(0)), [1, 2]) + deepStrictEqual(pipe(new Set([1, 2]), RA.drop(1)), [2]) + deepStrictEqual(pipe(new Set([1, 2]), RA.drop(2)), []) + // out of bound + deepStrictEqual(pipe(new Set(), RA.drop(1)), []) + deepStrictEqual(pipe(new Set(), RA.drop(-1)), []) + deepStrictEqual(pipe(new Set([1, 2]), RA.drop(3)), []) + deepStrictEqual(pipe(new Set([1, 2]), RA.drop(-1)), [1, 2]) + }) + + it("dropRight", () => { + deepStrictEqual(pipe([], RA.dropRight(0)), []) + deepStrictEqual(pipe([1, 2], RA.dropRight(0)), [1, 2]) + deepStrictEqual(pipe([1, 2], RA.dropRight(1)), [1]) + deepStrictEqual(pipe([1, 2], RA.dropRight(2)), []) + // out of bound + deepStrictEqual(pipe([], RA.dropRight(1)), []) + deepStrictEqual(pipe([1, 2], RA.dropRight(3)), []) + deepStrictEqual(pipe([], RA.dropRight(-1)), []) + deepStrictEqual(pipe([1, 2], RA.dropRight(-1)), [1, 2]) + + deepStrictEqual(pipe(new Set(), RA.dropRight(0)), []) + deepStrictEqual(pipe(new Set([1, 2]), RA.dropRight(0)), [1, 2]) + deepStrictEqual(pipe(new Set([1, 2]), RA.dropRight(1)), [1]) + deepStrictEqual(pipe(new Set([1, 2]), RA.dropRight(2)), []) + // out of bound + deepStrictEqual(pipe(new Set(), RA.dropRight(1)), []) + deepStrictEqual(pipe(new Set([1, 2]), RA.dropRight(3)), []) + deepStrictEqual(pipe(new Set(), RA.dropRight(-1)), []) + deepStrictEqual(pipe(new Set([1, 2]), RA.dropRight(-1)), [1, 2]) + }) + + it("dropWhile", () => { + const f = RA.dropWhile((n: number) => n > 0) + + deepStrictEqual(f([]), []) + deepStrictEqual(f([1, 2]), RA.empty()) + deepStrictEqual(f([-1, -2]), [-1, -2]) + deepStrictEqual(f([-1, 2]), [-1, 2]) + deepStrictEqual(f([1, -2, 3]), [-2, 3]) + + deepStrictEqual(f(new Set()), []) + deepStrictEqual(f(new Set([1, 2])), RA.empty()) + deepStrictEqual(f(new Set([-1, -2])), [-1, -2]) + deepStrictEqual(f(new Set([-1, 2])), [-1, 2]) + deepStrictEqual(f(new Set([1, -2, 3])), [-2, 3]) + }) + + it("findFirstIndex", () => { + deepStrictEqual(pipe([], RA.findFirstIndex((n) => n % 2 === 0)), O.none()) + deepStrictEqual(pipe([1, 2, 3], RA.findFirstIndex((n) => n % 2 === 0)), O.some(1)) + deepStrictEqual(pipe([1, 2, 3, 1], RA.findFirstIndex((n) => n % 2 === 0)), O.some(1)) + + deepStrictEqual(pipe(new Set(), RA.findFirstIndex((n) => n % 2 === 0)), O.none()) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.findFirstIndex((n) => n % 2 === 0)), O.some(1)) + deepStrictEqual(pipe(new Set([1, 2, 3, 4]), RA.findFirstIndex((n) => n % 2 === 0)), O.some(1)) + }) + + it("findLastIndex", () => { + deepStrictEqual(pipe([], RA.findLastIndex((n) => n % 2 === 0)), O.none()) + deepStrictEqual(pipe([1, 2, 3], RA.findLastIndex((n) => n % 2 === 0)), O.some(1)) + deepStrictEqual(pipe([1, 2, 3, 4], RA.findLastIndex((n) => n % 2 === 0)), O.some(3)) + + deepStrictEqual(pipe(new Set(), RA.findLastIndex((n) => n % 2 === 0)), O.none()) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.findLastIndex((n) => n % 2 === 0)), O.some(1)) + deepStrictEqual(pipe(new Set([1, 2, 3, 4]), RA.findLastIndex((n) => n % 2 === 0)), O.some(3)) + }) + + it("findFirst", () => { + deepStrictEqual(pipe([], RA.findFirst((n) => n % 2 === 0)), O.none()) + deepStrictEqual(pipe([1, 2, 3], RA.findFirst((n) => n % 2 === 0)), O.some(2)) + deepStrictEqual(pipe([1, 2, 3, 4], RA.findFirst((n) => n % 2 === 0)), O.some(2)) + + deepStrictEqual(pipe(new Set(), RA.findFirst((n) => n % 2 === 0)), O.none()) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.findFirst((n) => n % 2 === 0)), O.some(2)) + deepStrictEqual(pipe(new Set([1, 2, 3, 4]), RA.findFirst((n) => n % 2 === 0)), O.some(2)) + }) + + it("findLast", () => { + deepStrictEqual(pipe([], RA.findLast((n) => n % 2 === 0)), O.none()) + deepStrictEqual(pipe([1, 2, 3], RA.findLast((n) => n % 2 === 0)), O.some(2)) + deepStrictEqual(pipe([1, 2, 3, 4], RA.findLast((n) => n % 2 === 0)), O.some(4)) + + deepStrictEqual(pipe(new Set(), RA.findLast((n) => n % 2 === 0)), O.none()) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.findLast((n) => n % 2 === 0)), O.some(2)) + deepStrictEqual(pipe(new Set([1, 2, 3, 4]), RA.findLast((n) => n % 2 === 0)), O.some(4)) + }) + + it("insertAt", () => { + deepStrictEqual(RA.insertAt(1, 1)([]), O.none()) + deepStrictEqual(RA.insertAt(0, 1)([]), O.some([1])) + deepStrictEqual(RA.insertAt(2, 5)([1, 2, 3, 4]), O.some([1, 2, 5, 3, 4])) + // out of bound + deepStrictEqual(RA.insertAt(-1, 5)([1, 2, 3, 4]), O.none()) + deepStrictEqual(RA.insertAt(10, 5)([1, 2, 3, 4]), O.none()) + + deepStrictEqual(RA.insertAt(1, 1)(new Set([])), O.none()) + deepStrictEqual(RA.insertAt(0, 1)(new Set([])), O.some([1])) + deepStrictEqual(RA.insertAt(2, 5)(new Set([1, 2, 3, 4])), O.some([1, 2, 5, 3, 4])) + // out of bound + deepStrictEqual(RA.insertAt(-1, 5)(new Set([1, 2, 3, 4])), O.none()) + deepStrictEqual(RA.insertAt(10, 5)(new Set([1, 2, 3, 4])), O.none()) + }) + + it("replace", () => { + deepStrictEqual(pipe([1, 2, 3], RA.replace(1, "a")), [1, "a", 3]) + // out of bound + deepStrictEqual(pipe([], RA.replace(1, "a")), []) + deepStrictEqual(pipe([1, 2, 3], RA.replace(-1, "a")), [1, 2, 3]) + deepStrictEqual(pipe([1, 2, 3], RA.replace(10, "a")), [1, 2, 3]) + + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.replace(1, "a")), [1, "a", 3]) + // out of bound + deepStrictEqual(pipe(new Set([]), RA.replace(1, "a")), []) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.replace(-1, "a")), [1, 2, 3]) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.replace(10, "a")), [1, 2, 3]) + }) + + it("replaceOption", () => { + deepStrictEqual(pipe([1, 2, 3], RA.replaceOption(1, "a")), O.some([1, "a", 3])) + // out of bound + deepStrictEqual(pipe([], RA.replaceOption(1, "a")), O.none()) + deepStrictEqual(pipe([1, 2, 3], RA.replaceOption(-1, "a")), O.none()) + deepStrictEqual(pipe([1, 2, 3], RA.replaceOption(10, "a")), O.none()) + + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.replaceOption(1, "a")), O.some([1, "a", 3])) + // out of bound + deepStrictEqual(pipe(new Set([]), RA.replaceOption(1, "a")), O.none()) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.replaceOption(-1, "a")), O.none()) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.replaceOption(10, "a")), O.none()) + }) + + it("modify", () => { + deepStrictEqual(pipe([1, 2, 3], RA.modify(1, double)), [1, 4, 3]) + // out of bound + deepStrictEqual(pipe([], RA.modify(1, double)), []) + deepStrictEqual(pipe([1, 2, 3], RA.modify(10, double)), [1, 2, 3]) + + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.modify(1, double)), [1, 4, 3]) + // out of bound + deepStrictEqual(pipe(new Set([]), RA.modify(1, double)), []) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.modify(10, double)), [1, 2, 3]) + }) + + it("modifyOption", () => { + deepStrictEqual(pipe([1, 2, 3], RA.modifyOption(1, double)), O.some([1, 4, 3])) + // out of bound + deepStrictEqual(pipe([], RA.modifyOption(1, double)), O.none()) + deepStrictEqual(pipe([1, 2, 3], RA.modifyOption(10, double)), O.none()) + + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.modifyOption(1, double)), O.some([1, 4, 3])) + // out of bound + deepStrictEqual(pipe(new Set([]), RA.modifyOption(1, double)), O.none()) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.modifyOption(10, double)), O.none()) + }) + + it("remove", () => { + deepStrictEqual(pipe([1, 2, 3], RA.remove(0)), [2, 3]) + // out of bound + deepStrictEqual(pipe([], RA.remove(0)), []) + deepStrictEqual(pipe([1, 2, 3], RA.remove(-1)), [1, 2, 3]) + deepStrictEqual(pipe([1, 2, 3], RA.remove(10)), [1, 2, 3]) + + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.remove(0)), [2, 3]) + // out of bound + deepStrictEqual(pipe(new Set([]), RA.remove(0)), []) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.remove(-1)), [1, 2, 3]) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.remove(10)), [1, 2, 3]) + }) + + it("reverse", () => { + deepStrictEqual(RA.reverse([]), []) + deepStrictEqual(RA.reverse([1]), [1]) + deepStrictEqual(RA.reverse([1, 2, 3]), [3, 2, 1]) + + deepStrictEqual(RA.reverse(new Set([])), []) + deepStrictEqual(RA.reverse(new Set([1])), [1]) + deepStrictEqual(RA.reverse(new Set([1, 2, 3])), [3, 2, 1]) + }) + + it("rights", () => { + deepStrictEqual(RA.rights([]), []) + deepStrictEqual(RA.rights([E.right(1), E.left("a"), E.right(2)]), [1, 2]) + + deepStrictEqual(RA.rights(new Set>()), []) + deepStrictEqual(RA.rights(new Set([E.right(1), E.left("a"), E.right(2)])), [1, 2]) + }) + + it("lefts", () => { + deepStrictEqual(RA.lefts([]), []) + deepStrictEqual(RA.lefts([E.right(1), E.left("a"), E.right(2)]), ["a"]) + + deepStrictEqual(RA.lefts(new Set>()), []) + deepStrictEqual(RA.lefts(new Set([E.right(1), E.left("a"), E.right(2)])), ["a"]) + }) + + it("sort", () => { + deepStrictEqual(RA.sort(Number.Order)([]), []) + deepStrictEqual(RA.sort(Number.Order)([1, 3, 2]), [1, 2, 3]) + + deepStrictEqual(RA.sort(Number.Order)(new Set()), []) + deepStrictEqual(RA.sort(Number.Order)(new Set([1, 3, 2])), [1, 2, 3]) + }) + + it("zip", () => { + deepStrictEqual(pipe(new Set([]), RA.zip(new Set(["a", "b", "c", "d"]))), []) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.zip(new Set([]))), []) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.zip(new Set(["a", "b", "c", "d"]))), [ + [1, "a"], + [2, "b"], + [3, "c"] + ]) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.zip(new Set(["a", "b", "c", "d"]))), [ + [1, "a"], + [2, "b"], + [3, "c"] + ]) + }) + + it("zipWith", () => { + deepStrictEqual( + pipe(new Set([1, 2, 3]), RA.zipWith(new Set([]), (n, s) => s + n)), + [] + ) + deepStrictEqual( + pipe(new Set([]), RA.zipWith(new Set(["a", "b", "c", "d"]), (n, s) => s + n)), + [] + ) + deepStrictEqual( + pipe(new Set([]), RA.zipWith(new Set([]), (n, s) => s + n)), + [] + ) + deepStrictEqual( + pipe(new Set([1, 2, 3]), RA.zipWith(new Set(["a", "b", "c", "d"]), (n, s) => s + n)), + ["a1", "b2", "c3"] + ) + }) + + it("unzip", () => { + deepStrictEqual(RA.unzip(new Set([])), [[], []]) + deepStrictEqual( + RA.unzip( + new Set([ + [1, "a"], + [2, "b"], + [3, "c"] + ]) + ), + [ + [1, 2, 3], + ["a", "b", "c"] + ] + ) + }) + + it("intersperse", () => { + deepStrictEqual(pipe([], RA.intersperse(0)), []) + deepStrictEqual(pipe([1], RA.intersperse(0)), [1]) + deepStrictEqual(pipe([1, 2, 3], RA.intersperse(0)), [1, 0, 2, 0, 3]) + deepStrictEqual(pipe([1, 2], RA.intersperse(0)), [1, 0, 2]) + deepStrictEqual(pipe([1, 2, 3, 4], RA.intersperse(0)), [1, 0, 2, 0, 3, 0, 4]) + + deepStrictEqual(pipe(new Set([]), RA.intersperse(0)), []) + deepStrictEqual(pipe(new Set([1]), RA.intersperse(0)), [1]) + deepStrictEqual(pipe(new Set([1, 2, 3]), RA.intersperse(0)), [1, 0, 2, 0, 3]) + deepStrictEqual(pipe(new Set([1, 2]), RA.intersperse(0)), [1, 0, 2]) + deepStrictEqual(pipe(new Set([1, 2, 3, 4]), RA.intersperse(0)), [1, 0, 2, 0, 3, 0, 4]) + }) + + it("rotate", () => { + deepStrictEqual(RA.rotate(0)(RA.empty()), RA.empty()) + deepStrictEqual(RA.rotate(1)(RA.empty()), RA.empty()) + deepStrictEqual(RA.rotate(1)([1]), [1]) + deepStrictEqual(RA.rotate(2)([1]), [1]) + deepStrictEqual(RA.rotate(-1)([1]), [1]) + deepStrictEqual(RA.rotate(-2)([1]), [1]) + deepStrictEqual(RA.rotate(2)([1, 2]), [1, 2]) + deepStrictEqual(RA.rotate(0)([1, 2]), [1, 2]) + deepStrictEqual(RA.rotate(-2)([1, 2]), [1, 2]) + deepStrictEqual(RA.rotate(1)([1, 2]), [2, 1]) + deepStrictEqual(RA.rotate(1)(new Set([1, 2, 3, 4, 5])), [5, 1, 2, 3, 4]) + deepStrictEqual(RA.rotate(2)(new Set([1, 2, 3, 4, 5])), [4, 5, 1, 2, 3]) + deepStrictEqual(RA.rotate(-1)(new Set([1, 2, 3, 4, 5])), [2, 3, 4, 5, 1]) + deepStrictEqual(RA.rotate(-2)(new Set([1, 2, 3, 4, 5])), [3, 4, 5, 1, 2]) + // out of bounds + deepStrictEqual(RA.rotate(7)([1, 2, 3, 4, 5]), [4, 5, 1, 2, 3]) + deepStrictEqual(RA.rotate(-7)([1, 2, 3, 4, 5]), [3, 4, 5, 1, 2]) + deepStrictEqual(RA.rotate(2.2)([1, 2, 3, 4, 5]), [4, 5, 1, 2, 3]) + deepStrictEqual(RA.rotate(-2.2)([1, 2, 3, 4, 5]), [3, 4, 5, 1, 2]) + }) + + it("contains", () => { + const contains = RA.contains(Number.Equivalence) + deepStrictEqual(pipe([1, 2, 3], contains(2)), true) + deepStrictEqual(pipe([1, 2, 3], contains(0)), false) + + deepStrictEqual(pipe(new Set([1, 2, 3]), contains(2)), true) + deepStrictEqual(pipe(new Set([1, 2, 3]), contains(0)), false) + }) + + it("uniq", () => { + const uniq = RA.uniq(Number.Equivalence) + deepStrictEqual(uniq([]), []) + deepStrictEqual(uniq([-0, -0]), [-0]) + deepStrictEqual(uniq([0, -0]), [0]) + deepStrictEqual(uniq([1]), [1]) + deepStrictEqual(uniq([2, 1, 2]), [2, 1]) + deepStrictEqual(uniq([1, 2, 1]), [1, 2]) + deepStrictEqual(uniq([1, 2, 3, 4, 5]), [1, 2, 3, 4, 5]) + deepStrictEqual(uniq([1, 1, 2, 2, 3, 3, 4, 4, 5, 5]), [1, 2, 3, 4, 5]) + deepStrictEqual(uniq([1, 2, 3, 4, 5, 1, 2, 3, 4, 5]), [1, 2, 3, 4, 5]) + }) + + it("splitAt", () => { + const assertSplitAt = ( + input: ReadonlyArray, + index: number, + expectedInit: ReadonlyArray, + expectedRest: ReadonlyArray + ) => { + const [init, rest] = RA.splitAt(index)(input) + deepStrictEqual(init, expectedInit) + deepStrictEqual(rest, expectedRest) + } + deepStrictEqual(RA.splitAt(1)([1, 2]), [[1], [2]]) + assertSplitAt([1, 2], 2, [1, 2], []) + deepStrictEqual(RA.splitAt(2)([1, 2, 3, 4, 5]), [ + [1, 2], + [3, 4, 5] + ]) + deepStrictEqual(RA.splitAt(2)(new Set([1, 2, 3, 4, 5])), [ + [1, 2], + [3, 4, 5] + ]) + assertSplitAt([], 0, [], []) + assertSplitAt([1, 2], 0, [], [1, 2]) + + // out of bounds + assertSplitAt([], -1, [], []) + assertSplitAt([1, 2], -1, [], [1, 2]) + assertSplitAt([1, 2], 3, [1, 2], []) + assertSplitAt([], 3, [], []) + }) + }) + + it("splitNonEmptyAt", () => { + deepStrictEqual(pipe(RA.make(1, 2, 3, 4), RA.splitNonEmptyAt(2)), [[1, 2], [3, 4]]) + }) + + it("rotateNonEmpty", () => { + deepStrictEqual(RA.rotateNonEmpty(2)([1, 2, 3, 4, 5]), [4, 5, 1, 2, 3]) + }) + + it("intersperseNonEmpty", () => { + deepStrictEqual(pipe(RA.make(1), RA.intersperseNonEmpty(0)), [1]) + deepStrictEqual(pipe(RA.make(1, 2, 3), RA.intersperseNonEmpty(0)), [1, 0, 2, 0, 3]) + }) + + it("sortNonEmpty", () => { + deepStrictEqual(RA.sortNonEmpty(Number.Order)([1]), [1]) + deepStrictEqual(RA.sortNonEmpty(Number.Order)([1, 3, 2]), [1, 2, 3]) + }) + + describe("unsafeGet", () => { + it("should throw on index out of bound", () => { + expect(() => pipe([], RA.unsafeGet(100))).toThrowError(new Error("Index 100 out of bounds")) + }) + }) + + it("fromNullable", () => { + deepStrictEqual(RA.fromNullable(undefined), []) + deepStrictEqual(RA.fromNullable(null), []) + deepStrictEqual(RA.fromNullable(1), [1]) + }) + + it("liftNullable", () => { + const f = RA.liftNullable((n: number) => (n > 0 ? n : null)) + deepStrictEqual(f(1), [1]) + deepStrictEqual(f(-1), []) + }) + + it("flatMapNullable", () => { + const f = RA.flatMapNullable((n: number) => (n > 0 ? n : null)) + deepStrictEqual(pipe([], f), []) + deepStrictEqual(pipe([1], f), [1]) + deepStrictEqual(pipe([-1], f), []) + }) + + it("liftPredicate", () => { + const p = (n: number): boolean => n > 2 + const f = RA.liftPredicate(p) + deepStrictEqual(f(1), []) + deepStrictEqual(f(3), [3]) + }) + + it("liftOption", () => { + const f = RA.liftOption((n: number) => (n > 0 ? O.some(n) : O.none())) + deepStrictEqual(f(1), [1]) + deepStrictEqual(f(-1), []) + }) + + it("unprepend", () => { + deepStrictEqual(RA.unprepend([0]), [0, []]) + deepStrictEqual(RA.unprepend([1, 2, 3, 4]), [1, [2, 3, 4]]) + }) + + it("unappend", () => { + deepStrictEqual(RA.unappend([0]), [[], 0]) + deepStrictEqual(RA.unappend([1, 2, 3, 4]), [ + RA.make(1, 2, 3), + 4 + ]) + deepStrictEqual(RA.unappend([0]), [[], 0]) + deepStrictEqual(RA.unappend([1, 2, 3, 4]), [ + RA.make(1, 2, 3), + 4 + ]) + }) + + it("modifyNonEmptyHead", () => { + const f = (s: string) => s + "!" + deepStrictEqual(pipe(["a"], RA.modifyNonEmptyHead(f)), ["a!"]) + deepStrictEqual(pipe(["a", "b"], RA.modifyNonEmptyHead(f)), ["a!", "b"]) + deepStrictEqual(pipe(["a", "b", "c"], RA.modifyNonEmptyHead(f)), ["a!", "b", "c"]) + }) + + it("modifyNonEmptyLast", () => { + const f = (s: string) => s + "!" + deepStrictEqual(pipe(["a"], RA.modifyNonEmptyLast(f)), ["a!"]) + deepStrictEqual(pipe(["a", "b"], RA.modifyNonEmptyLast(f)), ["a", "b!"]) + deepStrictEqual(pipe(["a", "b", "c"], RA.modifyNonEmptyLast(f)), ["a", "b", "c!"]) + }) + + it("setNonEmptyHead", () => { + deepStrictEqual(pipe(RA.make("a"), RA.setNonEmptyHead("d")), ["d"]) + deepStrictEqual(pipe(RA.make("a", "b"), RA.setNonEmptyHead("d")), ["d", "b"]) + deepStrictEqual(pipe(RA.make("a", "b", "c"), RA.setNonEmptyHead("d")), ["d", "b", "c"]) + }) + + it("setNonEmptyLast", () => { + deepStrictEqual(pipe(RA.make("a"), RA.setNonEmptyLast("d")), ["d"]) + deepStrictEqual(pipe(RA.make("a", "b"), RA.setNonEmptyLast("d")), ["a", "d"]) + deepStrictEqual(pipe(RA.make("a", "b", "c"), RA.setNonEmptyLast("d")), ["a", "b", "d"]) + }) + + it("liftEither", () => { + const f = RA.liftEither((s: string) => s.length > 2 ? E.right(s.length) : E.left("e")) + deepStrictEqual(f("a"), []) + deepStrictEqual(f("aaa"), [3]) + }) + + it("headNonEmpty", () => { + deepStrictEqual(RA.headNonEmpty(RA.make(1, 2)), 1) + }) + + it("tailNonEmpty", () => { + deepStrictEqual(RA.tailNonEmpty(RA.make(1, 2)), [2]) + }) + + it("lastNonEmpty", () => { + deepStrictEqual(RA.lastNonEmpty(RA.make(1, 2, 3)), 3) + deepStrictEqual(RA.lastNonEmpty([1]), 1) + }) + + it("initNonEmpty", () => { + deepStrictEqual( + RA.initNonEmpty(RA.make(1, 2, 3)), + RA.make(1, 2) + ) + deepStrictEqual(RA.initNonEmpty([1]), []) + }) + + it("traverse", () => { + const traverse = RA.traverse(O.Applicative)(( + n: number + ): O.Option => (n % 2 === 0 ? O.none() : O.some(n))) + deepStrictEqual(traverse([1, 2]), O.none()) + deepStrictEqual(traverse([1, 3]), O.some([1, 3])) + }) + + it("sequence", () => { + const sequence = RA.sequence(O.Applicative) + deepStrictEqual(sequence([O.some(1), O.some(3)]), O.some([1, 3])) + deepStrictEqual(sequence([O.some(1), O.none()]), O.none()) + }) + + it("traverseWithIndex", () => { + deepStrictEqual( + pipe( + ["a", "bb"], + RA.traverseWithIndex(O.Applicative)(( + s, + i + ) => (s.length >= 1 ? O.some(s + i) : O.none())) + ), + O.some(["a0", "bb1"]) + ) + deepStrictEqual( + pipe( + ["a", "bb"], + RA.traverseWithIndex(O.Applicative)(( + s, + i + ) => (s.length > 1 ? O.some(s + i) : O.none())) + ), + O.none() + ) + }) + + it("get", () => { + deepStrictEqual(pipe([1, 2, 3], RA.get(0)), O.some(1)) + deepStrictEqual(pipe([1, 2, 3], RA.get(3)), O.none()) + }) + + it("unfold", () => { + const as = RA.unfold(5, (n) => (n > 0 ? O.some([n, n - 1]) : O.none())) + deepStrictEqual(as, [5, 4, 3, 2, 1]) + }) + + it("map", () => { + deepStrictEqual( + pipe( + [1, 2, 3], + RA.map((n) => n * 2) + ), + [2, 4, 6] + ) + }) + + it("mapWithIndex", () => { + deepStrictEqual( + pipe( + ["a", "b"], + RA.mapWithIndex((s, i) => s + i) + ), + ["a0", "b1"] + ) + }) + + it("ap", () => { + deepStrictEqual( + pipe([(x: number) => x * 2, (x: number) => x * 3], RA.ap([1, 2, 3])), + [ + 2, + 4, + 6, + 3, + 6, + 9 + ] + ) + }) + + it("flatMap", () => { + deepStrictEqual( + pipe( + [1, 2, 3], + RA.flatMap((n) => [n, n + 1]) + ), + [1, 2, 2, 3, 3, 4] + ) + }) + + it("flatMapWithIndex", () => { + const f = RA.flatMapWithIndex((n: number, i) => [n + i]) + deepStrictEqual(pipe([1, 2, 3], f), [1, 3, 5]) + deepStrictEqual(pipe(RA.empty(), f), RA.empty()) + const empty: ReadonlyArray = [] + deepStrictEqual(pipe(empty, f), RA.empty()) + }) + + it("extend", () => { + const sum = (as: ReadonlyArray) => Number.MonoidSum.combineAll(as) + deepStrictEqual(pipe([1, 2, 3, 4], RA.extend(sum)), [10, 9, 7, 4]) + deepStrictEqual(pipe([1, 2, 3, 4], RA.extend(identity)), [ + [1, 2, 3, 4], + [2, 3, 4], + [3, 4], + [ + 4 + ] + ]) + }) + + it("foldMap", () => { + deepStrictEqual(pipe(["a", "b", "c"], RA.foldMap(String.Monoid)(identity)), "abc") + deepStrictEqual(pipe([], RA.foldMap(String.Monoid)(identity)), "") + }) + + it("compact", () => { + deepStrictEqual(RA.compact([]), []) + deepStrictEqual(RA.compact([O.some(1), O.some(2), O.some(3)]), [ + 1, + 2, + 3 + ]) + deepStrictEqual(RA.compact([O.some(1), O.none(), O.some(3)]), [ + 1, + 3 + ]) + }) + + it("separate", () => { + deepStrictEqual(RA.separate([]), [[], []]) + deepStrictEqual( + RA.separate([E.left(123), E.right("123")]), + [[123], ["123"]] + ) + }) + + it("filter", () => { + const g = (n: number) => n % 2 === 1 + deepStrictEqual(pipe([1, 2, 3], RA.filter(g)), [1, 3]) + const x = pipe( + [O.some(3), O.some(2), O.some(1)], + RA.filter(O.isSome) + ) + assert.deepStrictEqual(x, [O.some(3), O.some(2), O.some(1)]) + const y = pipe( + [O.some(3), O.none(), O.some(1)], + RA.filter(O.isSome) + ) + assert.deepStrictEqual(y, [O.some(3), O.some(1)]) + }) + + it("filterWithIndex", () => { + const f = (n: number) => n % 2 === 0 + deepStrictEqual(pipe(["a", "b", "c"], RA.filterWithIndex((_, i) => f(i))), [ + "a", + "c" + ]) + }) + + it("filterMap", () => { + const f = (n: number) => (n % 2 === 0 ? O.none() : O.some(n)) + deepStrictEqual(pipe([1, 2, 3], RA.filterMap(f)), [1, 3]) + deepStrictEqual(pipe([], RA.filterMap(f)), []) + }) + + it("foldMapWithIndex", () => { + deepStrictEqual( + pipe( + ["a", "b"], + RA.foldMapWithIndex(String.Monoid)((a, i) => i + a) + ), + "0a1b" + ) + }) + + it("filterMapWithIndex", () => { + const f = (n: number, i: number) => ((i + n) % 2 === 0 ? O.none() : O.some(n)) + deepStrictEqual(pipe([1, 2, 4], RA.filterMapWithIndex(f)), [1, 2]) + deepStrictEqual(pipe([], RA.filterMapWithIndex(f)), []) + }) + + it("partitionMap", () => { + deepStrictEqual(pipe([], RA.partitionMap(identity)), [[], []]) + deepStrictEqual( + pipe( + [E.right(1), E.left("foo"), E.right(2)], + RA.partitionMap(identity) + ), + [["foo"], [1, 2]] + ) + }) + + it("partition", () => { + deepStrictEqual( + pipe([], RA.partition((n) => n > 2)), + [[], []] + ) + deepStrictEqual( + pipe([1, 3], RA.partition((n) => n > 2)), + [[1], [3]] + ) + }) + + it("partitionMapWithIndex", () => { + deepStrictEqual( + pipe([], RA.partitionMapWithIndex((a) => a)), + [[], []] + ) + deepStrictEqual( + pipe( + [E.right(1), E.left("foo"), E.right(2)], + RA.partitionMapWithIndex((a, i) => pipe(a, E.filter((n) => n > i, () => "err"))) + ), + [["foo", "err"], [1]] + ) + }) + + it("partitionWithIndex", () => { + deepStrictEqual( + pipe([], RA.partitionWithIndex((i, n) => i + n > 2)), + [[], []] + ) + deepStrictEqual( + pipe([1, 2], RA.partitionWithIndex((i, n) => i + n > 2)), + [[1], [2]] + ) + }) + + it("reduce", () => { + deepStrictEqual(pipe(["a", "b", "c"], RA.reduce("", (b, a) => b + a)), "abc") + }) + + it("reduceRight", () => { + const f = (b: string, a: string) => b + a + deepStrictEqual(pipe(["a", "b", "c"], RA.reduceRight("", f)), "cba") + deepStrictEqual(pipe([], RA.reduceRight("", f)), "") + }) + + it("reduceWithIndex", () => { + deepStrictEqual( + pipe( + ["a", "b"], + RA.reduceWithIndex("", (b, a, i) => b + i + a) + ), + "0a1b" + ) + }) + + it("reduceRightWithIndex", () => { + deepStrictEqual( + pipe( + ["a", "b"], + RA.reduceRightWithIndex("", (b, a, i) => b + i + a) + ), + "1b0a" + ) + }) + + it("traverseNonEmpty", () => { + const traverseNonEmpty = RA.traverseNonEmpty(O.Applicative) + deepStrictEqual( + pipe( + RA.make(1, 2, 3), + traverseNonEmpty((n) => (n >= 0 ? O.some(n) : O.none())) + ), + O.some(RA.make(1, 2, 3)) + ) + deepStrictEqual( + pipe( + RA.make(1, 2, 3), + traverseNonEmpty((n) => (n >= 2 ? O.some(n) : O.none())) + ), + O.none() + ) + }) + + it("traverseNonEmptyWithIndex", () => { + deepStrictEqual( + pipe( + RA.make("a", "bb"), + RA.traverseNonEmptyWithIndex(O.Applicative)(( + s, + i + ) => (s.length >= 1 ? O.some(s + i) : O.none())) + ), + O.some(RA.make("a0", "bb1")) + ) + deepStrictEqual( + pipe( + RA.make("a", "bb"), + RA.traverseNonEmptyWithIndex(O.Applicative)(( + s, + i + ) => (s.length > 1 ? O.some(s + i) : O.none())) + ), + O.none() + ) + }) + + it("getMonoid", () => { + const M = RA.getMonoid() + deepStrictEqual(M.combine([3, 4])([1, 2]), [1, 2, 3, 4]) + const x = [1, 2] + deepStrictEqual(M.combine(M.empty)(x), x) + deepStrictEqual(M.combine(x)(M.empty), x) + + deepStrictEqual(M.combineAll([[1, 2], [3, 4, 5], [5, 6, 7, 1]]), [1, 2, 3, 4, 5, 5, 6, 7, 1]) + }) + + it("liftOrder", () => { + const O = RA.liftOrder(String.Order) + deepStrictEqual(O.compare([])([]), 0) + deepStrictEqual(O.compare(["a"])(["a"]), 0) + + deepStrictEqual(O.compare(["b"])(["a"]), -1) + deepStrictEqual(O.compare(["a"])(["b"]), 1) + + deepStrictEqual(O.compare(["a"])([]), -1) + deepStrictEqual(O.compare([])(["a"]), 1) + deepStrictEqual(O.compare(["a", "a"])(["a"]), -1) + deepStrictEqual(O.compare(["a", "a"])(["b"]), 1) + + deepStrictEqual(O.compare(["a", "a"])(["a", "a"]), 0) + deepStrictEqual(O.compare(["a", "b"])(["a", "b"]), 0) + + deepStrictEqual(O.compare(["a", "a"])(["a", "b"]), 1) + deepStrictEqual(O.compare(["a", "b"])(["a", "a"]), -1) + + deepStrictEqual(O.compare(["a", "b"])(["b", "a"]), 1) + deepStrictEqual(O.compare(["b", "a"])(["a", "a"]), -1) + deepStrictEqual(O.compare(["b", "a"])(["a", "b"]), -1) + deepStrictEqual(O.compare(["b", "b"])(["b", "a"]), -1) + deepStrictEqual(O.compare(["b", "a"])(["b", "b"]), 1) + }) + + it("isEmpty", () => { + const as: ReadonlyArray = [1, 2, 3] + deepStrictEqual(RA.isEmpty(as), false) + deepStrictEqual(RA.isEmpty([]), true) + }) + + it("isNotEmpty", () => { + const as: ReadonlyArray = [1, 2, 3] + deepStrictEqual(RA.isNonEmpty(as), true) + deepStrictEqual(RA.isNonEmpty([]), false) + }) + + it("head", () => { + const as: ReadonlyArray = [1, 2, 3] + deepStrictEqual(RA.head(as), O.some(1)) + deepStrictEqual(RA.head([]), O.none()) + }) + + it("last", () => { + const as: ReadonlyArray = [1, 2, 3] + deepStrictEqual(RA.last(as), O.some(3)) + deepStrictEqual(RA.last([]), O.none()) + }) + + it("zipNonEmptyWith", () => { + deepStrictEqual( + pipe([1, 2, 3], RA.zipNonEmptyWith(["a", "b", "c", "d"], (n, s) => s + n)), + ["a1", "b2", "c3"] + ) + }) + + it("zipNonEmpty", () => { + deepStrictEqual(pipe(RA.make(1, 2, 3), RA.zipNonEmpty(["a", "b", "c", "d"])), [ + [1, "a"], + [2, "b"], + [3, "c"] + ]) + }) + + it("unzipNonEmpty", () => { + deepStrictEqual( + RA.unzipNonEmpty([ + [1, "a"], + [2, "b"], + [3, "c"] + ]), + [ + [1, 2, 3], + ["a", "b", "c"] + ] + ) + }) + + it("flatMapNonEmpty", () => { + const f = (a: number): RA.NonEmptyReadonlyArray => [a, 4] + deepStrictEqual(pipe(RA.make(1, 2), RA.flatMapNonEmpty(f)), [1, 4, 2, 4]) + }) + + it("flatMapNonEmptyWithIndex", () => { + const f = (a: number, i: number): RA.NonEmptyReadonlyArray => [a + i, 4] + deepStrictEqual(pipe(RA.make(1, 2), RA.flatMapNonEmptyWithIndex(f)), [1, 4, 3, 4]) + }) + + it("chunksOfNonEmpty", () => { + deepStrictEqual(RA.chunksOfNonEmpty(2)([1, 2, 3, 4, 5]), [ + RA.make(1, 2), + [3, 4], + [5] + ]) + deepStrictEqual(RA.chunksOfNonEmpty(2)([1, 2, 3, 4, 5, 6]), [ + RA.make(1, 2), + [3, 4], + [5, 6] + ]) + deepStrictEqual(RA.chunksOfNonEmpty(1)([1, 2, 3, 4, 5]), [[1], [2], [3], [4], [5]]) + deepStrictEqual(RA.chunksOfNonEmpty(5)([1, 2, 3, 4, 5]), [[1, 2, 3, 4, 5]]) + // out of bounds + deepStrictEqual(RA.chunksOfNonEmpty(0)([1, 2, 3, 4, 5]), [[1], [2], [3], [4], [5]]) + deepStrictEqual(RA.chunksOfNonEmpty(-1)([1, 2, 3, 4, 5]), [[1], [2], [3], [4], [5]]) + + const assertSingleChunk = ( + input: RA.NonEmptyReadonlyArray, + n: number + ) => { + const chunks = RA.chunksOfNonEmpty(n)(input) + strictEqual(chunks.length, 1) + deepStrictEqual(RA.headNonEmpty(chunks), input) + } + // n = length + assertSingleChunk(RA.make(1, 2), 2) + // n out of bounds + assertSingleChunk(RA.make(1, 2), 3) + }) + + it("mapNonEmpty", () => { + deepStrictEqual( + pipe( + RA.make(RA.make(1, 2), RA.make(3, 4)), + RA.flattenNonEmpty + ), + [1, 2, 3, 4] + ) + }) + + it("sequenceNonEmpty", () => { + const sequence = RA.sequenceNonEmpty(O.Applicative) + deepStrictEqual( + sequence([O.some(1), O.some(2), O.some(3)]), + O.some(RA.make(1, 2, 3)) + ) + deepStrictEqual(sequence([O.none(), O.some(2), O.some(3)]), O.none()) + }) + + it("mapNonEmpty", () => { + deepStrictEqual( + pipe( + RA.make(1, 2), + RA.mapNonEmpty((n) => n * 2) + ), + [2, 4] + ) + }) + + it("mapNonEmptyWithIndex", () => { + const add = (s: string, i: number) => s + i + deepStrictEqual( + pipe(RA.make("a", "b"), RA.mapNonEmptyWithIndex(add)), + ["a0", "b1"] + ) + }) + + it("min", () => { + deepStrictEqual(RA.min(Number.Order)([2, 1, 3]), 1) + deepStrictEqual(RA.min(Number.Order)([3]), 3) + }) + + it("max", () => { + deepStrictEqual( + RA.max(Number.Order)(RA.make(1, 2, 3)), + 3 + ) + deepStrictEqual(RA.max(Number.Order)([1]), 1) + }) + + it("flatten", () => { + deepStrictEqual(RA.flatten([[1], [2], [3]]), [1, 2, 3]) + }) + + it("intercalate", () => { + deepStrictEqual(RA.intercalate(String.Monoid)("-")([]), "") + deepStrictEqual(RA.intercalate(String.Monoid)("-")(["a"]), "a") + deepStrictEqual(RA.intercalate(String.Monoid)("-")(["a", "b", "c"]), "a-b-c") + deepStrictEqual(RA.intercalate(String.Monoid)("-")(["a", "", "c"]), "a--c") + deepStrictEqual(RA.intercalate(String.Monoid)("-")(["a", "b"]), "a-b") + deepStrictEqual(RA.intercalate(String.Monoid)("-")(["a", "b", "c", "d"]), "a-b-c-d") + }) + + it("group", () => { + const group = RA.group(Number.Equivalence) + deepStrictEqual(group([1, 2, 1, 1]), [[1], [2], [1, 1]]) + deepStrictEqual(group([1, 2, 1, 1, 3]), [[1], [2], [1, 1], [3]]) + }) + + it("groupBy", () => { + deepStrictEqual(RA.groupBy((_) => "")([]), {}) + deepStrictEqual(RA.groupBy((a) => `${a}`)([1]), { "1": [1] }) + deepStrictEqual( + RA.groupBy((s: string) => `${s.length}`)(["foo", "bar", "foobar"]), + { + "3": ["foo", "bar"], + "6": ["foobar"] + } + ) + }) + + it("reverseNonEmpty", () => { + deepStrictEqual(RA.reverseNonEmpty([1]), [1]) + deepStrictEqual(RA.reverseNonEmpty(RA.make(1, 2, 3)), [3, 2, 1]) + }) + + it("match", () => { + const len: (as: ReadonlyArray) => number = RA.match( + () => 0, + (_, tail) => 1 + len(tail) + ) + deepStrictEqual(len([1, 2, 3]), 3) + }) + + it("matchRight", () => { + const len: (as: ReadonlyArray) => number = RA.matchRight( + () => 0, + (init, _) => 1 + len(init) + ) + deepStrictEqual(len([1, 2, 3]), 3) + }) + + it("uniqNonEmpty", () => { + const uniqNonEmpty = RA.uniqNonEmpty(String.Equivalence) + deepStrictEqual(uniqNonEmpty(["a", "b", "A"]), ["a", "b", "A"]) + }) + + it("sortBy / sortByNonEmpty", () => { + interface X { + readonly a: string + readonly b: number + readonly c: boolean + } + + const byName = pipe( + String.Order, + Order.contramap((p: { readonly a: string; readonly b: number }) => p.a) + ) + + const byAge = pipe( + Number.Order, + Order.contramap((p: { readonly a: string; readonly b: number }) => p.b) + ) + + const sortByNameByAge = RA.sortBy(byName, byAge) + + const xs: RA.NonEmptyArray = [ + { a: "a", b: 1, c: true }, + { a: "b", b: 3, c: true }, + { a: "c", b: 2, c: true }, + { a: "b", b: 2, c: true } + ] + + deepStrictEqual(RA.sortBy()(xs), xs) + deepStrictEqual(sortByNameByAge([]), []) + deepStrictEqual(sortByNameByAge(xs), [ + { a: "a", b: 1, c: true }, + { a: "b", b: 2, c: true }, + { a: "b", b: 3, c: true }, + { a: "c", b: 2, c: true } + ]) + + deepStrictEqual(RA.sortBy()(new Set(xs)), xs) + deepStrictEqual(sortByNameByAge(new Set([])), []) + deepStrictEqual(sortByNameByAge(new Set(xs)), [ + { a: "a", b: 1, c: true }, + { a: "b", b: 2, c: true }, + { a: "b", b: 3, c: true }, + { a: "c", b: 2, c: true } + ]) + + const sortByAgeByName = RA.sortByNonEmpty(byAge, byName) + deepStrictEqual(sortByAgeByName(xs), [ + { a: "a", b: 1, c: true }, + { a: "b", b: 2, c: true }, + { a: "c", b: 2, c: true }, + { a: "b", b: 3, c: true } + ]) + }) + + it("copy", () => { + expect(pipe([], RA.copy)).toEqual([]) + expect(pipe([1, 2, 3], RA.copy)).toEqual([1, 2, 3]) + }) + + it("intercalateNonEmpty", () => { + expect(pipe(["a"], RA.intercalateNonEmpty(String.Semigroup)("b"))).toEqual("a") + expect(pipe(["a1", "a2"], RA.intercalateNonEmpty(String.Semigroup)("b"))).toEqual("a1ba2") + }) + + it("join", () => { + expect(pipe([], RA.join(", "))).toEqual("") + expect(pipe(["a"], RA.join(", "))).toEqual("a") + expect(pipe(["a", "b"], RA.join(", "))).toEqual("a, b") + }) + + it("chop", () => { + const f = RA.chop((as) => [as[0] * 2, as.slice(1)]) + const empty: ReadonlyArray = [] + deepStrictEqual(f(empty), RA.empty()) + deepStrictEqual(f(RA.empty()), RA.empty()) + deepStrictEqual(f([1, 2, 3]), [2, 4, 6]) + deepStrictEqual(RA.chopNonEmpty((as) => [as[0] * 2, as.slice(1)])([1, 2, 3]), [ + 2, + 4, + 6 + ]) + }) + + describe.concurrent("chunksOf", () => { + it("should split a `ReadonlyArray` into length-n pieces", () => { + deepStrictEqual(RA.chunksOf(2)([1, 2, 3, 4, 5]), [[1, 2], [3, 4], [5]]) + deepStrictEqual(RA.chunksOf(2)([1, 2, 3, 4, 5, 6]), [ + [1, 2], + [3, 4], + [5, 6] + ]) + deepStrictEqual(RA.chunksOf(1)([1, 2, 3, 4, 5]), [[1], [2], [3], [4], [5]]) + deepStrictEqual(RA.chunksOf(5)([1, 2, 3, 4, 5]), [[1, 2, 3, 4, 5]]) + // out of bounds + deepStrictEqual(RA.chunksOf(0)([1, 2, 3, 4, 5]), [[1], [2], [3], [4], [5]]) + deepStrictEqual(RA.chunksOf(-1)([1, 2, 3, 4, 5]), [[1], [2], [3], [4], [5]]) + + const assertSingleChunk = (input: ReadonlyArray, n: number) => { + const chunks = RA.chunksOf(n)(input) + deepStrictEqual(chunks.length, 1) + deepStrictEqual(chunks[0], input) + } + // n = length + assertSingleChunk([1, 2], 2) + // n out of bounds + assertSingleChunk([1, 2], 3) + }) + + it("returns an empty array if provided an empty array", () => { + const empty: ReadonlyArray = [] + deepStrictEqual(RA.chunksOf(0)(empty), RA.empty()) + deepStrictEqual(RA.chunksOf(0)(RA.empty()), RA.empty()) + deepStrictEqual(RA.chunksOf(1)(empty), RA.empty()) + deepStrictEqual(RA.chunksOf(1)(RA.empty()), RA.empty()) + deepStrictEqual(RA.chunksOf(2)(empty), RA.empty()) + deepStrictEqual(RA.chunksOf(2)(RA.empty()), RA.empty()) + }) + + it("should respect the law: chunksOf(n)(xs).concat(chunksOf(n)(ys)) == chunksOf(n)(xs.concat(ys)))", () => { + const xs: ReadonlyArray = [] + const ys: ReadonlyArray = [1, 2] + deepStrictEqual( + RA.chunksOf(2)(xs).concat(RA.chunksOf(2)(ys)), + RA.chunksOf(2)(xs.concat(ys)) + ) + fc.assert( + fc.property( + fc.array(fc.integer()).filter((xs) => xs.length % 2 === 0), // Ensures `xs.length` is even + fc.array(fc.integer()), + fc.integer({ min: 1, max: 1 }).map((x) => x * 2), // Generates `n` to be even so that it evenly divides `xs` + (xs, ys, n) => { + const as = RA.chunksOf(n)(xs).concat(RA.chunksOf(n)(ys)) + const bs = RA.chunksOf(n)(xs.concat(ys)) + deepStrictEqual(as, bs) + } + ) + ) + }) + }) + + it("makeBy", () => { + deepStrictEqual(RA.makeBy(double)(5), [0, 2, 4, 6, 8]) + deepStrictEqual(RA.makeBy(double)(2.2), [0, 2]) + }) + + it("replicate", () => { + deepStrictEqual(RA.replicate("a")(0), ["a"]) + deepStrictEqual(RA.replicate("a")(-1), ["a"]) + deepStrictEqual(RA.replicate("a")(3), ["a", "a", "a"]) + deepStrictEqual(RA.replicate("a")(2.2), ["a", "a"]) + }) + + it("range", () => { + deepStrictEqual(RA.range(0, 0), [0]) + deepStrictEqual(RA.range(0, 1), [0, 1]) + deepStrictEqual(RA.range(1, 5), [1, 2, 3, 4, 5]) + deepStrictEqual(RA.range(10, 15), [10, 11, 12, 13, 14, 15]) + deepStrictEqual(RA.range(-1, 0), [-1, 0]) + deepStrictEqual(RA.range(-5, -1), [-5, -4, -3, -2, -1]) + // out of bound + deepStrictEqual(RA.range(2, 1), [2]) + deepStrictEqual(RA.range(-1, -2), [-1]) + }) + + it("union", () => { + const union = RA.union(Number.Equivalence) + const two: ReadonlyArray = [1, 2] + deepStrictEqual(pipe(two, union([3, 4])), [1, 2, 3, 4]) + deepStrictEqual(pipe(two, union([2, 3])), [1, 2, 3]) + deepStrictEqual(pipe(two, union([1, 2])), [1, 2]) + deepStrictEqual(pipe(two, union(RA.empty())), two) + deepStrictEqual(pipe(RA.empty(), union(two)), two) + deepStrictEqual( + pipe(RA.empty(), union(RA.empty())), + RA.empty() + ) + deepStrictEqual(RA.unionNonEmpty(Number.Equivalence)([3, 4])([1, 2]), [1, 2, 3, 4]) + }) + + it("getSemigroup", () => { + const S = RA.getSemigroup() + expect(pipe([1, 2], S.combine([2, 3]))).toEqual([1, 2, 2, 3]) + }) + + it("getUnionSemigroup", () => { + const S = RA.getUnionSemigroup(Number.Equivalence) + expect(pipe([1, 2], S.combine([2, 3]))).toEqual([1, 2, 3]) + }) + + it("intersection", () => { + const intersection = RA.intersection(Number.Equivalence) + deepStrictEqual(pipe([1, 2], intersection([3, 4])), []) + deepStrictEqual(pipe([1, 2], intersection([2, 3])), [2]) + deepStrictEqual(pipe([1, 2], intersection([1, 2])), [1, 2]) + }) + + it("difference", () => { + const difference = RA.difference(Number.Equivalence) + deepStrictEqual(pipe([1, 2], difference([3, 4])), [1, 2]) + deepStrictEqual(pipe([1, 2], difference([2, 3])), [1]) + deepStrictEqual(pipe([1, 2], difference([1, 2])), []) + }) + + it("getUnionMonoid", () => { + const M = RA.getUnionMonoid(Number.Equivalence) + const two: ReadonlyArray = [1, 2] + deepStrictEqual(M.combine([3, 4])(two), [1, 2, 3, 4]) + deepStrictEqual(M.combine([2, 3])(two), [1, 2, 3]) + deepStrictEqual(M.combine([1, 2])(two), [1, 2]) + + deepStrictEqual(M.combine(two)(M.empty), two) + deepStrictEqual(M.combine(M.empty)(two), two) + deepStrictEqual(M.combine(M.empty)(M.empty), M.empty) + + deepStrictEqual(M.combineAll([[1, 2], [3, 4, 5], [5, 6, 7, 1]]), [1, 2, 3, 4, 5, 6, 7]) + }) + + it("getIntersectionSemigroup", () => { + const S = RA.getIntersectionSemigroup(Number.Equivalence) + deepStrictEqual(S.combine([1, 2])([3, 4]), []) + deepStrictEqual(S.combine([1, 2])([2, 3]), [2]) + deepStrictEqual(S.combine([1, 2])([1, 2]), [1, 2]) + }) + + it("should be safe when calling map with a binary function", () => { + interface Foo { + readonly bar: () => number + } + const f = (a: number, x?: Foo) => (x !== undefined ? `${a}${x.bar()}` : `${a}`) + deepStrictEqual(pipe([1, 2], RA.map(f)), ["1", "2"]) + }) + + it("empty", () => { + deepStrictEqual(RA.empty.length, 0) + }) + + it("do notation", () => { + deepStrictEqual( + pipe( + RA.Do, + RA.bind("a", () => [1, 2, 3]), + RA.map(({ a }) => a * 2) + ), + [2, 4, 6] + ) + + deepStrictEqual( + pipe( + RA.Do, + RA.bind("a", () => [1, 2, 3]), + RA.bind("b", () => ["a", "b"]), + RA.map(({ a, b }) => [a, b] as const) + ), + [ + [1, "a"], + [1, "b"], + [2, "a"], + [2, "b"], + [3, "a"], + [3, "b"] + ] + ) + + deepStrictEqual( + pipe( + RA.Do, + RA.bind("a", () => [1, 2, 3]), + RA.bind("b", () => ["a", "b"]), + RA.map(({ a, b }) => [a, b] as const), + RA.filter(([a, b]) => (a + b.length) % 2 === 0) + ), + [ + [1, "a"], + [1, "b"], + [3, "a"], + [3, "b"] + ] + ) + }) + + it("every", () => { + const isPositive: Predicate = (n) => n > 0 + deepStrictEqual(pipe([1, 2, 3], RA.every(isPositive)), true) + deepStrictEqual(pipe([1, 2, -3], RA.every(isPositive)), false) + }) + + it("foldMapNonEmpty", () => { + deepStrictEqual( + pipe( + RA.make("a", "b", "c"), + RA.foldMapNonEmpty(String.Semigroup)(identity) + ), + "abc" + ) + }) + + it("foldMapNonEmptyWithIndex", () => { + deepStrictEqual( + pipe( + RA.make("a", "b"), + RA.foldMapNonEmptyWithIndex(String.Semigroup)((a, i) => i + a) + ), + "0a1b" + ) + }) + + it("some", () => { + const isPositive: Predicate = (n) => n > 0 + deepStrictEqual(pipe([-1, -2, 3], RA.some(isPositive)), true) + deepStrictEqual(pipe([-1, -2, -3], RA.some(isPositive)), false) + // has is an alias of some + deepStrictEqual(pipe([-1, -2, -3], RA.has(isPositive)), false) + }) + + it("size", () => { + deepStrictEqual(RA.size(RA.empty()), 0) + deepStrictEqual(RA.size([]), 0) + deepStrictEqual(RA.size(["a"]), 1) + }) + + it("fromOption", () => { + deepStrictEqual(RA.fromOption(O.some("hello")), ["hello"]) + deepStrictEqual(RA.fromOption(O.none()), []) + }) + + it("fromResult", () => { + deepStrictEqual(RA.fromEither(E.right(1)), [1]) + deepStrictEqual(RA.fromEither(E.left("a")), RA.empty()) + }) + + test("product", () => { + expect(pipe([], RA.product(["a", "b"]))).toEqual([]) + expect(pipe([1, 2], RA.product([]))).toEqual([]) + expect(pipe([1, 2], RA.product(["a", "b"]))).toEqual([ + [1, "a"], + [1, "b"], + [2, "a"], + [2, "b"] + ]) + }) + + test("productMany", () => { + const productMany = semiProduct.productMany(RA.Covariant, RA.product) + expect(pipe( + [], + RA.productMany([ + [2], + [4, 5], + [8, 9, 10] + ]) + )).toEqual(pipe( + [], + productMany([ + [2], + [4, 5], + [8, 9, 10] + ]) + )) + expect(pipe( + [1, 2, 3], + RA.productMany([]) + )).toEqual(pipe( + [1, 2, 3], + productMany([]) + )) + expect(pipe( + [1, 2, 3], + RA.productMany([ + [2], + [4, 5], + [8, 9, 10] + ]) + )).toEqual(pipe( + [1, 2, 3], + productMany([ + [2], + [4, 5], + [8, 9, 10] + ]) + )) + }) + + test("productAll", () => { + expect(RA.productAll([])).toEqual([]) + expect(RA.productAll([[1, 2, 3]])).toEqual([[1], [2], [3]]) + expect(RA.productAll([[1, 2, 3], [4, 5]])).toEqual([[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [ + 3, + 5 + ]]) + }) +}) diff --git a/test/internal/Iterable.ts b/test/internal/Iterable.ts deleted file mode 100644 index 7ee04a196..000000000 --- a/test/internal/Iterable.ts +++ /dev/null @@ -1,12 +0,0 @@ -import * as iterable from "@fp-ts/core/internal/Iterable" - -describe.concurrent("internal/Iterable", () => { - it("fromIterable/Array should return the same reference if the iterable is an Array", () => { - const i = [1, 2, 3] - expect(iterable.fromIterable(i) === i).toEqual(true) - }) - - it("fromIterable/Iterable", () => { - expect(iterable.fromIterable(new Set([1, 2, 3]))).toEqual([1, 2, 3]) - }) -}) From 074c19ee575eb7b0fd270ccbed16f7f414ded816 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 15:05:45 +0100 Subject: [PATCH 023/255] chore: remove @category mutations --- src/Either.ts | 1 - src/ReadonlyArray.ts | 35 +---------------------------------- 2 files changed, 1 insertion(+), 35 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 421875f7a..1101c2435 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -852,7 +852,6 @@ export const liftThrowable = , B, E>( export const merge: (self: Either) => E | A = match(identity, identity) /** - * @category mutations * @since 1.0.0 */ export const reverse = (self: Either): Either => diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index b299f7ce3..8052add73 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -154,7 +154,6 @@ export const matchRight = ( /** * Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray`. * - * @category mutations * @since 1.0.0 */ export const prepend = ( @@ -162,14 +161,12 @@ export const prepend = ( ) => (self: Iterable): NonEmptyArray => [head, ...self] /** - * @category mutations * @since 1.0.0 */ export const prependAll = (that: Iterable) => (self: Iterable): Array => fromIterable(that).concat(fromIterable(self)) /** - * @category mutations * @since 1.0.0 */ export function prependAllNonEmpty( @@ -187,7 +184,6 @@ export function prependAllNonEmpty( /** * Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`. * - * @category mutations * @since 1.0.0 */ export const append = ( @@ -195,14 +191,12 @@ export const append = ( ) => (self: Iterable): NonEmptyArray => [...self, last] as any /** - * @category mutations * @since 1.0.0 */ export const appendAll = (that: Iterable) => (self: Iterable): Array => fromIterable(self).concat(fromIterable(that)) /** - * @category mutations * @since 1.0.0 */ export function appendAllNonEmpty( @@ -624,7 +618,6 @@ export function findLast(predicate: Predicate): (self: Iterable) => Opt * Insert an element at the specified index, creating a new `NonEmptyArray`, * or return `None` if the index is out of bounds. * - * @category mutations * @since 1.0.0 */ export const insertAt = (i: number, b: B) => @@ -642,7 +635,6 @@ export const insertAt = (i: number, b: B) => * Change the element at the specified index, creating a new `Array`, * or return a copy of the input if the index is out of bounds. * - * @category mutations * @since 1.0.0 */ export const replace = ( @@ -651,7 +643,6 @@ export const replace = ( ): ((self: Iterable) => Array) => modify(i, () => b) /** - * @category mutations * @since 1.0.0 */ export const replaceOption = ( @@ -663,7 +654,6 @@ export const replaceOption = ( * Apply a function to the element at the specified index, creating a new `Array`, * or return a copy of the input if the index is out of bounds. * - * @category mutations * @since 1.0.0 */ export const modify = (i: number, f: (a: A) => B) => @@ -673,8 +663,7 @@ export const modify = (i: number, f: (a: A) => B) => /** * Apply a function to the element at the specified index, creating a new `Array`, * or return `None` if the index is out of bounds. - -* @category mutations + * * @since 1.0.0 */ export const modifyOption = (i: number, f: (a: A) => B) => @@ -693,7 +682,6 @@ export const modifyOption = (i: number, f: (a: A) => B) => * Delete the element at the specified index, creating a new `Array`, * or return a copy of the input if the index is out of bounds. * - * @category mutations * @since 1.0.0 */ export const remove = (i: number) => @@ -709,7 +697,6 @@ export const remove = (i: number) => /** * Reverse an `Iterable`, creating a new `Array`. * - * @category mutations * @since 1.0.0 */ export const reverse = ( @@ -808,7 +795,6 @@ export const sortByNonEmpty = ( * If one input `Iterable` is short, excess elements of the * longer `Iterable` are discarded. * - * @category mutations * @since 1.0.0 */ export const zip = ( @@ -819,7 +805,6 @@ export const zip = ( * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results in a new `Array`. If one * input `Iterable` is short, excess elements of the longer `Iterable` are discarded. * - * @category mutations * @since 1.0.0 */ export const zipWith = (that: Iterable, f: (a: A, b: B) => C) => @@ -830,7 +815,6 @@ export const zipWith = (that: Iterable, f: (a: A, b: B) => C) => } /** - * @category mutations * @since 1.0.0 */ export const zipNonEmpty = (that: NonEmptyReadonlyArray) => @@ -841,7 +825,6 @@ export const zipNonEmpty = (that: NonEmptyReadonlyArray) => ) /** - * @category mutations * @since 1.0.0 */ export const zipNonEmptyWith = (that: NonEmptyReadonlyArray, f: (a: A, b: B) => C) => @@ -857,7 +840,6 @@ export const zipNonEmptyWith = (that: NonEmptyReadonlyArray, f: (a: /** * This function is the inverse of `zip`. Takes an `Iterable` of pairs and return two corresponding `Array`s. * - * @category mutations * @since 1.0.0 */ export const unzip = ( @@ -868,7 +850,6 @@ export const unzip = ( } /** - * @category mutations * @since 1.0.0 */ export const unzipNonEmpty = ( @@ -886,7 +867,6 @@ export const unzipNonEmpty = ( /** * Places an element in between members of an `Iterable` * - * @category mutations * @since 1.0.0 */ export const intersperse = (middle: B) => @@ -898,7 +878,6 @@ export const intersperse = (middle: B) => /** * Places an element in between members of a `NonEmptyReadonlyArray` * - * @category mutations * @since 1.0.0 */ export const intersperseNonEmpty = (middle: B) => @@ -917,7 +896,6 @@ export const intersperseNonEmpty = (middle: B) => /** * Apply a function to the head, creating a new `NonEmptyReadonlyArray`. * - * @category mutations * @since 1.0.0 */ export const modifyNonEmptyHead = (f: (a: A) => B) => @@ -928,7 +906,6 @@ export const modifyNonEmptyHead = (f: (a: A) => B) => /** * Change the head, creating a new `NonEmptyReadonlyArray`. * - * @category mutations * @since 1.0.0 */ export const setNonEmptyHead = ( @@ -938,7 +915,6 @@ export const setNonEmptyHead = ( /** * Apply a function to the last element, creating a new `NonEmptyReadonlyArray`. * - * @category mutations * @since 1.0.0 */ export const modifyNonEmptyLast = (f: (a: A) => B) => @@ -948,7 +924,6 @@ export const modifyNonEmptyLast = (f: (a: A) => B) => /** * Change the last element, creating a new `NonEmptyReadonlyArray`. * - * @category mutations * @since 1.0.0 */ export const setNonEmptyLast = ( @@ -958,7 +933,6 @@ export const setNonEmptyLast = ( /** * Rotate an `Iterable` by `n` steps. * - * @category mutations * @since 1.0.0 */ export const rotate = (n: number) => @@ -970,7 +944,6 @@ export const rotate = (n: number) => /** * Rotate a `NonEmptyReadonlyArray` by `n` steps. * - * @category mutations * @since 1.0.0 */ export const rotateNonEmpty = (n: number) => @@ -1008,7 +981,6 @@ export const contains = (equivalence: Equivalence) => /** * Remove duplicates from am `Iterable`, keeping the first occurrence of an element. * - * @category mutations * @since 1.0.0 */ export const uniq = (equivalence: Equivalence) => @@ -1020,7 +992,6 @@ export const uniq = (equivalence: Equivalence) => /** * Remove duplicates from a `NonEmptyReadonlyArray`, keeping the first occurrence of an element. * - * @category mutations * @since 1.0.0 */ export const uniqNonEmpty = (equivalence: Equivalence) => @@ -1191,7 +1162,6 @@ export const groupBy = (f: (a: A) => string) => } /** - * @category mutations * @since 1.0.0 */ export const union = (equivalence: Equivalence) => @@ -1207,7 +1177,6 @@ export const union = (equivalence: Equivalence) => } /** - * @category mutations * @since 1.0.0 */ export const unionNonEmpty = (equivalence: Equivalence): { @@ -1223,7 +1192,6 @@ export const unionNonEmpty = (equivalence: Equivalence): { * Creates an `Array` of unique values that are included in all given `Iterable`s. * The order and references of result values are determined by the first `Iterable`. * - * @category mutations * @since 1.0.0 */ export const intersection = (equivalence: Equivalence) => @@ -1235,7 +1203,6 @@ export const intersection = (equivalence: Equivalence) => * Creates a `Array` of values not included in the other given `Iterable`. * The order and references of result values are determined by the first `Iterable`. * - * @category mutations * @since 1.0.0 */ export const difference = (equivalence: Equivalence) => From 460374a11624a7e8419a151ca2992153a4b6e8c4 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 15:08:00 +0100 Subject: [PATCH 024/255] chore: remove @fp-ts/data --- src/Boolean.ts | 14 +++++----- src/Function.ts | 22 +++++++-------- src/Number.ts | 8 +++--- src/String.ts | 66 ++++++++++++++++++++++----------------------- test/data/Option.ts | 20 +++++++------- 5 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/Boolean.ts b/src/Boolean.ts index f10ed523f..7e9d8b8b1 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -33,9 +33,9 @@ export const or = (that: boolean) => (self: boolean): boolean => self || that * If `value` is `false`, `onFalse()` is returned, otherwise `onTrue()`. * * @example - * import { some, map } from '@fp-ts/data/Option' - * import { pipe } from '@fp-ts/data/Function' - * import { match } from '@fp-ts/data/Boolean' + * import { some, map } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * import { match } from '@fp-ts/core/Boolean' * * assert.deepStrictEqual( * pipe( @@ -55,8 +55,8 @@ export const match = (onFalse: LazyArg, onTrue: LazyArg) => * `boolean` semigroup under conjunction. * * @example - * import { SemigroupAll } from '@fp-ts/data/Boolean' - * import { pipe } from '@fp-ts/data/Function' + * import { SemigroupAll } from '@fp-ts/core/Boolean' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe(true, SemigroupAll.combine(true)), true) * assert.deepStrictEqual(pipe(true, SemigroupAll.combine(false)), false) @@ -84,8 +84,8 @@ export const SemigroupAll: semigroup.Semigroup = { * `boolean` semigroup under disjunction. * * @example - * import { SemigroupAny } from '@fp-ts/data/Boolean' - * import { pipe } from '@fp-ts/data/Function' + * import { SemigroupAny } from '@fp-ts/core/Boolean' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe(true, SemigroupAny.combine(true)), true) * assert.deepStrictEqual(pipe(true, SemigroupAny.combine(false)), true) diff --git a/src/Function.ts b/src/Function.ts index d93985a8a..6326f46fc 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -27,9 +27,9 @@ export const compose: (bc: (b: B) => C) => (ab: (a: A) => B) => (a: A) * Unary functions form a semigroup as long as you can provide a semigroup for the codomain. * * @example - * import { Predicate } from '@fp-ts/data/Predicate' - * import { pipe, getSemigroup } from '@fp-ts/data/Function' - * import * as B from '@fp-ts/data/Boolean' + * import { Predicate } from '@fp-ts/core/Predicate' + * import { pipe, getSemigroup } from '@fp-ts/core/Function' + * import * as B from '@fp-ts/core/Boolean' * * const f: Predicate = (n) => n <= 2 * const g: Predicate = (n) => n >= 0 @@ -55,9 +55,9 @@ export const getSemigroup = (Semigroup: semigroup.Semigroup) => * Unary functions form a monoid as long as you can provide a monoid for the codomain. * * @example - * import { Predicate } from '@fp-ts/data/Predicate' - * import { getMonoid, pipe } from '@fp-ts/data/Function' - * import * as B from '@fp-ts/data/Boolean' + * import { Predicate } from '@fp-ts/core/Predicate' + * import { getMonoid, pipe } from '@fp-ts/core/Function' + * import * as B from '@fp-ts/core/Boolean' * * const f: Predicate = (n) => n <= 2 * const g: Predicate = (n) => n >= 0 @@ -102,7 +102,7 @@ export interface LazyArg { /** * @example - * import { FunctionN } from '@fp-ts/data/Function' + * import { FunctionN } from '@fp-ts/core/Function' * * export const sum: FunctionN<[number, number], number> = (a, b) => a + b * @@ -166,7 +166,7 @@ export const constVoid: LazyArg = constUndefined * Flips the arguments of a curried function. * * @example - * import { flip } from '@fp-ts/data/Function' + * import { flip } from '@fp-ts/core/Function' * * const f = (a: number) => (b: string) => a - b.length * @@ -181,7 +181,7 @@ export const flip = (f: (a: A) => (b: B) => C): ((b: B) => (a: A) => C) * Performs left-to-right function composition. The first argument may have any arity, the remaining arguments must be unary. * * @example - * import { flow } from '@fp-ts/data/Function' + * import { flow } from '@fp-ts/core/Function' * * const len = (s: string): number => s.length * const double = (n: number): number => n * 2 @@ -315,7 +315,7 @@ export const absurd = (_: never): A => { * Creates a tupled version of this function: instead of `n` arguments, it accepts a single tuple argument. * * @example - * import { tupled } from '@fp-ts/data/Function' + * import { tupled } from '@fp-ts/core/Function' * * const add = tupled((x: number, y: number): number => x + y) * @@ -338,7 +338,7 @@ export const untupled = , B>(f: (a: A) => B): ( * Pipes the value of an expression into a pipeline of functions. * * @example - * import { pipe } from '@fp-ts/data/Function' + * import { pipe } from '@fp-ts/core/Function' * * const len = (s: string): number => s.length * const double = (n: number): number => n * 2 diff --git a/src/Number.ts b/src/Number.ts index ba33b56db..54067783b 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -69,8 +69,8 @@ export const Bounded: bounded.Bounded = { * `number` semigroup under addition. * * @example - * import { SemigroupSum } from '@fp-ts/data/Number' - * import { pipe } from '@fp-ts/data/Function' + * import { SemigroupSum } from '@fp-ts/core/Number' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe(2, SemigroupSum.combine(3)), 5) * @@ -83,8 +83,8 @@ export const SemigroupSum: semigroup.Semigroup = semigroup.fromCombine(s * `number` semigroup under multiplication. * * @example - * import { SemigroupMultiply } from '@fp-ts/data/Number' - * import { pipe } from '@fp-ts/data/Function' + * import { SemigroupMultiply } from '@fp-ts/core/Number' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe(2, SemigroupMultiply.combine(3)), 6) * diff --git a/src/String.ts b/src/String.ts index 74ecc7a96..950aca447 100644 --- a/src/String.ts +++ b/src/String.ts @@ -19,8 +19,8 @@ export const concat = (that: string) => (self: string): string => self + that * `string` semigroup under concatenation. * * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('a', S.Semigroup.combine('b')), 'ab') * @@ -42,8 +42,8 @@ export const empty: "" = "" as const * The `empty` value is `''`. * * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('a', S.Monoid.combine('b')), 'ab') * assert.deepStrictEqual(pipe('a', S.Monoid.combine(S.Monoid.empty)), 'a') @@ -65,8 +65,8 @@ export const Equivalence: equivalence.Equivalence = equivalence.string /** * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('a', S.Order.compare('a')), 0) * assert.deepStrictEqual(pipe('a', S.Order.compare('b')), -1) @@ -81,7 +81,7 @@ export const Order: order.Order = { /** * @example - * import * as S from '@fp-ts/data/String' + * import * as S from '@fp-ts/core/String' * * assert.deepStrictEqual(S.isString('a'), true) * assert.deepStrictEqual(S.isString(1), false) @@ -94,8 +94,8 @@ export const isString: Refinement = (u: unknown): u is string = /** * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('a', S.toUpperCase), 'A') * @@ -105,8 +105,8 @@ export const toUpperCase = (s: string): string => s.toUpperCase() /** * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('A', S.toLowerCase), 'a') * @@ -116,8 +116,8 @@ export const toLowerCase = (s: string): string => s.toLowerCase() /** * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('abc', S.replace('b', 'd')), 'adc') * @@ -128,8 +128,8 @@ export const replace = (searchValue: string | RegExp, replaceValue: string) => /** * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe(' a ', S.trim), 'a') * @@ -139,8 +139,8 @@ export const trim = (s: string): string => s.trim() /** * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe(' a ', S.trimLeft), 'a ') * @@ -150,8 +150,8 @@ export const trimLeft = (s: string): string => s.trimLeft() /** * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe(' a ', S.trimRight), ' a') * @@ -161,8 +161,8 @@ export const trimRight = (s: string): string => s.trimRight() /** * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('abcd', S.slice(1, 3)), 'bc') * @@ -174,8 +174,8 @@ export const slice = (start: number, end: number) => (s: string): string => s.sl * Test whether a `string` is empty. * * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('', S.isEmpty), true) * assert.deepStrictEqual(pipe('a', S.isEmpty), false) @@ -188,8 +188,8 @@ export const isEmpty = (s: string): s is "" => s.length === 0 * Calculate the number of characters in a `string`. * * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('abc', S.size), 3) * @@ -199,8 +199,8 @@ export const size = (s: string): number => s.length /** * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('abc', S.split('')), ['a', 'b', 'c']) * assert.deepStrictEqual(pipe('', S.split('')), ['']) @@ -215,8 +215,8 @@ export const split = (separator: string | RegExp) => /** * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('abc', S.includes('b')), true) * assert.deepStrictEqual(pipe('abc', S.includes('d')), false) @@ -228,8 +228,8 @@ export const includes = (searchString: string, position?: number) => /** * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('abc', S.startsWith('a')), true) * assert.deepStrictEqual(pipe('bc', S.startsWith('a')), false) @@ -241,8 +241,8 @@ export const startsWith = (searchString: string, position?: number) => /** * @example - * import * as S from '@fp-ts/data/String' - * import { pipe } from '@fp-ts/data/Function' + * import * as S from '@fp-ts/core/String' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(pipe('abc', S.endsWith('c')), true) * assert.deepStrictEqual(pipe('ab', S.endsWith('c')), false) diff --git a/test/data/Option.ts b/test/data/Option.ts index e88852b59..95e34df15 100644 --- a/test/data/Option.ts +++ b/test/data/Option.ts @@ -96,8 +96,8 @@ export const toNull: (self: Option) => A | null = getOrElse(null) * Extracts the value out of the structure, if it exists. Otherwise returns `undefined`. * * @exampleTodo - * import { some, none, toUndefined } from '@fp-ts/data/Option' - * import { pipe } from '@fp-ts/data/Function' + * import { some, none, toUndefined } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' * * assert.strictEqual( * pipe( @@ -233,8 +233,8 @@ export const catchAll = (that: LazyArg>) => * | some(a) | some(b) | some(a) | * * @exampleTodo - * import * as O from '@fp-ts/data/Option' - * import { pipe } from '@fp-ts/data/Function' + * import * as O from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual( * pipe( @@ -320,9 +320,9 @@ export const traverse = ( * `None` is considered to be less than any `Some` value. * * @exampleTodo - * import { none, some, liftOrder } from '@fp-ts/data/Option' - * import * as N from '@fp-ts/data/number' - * import { pipe } from '@fp-ts/data/Function' + * import { none, some, liftOrder } from '@fp-ts/core/Option' + * import * as N from '@fp-ts/core/number' + * import { pipe } from '@fp-ts/core/Function' * * const O = liftOrder(N.Order) * assert.strictEqual(pipe(none, O.compare(none)), 0) @@ -351,9 +351,9 @@ export const liftOrder = (O: order.Order): order.Order> => * | some(a) | some(b) | some(combine(b)(a)) | * * @exampleTodo - * import { getMonoid, some, none } from '@fp-ts/data/Option' - * import * as N from '@fp-ts/data/number' - * import { pipe } from '@fp-ts/data/Function' + * import { getMonoid, some, none } from '@fp-ts/core/Option' + * import * as N from '@fp-ts/core/number' + * import { pipe } from '@fp-ts/core/Function' * * const M = getMonoid(N.SemigroupSum) * assert.deepStrictEqual(pipe(none, M.combine(none)), none) From 329c42a85e2ed82f5d28d1bb61e370e62ec427ce Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 15:26:12 +0100 Subject: [PATCH 025/255] ReadonlyArray: add CovariantWithIndex, FilterableWithIndex instances --- src/ReadonlyArray.ts | 24 ++++++++++++++ test/ReadonlyArray.ts | 2 ++ test/typeclass/Compactable.ts | 25 ++++++++++++++ test/typeclass/CovariantWithIndex.ts | 2 +- test/typeclass/Filterable.ts | 44 +++++++++++++++++++++++++ test/typeclass/TraversableFilterable.ts | 36 ++++++++++++++++++++ 6 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 test/typeclass/Compactable.ts create mode 100644 test/typeclass/Filterable.ts create mode 100644 test/typeclass/TraversableFilterable.ts diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 8052add73..1a6b90d2c 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -18,8 +18,10 @@ import * as chainable from "@fp-ts/core/typeclass/Chainable" import type * as compactable from "@fp-ts/core/typeclass/Compactable" import type { Coproduct } from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" +import type * as covariantWithIndex from "@fp-ts/core/typeclass/CovariantWithIndex" import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" import * as filterable from "@fp-ts/core/typeclass/Filterable" +import type * as filterableWithIndex from "@fp-ts/core/typeclass/FilterableWithIndex" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" import type * as invariant from "@fp-ts/core/typeclass/Invariant" @@ -1291,6 +1293,17 @@ export const Invariant: invariant.Invariant = { imap } +/** + * @category instances + * @since 1.0.0 + */ +export const CovariantWithIndex: covariantWithIndex.CovariantWithIndex< + ReadonlyArrayTypeLambda, + number +> = { + mapWithIndex +} + /** * @category instances * @since 1.0.0 @@ -1492,6 +1505,17 @@ export const separate = ( return [left, right] } +/** + * @category instances + * @since 1.0.0 + */ +export const FilterableWithIndex: filterableWithIndex.FilterableWithIndex< + ReadonlyArrayTypeLambda, + number +> = { + filterMapWithIndex +} + /** * @category instances * @since 1.0.0 diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 550933a4e..d662c135c 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -16,6 +16,7 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.Invariant).exist expect(RA.imap).exist + expect(RA.CovariantWithIndex).exist expect(RA.Covariant).exist expect(RA.map).exist expect(RA.let).exist @@ -75,6 +76,7 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.compact).exist expect(RA.separate).exist + expect(RA.FilterableWithIndex).exist expect(RA.Filterable).exist expect(RA.filterMap).exist expect(RA.filter).exist diff --git a/test/typeclass/Compactable.ts b/test/typeclass/Compactable.ts new file mode 100644 index 000000000..50fed2746 --- /dev/null +++ b/test/typeclass/Compactable.ts @@ -0,0 +1,25 @@ +import * as E from "@fp-ts/core/Either" +import { pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" +import * as RA from "@fp-ts/core/ReadonlyArray" +import * as _ from "@fp-ts/core/typeclass/Compactable" +import * as U from "../util" + +describe("Compactable", () => { + it("compactComposition", () => { + const compact = _.compactComposition(RA.Covariant, O.Compactable) + U.deepStrictEqual(pipe([], compact), []) + U.deepStrictEqual(pipe([O.none()], compact), [O.none()]) + U.deepStrictEqual(pipe([O.some(O.none())], compact), [O.none()]) + U.deepStrictEqual(pipe([O.some(O.some(1))], compact), [O.some(1)]) + }) + + it("separate", () => { + const separate = _.separate({ ...RA.Covariant, ...RA.Compactable }) + U.deepStrictEqual(pipe([], separate), [[], []]) + U.deepStrictEqual(pipe([E.right(1), E.left("e"), E.right(2)], separate), [ + ["e"], + [1, 2] + ]) + }) +}) diff --git a/test/typeclass/CovariantWithIndex.ts b/test/typeclass/CovariantWithIndex.ts index a71e23efd..f60fa5511 100644 --- a/test/typeclass/CovariantWithIndex.ts +++ b/test/typeclass/CovariantWithIndex.ts @@ -3,7 +3,7 @@ import * as RA from "../data/ReadonlyArray" import * as _ from "../limbo/CovariantWithIndex" import * as U from "../util" -describe("FunctorWithIndex", () => { +describe("CovariantWithIndex", () => { it("mapWithIndexComposition", () => { const mapWithIndex = _.mapWithIndexComposition(RA.CovariantWithIndex, RA.CovariantWithIndex) const f = (a: string, [i, j]: readonly [number, number]) => a + i + j diff --git a/test/typeclass/Filterable.ts b/test/typeclass/Filterable.ts new file mode 100644 index 000000000..a22477b65 --- /dev/null +++ b/test/typeclass/Filterable.ts @@ -0,0 +1,44 @@ +import * as E from "@fp-ts/core/Either" +import { pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" +import * as RA from "@fp-ts/core/ReadonlyArray" +import * as _ from "@fp-ts/core/typeclass/Filterable" +import * as U from "../util" + +describe("Filterable", () => { + it("filterMapComposition", () => { + const filterMap = _.filterMapComposition(RA.Covariant, O.Filterable) + const f = filterMap((s: string) => s.length > 1 ? O.some(s.length) : O.none()) + U.deepStrictEqual(pipe([], f), []) + U.deepStrictEqual(pipe([O.none()], f), [O.none()]) + U.deepStrictEqual(pipe([O.some("a")], f), [O.none()]) + U.deepStrictEqual(pipe([O.some("aa")], f), [O.some(2)]) + }) + + it("filter", () => { + const filter = _.filter(RA.Filterable) + const f = filter((n: number) => n > 0) + U.deepStrictEqual(pipe([], f), []) + U.deepStrictEqual(pipe([1], f), [1]) + U.deepStrictEqual(pipe([-1], f), []) + U.deepStrictEqual(pipe([1, -1], f), [1]) + }) + + it("partitionMap", () => { + const partitionMap = _.partitionMap(RA.Filterable) + const f = partitionMap((s: string) => s.length > 1 ? E.right(s.length) : E.left(s)) + U.deepStrictEqual(pipe([], f), [[], []]) + U.deepStrictEqual(pipe(["a"], f), [["a"], []]) + U.deepStrictEqual(pipe(["aa"], f), [[], [2]]) + U.deepStrictEqual(pipe(["aa", "a"], f), [["a"], [2]]) + }) + + it("partition", () => { + const partition = _.partition(RA.Filterable) + const f = partition((n: number) => n > 0) + U.deepStrictEqual(pipe([], f), [[], []]) + U.deepStrictEqual(pipe([1], f), [[], [1]]) + U.deepStrictEqual(pipe([-1], f), [[-1], []]) + U.deepStrictEqual(pipe([1, -1], f), [[-1], [1]]) + }) +}) diff --git a/test/typeclass/TraversableFilterable.ts b/test/typeclass/TraversableFilterable.ts new file mode 100644 index 000000000..4b207fe9c --- /dev/null +++ b/test/typeclass/TraversableFilterable.ts @@ -0,0 +1,36 @@ +import * as O from "@fp-ts/core/Option" +import * as RA from "@fp-ts/core/ReadonlyArray" +import * as _ from "@fp-ts/core/typeclass/TraversableFilterable" +import * as U from "../util" + +describe("TraversableFilterable", () => { + it("traverseFilter", () => { + const traverseFilter = _.traverseFilter( + RA.TraversableFilterable + )(O.Applicative) + const f = traverseFilter((s: string) => + s.length > 2 ? O.some(false) : s.length > 1 ? O.some(true) : O.none() + ) + U.deepStrictEqual(f([]), O.some([])) + U.deepStrictEqual(f(["a"]), O.none()) + U.deepStrictEqual(f(["a", "aa"]), O.none()) + U.deepStrictEqual(f(["aa"]), O.some(["aa"])) + U.deepStrictEqual(f(["aaa"]), O.some([])) + U.deepStrictEqual(f(["aaa", "aa"]), O.some(["aa"])) + }) + + it("traversePartition", () => { + const traversePartition = _.traversePartition( + RA.TraversableFilterable + )(O.Applicative) + const f = traversePartition((s: string) => + s.length > 2 ? O.some(false) : s.length > 1 ? O.some(true) : O.none() + ) + U.deepStrictEqual(f([]), O.some([[], []] as const)) + U.deepStrictEqual(f(["a"]), O.none()) + U.deepStrictEqual(f(["a", "aa"]), O.none()) + U.deepStrictEqual(f(["aa"]), O.some([[], ["aa"]] as const)) + U.deepStrictEqual(f(["aaa"]), O.some([["aaa"], []] as const)) + U.deepStrictEqual(f(["aaa", "aa"]), O.some([["aaa"], ["aa"]] as const)) + }) +}) From 8d711d152585bac431800b02b07bf223d9cdab72 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 15:50:01 +0100 Subject: [PATCH 026/255] chore: remove /test/data --- src/ReadonlyArray.ts | 28 + test/data/Either.ts | 64 --- test/data/NonEmptyArray.ts | 3 - test/data/NonEmptyReadonlyArray.ts | 69 --- test/data/Option.ts | 701 ------------------------- test/data/Predicate.ts | 90 ---- test/data/ReadonlyArray.ts | 150 ------ test/data/boolean.ts | 42 -- test/data/number.ts | 41 -- test/data/string.ts | 13 - test/limbo/CovariantWithIndex.ts | 40 -- test/typeclass/Applicative.ts | 10 +- test/typeclass/Bicovariant.ts | 6 +- test/typeclass/Bounded.ts | 6 +- test/typeclass/Chainable.ts | 16 +- test/typeclass/Contravariant.ts | 8 +- test/typeclass/Coproduct.ts | 10 +- test/typeclass/Covariant.ts | 12 +- test/typeclass/CovariantWithIndex.ts | 4 +- test/typeclass/FlatMap.ts | 20 +- test/typeclass/Foldable.ts | 34 +- test/typeclass/FoldableWithIndex.ts | 104 ++-- test/typeclass/Invariant.ts | 22 +- test/typeclass/Monoid.ts | 18 +- test/typeclass/NonEmptyTraversable.ts | 35 +- test/typeclass/Of.ts | 4 +- test/typeclass/Order.ts | 8 +- test/typeclass/Product.ts | 23 +- test/typeclass/SemiApplicative.ts | 44 +- test/typeclass/SemiCoproduct.ts | 2 +- test/typeclass/SemiProduct.ts | 79 +-- test/typeclass/Semigroup.ts | 38 +- test/typeclass/Traversable.ts | 23 +- test/typeclass/TraversableWithIndex.ts | 68 +-- vitest.config.ts | 4 +- 35 files changed, 335 insertions(+), 1504 deletions(-) delete mode 100644 test/data/Either.ts delete mode 100644 test/data/NonEmptyArray.ts delete mode 100644 test/data/NonEmptyReadonlyArray.ts delete mode 100644 test/data/Option.ts delete mode 100644 test/data/Predicate.ts delete mode 100644 test/data/ReadonlyArray.ts delete mode 100644 test/data/boolean.ts delete mode 100644 test/data/number.ts delete mode 100644 test/data/string.ts delete mode 100644 test/limbo/CovariantWithIndex.ts diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 1a6b90d2c..9d6947353 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -40,6 +40,8 @@ import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" import * as traversableFilterable from "@fp-ts/core/typeclass/TraversableFilterable" +import type * as nonEmptyTraversable from "@fp-ts/core/typeclass/NonEmptyTraversable" + /** * @category type lambdas * @since 1.0.0 @@ -48,6 +50,14 @@ export interface ReadonlyArrayTypeLambda extends TypeLambda { readonly type: ReadonlyArray } +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface NonEmptyReadonlyArrayTypeLambda extends TypeLambda { + readonly type: NonEmptyReadonlyArray +} + /** * @category models * @since 1.0.0 @@ -2254,3 +2264,21 @@ export const liftOrder = (O: Order): Order> => return number.Order.compare(bLen)(aLen) } ) + +/** + * @category instances + * @since 1.0.0 + */ +export const NonEmptyCovariant: covariant.Covariant = covariant + .make(mapNonEmpty) + +/** + * @category instances + * @since 1.0.0 + */ +export const NonEmptyTraversable: nonEmptyTraversable.NonEmptyTraversable< + NonEmptyReadonlyArrayTypeLambda +> = { + traverseNonEmpty, + sequenceNonEmpty: F => self => pipe(self, traverseNonEmpty(F)(identity)) +} diff --git a/test/data/Either.ts b/test/data/Either.ts deleted file mode 100644 index 643702a48..000000000 --- a/test/data/Either.ts +++ /dev/null @@ -1,64 +0,0 @@ -import type { TypeLambda } from "@fp-ts/core/HKT" -import * as covariant from "@fp-ts/core/typeclass/Covariant" -import * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" -import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" - -export interface Left { - readonly _tag: "Left" - readonly left: E -} - -export interface Right { - readonly _tag: "Right" - readonly right: A -} - -export type Either = Left | Right - -export interface EitherTypeLambda extends TypeLambda { - readonly type: Either -} - -export const left = (e: E): Either => ({ _tag: "Left", left: e }) - -export const right = (a: A): Either => ({ _tag: "Right", right: a }) - -/** - * @since 1.0.0 - */ -export const isLeft = (self: Either): self is Left => self._tag === "Left" - -/** - * @since 1.0.0 - */ -export const isRight = (self: Either): self is Right => self._tag === "Right" - -const map = (f: (a: A) => B) => - (self: Either): Either => isRight(self) ? right(f(self.right)) : self - -const imap = covariant.imap(map) - -const coproduct = ( - that: Either -) => (self: Either): Either => isRight(self) ? self : that - -export const SemiCoproduct: semiCoproduct.SemiCoproduct = { - imap, - coproduct, - coproductMany: collection => - self => { - let out = self - if (isRight(out)) { - return out - } - for (out of collection) { - if (isRight(out)) { - return out - } - } - return out - } -} - -export const getSemigroup: () => Semigroup> = semiCoproduct - .getSemigroup(SemiCoproduct) diff --git a/test/data/NonEmptyArray.ts b/test/data/NonEmptyArray.ts deleted file mode 100644 index 02b536784..000000000 --- a/test/data/NonEmptyArray.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const make = ( - ...as: [A, ...Array] -): [A, ...Array] => as diff --git a/test/data/NonEmptyReadonlyArray.ts b/test/data/NonEmptyReadonlyArray.ts deleted file mode 100644 index 0a53f4b2f..000000000 --- a/test/data/NonEmptyReadonlyArray.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { identity, pipe } from "@fp-ts/core/Function" -import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import * as covariant from "@fp-ts/core/typeclass/Covariant" -import type * as nonEmptyTraversable from "@fp-ts/core/typeclass/NonEmptyTraversable" -import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" - -/** - * @category models - * @since 1.0.0 - */ -export type NonEmptyReadonlyArray = readonly [A, ...ReadonlyArray] - -/** - * @category type lambdas - * @since 1.0.0 - */ -export interface NonEmptyReadonlyArrayTypeLambda extends TypeLambda { - readonly type: NonEmptyReadonlyArray -} - -export const isNonEmpty = (self: ReadonlyArray): self is readonly [A, ...ReadonlyArray] => - self.length > 0 - -export const head = (as: readonly [A, ...ReadonlyArray]): A => as[0] -export const tail = (as: readonly [A, ...ReadonlyArray]): ReadonlyArray => as.slice(1) - -export const mapWithIndex = ( - f: (a: A, i: number) => B -) => - (self: NonEmptyReadonlyArray): NonEmptyReadonlyArray => { - const out: [B, ...Array] = [f(head(self), 0)] - for (let i = 1; i < self.length; i++) { - out.push(f(self[i], i)) - } - return out - } - -export const map = ( - f: (a: A) => B -): (self: NonEmptyReadonlyArray) => NonEmptyReadonlyArray => mapWithIndex(f) - -export const traverseWithIndex = ( - F: SemiApplicative -) => - (f: (a: A, i: number) => Kind) => - (self: NonEmptyReadonlyArray): Kind> => { - const fbs = pipe(self, mapWithIndex(f)) - return pipe( - head(fbs), - F.productMany(tail(fbs)) - ) - } - -export const traverseNonEmpty = ( - F: SemiApplicative -) => - ( - f: (a: A) => Kind - ): ((self: NonEmptyReadonlyArray) => Kind>) => - traverseWithIndex(F)(f) - -export const Covariant: covariant.Covariant = covariant.make(map) - -export const NonEmptyTraversable: nonEmptyTraversable.NonEmptyTraversable< - NonEmptyReadonlyArrayTypeLambda -> = { - traverseNonEmpty, - sequenceNonEmpty: F => self => pipe(self, traverseNonEmpty(F)(identity)) -} diff --git a/test/data/Option.ts b/test/data/Option.ts deleted file mode 100644 index 95e34df15..000000000 --- a/test/data/Option.ts +++ /dev/null @@ -1,701 +0,0 @@ -/** - * ```ts - * type Option = None | Some - * ``` - * - * `Option` is a container for an optional value of type `A`. If the value of type `A` is present, the `Option` is - * an instance of `Some`, containing the present value of type `A`. If the value is absent, the `Option` is an - * instance of `None`. - * - * An option could be looked at as a collection or foldable structure with either one or zero elements. - * Another way to look at `Option` is: it represents the effect of a possibly failing computation. - * - * @since 1.0.0 - */ -import { identity, pipe } from "@fp-ts/core/Function" -import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import type * as extendable from "@fp-ts/core/test/limbo/Extendable" -import type * as alternative from "@fp-ts/core/typeclass/Alternative" -import type * as applicative from "@fp-ts/core/typeclass/Applicative" -import * as chainable from "@fp-ts/core/typeclass/Chainable" -import * as covariant from "@fp-ts/core/typeclass/Covariant" -import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" -import type * as foldable from "@fp-ts/core/typeclass/Foldable" -import * as invariant from "@fp-ts/core/typeclass/Invariant" -import type * as monad from "@fp-ts/core/typeclass/Monad" -import type * as monoid from "@fp-ts/core/typeclass/Monoid" -import type * as of_ from "@fp-ts/core/typeclass/Of" -import * as order from "@fp-ts/core/typeclass/Order" -import type * as pointed from "@fp-ts/core/typeclass/Pointed" -import type * as product from "@fp-ts/core/typeclass/Product" -import type * as semiAlternative from "@fp-ts/core/typeclass/SemiAlternative" -import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" -import type * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" -import type * as semigroup from "@fp-ts/core/typeclass/Semigroup" -import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" -import * as traversable from "@fp-ts/core/typeclass/Traversable" -import type * as foldableWithIndex from "../limbo/FoldableWithIndex" -import * as nonEmptyArray from "./NonEmptyArray" -import * as nonEmptyReadonlyArray from "./NonEmptyReadonlyArray" - -export interface LazyArg { - (): A -} - -export interface None { - readonly _tag: "None" -} - -export interface Some { - readonly _tag: "Some" - readonly value: A -} - -export type Option = None | Some - -export interface OptionTypeLambda extends TypeLambda { - readonly type: Option -} - -export const isNone = (fa: Option): fa is None => fa._tag === "None" - -export const isSome = (fa: Option): fa is Some => fa._tag === "Some" - -export const none: Option = { _tag: "None" } - -export const some = (a: A): Option => ({ _tag: "Some", value: a }) - -export const fromIterable = (collection: Iterable): Option => { - for (const a of collection) { - return some(a) - } - return none -} - -export const match = (onNone: LazyArg, onSome: (a: A) => C) => - (ma: Option): B | C => isNone(ma) ? onNone() : onSome(ma.value) - -export const getOrElse = (onNone: B) => - (ma: Option): A | B => isNone(ma) ? onNone : ma.value - -export const fromThrowable = (f: () => A): Option => { - try { - return some(f()) - } catch (e) { - return none - } -} - -export const liftThrowable = , B>( - f: (...a: A) => B -): ((...a: A) => Option) => (...a) => fromThrowable(() => f(...a)) - -export const toNull: (self: Option) => A | null = getOrElse(null) - -/** - * Extracts the value out of the structure, if it exists. Otherwise returns `undefined`. - * - * @exampleTodo - * import { some, none, toUndefined } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' - * - * assert.strictEqual( - * pipe( - * some(1), - * toUndefined - * ), - * 1 - * ) - * assert.strictEqual( - * pipe( - * none, - * toUndefined - * ), - * undefined - * ) - * - * @category conversions - * @since 1.0.0 - */ -export const toUndefined: (self: Option) => A | undefined = getOrElse(undefined) - -/** - * Returns an effect whose success is mapped by the specified `f` function. - * - * @category mapping - * @since 1.0.0 - */ -export const map: (f: (a: A) => B) => (fa: Option) => Option = (f) => - (fa) => isNone(fa) ? none : some(f(fa.value)) - -/** - * @category instances - * @since 1.0.0 - */ -export const Covariant: covariant.Covariant = covariant.make(map) - -export const Of: of_.Of = { - of: some -} - -/** - * @category instances - * @since 1.0.0 - */ -export const Pointed: pointed.Pointed = { - ...Covariant, - ...Of -} - -/** - * @category sequencing - * @since 1.0.0 - */ -export const flatMap: (f: (a: A) => Option) => (self: Option) => Option = (f) => - (self) => isNone(self) ? none : f(self.value) - -/** - * @category instances - * @since 1.0.0 - */ -export const FlatMap: flatMap_.FlatMap = { - flatMap -} - -/** - * A variant of `flatMap` that ignores the value produced by this effect. - * - * @category sequencing - * @since 1.0.0 - */ -export const andThen: (that: Option) => (self: Option) => Option = flatMap_ - .andThen(FlatMap) - -/** - * @category instances - * @since 1.0.0 - */ -export const Chainable: chainable.Chainable = { - ...FlatMap, - ...Covariant -} - -/** - * Returns an effect that effectfully "peeks" at the success of this effect. - * - * @since 1.0.0 - */ -export const tap: (f: (a: A) => Option) => (self: Option) => Option = chainable - .tap(Chainable) - -/** - * Sequences the specified effect after this effect, but ignores the value - * produced by the effect. - * - * @category sequencing - * @since 1.0.0 - */ -export const andThenDiscard: (that: Option) => (self: Option) => Option = - chainable - .andThenDiscard(Chainable) - -/** - * @since 1.0.0 - */ -export const ap: (fa: Option) => (fab: Option<(a: A) => B>) => Option = (fa) => - (fab) => pipe(fab, flatMap((ab) => pipe(fa, map((a) => ab(a))))) - -/** - * @since 1.0.0 - */ -export const flatten: (mma: Option>) => Option = flatMap(identity) - -/** - * Lazy version of `orElse`. - * - * @category error handling - * @since 1.0.0 - */ -export const catchAll = (that: LazyArg>) => - (self: Option): Option => isNone(self) ? that() : self - -/** - * Identifies an associative operation on a type constructor. It is similar to `Semigroup`, except that it applies to - * types of kind `* -> *`. - * - * In case of `Option` returns the left-most non-`None` value. - * - * | x | y | pipe(x, orElse(y) | - * | ------- | ------- | ------------------| - * | none | none | none | - * | some(a) | none | some(a) | - * | none | some(b) | some(b) | - * | some(a) | some(b) | some(a) | - * - * @exampleTodo - * import * as O from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' - * - * assert.deepStrictEqual( - * pipe( - * O.none, - * O.orElse(O.none) - * ), - * O.none - * ) - * assert.deepStrictEqual( - * pipe( - * O.some('a'), - * O.orElse(O.none) - * ), - * O.some('a') - * ) - * assert.deepStrictEqual( - * pipe( - * O.none, - * O.orElse(O.some('b')) - * ), - * O.some('b') - * ) - * assert.deepStrictEqual( - * pipe( - * O.some('a'), - * O.orElse(O.some('b')) - * ), - * O.some('a') - * ) - * - * @category instance operations - * @since 1.0.0 - */ -export const orElse = (that: Option): ((self: Option) => Option) => - catchAll(() => that) - -/** - * @since 1.0.0 - */ -export const extend: (f: (wa: Option) => B) => (wa: Option) => Option = (f) => - (wa) => isNone(wa) ? none : some(f(wa)) - -/** - * @since 1.0.0 - */ -export const duplicate: (ma: Option) => Option> = extend(identity) - -/** - * @category filtering - * @since 1.0.0 - */ -export const compact: (foa: Option>) => Option = flatten - -/** - * @category filtering - * @since 1.0.0 - */ -export const filterMap: (f: (a: A) => Option) => (fa: Option) => Option = (f) => - (fa) => isNone(fa) ? none : f(fa.value) - -/** - * @category traversing - * @since 1.0.0 - */ -export const traverse = ( - F: applicative.Applicative -) => - ( - f: (a: A) => Kind - ) => - (ta: Option): Kind> => - isNone(ta) ? F.of>(none) : pipe(f(ta.value), F.map(some)) - -// ------------------------------------------------------------------------------------- -// instances -// ------------------------------------------------------------------------------------- - -/** - * The `Sortable` instance allows `Option` values to be compared with - * `compare`, whenever there is an `Sortable` instance for - * the type the `Option` contains. - * - * `None` is considered to be less than any `Some` value. - * - * @exampleTodo - * import { none, some, liftOrder } from '@fp-ts/core/Option' - * import * as N from '@fp-ts/core/number' - * import { pipe } from '@fp-ts/core/Function' - * - * const O = liftOrder(N.Order) - * assert.strictEqual(pipe(none, O.compare(none)), 0) - * assert.strictEqual(pipe(none, O.compare(some(1))), -1) - * assert.strictEqual(pipe(some(1), O.compare(none)), 1) - * assert.strictEqual(pipe(some(1), O.compare(some(2))), -1) - * assert.strictEqual(pipe(some(1), O.compare(some(1))), 0) - * - * @category instances - * @since 1.0.0 - */ -export const liftOrder = (O: order.Order): order.Order> => - order.fromCompare((that) => - (self) => isSome(self) ? (isSome(that) ? O.compare(that.value)(self.value) : 1) : -1 - ) - -/** - * Monoid returning the left-most non-`None` value. If both operands are `Some`s then the inner values are - * combined using the provided `Semigroup` - * - * | x | y | combine(y)(x) | - * | ------- | ------- | ------------------- | - * | none | none | none | - * | some(a) | none | some(a) | - * | none | some(a) | some(a) | - * | some(a) | some(b) | some(combine(b)(a)) | - * - * @exampleTodo - * import { getMonoid, some, none } from '@fp-ts/core/Option' - * import * as N from '@fp-ts/core/number' - * import { pipe } from '@fp-ts/core/Function' - * - * const M = getMonoid(N.SemigroupSum) - * assert.deepStrictEqual(pipe(none, M.combine(none)), none) - * assert.deepStrictEqual(pipe(some(1), M.combine(none)), some(1)) - * assert.deepStrictEqual(pipe(none, M.combine(some(1))), some(1)) - * assert.deepStrictEqual(pipe(some(1), M.combine(some(2))), some(3)) - * - * @category instances - * @since 1.0.0 - */ -export const getMonoid = ( - S: semigroup.Semigroup -): monoid.Monoid> => { - const combine = (that: Option) => - (self: Option): Option => - isNone(self) ? that : isNone(that) ? self : some(S.combine(that.value)(self.value)) - return ({ - combine, - combineMany: (others) => - (start) => { - let c = start - for (const o of others) { - c = combine(o)(c) - } - return c - }, - combineAll: (collection: Iterable>): Option => { - let c: Option = none - for (const o of collection) { - c = combine(o)(c) - } - return c - }, - empty: none - }) -} - -/** - * @category mapping - * @since 1.0.0 - */ -export const flap: (a: A) => (fab: Option<(a: A) => B>) => Option = covariant.flap( - Covariant -) - -/** - * Maps the success value of this effect to the specified constant value. - * - * @category mapping - * @since 1.0.0 - */ -export const as: (b: B) => (self: Option) => Option = covariant.as(Covariant) - -/** - * Returns the effect resulting from mapping the success of this effect to unit. - * - * @category mapping - * @since 1.0.0 - */ -export const asUnit: (self: Option) => Option = covariant.asUnit(Covariant) - -/** - * @category instances - * @since 1.0.0 - */ -export const Invariant: invariant.Invariant = { - imap: covariant.imap(Covariant.map) -} - -/** - * @category instances - * @since 1.0.0 - */ -export const SemiProduct: semiProduct.SemiProduct = { - imap: Invariant.imap, - product: that => self => isSome(self) && isSome(that) ? some([self.value, that.value]) : none, - productMany: collection => - self => { - if (isNone(self)) { - return none - } - const out = nonEmptyArray.make(self.value) - for (const o of collection) { - if (isNone(o)) { - return none - } - out.push(o.value) - } - return some(out) - } -} - -/** - * @category instances - * @since 1.0.0 - */ -export const SemiApplicative: semiApplicative.SemiApplicative = { - ...Covariant, - ...SemiProduct -} - -const coproduct = ( - that: Option -) => (self: Option): Option => isSome(self) ? self : isSome(that) ? that : none - -export const SemiCoproduct: semiCoproduct.SemiCoproduct = { - imap: Invariant.imap, - coproduct, - coproductMany: collection => - self => { - if (isSome(self)) { - return self - } - for (const o of collection) { - if (isSome(o)) { - return o - } - } - return none - } -} - -export const SemiAlternative: semiAlternative.SemiAlternative = { - ...Covariant, - ...SemiCoproduct -} - -export const Alternative: alternative.Alternative = { - ...SemiAlternative, - zero: () => none, - coproductAll: collection => SemiAlternative.coproductMany(collection)(none) -} - -/** - * Lifts a binary function into `Option`. - * - * @category lifting - * @since 1.0.0 - */ -export const lift2: (f: (a: A, b: B) => C) => (fa: Option, fb: Option) => Option = - semiApplicative.lift2(SemiApplicative) - -/** - * Lifts a ternary function into `Option`. - * - * @category lifting - * @since 1.0.0 - */ -export const lift3: ( - f: (a: A, b: B, c: C) => D -) => (fa: Option, fb: Option, fc: Option) => Option = semiApplicative.lift3( - SemiApplicative -) - -export const Product: product.Product = { - ...SemiProduct, - ...Of, - productAll: collection => { - const as = Array.from(collection) - return nonEmptyReadonlyArray.isNonEmpty(as) ? - SemiApplicative.productMany(nonEmptyReadonlyArray.tail(as))( - nonEmptyReadonlyArray.head(as) - ) : - some([]) - } -} - -/** - * @category instances - * @since 1.0.0 - */ -export const Applicative: applicative.Applicative = { - ...SemiApplicative, - ...Product -} - -/** - * @category instances - * @since 1.0.0 - */ -export const Monad: monad.Monad = { - ...Covariant, - ...Of, - flatMap -} - -/** - * @category conversions - * @since 1.0.0 - */ -export const toReadonlyArray = ( - self: Option -): ReadonlyArray => (isNone(self) ? [] : [self.value]) - -/** - * @category folding - * @since 1.0.0 - */ -export const reduce = (b: B, f: (b: B, a: A) => B) => - (self: Option): B => isNone(self) ? b : f(b, self.value) - -/** - * @category folding - * @since 1.0.0 - */ -export const foldMap = (Monoid: monoid.Monoid) => - (f: (a: A) => M) => (self: Option): M => isNone(self) ? Monoid.empty : f(self.value) - -/** - * @category folding - * @since 1.0.0 - */ -export const reduceRight = (b: B, f: (b: B, a: A) => B) => - (self: Option): B => isNone(self) ? b : f(b, self.value) - -/** - * @category instances - * @since 1.0.0 - */ -export const Foldable: foldable.Foldable = { - reduce -} - -/** - * @category folding - * @since 1.0.0 - */ -export const reduceWithIndex = (b: B, f: (b: B, a: A, i: number) => B) => - (self: Option): B => isNone(self) ? b : f(b, self.value, 0) - -/** - * @category folding - * @since 1.0.0 - */ -export const reduceRightWithIndex = (b: B, f: (b: B, a: A, i: number) => B) => - (self: Option): B => isNone(self) ? b : f(b, self.value, 0) - -/** - * @category instances - * @since 1.0.0 - */ -export const FoldableWithIndex: foldableWithIndex.FoldableWithIndex = { - reduceWithIndex, - reduceRightWithIndex -} - -/** - * @category instances - * @since 1.0.0 - */ -export const Extendable: extendable.Extendable = { - ...Covariant, - extend -} - -/** - * @category traversing - * @since 1.0.0 - */ -export const sequence: ( - Applicative: applicative.Applicative -) => (fas: Option>) => Kind> = traversable - .sequence(traverse) - -/** - * @category instances - * @since 1.0.0 - */ -export const Traversable: traversable.Traversable = { - traverse, - sequence -} - -export const exists = (predicate: (a: A) => boolean) => - (ma: Option): boolean => isNone(ma) ? false : predicate(ma.value) - -/** - * @category do notation - * @since 1.0.0 - */ -export const Do: Option<{}> = some({}) - -/** - * @category do notation - * @since 1.0.0 - */ -export const bindTo: ( - name: N -) => (self: Option) => Option<{ readonly [K in N]: A }> = invariant.bindTo(Invariant) - -const let_: ( - name: Exclude, - f: (a: A) => B -) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = - covariant.let(Covariant) - -export { let_ as let } - -/** - * @category do notation - * @since 1.0.0 - */ -export const bind: ( - name: Exclude, - f: (a: A) => Option -) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = - chainable.bind(Chainable) - -/** - * A variant of `bind` that sequentially ignores the scope. - * - * @category do notation - * @since 1.0.0 - */ -export const andThenBind: ( - name: Exclude, - fb: Option -) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = - semiProduct.andThenBind(SemiApplicative) - -// ------------------------------------------------------------------------------------- -// tuple sequencing -// ------------------------------------------------------------------------------------- - -/** - * @category tuple sequencing - * @since 1.0.0 - */ -export const Zip: Option = some([]) - -/** - * @since 1.0.0 - */ -export const tupled: (self: Option) => Option = invariant.tupled(Invariant) - -/** - * Sequentially zips this effect with the specified effect. - * - * @category tuple sequencing - * @since 1.0.0 - */ -export const productFlatten: ( - fb: Option -) => >(self: Option) => Option = semiProduct - .productFlatten(SemiProduct) diff --git a/test/data/Predicate.ts b/test/data/Predicate.ts deleted file mode 100644 index 872b8bd0a..000000000 --- a/test/data/Predicate.ts +++ /dev/null @@ -1,90 +0,0 @@ -import type { TypeLambda } from "@fp-ts/core/HKT" -import * as contravariant from "@fp-ts/core/typeclass/Contravariant" -import * as invariant from "@fp-ts/core/typeclass/Invariant" -import * as of_ from "@fp-ts/core/typeclass/Of" -import * as product from "@fp-ts/core/typeclass/Product" -import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" - -export interface Predicate { - (a: A): boolean -} - -export interface PredicateTypeLambda extends TypeLambda { - readonly type: Predicate -} - -export const contramap = (f: (b: B) => A) => - (self: Predicate): Predicate => b => self(f(b)) - -export const Contravariant: contravariant.Contravariant = contravariant.make( - contramap -) - -export const Invariant: invariant.Invariant = { - imap: Contravariant.imap -} - -export const SemiProduct: semiProduct.SemiProduct = { - imap: Contravariant.imap, - product: that => self => ([a, b]) => self(a) && that(b), - productMany: collection => - self => { - return ([head, ...tail]) => { - if (self(head) === false) { - return false - } - const predicates = Array.from(collection) - for (let i = 0; i < predicates.length; i++) { - if (predicates[i](tail[i]) === false) { - return false - } - } - return true - } - } -} - -export const of = (_: A): Predicate => () => true - -export const Of: of_.Of = { - of -} - -export const Do = of_.Do(Of) - -export const Product: product.Product = { - ...SemiProduct, - of, - productAll: collection => - as => { - const predicates = Array.from(collection) - for (let i = 0; i < predicates.length; i++) { - if (predicates[i](as[i]) === false) { - return false - } - } - return true - } -} - -export const andThenBind: ( - name: Exclude, - fb: Predicate -) => ( - self: Predicate -) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct - .andThenBind( - SemiProduct - ) - -export const tupled: (self: Predicate) => Predicate = invariant.tupled( - Invariant -) - -export const tuple = product.tuple(Product) - -export const isString = (u: unknown): u is string => typeof u === "string" - -export const isNumber = (u: unknown): u is number => typeof u === "number" - -export const isBoolean = (u: unknown): u is boolean => typeof u === "boolean" diff --git a/test/data/ReadonlyArray.ts b/test/data/ReadonlyArray.ts deleted file mode 100644 index 9c3e7cd63..000000000 --- a/test/data/ReadonlyArray.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { semiProduct } from "@fp-ts/core" -import { identity, pipe } from "@fp-ts/core/Function" -import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import type * as applicative from "@fp-ts/core/typeclass/Applicative" -import * as covariant from "@fp-ts/core/typeclass/Covariant" -import type * as foldable from "@fp-ts/core/typeclass/Foldable" -import type * as of_ from "@fp-ts/core/typeclass/Of" -import type { Order } from "@fp-ts/core/typeclass/Order" -import type * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" -import type * as traverse_ from "@fp-ts/core/typeclass/Traversable" -import type * as covariantWithIndex from "../limbo/CovariantWithIndex" -import * as foldableWithIndex from "../limbo/FoldableWithIndex" -import type * as traversableWithIndex from "../limbo/TraversableWithIndex" -import type { NonEmptyReadonlyArray } from "./NonEmptyReadonlyArray" -import * as nonEmptyReadonlyArray from "./NonEmptyReadonlyArray" -import * as O from "./Option" -import type { Option } from "./Option" - -export interface ReadonlyArrayTypeLambda extends TypeLambda { - readonly type: ReadonlyArray -} - -export const map = (f: (a: A) => B) => - (self: ReadonlyArray): ReadonlyArray => self.map(a => f(a)) - -export const mapWithIndex = (f: (a: A, i: number) => B) => - (self: ReadonlyArray): ReadonlyArray => self.map((a, i) => f(a, i)) - -export const Covariant: covariant.Covariant = covariant.make(map) - -export const CovariantWithIndex: covariantWithIndex.CovariantWithIndex< - ReadonlyArrayTypeLambda, - number -> = { - mapWithIndex: (f) => (self) => self.map((a, i) => f(a, i)) -} - -export const reduceWithIndex = ( - b: B, - f: (b: B, a: A, i: number) => B -) => (self: ReadonlyArray) => self.reduce((b, a, i) => f(b, a, i), b) - -export const reduceRightWithIndex = (b: B, f: (b: B, a: A, i: number) => B) => - (self: ReadonlyArray): B => self.reduceRight((b, a, i) => f(b, a, i), b) - -export const FoldableWithIndex: foldableWithIndex.FoldableWithIndex< - ReadonlyArrayTypeLambda, - number -> = { - reduceWithIndex, - reduceRightWithIndex -} - -export const Foldable: foldable.Foldable = { - reduce: foldableWithIndex.reduce(FoldableWithIndex) -} - -export const isNonEmpty: (self: ReadonlyArray) => self is NonEmptyReadonlyArray = - nonEmptyReadonlyArray.isNonEmpty - -export const head = ( - self: ReadonlyArray -): O.Option => (isNonEmpty(self) ? O.some(self[0]) : O.none) - -export const sort = (Compare: Order) => - (as: ReadonlyArray): ReadonlyArray => - as.length <= 1 ? as : as.slice().sort((a1, a2) => Compare.compare(a2)(a1)) - -export function concat( - that: NonEmptyReadonlyArray -): (self: ReadonlyArray) => NonEmptyReadonlyArray -export function concat( - that: ReadonlyArray -): (self: NonEmptyReadonlyArray) => NonEmptyReadonlyArray -export function concat( - that: ReadonlyArray -): (self: NonEmptyReadonlyArray) => ReadonlyArray { - return (self: NonEmptyReadonlyArray) => self.concat(that) -} - -export const traverseWithIndex = ( - Applicative: applicative.Applicative -) => - (f: (a: A, i: number) => Kind) => - (self: Iterable): Kind> => { - const fbs: Array> = [] - let i = 0 - for (const a of self) { - fbs.push(f(a, i++)) - } - return Applicative.productAll(fbs) - } - -export const traverse = ( - Applicative: applicative.Applicative -) => - ( - f: (a: A) => Kind - ): (self: ReadonlyArray) => Kind> => - traverseWithIndex(Applicative)(f) - -export const Traversable: traverse_.Traversable = { - traverse, - sequence: F => self => pipe(self, traverse(F)(identity)) -} - -export const TraversableWithIndex: traversableWithIndex.TraversableWithIndex< - ReadonlyArrayTypeLambda, - number -> = { - traverseWithIndex -} - -export const product = (that: ReadonlyArray) => - (self: ReadonlyArray): ReadonlyArray => { - const out: Array = [] - for (const a of self) { - for (const b of that) { - out.push([a, b]) - } - } - return out - } - -export const Of: of_.Of = { - of: a => [a] -} - -const SemiProduct: semiProduct.SemiProduct = { - imap: Covariant.imap, - product, - productMany: semiProduct.productMany(Covariant, product) -} - -export const SemiApplicative: semiApplicative.SemiApplicative = { - ...Covariant, - ...SemiProduct -} - -export const filterMapWithIndex = (f: (a: A, i: number) => Option) => - (fa: ReadonlyArray): ReadonlyArray => { - const out: Array = [] - for (let i = 0; i < fa.length; i++) { - const optionB = f(fa[i], i) - if (O.isSome(optionB)) { - out.push(optionB.value) - } - } - return out - } diff --git a/test/data/boolean.ts b/test/data/boolean.ts deleted file mode 100644 index 6145df49a..000000000 --- a/test/data/boolean.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { Monoid } from "@fp-ts/core/typeclass/Monoid" -import * as monoid from "@fp-ts/core/typeclass/Monoid" -import * as order from "@fp-ts/core/typeclass/Order" -import type * as semigroup from "@fp-ts/core/typeclass/Semigroup" - -export const Order: order.Order = order.fromCompare((that) => - (self) => self < that ? -1 : self > that ? 1 : 0 -) - -export const SemigroupAll: semigroup.Semigroup = ({ - combine: (that) => (self) => self && that, - combineMany: (collection) => - (self) => { - if (self === false) { - return false - } - for (const bool of collection) { - if (bool === false) { - return false - } - } - return true - } -}) - -export const SemigroupAny: semigroup.Semigroup = { - combine: (that) => (self) => self || that, - combineMany: (collection) => - (self) => { - if (self === true) { - return true - } - for (const bool of collection) { - if (bool === true) { - return true - } - } - return false - } -} - -export const MonoidAll: Monoid = monoid.fromSemigroup(SemigroupAll, true) diff --git a/test/data/number.ts b/test/data/number.ts deleted file mode 100644 index 9b30eae41..000000000 --- a/test/data/number.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type * as bounded from "@fp-ts/core/typeclass/Bounded" -import type { Monoid } from "@fp-ts/core/typeclass/Monoid" -import * as monoid from "@fp-ts/core/typeclass/Monoid" -import * as order from "@fp-ts/core/typeclass/Order" -import * as semigroup from "@fp-ts/core/typeclass/Semigroup" - -const sum = (that: number) => (self: number): number => self + that - -export const SemigroupSum: semigroup.Semigroup = semigroup.fromCombine(sum) - -export const MonoidSum: Monoid = monoid.fromSemigroup(SemigroupSum, 0) - -const multiply = (that: number) => (self: number): number => self * that - -export const SemigroupMultiply: semigroup.Semigroup = { - combine: multiply, - combineMany: (collection) => - (self) => { - let multiplication: number = self - if (multiplication === 0) { - return 0 - } - for (const n of collection) { - if (n === 0) { - return 0 - } - multiplication = multiplication * n - } - return multiplication - } -} - -export const Order: order.Order = order.fromCompare((that) => - (self) => self < that ? -1 : self > that ? 1 : 0 -) - -export const Bounded: bounded.Bounded = { - ...Order, - maxBound: Infinity, - minBound: -Infinity -} diff --git a/test/data/string.ts b/test/data/string.ts deleted file mode 100644 index d317c3cc0..000000000 --- a/test/data/string.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as monoid from "@fp-ts/core/typeclass/Monoid" -import type * as order from "@fp-ts/core/typeclass/Order" -import * as semigroup from "@fp-ts/core/typeclass/Semigroup" - -export const Semigroup: semigroup.Semigroup = semigroup.fromCombine((that) => - (self) => self + that -) - -export const Monoid: monoid.Monoid = monoid.fromSemigroup(Semigroup, "") - -export const Order: order.Order = { - compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 -} diff --git a/test/limbo/CovariantWithIndex.ts b/test/limbo/CovariantWithIndex.ts deleted file mode 100644 index 0ef9c20d9..000000000 --- a/test/limbo/CovariantWithIndex.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @since 1.0.0 - */ -import { pipe } from "@fp-ts/core/Function" -import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import type { Covariant } from "@fp-ts/core/typeclass/Covariant" - -/** - * @category type class - * @since 1.0.0 - */ -export interface CovariantWithIndex extends TypeClass { - readonly mapWithIndex: ( - f: (a: A, i: I) => B - ) => (self: Kind) => Kind -} - -/** - * Returns a default `mapWithIndex` composition. - * - * @since 1.0.0 - */ -export const mapWithIndexComposition = ( - F: CovariantWithIndex, - G: CovariantWithIndex -): (( - f: (a: A, ij: readonly [I, J]) => B -) => ( - self: Kind> -) => Kind>) => - (f) => F.mapWithIndex((ga, i) => pipe(ga, G.mapWithIndex((a, j) => f(a, [i, j])))) - -/** - * Returns a default `map` implementation. - * - * @since 1.0.0 - */ -export const map = ( - F: CovariantWithIndex -): Covariant["map"] => f => F.mapWithIndex(f) diff --git a/test/typeclass/Applicative.ts b/test/typeclass/Applicative.ts index 80d5a7908..c62252223 100644 --- a/test/typeclass/Applicative.ts +++ b/test/typeclass/Applicative.ts @@ -1,16 +1,16 @@ import { pipe } from "@fp-ts/core/Function" +import * as N from "@fp-ts/core/Number" +import * as O from "@fp-ts/core/Option" import * as _ from "@fp-ts/core/typeclass/Applicative" -import * as N from "../data/number" -import * as O from "../data/Option" import * as U from "../util" describe("Applicative", () => { it("liftMonoid", () => { const liftMonoid = _.liftMonoid(O.Applicative) const M = liftMonoid(N.MonoidSum) - U.deepStrictEqual(pipe(O.none, M.combine(O.none)), O.none) - U.deepStrictEqual(pipe(O.some(1), M.combine(O.none)), O.none) - U.deepStrictEqual(pipe(O.none, M.combine(O.some(2))), O.none) + U.deepStrictEqual(pipe(O.none(), M.combine(O.none())), O.none()) + U.deepStrictEqual(pipe(O.some(1), M.combine(O.none())), O.none()) + U.deepStrictEqual(pipe(O.none(), M.combine(O.some(2))), O.none()) U.deepStrictEqual(pipe(O.some(1), M.combine(O.some(2))), O.some(3)) }) }) diff --git a/test/typeclass/Bicovariant.ts b/test/typeclass/Bicovariant.ts index 6b661cf0d..5bc02c0f5 100644 --- a/test/typeclass/Bicovariant.ts +++ b/test/typeclass/Bicovariant.ts @@ -1,8 +1,8 @@ +import type { EitherTypeLambda } from "@fp-ts/core/Either" +import * as E from "@fp-ts/core/Either" import { pipe } from "@fp-ts/core/Function" +import * as RA from "@fp-ts/core/ReadonlyArray" import * as _ from "@fp-ts/core/typeclass/Bicovariant" -import type { EitherTypeLambda } from "../data/Either" -import * as E from "../data/Either" -import * as RA from "../data/ReadonlyArray" import * as U from "../util" export const Bicovariant: _.Bicovariant = { diff --git a/test/typeclass/Bounded.ts b/test/typeclass/Bounded.ts index 7c02285dc..0744c5c9b 100644 --- a/test/typeclass/Bounded.ts +++ b/test/typeclass/Bounded.ts @@ -1,10 +1,10 @@ +import * as Number from "@fp-ts/core/Number" import * as _ from "@fp-ts/core/typeclass/Bounded" -import * as number from "../data/number" import * as U from "../util" describe("Bounded", () => { it("clamp", () => { - const clamp = _.clamp({ ...number.Order, minBound: 1, maxBound: 10 }) + const clamp = _.clamp({ ...Number.Order, minBound: 1, maxBound: 10 }) U.deepStrictEqual(clamp(2), 2) U.deepStrictEqual(clamp(10), 10) U.deepStrictEqual(clamp(20), 10) @@ -13,7 +13,7 @@ describe("Bounded", () => { }) it("reverse", () => { - const B = _.reverse({ ...number.Order, minBound: 10, maxBound: 1 }) + const B = _.reverse({ ...Number.Order, minBound: 10, maxBound: 1 }) U.deepStrictEqual(B.maxBound, 1) U.deepStrictEqual(B.minBound, 10) }) diff --git a/test/typeclass/Chainable.ts b/test/typeclass/Chainable.ts index a608ff5ac..944c8f118 100644 --- a/test/typeclass/Chainable.ts +++ b/test/typeclass/Chainable.ts @@ -1,28 +1,28 @@ import { pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" import * as _ from "@fp-ts/core/typeclass/Chainable" -import * as O from "../data/Option" import * as U from "../util" describe("Chainable", () => { it("andThenDiscard", () => { const andThenDiscard = _.andThenDiscard(O.Chainable) - U.deepStrictEqual(pipe(O.none, andThenDiscard(O.none)), O.none) - U.deepStrictEqual(pipe(O.none, andThenDiscard(O.some(2))), O.none) - U.deepStrictEqual(pipe(O.some(1), andThenDiscard(O.none)), O.none) + U.deepStrictEqual(pipe(O.none(), andThenDiscard(O.none())), O.none()) + U.deepStrictEqual(pipe(O.none(), andThenDiscard(O.some(2))), O.none()) + U.deepStrictEqual(pipe(O.some(1), andThenDiscard(O.none())), O.none()) U.deepStrictEqual(pipe(O.some(1), andThenDiscard(O.some(2))), O.some(1)) }) it("bind", () => { const bind = _.bind(O.Chainable) - U.deepStrictEqual(pipe(O.Do, bind("a", () => O.none)), O.none) + U.deepStrictEqual(pipe(O.Do, bind("a", () => O.none())), O.none()) U.deepStrictEqual(pipe(O.Do, bind("a", () => O.some(1))), O.some({ a: 1 })) }) it("tap", () => { const tap = _.tap(O.Chainable) - U.deepStrictEqual(pipe(O.none, tap(() => O.none)), O.none) - U.deepStrictEqual(pipe(O.none, tap(() => O.some(2))), O.none) - U.deepStrictEqual(pipe(O.some(1), tap(() => O.none)), O.none) + U.deepStrictEqual(pipe(O.none(), tap(() => O.none())), O.none()) + U.deepStrictEqual(pipe(O.none(), tap(() => O.some(2))), O.none()) + U.deepStrictEqual(pipe(O.some(1), tap(() => O.none())), O.none()) U.deepStrictEqual(pipe(O.some(1), tap(() => O.some(2))), O.some(1)) }) }) diff --git a/test/typeclass/Contravariant.ts b/test/typeclass/Contravariant.ts index ca8255303..de754eb91 100644 --- a/test/typeclass/Contravariant.ts +++ b/test/typeclass/Contravariant.ts @@ -1,8 +1,8 @@ import { pipe } from "@fp-ts/core/Function" +import * as P from "@fp-ts/core/Predicate" +import * as S from "@fp-ts/core/String" import * as _ from "@fp-ts/core/typeclass/Contravariant" import * as order from "@fp-ts/core/typeclass/Order" -import * as P from "../data/Predicate" -import * as string from "../data/string" import * as U from "../util" describe("Contravariant", () => { @@ -10,7 +10,7 @@ describe("Contravariant", () => { const map = _.contramapComposition(P.Contravariant, P.Contravariant) const emptyString: P.Predicate> = p => p("") === true const a = pipe(emptyString, map(s => s.length)) - U.deepStrictEqual(a(P.isString), false) + U.deepStrictEqual(a(S.isString), false) U.deepStrictEqual(a(n => n === 0), true) }) @@ -19,7 +19,7 @@ describe("Contravariant", () => { (s: string) => [s], ([s]) => s )( - string.Order + S.Order ) U.deepStrictEqual(pipe(["a"], O.compare(["b"])), -1) U.deepStrictEqual(pipe(["a"], O.compare(["a"])), 0) diff --git a/test/typeclass/Coproduct.ts b/test/typeclass/Coproduct.ts index 9299dfa1a..0a138b74e 100644 --- a/test/typeclass/Coproduct.ts +++ b/test/typeclass/Coproduct.ts @@ -1,17 +1,17 @@ import { pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" import * as _ from "@fp-ts/core/typeclass/Coproduct" -import * as O from "../data/Option" import * as U from "../util" describe("Coproduct", () => { it("getMonoid", () => { const M = _.getMonoid(O.Alternative)() - U.deepStrictEqual(pipe(O.none, M.combine(O.none)), O.none) - U.deepStrictEqual(pipe(O.some(1), M.combine(O.none)), O.some(1)) - U.deepStrictEqual(pipe(O.none, M.combine(O.some(2))), O.some(2)) + U.deepStrictEqual(pipe(O.none(), M.combine(O.none())), O.none()) + U.deepStrictEqual(pipe(O.some(1), M.combine(O.none())), O.some(1)) + U.deepStrictEqual(pipe(O.none(), M.combine(O.some(2))), O.some(2)) U.deepStrictEqual(pipe(O.some(1), M.combine(O.some(2))), O.some(1)) - U.deepStrictEqual(pipe(M.empty, M.combine(O.none)), O.none) + U.deepStrictEqual(pipe(M.empty, M.combine(O.none())), O.none()) U.deepStrictEqual(pipe(M.empty, M.combine(O.some(2))), O.some(2)) U.deepStrictEqual(pipe(O.some(1), M.combine(M.empty)), O.some(1)) }) diff --git a/test/typeclass/Covariant.ts b/test/typeclass/Covariant.ts index 309380285..5fc4acac0 100644 --- a/test/typeclass/Covariant.ts +++ b/test/typeclass/Covariant.ts @@ -1,7 +1,7 @@ import { pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" +import * as RA from "@fp-ts/core/ReadonlyArray" import * as _ from "@fp-ts/core/typeclass/Covariant" -import * as O from "../data/Option" -import * as RA from "../data/ReadonlyArray" import * as U from "../util" describe("Covariant", () => { @@ -21,19 +21,19 @@ describe("Covariant", () => { it("flap", () => { const flap = _.flap(O.Covariant) - U.deepStrictEqual(pipe(O.none, flap(1)), O.none) + U.deepStrictEqual(pipe(O.none(), flap(1)), O.none()) U.deepStrictEqual(pipe(O.some(U.double), flap(1)), O.some(2)) }) it("as", () => { const as = _.as(O.Covariant) - U.deepStrictEqual(pipe(O.none, as(1)), O.none) + U.deepStrictEqual(pipe(O.none(), as(1)), O.none()) U.deepStrictEqual(pipe(O.some(1), as(2)), O.some(2)) }) it("asUnit", () => { const asUnit = _.asUnit(O.Covariant) - U.deepStrictEqual(pipe(O.none, asUnit), O.none) + U.deepStrictEqual(pipe(O.none(), asUnit), O.none()) U.deepStrictEqual(pipe(O.some(1), asUnit), O.some(undefined)) }) @@ -47,7 +47,7 @@ describe("Covariant", () => { it("imap", () => { const f = _.imap(O.map)((s: string) => [s], ([s]) => s) - U.deepStrictEqual(pipe(O.none, f), O.none) + U.deepStrictEqual(pipe(O.none(), f), O.none()) U.deepStrictEqual(pipe(O.some("a"), f), O.some(["a"])) }) }) diff --git a/test/typeclass/CovariantWithIndex.ts b/test/typeclass/CovariantWithIndex.ts index f60fa5511..d2a92dd15 100644 --- a/test/typeclass/CovariantWithIndex.ts +++ b/test/typeclass/CovariantWithIndex.ts @@ -1,6 +1,6 @@ import { pipe } from "@fp-ts/core/Function" -import * as RA from "../data/ReadonlyArray" -import * as _ from "../limbo/CovariantWithIndex" +import * as RA from "@fp-ts/core/ReadonlyArray" +import * as _ from "@fp-ts/core/typeclass/CovariantWithIndex" import * as U from "../util" describe("CovariantWithIndex", () => { diff --git a/test/typeclass/FlatMap.ts b/test/typeclass/FlatMap.ts index 3ee00c623..4ce685825 100644 --- a/test/typeclass/FlatMap.ts +++ b/test/typeclass/FlatMap.ts @@ -1,31 +1,31 @@ import { pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" import * as _ from "@fp-ts/core/typeclass/FlatMap" -import * as O from "../data/Option" import * as U from "../util" describe("FlatMap", () => { it("flatten", () => { const flatten = _.flatten(O.FlatMap) - U.deepStrictEqual(pipe(O.none, flatten), O.none) - U.deepStrictEqual(pipe(O.some(O.none), flatten), O.none) + U.deepStrictEqual(pipe(O.none(), flatten), O.none()) + U.deepStrictEqual(pipe(O.some(O.none()), flatten), O.none()) U.deepStrictEqual(pipe(O.some(O.some(1)), flatten), O.some(1)) }) it("andThen", () => { const andThen = _.andThen(O.FlatMap) - U.deepStrictEqual(pipe(O.none, andThen(O.none)), O.none) - U.deepStrictEqual(pipe(O.none, andThen(O.some(2))), O.none) - U.deepStrictEqual(pipe(O.some(1), andThen(O.none)), O.none) + U.deepStrictEqual(pipe(O.none(), andThen(O.none())), O.none()) + U.deepStrictEqual(pipe(O.none(), andThen(O.some(2))), O.none()) + U.deepStrictEqual(pipe(O.some(1), andThen(O.none())), O.none()) U.deepStrictEqual(pipe(O.some(1), andThen(O.some(2))), O.some(2)) }) it("composeKleisliArrow", () => { const composeKleisliArrow = _.composeKleisliArrow(O.FlatMap) - const f = (s: string): O.Option => s.length > 0 ? O.some(s.length) : O.none - const g = (n: number): O.Option => n > 1 ? O.some(n) : O.none + const f = (s: string): O.Option => s.length > 0 ? O.some(s.length) : O.none() + const g = (n: number): O.Option => n > 1 ? O.some(n) : O.none() const h = pipe(f, composeKleisliArrow(g)) - U.deepStrictEqual(h(""), O.none) - U.deepStrictEqual(h("a"), O.none) + U.deepStrictEqual(h(""), O.none()) + U.deepStrictEqual(h("a"), O.none()) U.deepStrictEqual(h("aa"), O.some(2)) }) }) diff --git a/test/typeclass/Foldable.ts b/test/typeclass/Foldable.ts index dec700db0..a2569c4a3 100644 --- a/test/typeclass/Foldable.ts +++ b/test/typeclass/Foldable.ts @@ -1,8 +1,8 @@ import { pipe } from "@fp-ts/core/Function" +import * as N from "@fp-ts/core/Number" +import * as O from "@fp-ts/core/Option" +import * as RA from "@fp-ts/core/ReadonlyArray" import * as _ from "@fp-ts/core/typeclass/Foldable" -import * as number from "../data/number" -import * as O from "../data/Option" -import * as RA from "../data/ReadonlyArray" import * as U from "../util" describe("Foldable", () => { @@ -16,19 +16,19 @@ describe("Foldable", () => { it("toArray", () => { const toArray = _.toArray(O.Foldable) - U.deepStrictEqual(toArray(O.none), []) + U.deepStrictEqual(toArray(O.none()), []) U.deepStrictEqual(toArray(O.some(2)), [2]) }) it("toArrayWith", () => { const toArrayWith = _.toArrayWith(O.Foldable) - U.deepStrictEqual(pipe(O.none, toArrayWith(U.double)), []) + U.deepStrictEqual(pipe(O.none(), toArrayWith(U.double)), []) U.deepStrictEqual(pipe(O.some(2), toArrayWith(U.double)), [4]) }) it("foldMap", () => { const foldMap = _.foldMap(RA.Foldable) - U.deepStrictEqual(pipe([1, 2, 3], foldMap(number.MonoidSum)(U.double)), 12) + U.deepStrictEqual(pipe([1, 2, 3], foldMap(N.MonoidSum)(U.double)), 12) }) it("reduceRight", () => { @@ -38,39 +38,39 @@ describe("Foldable", () => { it("reduceKind", () => { const reduceKind = _.reduceKind(RA.Foldable)(O.Monad) - U.deepStrictEqual(pipe([], reduceKind("-", () => O.none)), O.some("-")) - U.deepStrictEqual(pipe(["a"], reduceKind("-", () => O.none)), O.none) + U.deepStrictEqual(pipe([], reduceKind("-", () => O.none())), O.some("-")) + U.deepStrictEqual(pipe(["a"], reduceKind("-", () => O.none())), O.none()) U.deepStrictEqual( pipe(["a", "b", "c"], reduceKind("-", (b, a) => O.some(b + a))), O.some("-abc") ) U.deepStrictEqual( - pipe(["a", "b", "c"], reduceKind("-", (b, a) => a === "b" ? O.none : O.some(b + a))), - O.none + pipe(["a", "b", "c"], reduceKind("-", (b, a) => a === "b" ? O.none() : O.some(b + a))), + O.none() ) }) it("reduceRightKind", () => { const reduceRightKind = _.reduceRightKind(RA.Foldable)(O.Monad) - U.deepStrictEqual(pipe([], reduceRightKind("-", () => O.none)), O.some("-")) - U.deepStrictEqual(pipe(["a"], reduceRightKind("-", () => O.none)), O.none) + U.deepStrictEqual(pipe([], reduceRightKind("-", () => O.none())), O.some("-")) + U.deepStrictEqual(pipe(["a"], reduceRightKind("-", () => O.none())), O.none()) U.deepStrictEqual( pipe(["a", "b", "c"], reduceRightKind("-", (b, a) => O.some(b + a))), O.some("-cba") ) U.deepStrictEqual( - pipe(["a", "b", "c"], reduceRightKind("-", (b, a) => a === "b" ? O.none : O.some(b + a))), - O.none + pipe(["a", "b", "c"], reduceRightKind("-", (b, a) => a === "b" ? O.none() : O.some(b + a))), + O.none() ) }) it("foldMapKind", () => { const foldMapKind = _.foldMapKind(RA.Foldable)(O.Alternative) - U.deepStrictEqual(pipe([], foldMapKind(() => O.none)), O.none) - U.deepStrictEqual(pipe(["a"], foldMapKind(() => O.none)), O.none) + U.deepStrictEqual(pipe([], foldMapKind(() => O.none())), O.none()) + U.deepStrictEqual(pipe(["a"], foldMapKind(() => O.none())), O.none()) U.deepStrictEqual(pipe(["a", "b", "c"], foldMapKind((a) => O.some(a))), O.some("a")) U.deepStrictEqual( - pipe(["a", "b", "c"], foldMapKind((a) => a === "b" ? O.none : O.some(a))), + pipe(["a", "b", "c"], foldMapKind((a) => a === "b" ? O.none() : O.some(a))), O.some("a") ) }) diff --git a/test/typeclass/FoldableWithIndex.ts b/test/typeclass/FoldableWithIndex.ts index cdcffd5ee..7cadae671 100644 --- a/test/typeclass/FoldableWithIndex.ts +++ b/test/typeclass/FoldableWithIndex.ts @@ -1,57 +1,57 @@ -import { pipe } from "@fp-ts/core/Function" -import * as number from "../data/number" -import * as O from "../data/Option" -import * as RA from "../data/ReadonlyArray" -import * as foldableWithIndex from "../limbo/FoldableWithIndex" -import * as U from "../util" +// import { pipe } from "@fp-ts/core/Function" +// import * as N from "@fp-ts/core/Number" +// import * as O from "@fp-ts/core/Option" +// import * as RA from "@fp-ts/core/ReadonlyArray" +// import * as foldableWithIndex from "../limbo/FoldableWithIndex" +// import * as U from "../util" -describe("FoldableWithIndex", () => { - it("reduceWithIndexComposition", () => { - const reduceWithIndex = foldableWithIndex.reduceWithIndexComposition( - RA.FoldableWithIndex, - RA.FoldableWithIndex - ) - const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j - U.deepStrictEqual(pipe([], reduceWithIndex("-", f)), "-") - U.deepStrictEqual(pipe([[]], reduceWithIndex("-", f)), "-") - U.deepStrictEqual( - pipe([["a", "c"], ["b", "d"]], reduceWithIndex("-", f)), - "-a00c01b10d11" - ) - }) +// describe("FoldableWithIndex", () => { +// it("reduceWithIndexComposition", () => { +// const reduceWithIndex = foldableWithIndex.reduceWithIndexComposition( +// RA.FoldableWithIndex, +// RA.FoldableWithIndex +// ) +// const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j +// U.deepStrictEqual(pipe([], reduceWithIndex("-", f)), "-") +// U.deepStrictEqual(pipe([[]], reduceWithIndex("-", f)), "-") +// U.deepStrictEqual( +// pipe([["a", "c"], ["b", "d"]], reduceWithIndex("-", f)), +// "-a00c01b10d11" +// ) +// }) - it("reduceRightWithIndexComposition", () => { - const reduceRightWithIndex = foldableWithIndex.reduceRightWithIndexComposition( - RA.FoldableWithIndex, - RA.FoldableWithIndex - ) - const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j - U.deepStrictEqual(pipe([], reduceRightWithIndex("-", f)), "-") - U.deepStrictEqual(pipe([[]], reduceRightWithIndex("-", f)), "-") - U.deepStrictEqual( - pipe([["a", "c"], ["b", "d"]], reduceRightWithIndex("-", f)), - "-d11b10c01a00" - ) - }) +// it("reduceRightWithIndexComposition", () => { +// const reduceRightWithIndex = foldableWithIndex.reduceRightWithIndexComposition( +// RA.FoldableWithIndex, +// RA.FoldableWithIndex +// ) +// const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j +// U.deepStrictEqual(pipe([], reduceRightWithIndex("-", f)), "-") +// U.deepStrictEqual(pipe([[]], reduceRightWithIndex("-", f)), "-") +// U.deepStrictEqual( +// pipe([["a", "c"], ["b", "d"]], reduceRightWithIndex("-", f)), +// "-d11b10c01a00" +// ) +// }) - it("toArray", () => { - const toReadonlyArray = foldableWithIndex.toArray(O.FoldableWithIndex) - U.deepStrictEqual(toReadonlyArray(O.none), []) - U.deepStrictEqual(toReadonlyArray(O.some(2)), [2]) - }) +// it("toArray", () => { +// const toReadonlyArray = foldableWithIndex.toArray(O.FoldableWithIndex) +// U.deepStrictEqual(toReadonlyArray(O.none()), []) +// U.deepStrictEqual(toReadonlyArray(O.some(2)), [2]) +// }) - it("toArrayWith", () => { - const toReadonlyArrayWith = foldableWithIndex.toArrayWith(O.FoldableWithIndex) - U.deepStrictEqual(pipe(O.none, toReadonlyArrayWith(U.double)), []) - U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith(U.double)), [4]) - U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith((a, i) => U.double(a) * i)), [0]) - }) +// it("toArrayWith", () => { +// const toReadonlyArrayWith = foldableWithIndex.toArrayWith(O.FoldableWithIndex) +// U.deepStrictEqual(pipe(O.none(), toReadonlyArrayWith(U.double)), []) +// U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith(U.double)), [4]) +// U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith((a, i) => U.double(a) * i)), [0]) +// }) - it("foldMapWithIndex", () => { - const foldMapWithIndex = foldableWithIndex.foldMapWithIndex(RA.FoldableWithIndex) - U.deepStrictEqual( - pipe([1, 2, 3], foldMapWithIndex(number.MonoidSum)((n, i) => (n * 2) + i)), - 15 - ) - }) -}) +// it("foldMapWithIndex", () => { +// const foldMapWithIndex = foldableWithIndex.foldMapWithIndex(RA.FoldableWithIndex) +// U.deepStrictEqual( +// pipe([1, 2, 3], foldMapWithIndex(N.MonoidSum)((n, i) => (n * 2) + i)), +// 15 +// ) +// }) +// }) diff --git a/test/typeclass/Invariant.ts b/test/typeclass/Invariant.ts index 808c746ea..c12bfc3b5 100644 --- a/test/typeclass/Invariant.ts +++ b/test/typeclass/Invariant.ts @@ -1,18 +1,18 @@ import { pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" +import * as P from "@fp-ts/core/Predicate" +import * as String from "@fp-ts/core/String" import * as _ from "@fp-ts/core/typeclass/Invariant" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" -import * as O from "../data/Option" -import * as P from "../data/Predicate" -import * as string from "../data/string" import * as U from "../util" describe("Invariant", () => { it("imapComposition", () => { const imap = _.imapComposition(semigroup.Invariant, O.Invariant) - const S = pipe(O.getMonoid(string.Semigroup), imap(s => [s] as const, ([s]) => s)) - U.deepStrictEqual(pipe(O.none, S.combine(O.none)), O.none) - U.deepStrictEqual(pipe(O.none, S.combine(O.some(["b"]))), O.some(["b"] as const)) - U.deepStrictEqual(pipe(O.some(["a"] as const), S.combine(O.none)), O.some(["a"] as const)) + const S = pipe(O.getMonoid(String.Semigroup), imap(s => [s] as const, ([s]) => s)) + U.deepStrictEqual(pipe(O.none(), S.combine(O.none())), O.none()) + U.deepStrictEqual(pipe(O.none(), S.combine(O.some(["b"]))), O.some(["b"] as const)) + U.deepStrictEqual(pipe(O.some(["a"] as const), S.combine(O.none())), O.some(["a"] as const)) U.deepStrictEqual( pipe(O.some(["a"] as const), S.combine(O.some(["b"]))), O.some(["ab"] as const) @@ -22,13 +22,13 @@ describe("Invariant", () => { describe("bindTo", () => { it("Covariant (Option)", () => { const bindTo = _.bindTo(O.Invariant) - U.deepStrictEqual(pipe(O.none, bindTo("a")), O.none) + U.deepStrictEqual(pipe(O.none(), bindTo("a")), O.none()) U.deepStrictEqual(pipe(O.some(1), bindTo("a")), O.some({ a: 1 })) }) it("Contravariant (Predicate)", () => { const bindTo = _.bindTo(P.Invariant) - const p = pipe(P.isString, bindTo("a")) + const p = pipe(String.isString, bindTo("a")) U.deepStrictEqual(p({ a: "a" }), true) U.deepStrictEqual(p({ a: 1 }), false) }) @@ -37,13 +37,13 @@ describe("Invariant", () => { describe("tupled", () => { it("Covariant (Option)", () => { const tupled = _.tupled(O.Invariant) - U.deepStrictEqual(pipe(O.none, tupled), O.none) + U.deepStrictEqual(pipe(O.none(), tupled), O.none()) U.deepStrictEqual(pipe(O.some(1), tupled), O.some([1] as const)) }) it("Contravariant (Predicate)", () => { const tupled = _.tupled(P.Invariant) - const p = pipe(P.isString, tupled) + const p = pipe(String.isString, tupled) U.deepStrictEqual(p(["a"]), true) U.deepStrictEqual(p([1]), false) }) diff --git a/test/typeclass/Monoid.ts b/test/typeclass/Monoid.ts index fd46f6808..4e9dbae21 100644 --- a/test/typeclass/Monoid.ts +++ b/test/typeclass/Monoid.ts @@ -1,26 +1,26 @@ import { pipe } from "@fp-ts/core/Function" +import * as N from "@fp-ts/core/Number" +import * as String from "@fp-ts/core/String" import * as monoid from "@fp-ts/core/typeclass/Monoid" -import * as number from "../data/number" -import * as string from "../data/string" import * as U from "../util" describe("Monoid", () => { it("min", () => { - const M = monoid.min(number.Bounded) + const M = monoid.min(N.Bounded) U.deepStrictEqual(M.combineAll([]), +Infinity) U.deepStrictEqual(M.combineAll([1]), 1) U.deepStrictEqual(M.combineAll([1, -1]), -1) }) it("max", () => { - const M = monoid.max(number.Bounded) + const M = monoid.max(N.Bounded) U.deepStrictEqual(M.combineAll([]), -Infinity) U.deepStrictEqual(M.combineAll([1]), 1) U.deepStrictEqual(M.combineAll([1, -1]), 1) }) it("reverse", () => { - const M = monoid.reverse(string.Monoid) + const M = monoid.reverse(String.Monoid) U.deepStrictEqual(pipe("a", M.combine("b")), "ba") U.deepStrictEqual(pipe("a", M.combine(M.empty)), "a") U.deepStrictEqual(pipe(M.empty, M.combine("a")), "a") @@ -33,8 +33,8 @@ describe("Monoid", () => { describe("struct", () => { it("baseline", () => { const M = monoid.struct({ - name: string.Monoid, - age: number.MonoidSum + name: String.Monoid, + age: N.MonoidSum }) U.deepStrictEqual(M.empty, { name: "", age: 0 }) U.deepStrictEqual(pipe({ name: "a", age: 10 }, M.combine({ name: "b", age: 20 })), { @@ -52,8 +52,8 @@ describe("Monoid", () => { it("tuple", () => { const M = monoid.tuple( - string.Monoid, - number.MonoidSum + String.Monoid, + N.MonoidSum ) U.deepStrictEqual(M.empty, ["", 0]) U.deepStrictEqual(pipe(["a", 10], M.combine(["b", 20])), ["ab", 30]) diff --git a/test/typeclass/NonEmptyTraversable.ts b/test/typeclass/NonEmptyTraversable.ts index ce901b412..4fbb4de6b 100644 --- a/test/typeclass/NonEmptyTraversable.ts +++ b/test/typeclass/NonEmptyTraversable.ts @@ -1,42 +1,45 @@ +import * as O from "@fp-ts/core/Option" +import * as RA from "@fp-ts/core/ReadonlyArray" import * as _ from "@fp-ts/core/typeclass/NonEmptyTraversable" -import * as NERA from "../data/NonEmptyReadonlyArray" -import * as O from "../data/Option" import * as U from "../util" describe("NonEmptyTraversable", () => { it("traverseNonEmptyComposition", () => { const traverseNonEmpty = _.traverseNonEmptyComposition( - NERA.NonEmptyTraversable, - NERA.NonEmptyTraversable - )(O.SemiApplicative)((n: number) => (n > 0 ? O.some(n) : O.none)) + RA.NonEmptyTraversable, + RA.NonEmptyTraversable + )(O.SemiApplicative)((n: number) => (n > 0 ? O.some(n) : O.none())) U.deepStrictEqual(traverseNonEmpty([[1]]), O.some([[1]] as const)) - U.deepStrictEqual(traverseNonEmpty([[1, -1]]), O.none) + U.deepStrictEqual(traverseNonEmpty([[1, -1]]), O.none()) U.deepStrictEqual(traverseNonEmpty([[1, 2, 3], [4, 5]]), O.some([[1, 2, 3], [4, 5]] as const)) - U.deepStrictEqual(traverseNonEmpty([[1, 2, 3], [4, -1]]), O.none) + U.deepStrictEqual(traverseNonEmpty([[1, 2, 3], [4, -1]]), O.none()) }) it("traverseNonEmptyComposition", () => { const sequence = _.sequenceNonEmptyComposition( - { ...NERA.NonEmptyTraversable, ...NERA.Covariant }, - NERA.NonEmptyTraversable + { ...RA.NonEmptyTraversable, ...RA.NonEmptyCovariant }, + RA.NonEmptyTraversable )(O.SemiApplicative) U.deepStrictEqual(sequence([[O.some(1)]]), O.some([[1]] as const)) - U.deepStrictEqual(sequence([[O.some(1), O.none]]), O.none) + U.deepStrictEqual(sequence([[O.some(1), O.none()]]), O.none()) U.deepStrictEqual( sequence([[O.some(1), O.some(2), O.some(3)], [O.some(4), O.some(5)]]), O.some([[1, 2, 3], [4, 5]] as const) ) - U.deepStrictEqual(sequence([[O.some(1), O.some(2), O.some(3)], [O.some(4), O.none]]), O.none) + U.deepStrictEqual( + sequence([[O.some(1), O.some(2), O.some(3)], [O.some(4), O.none()]]), + O.none() + ) }) it("sequenceNonEmpty", () => { - const sequenceNonEmpty = _.sequenceNonEmpty( - NERA.NonEmptyTraversable.traverseNonEmpty + const sequenceNonEmpty = _.sequenceNonEmpty( + RA.NonEmptyTraversable.traverseNonEmpty )(O.SemiApplicative) - U.deepStrictEqual(sequenceNonEmpty([O.none]), O.none) + U.deepStrictEqual(sequenceNonEmpty([O.none()]), O.none()) U.deepStrictEqual(sequenceNonEmpty([O.some(1)]), O.some([1] as const)) - U.deepStrictEqual(sequenceNonEmpty([O.none]), O.none) - U.deepStrictEqual(sequenceNonEmpty([O.some(1), O.none]), O.none) + U.deepStrictEqual(sequenceNonEmpty([O.none()]), O.none()) + U.deepStrictEqual(sequenceNonEmpty([O.some(1), O.none()]), O.none()) U.deepStrictEqual(sequenceNonEmpty([O.some(1), O.some(2)]), O.some([1, 2] as const)) }) }) diff --git a/test/typeclass/Of.ts b/test/typeclass/Of.ts index 8fb357fdd..487f8e39a 100644 --- a/test/typeclass/Of.ts +++ b/test/typeclass/Of.ts @@ -1,6 +1,6 @@ +import * as O from "@fp-ts/core/Option" +import * as RA from "@fp-ts/core/ReadonlyArray" import * as _ from "@fp-ts/core/typeclass/Of" -import * as O from "../data/Option" -import * as RA from "../data/ReadonlyArray" import * as U from "../util" describe("Of", () => { diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index 4fccb6243..7910bbc90 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -1,9 +1,9 @@ +import * as boolean from "@fp-ts/core/Boolean" import { pipe } from "@fp-ts/core/Function" +import * as number from "@fp-ts/core/Number" +import { sort } from "@fp-ts/core/ReadonlyArray" +import * as string from "@fp-ts/core/String" import * as _ from "@fp-ts/core/typeclass/Order" -import * as boolean from "../data/boolean" -import * as number from "../data/number" -import { sort } from "../data/ReadonlyArray" -import * as string from "../data/string" import * as U from "../util" describe("Order", () => { diff --git a/test/typeclass/Product.ts b/test/typeclass/Product.ts index 16a74eb35..3ae0590ff 100644 --- a/test/typeclass/Product.ts +++ b/test/typeclass/Product.ts @@ -1,10 +1,11 @@ +import * as Boolean from "@fp-ts/core/Boolean" import { pipe } from "@fp-ts/core/Function" +import * as Number from "@fp-ts/core/Number" +import * as O from "@fp-ts/core/Option" +import * as P from "@fp-ts/core/Predicate" +import * as String from "@fp-ts/core/String" import * as _ from "@fp-ts/core/typeclass/Product" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" -import * as number from "../data/number" -import * as O from "../data/Option" -import * as P from "../data/Predicate" -import * as string from "../data/string" import * as U from "../util" describe("Product", () => { @@ -17,20 +18,20 @@ describe("Product", () => { tuple(O.some("a"), O.some(1), O.some(true)), O.some(["a", 1, true] as const) ) - U.deepStrictEqual(tuple(O.some("a"), O.some(1), O.none), O.none) + U.deepStrictEqual(tuple(O.some("a"), O.some(1), O.none()), O.none()) }) it("Invariant (Semigroup)", () => { const tuple = _.tuple(semigroup.Product) U.deepStrictEqual(pipe([], tuple().combine([])), []) - const S = tuple(string.Semigroup, number.SemigroupSum) + const S = tuple(String.Semigroup, Number.SemigroupSum) U.deepStrictEqual(pipe(["a", 2], S.combine(["b", 3])), ["ab", 5]) }) it("Contravariant (Predicate)", () => { const tuple = _.tuple(P.Product) U.deepStrictEqual(tuple()([]), true) - const p = tuple(P.isString, P.isNumber, P.isBoolean) + const p = tuple(String.isString, Number.isNumber, Boolean.isBoolean) U.deepStrictEqual(p(["a", 1, true]), true) U.deepStrictEqual(p(["a", 1, "b"]), false) }) @@ -46,22 +47,22 @@ describe("Product", () => { O.some({ a: "a", b: 1, c: true }) ) U.deepStrictEqual( - struct({ a: O.some("a"), b: O.some(1), c: O.none }), - O.none + struct({ a: O.some("a"), b: O.some(1), c: O.none() }), + O.none() ) }) it("Invariant (Semigroup)", () => { const struct = _.struct(semigroup.Product) U.deepStrictEqual(pipe({}, struct({}).combine({})), {}) - const S = struct({ x: string.Semigroup, y: number.SemigroupSum }) + const S = struct({ x: String.Semigroup, y: Number.SemigroupSum }) U.deepStrictEqual(pipe({ x: "a", y: 2 }, S.combine({ x: "b", y: 3 })), { x: "ab", y: 5 }) }) it("Contravariant (Predicate)", () => { const struct = _.struct(P.Product) U.deepStrictEqual(struct({})({}), true) - const p = struct({ x: P.isString, y: P.isNumber, z: P.isBoolean }) + const p = struct({ x: String.isString, y: Number.isNumber, z: Boolean.isBoolean }) U.deepStrictEqual(p({ x: "a", y: 1, z: true }), true) U.deepStrictEqual(p({ x: "a", y: 1, z: "b" }), false) }) diff --git a/test/typeclass/SemiApplicative.ts b/test/typeclass/SemiApplicative.ts index a1a81f87d..fad3732da 100644 --- a/test/typeclass/SemiApplicative.ts +++ b/test/typeclass/SemiApplicative.ts @@ -1,41 +1,41 @@ import { pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" +import * as String from "@fp-ts/core/String" import * as _ from "@fp-ts/core/typeclass/SemiApplicative" -import * as O from "../data/Option" -import * as string from "../data/string" import * as U from "../util" describe("SemiApplicative", () => { it("ap", () => { const ap = _.ap(O.SemiApplicative) const double = (n: number) => n * 2 - U.deepStrictEqual(pipe(O.none, ap(O.none)), O.none) - U.deepStrictEqual(pipe(O.none, ap(O.some(1))), O.none) - U.deepStrictEqual(pipe(O.some(double), ap(O.none)), O.none) + U.deepStrictEqual(pipe(O.none(), ap(O.none())), O.none()) + U.deepStrictEqual(pipe(O.none(), ap(O.some(1))), O.none()) + U.deepStrictEqual(pipe(O.some(double), ap(O.none())), O.none()) U.deepStrictEqual(pipe(O.some(double), ap(O.some(1))), O.some(2)) }) it("andThenDiscard", () => { const andThenDiscard = _.andThenDiscard(O.SemiApplicative) - U.deepStrictEqual(pipe(O.none, andThenDiscard(O.none)), O.none) - U.deepStrictEqual(pipe(O.none, andThenDiscard(O.some(2))), O.none) - U.deepStrictEqual(pipe(O.some(1), andThenDiscard(O.none)), O.none) + U.deepStrictEqual(pipe(O.none(), andThenDiscard(O.none())), O.none()) + U.deepStrictEqual(pipe(O.none(), andThenDiscard(O.some(2))), O.none()) + U.deepStrictEqual(pipe(O.some(1), andThenDiscard(O.none())), O.none()) U.deepStrictEqual(pipe(O.some(1), andThenDiscard(O.some(2))), O.some(1)) }) it("andThen", () => { const andThen = _.andThen(O.SemiApplicative) - U.deepStrictEqual(pipe(O.none, andThen(O.none)), O.none) - U.deepStrictEqual(pipe(O.none, andThen(O.some(2))), O.none) - U.deepStrictEqual(pipe(O.some(1), andThen(O.none)), O.none) + U.deepStrictEqual(pipe(O.none(), andThen(O.none())), O.none()) + U.deepStrictEqual(pipe(O.none(), andThen(O.some(2))), O.none()) + U.deepStrictEqual(pipe(O.some(1), andThen(O.none())), O.none()) U.deepStrictEqual(pipe(O.some(1), andThen(O.some(2))), O.some(2)) }) it("liftSemigroup", () => { const liftSemigroup = _.liftSemigroup(O.SemiApplicative) - const S = liftSemigroup(string.Semigroup) - U.deepStrictEqual(pipe(O.none, S.combine(O.none)), O.none) - U.deepStrictEqual(pipe(O.none, S.combine(O.some("b"))), O.none) - U.deepStrictEqual(pipe(O.some("a"), S.combine(O.none)), O.none) + const S = liftSemigroup(String.Semigroup) + U.deepStrictEqual(pipe(O.none(), S.combine(O.none())), O.none()) + U.deepStrictEqual(pipe(O.none(), S.combine(O.some("b"))), O.none()) + U.deepStrictEqual(pipe(O.some("a"), S.combine(O.none())), O.none()) U.deepStrictEqual(pipe(O.some("a"), S.combine(O.some("b"))), O.some("ab")) U.deepStrictEqual(pipe(O.some("a"), S.combineMany([O.some("b"), O.some("c")])), O.some("abc")) @@ -43,18 +43,18 @@ describe("SemiApplicative", () => { it("lift2", () => { const sum = _.lift2(O.SemiApplicative)((a: number, b: number) => a + b) - U.deepStrictEqual(sum(O.none, O.none), O.none) - U.deepStrictEqual(sum(O.some(1), O.none), O.none) - U.deepStrictEqual(sum(O.none, O.some(2)), O.none) + U.deepStrictEqual(sum(O.none(), O.none()), O.none()) + U.deepStrictEqual(sum(O.some(1), O.none()), O.none()) + U.deepStrictEqual(sum(O.none(), O.some(2)), O.none()) U.deepStrictEqual(sum(O.some(1), O.some(2)), O.some(3)) }) it("lift3", () => { const sum = _.lift3(O.SemiApplicative)((a: number, b: number, c: number) => a + b + c) - U.deepStrictEqual(sum(O.none, O.none, O.none), O.none) - U.deepStrictEqual(sum(O.some(1), O.none, O.none), O.none) - U.deepStrictEqual(sum(O.none, O.some(2), O.none), O.none) - U.deepStrictEqual(sum(O.none, O.none, O.some(3)), O.none) + U.deepStrictEqual(sum(O.none(), O.none(), O.none()), O.none()) + U.deepStrictEqual(sum(O.some(1), O.none(), O.none()), O.none()) + U.deepStrictEqual(sum(O.none(), O.some(2), O.none()), O.none()) + U.deepStrictEqual(sum(O.none(), O.none(), O.some(3)), O.none()) U.deepStrictEqual(sum(O.some(1), O.some(2), O.some(3)), O.some(6)) }) }) diff --git a/test/typeclass/SemiCoproduct.ts b/test/typeclass/SemiCoproduct.ts index 55eec17be..1049fd717 100644 --- a/test/typeclass/SemiCoproduct.ts +++ b/test/typeclass/SemiCoproduct.ts @@ -1,6 +1,6 @@ +import * as E from "@fp-ts/core/Either" import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/SemiCoproduct" -import * as E from "../data/Either" import * as U from "../util" describe("SemiCoproduct", () => { diff --git a/test/typeclass/SemiProduct.ts b/test/typeclass/SemiProduct.ts index a822c89bf..aacea2833 100644 --- a/test/typeclass/SemiProduct.ts +++ b/test/typeclass/SemiProduct.ts @@ -1,13 +1,14 @@ +import * as Boolean from "@fp-ts/core/Boolean" import { pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" +import * as Number from "@fp-ts/core/Number" +import * as O from "@fp-ts/core/Option" +import * as P from "@fp-ts/core/Predicate" +import * as RA from "@fp-ts/core/ReadonlyArray" +import * as String from "@fp-ts/core/String" import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as _ from "@fp-ts/core/typeclass/SemiProduct" -import * as number from "../data/number" -import * as O from "../data/Option" -import * as P from "../data/Predicate" -import * as RA from "../data/ReadonlyArray" -import * as string from "../data/string" import * as U from "../util" describe("SemiProduct", () => { @@ -81,19 +82,19 @@ describe("SemiProduct", () => { describe("productComposition", () => { it("ReadonlyArray", () => { const product = _.productComposition(RA.SemiApplicative, O.SemiProduct) - U.deepStrictEqual(pipe([], product([O.none])), []) - U.deepStrictEqual(pipe([O.none], product([])), []) - U.deepStrictEqual(pipe([O.none], product([O.none])), [O.none]) + U.deepStrictEqual(pipe([], product([O.none()])), []) + U.deepStrictEqual(pipe([O.none()], product([])), []) + U.deepStrictEqual(pipe([O.none()], product([O.none()])), [O.none()]) U.deepStrictEqual(pipe([O.some(1)], product([O.some(2)])), [O.some([1, 2] as const)]) }) it("Option", () => { const product = _.productComposition(O.SemiApplicative, O.SemiProduct) - U.deepStrictEqual(pipe(O.none, product(O.none)), O.none) - U.deepStrictEqual(pipe(O.some(O.none), product(O.none)), O.none) - U.deepStrictEqual(pipe(O.some(O.some(1)), product(O.none)), O.none) - U.deepStrictEqual(pipe(O.some(O.some(1)), product(O.some(O.none))), O.some(O.none)) - U.deepStrictEqual(pipe(O.some(O.none), product(O.some(O.some(2)))), O.some(O.none)) + U.deepStrictEqual(pipe(O.none(), product(O.none())), O.none()) + U.deepStrictEqual(pipe(O.some(O.none()), product(O.none())), O.none()) + U.deepStrictEqual(pipe(O.some(O.some(1)), product(O.none())), O.none()) + U.deepStrictEqual(pipe(O.some(O.some(1)), product(O.some(O.none()))), O.some(O.none())) + U.deepStrictEqual(pipe(O.some(O.none()), product(O.some(O.some(2)))), O.some(O.none())) U.deepStrictEqual( pipe(O.some(O.some(1)), product(O.some(O.some(2)))), O.some(O.some([1, 2] as const)) @@ -104,12 +105,15 @@ describe("SemiProduct", () => { describe("productManyComposition", () => { it("ReadonlyArray", () => { const productMany = _.productManyComposition(RA.SemiApplicative, O.SemiProduct) - U.deepStrictEqual(pipe([O.some(1), O.none], productMany([])), [O.some([1] as const), O.none]) - U.deepStrictEqual(pipe([O.some(1), O.none], productMany([[O.some(2), O.none]])), [ + U.deepStrictEqual(pipe([O.some(1), O.none()], productMany([])), [ + O.some([1] as const), + O.none() + ]) + U.deepStrictEqual(pipe([O.some(1), O.none()], productMany([[O.some(2), O.none()]])), [ O.some([1, 2] as const), - O.none, - O.none, - O.none + O.none(), + O.none(), + O.none() ]) U.deepStrictEqual( pipe([O.some(1), O.some(2)], productMany([[O.some(3), O.some(4)], [O.some(5)]])), @@ -124,13 +128,16 @@ describe("SemiProduct", () => { it("Option", () => { const productMany = _.productManyComposition(O.SemiApplicative, O.SemiProduct) - U.deepStrictEqual(pipe(O.none, productMany([])), O.none) - U.deepStrictEqual(pipe(O.some(O.none), productMany([])), O.some(O.none)) + U.deepStrictEqual(pipe(O.none(), productMany([])), O.none()) + U.deepStrictEqual(pipe(O.some(O.none()), productMany([])), O.some(O.none())) U.deepStrictEqual(pipe(O.some(O.some(1)), productMany([])), O.some(O.some([1] as const))) - U.deepStrictEqual(pipe(O.none, productMany([O.none])), O.none) - U.deepStrictEqual(pipe(O.some(O.none), productMany([O.none])), O.none) - U.deepStrictEqual(pipe(O.some(O.none), productMany([O.some(O.none)])), O.some(O.none)) - U.deepStrictEqual(pipe(O.some(O.none), productMany([O.some(O.some("a"))])), O.some(O.none)) + U.deepStrictEqual(pipe(O.none(), productMany([O.none()])), O.none()) + U.deepStrictEqual(pipe(O.some(O.none()), productMany([O.none()])), O.none()) + U.deepStrictEqual(pipe(O.some(O.none()), productMany([O.some(O.none())])), O.some(O.none())) + U.deepStrictEqual( + pipe(O.some(O.none()), productMany([O.some(O.some("a"))])), + O.some(O.none()) + ) U.deepStrictEqual( pipe(O.some(O.some(1)), productMany([O.some(O.some(2))])), O.some(O.some([1, 2] as const)) @@ -141,15 +148,15 @@ describe("SemiProduct", () => { describe("andThenBind", () => { it("Covariant (Option)", () => { const andThenBind = _.andThenBind(O.Applicative) - U.deepStrictEqual(pipe(O.some({ a: 1 }), andThenBind("b", O.none)), O.none) + U.deepStrictEqual(pipe(O.some({ a: 1 }), andThenBind("b", O.none())), O.none()) U.deepStrictEqual(pipe(O.some({ a: 1 }), andThenBind("b", O.some(2))), O.some({ a: 1, b: 2 })) }) it("Contravariant (Predicate)", () => { const p = pipe( P.Do, - P.andThenBind("x", P.isString), - P.andThenBind("y", P.isNumber) + P.andThenBind("x", String.isString), + P.andThenBind("y", Number.isNumber) ) U.deepStrictEqual(p({ x: "a", y: 1 }), true) U.deepStrictEqual(p({ x: "a", y: "x" }), false) @@ -159,13 +166,13 @@ describe("SemiProduct", () => { describe("productFlatten", () => { it("Covariant (Option)", () => { const productFlatten = _.productFlatten(O.SemiProduct) - U.deepStrictEqual(pipe(O.some([1, 2]), productFlatten(O.none)), O.none) + U.deepStrictEqual(pipe(O.some([1, 2]), productFlatten(O.none())), O.none()) U.deepStrictEqual(pipe(O.some([1, 2]), productFlatten(O.some(3))), O.some([1, 2, 3] as const)) }) it("Contravariant (Predicate)", () => { const productFlatten = _.productFlatten(P.SemiProduct) - const p = pipe(P.tuple(P.isString, P.isString), productFlatten(P.isNumber)) + const p = pipe(P.tuple(String.isString, String.isString), productFlatten(Number.isNumber)) U.deepStrictEqual(p(["a", "b", 3]), true) U.deepStrictEqual(p(["a", "b", "c"]), false) U.deepStrictEqual(p([1, "b", 1]), false) @@ -180,18 +187,18 @@ describe("SemiProduct", () => { nonEmptyTuple(O.some("a"), O.some(1), O.some(true)), O.some(["a", 1, true] as const) ) - U.deepStrictEqual(nonEmptyTuple(O.some("a"), O.some(1), O.none), O.none) + U.deepStrictEqual(nonEmptyTuple(O.some("a"), O.some(1), O.none()), O.none()) }) it("Invariant (Semigroup)", () => { const nonEmptyTuple = _.nonEmptyTuple(semigroup.SemiProduct) - const S = nonEmptyTuple(string.Semigroup, number.SemigroupSum) + const S = nonEmptyTuple(String.Semigroup, Number.SemigroupSum) U.deepStrictEqual(pipe(["a", 2], S.combine(["b", 3])), ["ab", 5]) }) it("Contravariant (Predicate)", () => { const nonEmptyTuple = _.nonEmptyTuple(P.SemiProduct) - const p = nonEmptyTuple(P.isString, P.isNumber, P.isBoolean) + const p = nonEmptyTuple(String.isString, Number.isNumber, Boolean.isBoolean) U.deepStrictEqual(p(["a", 1, true]), true) U.deepStrictEqual(p(["a", 1, "b"]), false) }) @@ -206,20 +213,20 @@ describe("SemiProduct", () => { O.some({ a: "a", b: 1, c: true }) ) U.deepStrictEqual( - nonEmptyStruct({ a: O.some("a"), b: O.some(1), c: O.none }), - O.none + nonEmptyStruct({ a: O.some("a"), b: O.some(1), c: O.none() }), + O.none() ) }) it("Invariant (Semigroup)", () => { const nonEmptyStruct = _.nonEmptyStruct(semigroup.Product) - const S = nonEmptyStruct({ x: string.Semigroup, y: number.SemigroupSum }) + const S = nonEmptyStruct({ x: String.Semigroup, y: Number.SemigroupSum }) U.deepStrictEqual(pipe({ x: "a", y: 2 }, S.combine({ x: "b", y: 3 })), { x: "ab", y: 5 }) }) it("Contravariant (Predicate)", () => { const nonEmptyStruct = _.nonEmptyStruct(P.Product) - const p = nonEmptyStruct({ x: P.isString, y: P.isNumber, z: P.isBoolean }) + const p = nonEmptyStruct({ x: String.isString, y: Number.isNumber, z: Boolean.isBoolean }) U.deepStrictEqual(p({ x: "a", y: 1, z: true }), true) U.deepStrictEqual(p({ x: "a", y: 1, z: "b" }), false) }) diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index 56d55d05c..b7b3d3999 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -1,13 +1,13 @@ import { pipe } from "@fp-ts/core/Function" +import * as Number from "@fp-ts/core/Number" +import * as String from "@fp-ts/core/String" import * as order from "@fp-ts/core/typeclass/Order" import * as _ from "@fp-ts/core/typeclass/Semigroup" -import * as number from "../data/number" -import * as string from "../data/string" import * as U from "../util" describe("Semigroup", () => { it("reverse", () => { - const A = _.reverse(string.Semigroup) + const A = _.reverse(String.Semigroup) U.deepStrictEqual(pipe("a", A.combine("b")), "ba") U.deepStrictEqual(pipe("a", A.combineMany([])), "a") U.deepStrictEqual(pipe("a", A.combineMany(["b"])), "ba") @@ -22,7 +22,7 @@ describe("Semigroup", () => { }) it("intercalate", () => { - const A = pipe(string.Semigroup, _.intercalate("|")) + const A = pipe(String.Semigroup, _.intercalate("|")) U.deepStrictEqual(pipe("a", A.combine("b")), "a|b") U.deepStrictEqual(pipe("a", A.combineMany([])), "a") U.deepStrictEqual(pipe("a", A.combineMany(["b"])), "a|b") @@ -31,14 +31,14 @@ describe("Semigroup", () => { describe("min", () => { it("should return the minimum", () => { - const A = _.min(number.Order) + const A = _.min(Number.Order) U.deepStrictEqual(pipe(1, A.combineMany([])), 1) U.deepStrictEqual(pipe(1, A.combineMany([3, 2])), 1) }) it("should return the last minimum", () => { type Item = { a: number } - const A = _.min(pipe(number.Order, order.contramap((_: Item) => _.a))) + const A = _.min(pipe(Number.Order, order.contramap((_: Item) => _.a))) const item: Item = { a: 1 } U.strictEqual(pipe({ a: 2 }, A.combineMany([{ a: 1 }, item])), item) U.strictEqual(pipe(item, A.combineMany([])), item) @@ -47,14 +47,14 @@ describe("Semigroup", () => { describe("max", () => { it("should return the maximum", () => { - const A = _.max(number.Order) + const A = _.max(Number.Order) U.deepStrictEqual(pipe(1, A.combineMany([])), 1) U.deepStrictEqual(pipe(1, A.combineMany([3, 2])), 3) }) it("should return the last minimum", () => { type Item = { a: number } - const A = _.max(pipe(number.Order, order.contramap((_: Item) => _.a))) + const A = _.max(pipe(Number.Order, order.contramap((_: Item) => _.a))) const item: Item = { a: 2 } U.strictEqual(pipe({ a: 1 }, A.combineMany([{ a: 2 }, item])), item) U.strictEqual(pipe(item, A.combineMany([])), item) @@ -63,8 +63,8 @@ describe("Semigroup", () => { it("struct", () => { const A = _.struct({ - name: string.Semigroup, - age: number.SemigroupSum + name: String.Semigroup, + age: Number.SemigroupSum }) U.deepStrictEqual(pipe({ name: "a", age: 10 }, A.combine({ name: "b", age: 20 })), { name: "ab", @@ -89,8 +89,8 @@ describe("Semigroup", () => { it("tuple", () => { const A = _.tuple( - string.Semigroup, - number.SemigroupSum + String.Semigroup, + Number.SemigroupSum ) U.deepStrictEqual(pipe(["a", 10], A.combine(["b", 20])), ["ab", 30]) U.deepStrictEqual(pipe(["a", 10], A.combineMany([])), ["a", 10]) @@ -114,7 +114,7 @@ describe("Semigroup", () => { it("imap", () => { const imap = _.imap - const To = imap((s: string) => [s], ([s]) => s)(string.Semigroup) + const To = imap((s: string) => [s], ([s]) => s)(String.Semigroup) U.deepStrictEqual(pipe(["a"], To.combine(["b"])), ["ab"]) U.deepStrictEqual(pipe(["a"], To.combineMany([])), ["a"]) U.deepStrictEqual(pipe(["a"], To.combineMany([["b"]])), ["ab"]) @@ -123,7 +123,7 @@ describe("Semigroup", () => { U.deepStrictEqual( pipe( ["a"], - _.Invariant.imap((s: string) => [s], ([s]) => s)(string.Semigroup).combineMany([["b"], [ + _.Invariant.imap((s: string) => [s], ([s]) => s)(String.Semigroup).combineMany([["b"], [ "c" ]]) ), @@ -135,9 +135,9 @@ describe("Semigroup", () => { it("product", () => { const A = pipe( - string.Semigroup, - _.SemiProduct.product(number.SemigroupSum), - _.SemiProduct.product(number.SemigroupMultiply), + String.Semigroup, + _.SemiProduct.product(Number.SemigroupSum), + _.SemiProduct.product(Number.SemigroupMultiply), _.imap(([[a, b], c]) => [a, b, c] as const, ([a, b, c]) => [[a, b], c] as const) ) U.deepStrictEqual(pipe(["a", 2, 3], A.combine(["b", 3, 4])), ["ab", 5, 12]) @@ -145,8 +145,8 @@ describe("Semigroup", () => { it("productMany", () => { const A = pipe( - string.Semigroup, - _.SemiProduct.productMany([string.Semigroup, string.Semigroup]) + String.Semigroup, + _.SemiProduct.productMany([String.Semigroup, String.Semigroup]) ) U.deepStrictEqual(pipe(["a", "b", "c"], A.combine(["d", "e", "f"])), ["ad", "be", "cf"]) }) diff --git a/test/typeclass/Traversable.ts b/test/typeclass/Traversable.ts index 794205dbd..79386bae9 100644 --- a/test/typeclass/Traversable.ts +++ b/test/typeclass/Traversable.ts @@ -1,17 +1,20 @@ import { pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" +import * as RA from "@fp-ts/core/ReadonlyArray" import * as _ from "@fp-ts/core/typeclass/Traversable" -import * as O from "../data/Option" -import * as RA from "../data/ReadonlyArray" import * as U from "../util" describe("Traversable", () => { it("traverseComposition", () => { const traverse = _.traverseComposition(RA.Traversable, RA.Traversable)(O.Applicative) U.deepStrictEqual( - pipe([[1, 2], [3]], traverse((a) => (a > 0 ? O.some(a) : O.none))), + pipe([[1, 2], [3]], traverse((a) => (a > 0 ? O.some(a) : O.none()))), O.some([[1, 2], [3]]) ) - U.deepStrictEqual(pipe([[1, -2], [3]], traverse((a) => (a > 0 ? O.some(a) : O.none))), O.none) + U.deepStrictEqual( + pipe([[1, -2], [3]], traverse((a) => (a > 0 ? O.some(a) : O.none()))), + O.none() + ) }) it("sequenceComposition", () => { @@ -22,28 +25,28 @@ describe("Traversable", () => { pipe([[O.some(1), O.some(2)], [O.some(3)]], sequence), O.some([[1, 2], [3]]) ) - U.deepStrictEqual(pipe([[O.some(1), O.none], [O.some(3)]], sequence), O.none) + U.deepStrictEqual(pipe([[O.some(1), O.none()], [O.some(3)]], sequence), O.none()) }) it("sequence", () => { const sequence = _.sequence(RA.Traversable.traverse)(O.Applicative) - U.deepStrictEqual(pipe([O.none, O.some(2)], sequence), O.none) + U.deepStrictEqual(pipe([O.none(), O.some(2)], sequence), O.none()) U.deepStrictEqual(pipe([O.some(1), O.some(2)], sequence), O.some([1, 2])) }) it("traverseTap", () => { const traverseTap = _.traverseTap(RA.Traversable)(O.Applicative) U.deepStrictEqual( - pipe([], traverseTap(n => n > 0 ? O.some(n) : O.none)), + pipe([], traverseTap(n => n > 0 ? O.some(n) : O.none())), O.some([]) ) U.deepStrictEqual( - pipe(["a", "b", "c"], traverseTap(s => s.length > 0 ? O.some(s.length) : O.none)), + pipe(["a", "b", "c"], traverseTap(s => s.length > 0 ? O.some(s.length) : O.none())), O.some(["a", "b", "c"]) ) U.deepStrictEqual( - pipe(["a", "", "c"], traverseTap(s => s.length > 0 ? O.some(s) : O.none)), - O.none + pipe(["a", "", "c"], traverseTap(s => s.length > 0 ? O.some(s) : O.none())), + O.none() ) }) }) diff --git a/test/typeclass/TraversableWithIndex.ts b/test/typeclass/TraversableWithIndex.ts index b35b3a699..fad0b7b1a 100644 --- a/test/typeclass/TraversableWithIndex.ts +++ b/test/typeclass/TraversableWithIndex.ts @@ -1,36 +1,36 @@ -import { pipe } from "@fp-ts/core/Function" -import * as O from "../data/Option" -import * as RA from "../data/ReadonlyArray" -import * as _ from "../limbo/TraversableWithIndex" -import * as U from "../util" +// import { pipe } from "@fp-ts/core/Function" +// import * as O from "@fp-ts/core/Option" +// import * as RA from "@fp-ts/core/ReadonlyArray" +// import * as _ from "../limbo/TraversableWithIndex" +// import * as U from "../util" -describe("TraversableWithIndex", () => { - it("traverseWithIndexComposition", () => { - const traverseWithIndex = _.traverseWithIndexComposition( - RA.TraversableWithIndex, - RA.TraversableWithIndex - )(O.Applicative) - U.deepStrictEqual( - pipe( - [["a"], ["bb"]], - traverseWithIndex((s, [i, j]) => (s.length >= 1 ? O.some(s + i + j) : O.none)) - ), - O.some([["a00"], ["bb10"]]) - ) - U.deepStrictEqual( - pipe( - [["a"], ["bb"]], - traverseWithIndex((s, [i, j]) => (s.length > 1 ? O.some(s + i + j) : O.none)) - ), - O.none - ) - }) +// describe("TraversableWithIndex", () => { +// it("traverseWithIndexComposition", () => { +// const traverseWithIndex = _.traverseWithIndexComposition( +// RA.TraversableWithIndex, +// RA.TraversableWithIndex +// )(O.Applicative) +// U.deepStrictEqual( +// pipe( +// [["a"], ["bb"]], +// traverseWithIndex((s, [i, j]) => (s.length >= 1 ? O.some(s + i + j) : O.none())) +// ), +// O.some([["a00"], ["bb10"]]) +// ) +// U.deepStrictEqual( +// pipe( +// [["a"], ["bb"]], +// traverseWithIndex((s, [i, j]) => (s.length > 1 ? O.some(s + i + j) : O.none())) +// ), +// O.none() +// ) +// }) - it("traverse", () => { - const traverse = _.traverse(RA.TraversableWithIndex)(O.Applicative) - const f = (n: number) => n > 0 ? O.some(n) : O.none - U.deepStrictEqual(pipe([], traverse(f)), O.some([])) - U.deepStrictEqual(pipe([1, 2, 3], traverse(f)), O.some([1, 2, 3])) - U.deepStrictEqual(pipe([1, -2, 3], traverse(f)), O.none) - }) -}) +// it("traverse", () => { +// const traverse = _.traverse(RA.TraversableWithIndex)(O.Applicative) +// const f = (n: number) => n > 0 ? O.some(n) : O.none() +// U.deepStrictEqual(pipe([], traverse(f)), O.some([])) +// U.deepStrictEqual(pipe([1, 2, 3], traverse(f)), O.some([1, 2, 3])) +// U.deepStrictEqual(pipe([1, -2, 3], traverse(f)), O.none()) +// }) +// }) diff --git a/vitest.config.ts b/vitest.config.ts index 9469eb3d4..2baea9ee6 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -8,7 +8,9 @@ export default defineConfig({ exclude: [ "./test/util.ts", "./test/data/*.ts", - "./test/limbo/*.ts" + "./test/limbo/*.ts", + "./test/typeclass/FoldableWithIndex.ts", + "./test/typeclass/TraversableWithIndex.ts" ], globals: true }, From d625eab78ecaa857f8d4d0a768d27041a156d48b Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 16:45:53 +0100 Subject: [PATCH 027/255] FilterableWithIndex: 100% coverage --- test/typeclass/FilterableWithIndex.ts | 69 +++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 test/typeclass/FilterableWithIndex.ts diff --git a/test/typeclass/FilterableWithIndex.ts b/test/typeclass/FilterableWithIndex.ts new file mode 100644 index 000000000..64bb94e27 --- /dev/null +++ b/test/typeclass/FilterableWithIndex.ts @@ -0,0 +1,69 @@ +import * as E from "@fp-ts/core/Either" +import { pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" +import * as RA from "@fp-ts/core/ReadonlyArray" +import * as _ from "@fp-ts/core/typeclass/FilterableWithIndex" +import * as U from "../util" + +describe("FilterableWithIndex", () => { + it("filterMapComposition", () => { + const filterMapWithIndex: ( + f: (a: A, i: number) => O.Option + ) => ( + self: ReadonlyArray> + ) => ReadonlyArray> = _ + .filterMapWithIndexComposition(RA.Covariant, RA.FilterableWithIndex) + const f = filterMapWithIndex((s: string, i: number) => + s.length + i > 1 ? O.some(s.length) : O.none() + ) + U.deepStrictEqual(pipe([], f), []) + U.deepStrictEqual(pipe([[]], f), [[]]) + U.deepStrictEqual(pipe([["a"]], f), [[]]) + U.deepStrictEqual(pipe([["aa", "a"]], f), [[2, 1]]) + }) + + it("filterMap", () => { + const filterMap: ( + f: (a: A) => O.Option + ) => (self: ReadonlyArray) => ReadonlyArray = _.filterMap(RA.FilterableWithIndex) + const f = (n: number) => (n % 2 === 0 ? O.none() : O.some(n)) + U.deepStrictEqual(pipe([1, 2, 3], filterMap(f)), [1, 3]) + U.deepStrictEqual(pipe([], filterMap(f)), []) + }) + + it("filterWithIndex", () => { + const filterWithIndex = _.filterWithIndex(RA.FilterableWithIndex) + const f = (n: number) => n % 2 === 0 + U.deepStrictEqual(pipe(["a", "b", "c"], filterWithIndex((_, i) => f(i))), [ + "a", + "c" + ]) + }) + + it("partitionMapWithIndex", () => { + const partitionMapWithIndex = _.partitionMapWithIndex(RA.FilterableWithIndex) + U.deepStrictEqual( + pipe([], partitionMapWithIndex((a) => a)), + [[], []] + ) + U.deepStrictEqual( + pipe( + [E.right(1), E.left("foo"), E.right(2)], + partitionMapWithIndex((a, i) => pipe(a, E.filter((n) => n > i, () => "err"))) + ), + [["foo", "err"], [1]] + ) + }) + + it("partitionWithIndex", () => { + const partitionWithIndex = _.partitionWithIndex(RA.FilterableWithIndex) + U.deepStrictEqual( + pipe([], partitionWithIndex((i, n) => i + n > 2)), + [[], []] + ) + U.deepStrictEqual( + pipe([1, 2], partitionWithIndex((i, n) => i + n > 2)), + [[1], [2]] + ) + }) +}) From 90c00024fb9045b01a9646815686cc87e38d4a88 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 17:43:16 +0100 Subject: [PATCH 028/255] remove NonEmptyTraversable typeclass --- .changeset/nervous-schools-knock.md | 5 + Overview.md | 15 --- src/ReadonlyArray.ts | 37 ------ src/index.ts | 18 --- test/ReadonlyArray.ts | 2 - .../limbo}/CovariantWithIndex.ts | 0 .../limbo}/FilterableWithIndex.ts | 0 .../limbo}/NonEmptyTraversable.ts | 0 test/typeclass/CovariantWithIndex.ts | 10 +- test/typeclass/FilterableWithIndex.ts | 16 ++- test/typeclass/FoldableWithIndex.ts | 114 ++++++++++-------- test/typeclass/NonEmptyTraversable.ts | 18 ++- test/typeclass/TraversableWithIndex.ts | 72 +++++------ vitest.config.ts | 4 +- 14 files changed, 135 insertions(+), 176 deletions(-) create mode 100644 .changeset/nervous-schools-knock.md rename {src/typeclass => test/limbo}/CovariantWithIndex.ts (100%) rename {src/typeclass => test/limbo}/FilterableWithIndex.ts (100%) rename {src/typeclass => test/limbo}/NonEmptyTraversable.ts (100%) diff --git a/.changeset/nervous-schools-knock.md b/.changeset/nervous-schools-knock.md new file mode 100644 index 000000000..1defb228e --- /dev/null +++ b/.changeset/nervous-schools-knock.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +remove NonEmptyTraversable typeclass diff --git a/Overview.md b/Overview.md index 0ced453dc..df6fdd915 100644 --- a/Overview.md +++ b/Overview.md @@ -311,21 +311,6 @@ Extends: - `FlatMap` - `Pointed` -### NonEmptyTraversable - -`NonEmptyTraversable`, also known as `Traversable1`. - -`NonEmptyTraversable` is like a non-empty `Traversable`. Unlike the `traverse` and `sequence` -methods of `Traversable` it provides `traverseNonEmpty` and `sequenceNonEmpty` methods which require a `SemiApplicative` -instance instead of `Applicative`. - -| Name | Given | To | -| --------------------------- | -------------------------------------------- | ------------ | -| **traverseNonEmpty** | `SemiApplicative`, `T`, `A => F` | `F>` | -| **sequenceNonEmpty** | `SemiApplicative`, `T>` | `F>` | -| traverseNonEmptyComposition | `SemiApplicative`, `T>`, `A => F` | `F>>` | -| sequenceNonEmptyComposition | `SemiApplicative`, `T>>` | `F>>` | - ### Of | Name | Given | To | diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 9d6947353..2509e2860 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -18,10 +18,8 @@ import * as chainable from "@fp-ts/core/typeclass/Chainable" import type * as compactable from "@fp-ts/core/typeclass/Compactable" import type { Coproduct } from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" -import type * as covariantWithIndex from "@fp-ts/core/typeclass/CovariantWithIndex" import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" import * as filterable from "@fp-ts/core/typeclass/Filterable" -import type * as filterableWithIndex from "@fp-ts/core/typeclass/FilterableWithIndex" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" import type * as invariant from "@fp-ts/core/typeclass/Invariant" @@ -40,8 +38,6 @@ import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" import * as traversableFilterable from "@fp-ts/core/typeclass/TraversableFilterable" -import type * as nonEmptyTraversable from "@fp-ts/core/typeclass/NonEmptyTraversable" - /** * @category type lambdas * @since 1.0.0 @@ -1303,17 +1299,6 @@ export const Invariant: invariant.Invariant = { imap } -/** - * @category instances - * @since 1.0.0 - */ -export const CovariantWithIndex: covariantWithIndex.CovariantWithIndex< - ReadonlyArrayTypeLambda, - number -> = { - mapWithIndex -} - /** * @category instances * @since 1.0.0 @@ -1515,17 +1500,6 @@ export const separate = ( return [left, right] } -/** - * @category instances - * @since 1.0.0 - */ -export const FilterableWithIndex: filterableWithIndex.FilterableWithIndex< - ReadonlyArrayTypeLambda, - number -> = { - filterMapWithIndex -} - /** * @category instances * @since 1.0.0 @@ -2271,14 +2245,3 @@ export const liftOrder = (O: Order): Order> => */ export const NonEmptyCovariant: covariant.Covariant = covariant .make(mapNonEmpty) - -/** - * @category instances - * @since 1.0.0 - */ -export const NonEmptyTraversable: nonEmptyTraversable.NonEmptyTraversable< - NonEmptyReadonlyArrayTypeLambda -> = { - traverseNonEmpty, - sequenceNonEmpty: F => self => pipe(self, traverseNonEmpty(F)(identity)) -} diff --git a/src/index.ts b/src/index.ts index 97ddb8daf..651a2e6f8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -32,16 +32,13 @@ import * as compactable from "@fp-ts/core/typeclass/Compactable" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import * as coproduct from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" -import * as covariantWithIndex from "@fp-ts/core/typeclass/CovariantWithIndex" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as filterable from "@fp-ts/core/typeclass/Filterable" -import * as filterableWithIndex from "@fp-ts/core/typeclass/FilterableWithIndex" import * as flatMap from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import * as monad from "@fp-ts/core/typeclass/Monad" import * as monoid from "@fp-ts/core/typeclass/Monoid" -import * as nonEmptyTraversable from "@fp-ts/core/typeclass/NonEmptyTraversable" import * as of from "@fp-ts/core/typeclass/Of" import * as order from "@fp-ts/core/typeclass/Order" import * as pointed from "@fp-ts/core/typeclass/Pointed" @@ -108,11 +105,6 @@ export { * @since 1.0.0 */ covariant, - /** - * @category typeclass - * @since 1.0.0 - */ - covariantWithIndex, /** * @since 1.0.0 */ @@ -127,11 +119,6 @@ export { * @since 1.0.0 */ filterable, - /** - * @category typeclass - * @since 1.0.0 - */ - filterableWithIndex, /** * @category typeclass * @since 1.0.0 @@ -165,11 +152,6 @@ export { * @since 1.0.0 */ monoid, - /** - * @category typeclass - * @since 1.0.0 - */ - nonEmptyTraversable, /** * @since 1.0.0 */ diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index d662c135c..550933a4e 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -16,7 +16,6 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.Invariant).exist expect(RA.imap).exist - expect(RA.CovariantWithIndex).exist expect(RA.Covariant).exist expect(RA.map).exist expect(RA.let).exist @@ -76,7 +75,6 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.compact).exist expect(RA.separate).exist - expect(RA.FilterableWithIndex).exist expect(RA.Filterable).exist expect(RA.filterMap).exist expect(RA.filter).exist diff --git a/src/typeclass/CovariantWithIndex.ts b/test/limbo/CovariantWithIndex.ts similarity index 100% rename from src/typeclass/CovariantWithIndex.ts rename to test/limbo/CovariantWithIndex.ts diff --git a/src/typeclass/FilterableWithIndex.ts b/test/limbo/FilterableWithIndex.ts similarity index 100% rename from src/typeclass/FilterableWithIndex.ts rename to test/limbo/FilterableWithIndex.ts diff --git a/src/typeclass/NonEmptyTraversable.ts b/test/limbo/NonEmptyTraversable.ts similarity index 100% rename from src/typeclass/NonEmptyTraversable.ts rename to test/limbo/NonEmptyTraversable.ts diff --git a/test/typeclass/CovariantWithIndex.ts b/test/typeclass/CovariantWithIndex.ts index d2a92dd15..0bbe11bc8 100644 --- a/test/typeclass/CovariantWithIndex.ts +++ b/test/typeclass/CovariantWithIndex.ts @@ -1,11 +1,15 @@ import { pipe } from "@fp-ts/core/Function" import * as RA from "@fp-ts/core/ReadonlyArray" -import * as _ from "@fp-ts/core/typeclass/CovariantWithIndex" +import * as _ from "@fp-ts/core/test/limbo/CovariantWithIndex" import * as U from "../util" +const CovariantWithIndex: _.CovariantWithIndex = { + mapWithIndex: RA.mapWithIndex +} + describe("CovariantWithIndex", () => { it("mapWithIndexComposition", () => { - const mapWithIndex = _.mapWithIndexComposition(RA.CovariantWithIndex, RA.CovariantWithIndex) + const mapWithIndex = _.mapWithIndexComposition(CovariantWithIndex, CovariantWithIndex) const f = (a: string, [i, j]: readonly [number, number]) => a + i + j U.deepStrictEqual(pipe([], mapWithIndex(f)), []) U.deepStrictEqual(pipe([[]], mapWithIndex(f)), [[]]) @@ -19,7 +23,7 @@ describe("CovariantWithIndex", () => { }) it("map", () => { - const map = _.map(RA.CovariantWithIndex) + const map = _.map(CovariantWithIndex) const f = (a: string) => a + "!" U.deepStrictEqual(pipe([], map(f)), []) U.deepStrictEqual(pipe(["a", "b", "c"], map(f)), ["a!", "b!", "c!"]) diff --git a/test/typeclass/FilterableWithIndex.ts b/test/typeclass/FilterableWithIndex.ts index 64bb94e27..64ec04ade 100644 --- a/test/typeclass/FilterableWithIndex.ts +++ b/test/typeclass/FilterableWithIndex.ts @@ -2,9 +2,13 @@ import * as E from "@fp-ts/core/Either" import { pipe } from "@fp-ts/core/Function" import * as O from "@fp-ts/core/Option" import * as RA from "@fp-ts/core/ReadonlyArray" -import * as _ from "@fp-ts/core/typeclass/FilterableWithIndex" +import * as _ from "@fp-ts/core/test/limbo/FilterableWithIndex" import * as U from "../util" +const FilterableWithIndex: _.FilterableWithIndex = { + filterMapWithIndex: RA.filterMapWithIndex +} + describe("FilterableWithIndex", () => { it("filterMapComposition", () => { const filterMapWithIndex: ( @@ -12,7 +16,7 @@ describe("FilterableWithIndex", () => { ) => ( self: ReadonlyArray> ) => ReadonlyArray> = _ - .filterMapWithIndexComposition(RA.Covariant, RA.FilterableWithIndex) + .filterMapWithIndexComposition(RA.Covariant, FilterableWithIndex) const f = filterMapWithIndex((s: string, i: number) => s.length + i > 1 ? O.some(s.length) : O.none() ) @@ -25,14 +29,14 @@ describe("FilterableWithIndex", () => { it("filterMap", () => { const filterMap: ( f: (a: A) => O.Option - ) => (self: ReadonlyArray) => ReadonlyArray = _.filterMap(RA.FilterableWithIndex) + ) => (self: ReadonlyArray) => ReadonlyArray = _.filterMap(FilterableWithIndex) const f = (n: number) => (n % 2 === 0 ? O.none() : O.some(n)) U.deepStrictEqual(pipe([1, 2, 3], filterMap(f)), [1, 3]) U.deepStrictEqual(pipe([], filterMap(f)), []) }) it("filterWithIndex", () => { - const filterWithIndex = _.filterWithIndex(RA.FilterableWithIndex) + const filterWithIndex = _.filterWithIndex(FilterableWithIndex) const f = (n: number) => n % 2 === 0 U.deepStrictEqual(pipe(["a", "b", "c"], filterWithIndex((_, i) => f(i))), [ "a", @@ -41,7 +45,7 @@ describe("FilterableWithIndex", () => { }) it("partitionMapWithIndex", () => { - const partitionMapWithIndex = _.partitionMapWithIndex(RA.FilterableWithIndex) + const partitionMapWithIndex = _.partitionMapWithIndex(FilterableWithIndex) U.deepStrictEqual( pipe([], partitionMapWithIndex((a) => a)), [[], []] @@ -56,7 +60,7 @@ describe("FilterableWithIndex", () => { }) it("partitionWithIndex", () => { - const partitionWithIndex = _.partitionWithIndex(RA.FilterableWithIndex) + const partitionWithIndex = _.partitionWithIndex(FilterableWithIndex) U.deepStrictEqual( pipe([], partitionWithIndex((i, n) => i + n > 2)), [[], []] diff --git a/test/typeclass/FoldableWithIndex.ts b/test/typeclass/FoldableWithIndex.ts index 7cadae671..1fc9c8f4d 100644 --- a/test/typeclass/FoldableWithIndex.ts +++ b/test/typeclass/FoldableWithIndex.ts @@ -1,57 +1,67 @@ -// import { pipe } from "@fp-ts/core/Function" -// import * as N from "@fp-ts/core/Number" -// import * as O from "@fp-ts/core/Option" -// import * as RA from "@fp-ts/core/ReadonlyArray" -// import * as foldableWithIndex from "../limbo/FoldableWithIndex" -// import * as U from "../util" +import { pipe } from "@fp-ts/core/Function" +import * as N from "@fp-ts/core/Number" +import * as O from "@fp-ts/core/Option" +import * as RA from "@fp-ts/core/ReadonlyArray" +import * as _ from "../limbo/FoldableWithIndex" +import * as U from "../util" -// describe("FoldableWithIndex", () => { -// it("reduceWithIndexComposition", () => { -// const reduceWithIndex = foldableWithIndex.reduceWithIndexComposition( -// RA.FoldableWithIndex, -// RA.FoldableWithIndex -// ) -// const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j -// U.deepStrictEqual(pipe([], reduceWithIndex("-", f)), "-") -// U.deepStrictEqual(pipe([[]], reduceWithIndex("-", f)), "-") -// U.deepStrictEqual( -// pipe([["a", "c"], ["b", "d"]], reduceWithIndex("-", f)), -// "-a00c01b10d11" -// ) -// }) +const FoldableWithIndex: _.FoldableWithIndex = { + reduceWithIndex: RA.reduceWithIndex, + reduceRightWithIndex: RA.reduceRightWithIndex +} -// it("reduceRightWithIndexComposition", () => { -// const reduceRightWithIndex = foldableWithIndex.reduceRightWithIndexComposition( -// RA.FoldableWithIndex, -// RA.FoldableWithIndex -// ) -// const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j -// U.deepStrictEqual(pipe([], reduceRightWithIndex("-", f)), "-") -// U.deepStrictEqual(pipe([[]], reduceRightWithIndex("-", f)), "-") -// U.deepStrictEqual( -// pipe([["a", "c"], ["b", "d"]], reduceRightWithIndex("-", f)), -// "-d11b10c01a00" -// ) -// }) +const FoldableWithIndexO: _.FoldableWithIndex = { + reduceWithIndex: (b, f) => (self) => O.isNone(self) ? b : f(b, self.value, 0), + reduceRightWithIndex: (b, f) => (self) => O.isNone(self) ? b : f(b, self.value, 0) +} -// it("toArray", () => { -// const toReadonlyArray = foldableWithIndex.toArray(O.FoldableWithIndex) -// U.deepStrictEqual(toReadonlyArray(O.none()), []) -// U.deepStrictEqual(toReadonlyArray(O.some(2)), [2]) -// }) +describe("FoldableWithIndex", () => { + it("reduceWithIndexComposition", () => { + const reduceWithIndex = _.reduceWithIndexComposition( + FoldableWithIndex, + FoldableWithIndex + ) + const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j + U.deepStrictEqual(pipe([], reduceWithIndex("-", f)), "-") + U.deepStrictEqual(pipe([[]], reduceWithIndex("-", f)), "-") + U.deepStrictEqual( + pipe([["a", "c"], ["b", "d"]], reduceWithIndex("-", f)), + "-a00c01b10d11" + ) + }) -// it("toArrayWith", () => { -// const toReadonlyArrayWith = foldableWithIndex.toArrayWith(O.FoldableWithIndex) -// U.deepStrictEqual(pipe(O.none(), toReadonlyArrayWith(U.double)), []) -// U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith(U.double)), [4]) -// U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith((a, i) => U.double(a) * i)), [0]) -// }) + it("reduceRightWithIndexComposition", () => { + const reduceRightWithIndex = _.reduceRightWithIndexComposition( + FoldableWithIndex, + FoldableWithIndex + ) + const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j + U.deepStrictEqual(pipe([], reduceRightWithIndex("-", f)), "-") + U.deepStrictEqual(pipe([[]], reduceRightWithIndex("-", f)), "-") + U.deepStrictEqual( + pipe([["a", "c"], ["b", "d"]], reduceRightWithIndex("-", f)), + "-d11b10c01a00" + ) + }) -// it("foldMapWithIndex", () => { -// const foldMapWithIndex = foldableWithIndex.foldMapWithIndex(RA.FoldableWithIndex) -// U.deepStrictEqual( -// pipe([1, 2, 3], foldMapWithIndex(N.MonoidSum)((n, i) => (n * 2) + i)), -// 15 -// ) -// }) -// }) + it("toArray", () => { + const toReadonlyArray = _.toArray(FoldableWithIndexO) + U.deepStrictEqual(toReadonlyArray(O.none()), []) + U.deepStrictEqual(toReadonlyArray(O.some(2)), [2]) + }) + + it("toArrayWith", () => { + const toReadonlyArrayWith = _.toArrayWith(FoldableWithIndexO) + U.deepStrictEqual(pipe(O.none(), toReadonlyArrayWith(U.double)), []) + U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith(U.double)), [4]) + U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith((a, i) => U.double(a) * i)), [0]) + }) + + it("foldMapWithIndex", () => { + const foldMapWithIndex = _.foldMapWithIndex(FoldableWithIndex) + U.deepStrictEqual( + pipe([1, 2, 3], foldMapWithIndex(N.MonoidSum)((n, i) => (n * 2) + i)), + 15 + ) + }) +}) diff --git a/test/typeclass/NonEmptyTraversable.ts b/test/typeclass/NonEmptyTraversable.ts index 4fbb4de6b..666f074c6 100644 --- a/test/typeclass/NonEmptyTraversable.ts +++ b/test/typeclass/NonEmptyTraversable.ts @@ -1,13 +1,19 @@ +import { identity, pipe } from "@fp-ts/core/Function" import * as O from "@fp-ts/core/Option" import * as RA from "@fp-ts/core/ReadonlyArray" -import * as _ from "@fp-ts/core/typeclass/NonEmptyTraversable" +import * as _ from "@fp-ts/core/test/limbo/NonEmptyTraversable" import * as U from "../util" +const NonEmptyTraversable: _.NonEmptyTraversable = { + traverseNonEmpty: RA.traverseNonEmpty, + sequenceNonEmpty: F => self => pipe(self, RA.traverseNonEmpty(F)(identity)) +} + describe("NonEmptyTraversable", () => { it("traverseNonEmptyComposition", () => { const traverseNonEmpty = _.traverseNonEmptyComposition( - RA.NonEmptyTraversable, - RA.NonEmptyTraversable + NonEmptyTraversable, + NonEmptyTraversable )(O.SemiApplicative)((n: number) => (n > 0 ? O.some(n) : O.none())) U.deepStrictEqual(traverseNonEmpty([[1]]), O.some([[1]] as const)) U.deepStrictEqual(traverseNonEmpty([[1, -1]]), O.none()) @@ -17,8 +23,8 @@ describe("NonEmptyTraversable", () => { it("traverseNonEmptyComposition", () => { const sequence = _.sequenceNonEmptyComposition( - { ...RA.NonEmptyTraversable, ...RA.NonEmptyCovariant }, - RA.NonEmptyTraversable + { ...NonEmptyTraversable, ...RA.NonEmptyCovariant }, + NonEmptyTraversable )(O.SemiApplicative) U.deepStrictEqual(sequence([[O.some(1)]]), O.some([[1]] as const)) U.deepStrictEqual(sequence([[O.some(1), O.none()]]), O.none()) @@ -34,7 +40,7 @@ describe("NonEmptyTraversable", () => { it("sequenceNonEmpty", () => { const sequenceNonEmpty = _.sequenceNonEmpty( - RA.NonEmptyTraversable.traverseNonEmpty + NonEmptyTraversable.traverseNonEmpty )(O.SemiApplicative) U.deepStrictEqual(sequenceNonEmpty([O.none()]), O.none()) U.deepStrictEqual(sequenceNonEmpty([O.some(1)]), O.some([1] as const)) diff --git a/test/typeclass/TraversableWithIndex.ts b/test/typeclass/TraversableWithIndex.ts index fad0b7b1a..0b7e83638 100644 --- a/test/typeclass/TraversableWithIndex.ts +++ b/test/typeclass/TraversableWithIndex.ts @@ -1,36 +1,40 @@ -// import { pipe } from "@fp-ts/core/Function" -// import * as O from "@fp-ts/core/Option" -// import * as RA from "@fp-ts/core/ReadonlyArray" -// import * as _ from "../limbo/TraversableWithIndex" -// import * as U from "../util" +import { pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" +import * as RA from "@fp-ts/core/ReadonlyArray" +import * as _ from "@fp-ts/core/test/limbo/TraversableWithIndex" +import * as U from "../util" -// describe("TraversableWithIndex", () => { -// it("traverseWithIndexComposition", () => { -// const traverseWithIndex = _.traverseWithIndexComposition( -// RA.TraversableWithIndex, -// RA.TraversableWithIndex -// )(O.Applicative) -// U.deepStrictEqual( -// pipe( -// [["a"], ["bb"]], -// traverseWithIndex((s, [i, j]) => (s.length >= 1 ? O.some(s + i + j) : O.none())) -// ), -// O.some([["a00"], ["bb10"]]) -// ) -// U.deepStrictEqual( -// pipe( -// [["a"], ["bb"]], -// traverseWithIndex((s, [i, j]) => (s.length > 1 ? O.some(s + i + j) : O.none())) -// ), -// O.none() -// ) -// }) +const TraversableWithIndex: _.TraversableWithIndex = { + traverseWithIndex: RA.traverseWithIndex +} -// it("traverse", () => { -// const traverse = _.traverse(RA.TraversableWithIndex)(O.Applicative) -// const f = (n: number) => n > 0 ? O.some(n) : O.none() -// U.deepStrictEqual(pipe([], traverse(f)), O.some([])) -// U.deepStrictEqual(pipe([1, 2, 3], traverse(f)), O.some([1, 2, 3])) -// U.deepStrictEqual(pipe([1, -2, 3], traverse(f)), O.none()) -// }) -// }) +describe("TraversableWithIndex", () => { + it("traverseWithIndexComposition", () => { + const traverseWithIndex = _.traverseWithIndexComposition( + TraversableWithIndex, + TraversableWithIndex + )(O.Applicative) + U.deepStrictEqual( + pipe( + [["a"], ["bb"]], + traverseWithIndex((s, [i, j]) => (s.length >= 1 ? O.some(s + i + j) : O.none())) + ), + O.some([["a00"], ["bb10"]]) + ) + U.deepStrictEqual( + pipe( + [["a"], ["bb"]], + traverseWithIndex((s, [i, j]) => (s.length > 1 ? O.some(s + i + j) : O.none())) + ), + O.none() + ) + }) + + it("traverse", () => { + const traverse = _.traverse(TraversableWithIndex)(O.Applicative) + const f = (n: number) => n > 0 ? O.some(n) : O.none() + U.deepStrictEqual(pipe([], traverse(f)), O.some([])) + U.deepStrictEqual(pipe([1, 2, 3], traverse(f)), O.some([1, 2, 3])) + U.deepStrictEqual(pipe([1, -2, 3], traverse(f)), O.none()) + }) +}) diff --git a/vitest.config.ts b/vitest.config.ts index 2baea9ee6..9469eb3d4 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -8,9 +8,7 @@ export default defineConfig({ exclude: [ "./test/util.ts", "./test/data/*.ts", - "./test/limbo/*.ts", - "./test/typeclass/FoldableWithIndex.ts", - "./test/typeclass/TraversableWithIndex.ts" + "./test/limbo/*.ts" ], globals: true }, From 971f8eb1e798ef8f436c3892fc64a658d1b66130 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 18:10:19 +0100 Subject: [PATCH 029/255] docs: add Equivalence to Overview.md --- Overview.md | 23 ++++++++++++++++++++--- src/Option.ts | 9 +++++---- src/These.ts | 16 ++++++---------- src/typeclass/Equivalence.ts | 5 +++-- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/Overview.md b/Overview.md index df6fdd915..04cb78a75 100644 --- a/Overview.md +++ b/Overview.md @@ -26,10 +26,27 @@ Extends: | reverse | `Bounded` | `Bounded` | | clamp | `A` | `A` | +### Equivalence + +`Equivalence` defines a binary relation that is reflexive, symmetric, and transitive. +In other words, it defines a notion of equivalence between values of a certain type. +These properties are also known in mathematics as an "equivalence relation". + +| Name | Given | To | +| ------------ | ----------------------------------------------- | ------------------------------------------ | +| strict | `A` | `Equivalence` | +| tuple | `[Equivalence, Equivalence, ...]` | `Equivalence<[A, B, ...]>` | +| array | `Equivalence` | `Equivalence` | +| struct | `{ a: Equivalence, b: Equivalence, ... }` | `Equivalence<{ a: A, b: B, ... }>` | +| record | `Equivalence` | `Equivalence<{ readonly [x: string]: A }>` | +| getSemigroup | `A` | `Semigroup>` | +| getMonoid | `A` | `Monoid>` | +| contramap | `Equivalence`, `B => A` | `Equivalence` | + ### Monoid -A monoid is a semigroup with an identity. A monoid is a specialization of a -semigroup, so its operation must be associative. Additionally, +A `Monoid` is a `Semigroup` with an identity. A `Monoid` is a specialization of a +`Semigroup`, so its operation must be associative. Additionally, `x |> combine(empty) == empty |> combine(x) == x`. For example, if we have `Monoid`, with `combine` as string concatenation, then `empty = ""`. @@ -85,7 +102,7 @@ By the totality law, `x <= y` and `y <= x` cannot be both `false`. ### Semigroup -A semigroup is any set `A` with an associative operation (`combine`): +A `Semigroup` is any set `A` with an associative operation (`combine`): `x |> combine(y) |> combine(z) == x |> combine(y |> combine(z))` diff --git a/src/Option.ts b/src/Option.ts index 819f08f3a..7ab3091e2 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -3,12 +3,13 @@ * type Option = None | Some * ``` * - * `Option` is a container for an optional value of type `A`. If the value of type `A` is present, the `Option` is + * The `Option` type can be interpreted in a few ways: + * + * 1) `Option` is a container for an optional value of type `A`. If the value of type `A` is present, the `Option` is * an instance of `Some`, containing the present value of type `A`. If the value is absent, the `Option` is an * instance of `None`. - * - * An option could be looked at as a collection or foldable structure with either one or zero elements. - * Another way to look at `Option` is: it represents the effect of a possibly failing computation. + * 2) Another way to view `Option` is as a representation of a possibly failing computation. + * 3) An option can also be thought of as a collection or foldable structure with either one or zero elements. * * @since 1.0.0 */ diff --git a/src/These.ts b/src/These.ts index 61a16d21d..0784b7cd9 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1,22 +1,18 @@ /** * A data structure providing "inclusive-or" as opposed to `Either`'s "exclusive-or". * - * If you interpret `Either` as suggesting the computation may either fail or of (exclusively), then - * `These` may fail, of, or do both at the same time. + * If you interpret `Either` as suggesting the computation may either fail or succeed (exclusively), then + * `These` may fail, succeed, or do both at the same time. * - * There are a few ways to interpret the both case: + * There are a few ways to interpret the `Both` case: * - * - You can think of a computation that has a non-fatal error. - * - You can think of a computation that went as far as it could before erroring. - * - You can think of a computation that keeps track of errors as it completes. + * 1) You can think of a computation that has a non-fatal error. + * 2) You can think of a computation that went as far as it could before erroring. + * 3) You can think of a computation that keeps track of errors as it completes. * * Another way you can think of `These` is saying that we want to handle `E` kind of data, `A` kind of data, or * both `E` and `A` kind of data at the same time. This is particularly useful when it comes to displaying UI's. * - * (description adapted from https://package.elm-lang.org/packages/joneshf/elm-these) - * - * Adapted from https://github.com/purescript-contrib/purescript-these - * * @since 1.0.0 */ import type { Either, Left, Right } from "@fp-ts/core/Either" diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 762f7790c..ee2ee8fcf 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -1,6 +1,7 @@ /** - * This module provides an implementation of the `Equivalence` type class. - * An `Equivalence` is a binary relation that is reflexive, symmetric and transitive. + * This module provides an implementation of the `Equivalence` type class, which defines a binary relation + * that is reflexive, symmetric, and transitive. In other words, it defines a notion of equivalence between values of a certain type. + * These properties are also known in mathematics as an "equivalence relation". * * @since 1.0.0 */ From 4e7c9133ddd2df7cbb3d1a8bb7ff80c07879c63e Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 18:50:29 +0100 Subject: [PATCH 030/255] update README --- README.md | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index aed36b388..364c07560 100644 --- a/README.md +++ b/README.md @@ -16,30 +16,29 @@ Functional programming in TypeScript # Typed functional programming in TypeScript -This project represents the next major iteration of [`fp-ts`](https://github.com/gcanti/fp-ts) and it's objective is a reconciliation with [`Effect`](https://github.com/Effect-TS) in order to unify the ecosystems. +This project represents the next major iteration of [`fp-ts`](https://github.com/gcanti/fp-ts) and it's objective is a reconciliation with [`@effect`](https://github.com/Effect-TS) in order to unify the ecosystems. -The [`Effect`](https://github.com/Effect-TS) project will reduce it's scope to simply being an effect system and will delegate to `fp-ts org` all the lower level abstractions such as typeclasses and common data structures. +The [`@effect`](https://github.com/Effect-TS) project will reduce it's scope to simply being an effect system and will delegate to `fp-ts org` all the lower level abstractions such as typeclasses and common data structures. The objective of the `fp-ts org` in github and in npm (`@fp-ts`) is to simplify structure and management of the project, have smaller and better scoped packages. Our "current" idea (that is well open for changes) is for `fp-ts org` to have: -- `@fp-ts/core` with the new `HKT` implementation and the most common typeclasses such as `Monad` -- `@fp-ts/data` with `Option`, `Either`, `ReadonlyArray`, `List` and the most common data structures together with data related typeclasses (i.e. `Compactable`, etc) -- `@fp-ts/optics` with an optic implementation that will provide also optics for structures in `@fp-ts/data` -- `@fp-ts/schema` with a concrete codec such as `io-ts` again for all the structures in `@fp-ts/data` +- The [`@fp-ts/core`](https://github.com/fp-ts/core) library features a new implementation of the Higher Kinded Type (HKT) pattern, including common typeclasses such as `Monad` and widely-used data types like `Option`, `Either`, and `ReadonlyArray` +- [`@fp-ts/schema`](https://github.com/fp-ts/schema) offers schema validation with static type inference, including decoders for data structures in `@fp-ts/core` and `@effect/data` +- [`@fp-ts/optic`](https://github.com/fp-ts/optic) provides optics for structures in both `@fp-ts/core` and `@effect/data` -And for [`Effect`](https://github.com/Effect-TS) to have: +For those using [`fp-ts`](https://github.com/gcanti/fp-ts) v2 and its ecosystem, roughly these are the equivalents: -- `@effect/core` with the effect system -- `@effect/query` with the query impl -- `@effect/*` every other effect based impl +- [`fp-ts`](https://github.com/gcanti/fp-ts) -> [`@fp-ts/core`](https://github.com/fp-ts/core) + [`@effect/*` packages](https://github.com/Effect-TS) +- [`io-ts`](https://github.com/gcanti/io-ts) -> [`@fp-ts/schema`](https://github.com/fp-ts/schema) +- [`monocle-ts`](https://github.com/gcanti/monocle-ts) -> [`@fp-ts/optic`](https://github.com/fp-ts/optic) -Note that [`Effect`](https://github.com/Effect-TS) will not have base structures like `Option` / `Either` / `List` and typeclasses like `Monad` / `Functor` and [`fp-ts`](https://github.com/fp-ts) will not have effect execution modules like `Task` / `IO` as both projects are made to be the same ecosystem and each answer a specific set of needs in the best way possible. +Note that `@fp-ts/core` will not contain any effect system (e.g. `Task`, `TaskEither`, `ReaderTaskEither`) since the handling of effects is entirely delegated to the packages contained in [`@effect/*`](https://github.com/Effect-TS)." # Installation -To install the **pre-alpha** version: +To install the **alpha** version: ``` npm install @fp-ts/core @@ -47,7 +46,7 @@ npm install @fp-ts/core # Documentation -- [Overview](./Overview.md) +- [Typeclass overview](./Overview.md) - [API Reference](https://fp-ts.github.io/core/) # License From a35cd577baca8ff0eefb515512288a9a8424e766 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 18:57:30 +0100 Subject: [PATCH 031/255] add the prefix @fp-ts/core to the _tag of the data types --- .changeset/olive-pumas-trade.md | 5 +++++ src/Either.ts | 4 ++-- src/Option.ts | 4 ++-- src/These.ts | 30 +++++++++++++++++------------- src/internal/Either.ts | 12 +++++++----- src/internal/Option.ts | 10 +++++----- 6 files changed, 38 insertions(+), 27 deletions(-) create mode 100644 .changeset/olive-pumas-trade.md diff --git a/.changeset/olive-pumas-trade.md b/.changeset/olive-pumas-trade.md new file mode 100644 index 000000000..6a5413982 --- /dev/null +++ b/.changeset/olive-pumas-trade.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add the prefix @fp-ts/core to the \_tag of the data types diff --git a/src/Either.ts b/src/Either.ts index 1101c2435..42194e2c5 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -45,7 +45,7 @@ import * as traversable from "@fp-ts/core/typeclass/Traversable" * @since 1.0.0 */ export type Left = { - readonly _tag: "Left" + readonly _tag: "@fp-ts/core/Either/Left" readonly left: E } @@ -54,7 +54,7 @@ export type Left = { * @since 1.0.0 */ export type Right = { - readonly _tag: "Right" + readonly _tag: "@fp-ts/core/Either/Right" readonly right: A } diff --git a/src/Option.ts b/src/Option.ts index 7ab3091e2..aa76952bc 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -51,7 +51,7 @@ import * as traversable from "@fp-ts/core/typeclass/Traversable" * @since 1.0.0 */ export type None = { - readonly _tag: "None" + readonly _tag: "@fp-ts/core/Option/None" } /** @@ -59,7 +59,7 @@ export type None = { * @since 1.0.0 */ export type Some = { - readonly _tag: "Some" + readonly _tag: "@fp-ts/core/Option/Some" readonly value: A } diff --git a/src/These.ts b/src/These.ts index 0784b7cd9..5ed4e4e80 100644 --- a/src/These.ts +++ b/src/These.ts @@ -50,7 +50,7 @@ import * as traversable from "@fp-ts/core/typeclass/Traversable" * @since 1.0.0 */ export type Both = { - readonly _tag: "Both" + readonly _tag: "@fp-ts/core/These/Both" readonly left: E readonly right: A } @@ -87,13 +87,13 @@ export interface ValidatedTypeLambda extends TypeLambda { * @category constructors * @since 1.0.0 */ -export const left = (left: E): These => ({ _tag: "Left", left }) +export const left = (left: E): These => ({ _tag: "@fp-ts/core/Either/Left", left }) /** * @category constructors * @since 1.0.0 */ -export const right = (right: A): These => ({ _tag: "Right", right }) +export const right = (right: A): These => ({ _tag: "@fp-ts/core/Either/Right", right }) /** * Alias of `right`. @@ -108,7 +108,7 @@ export const of = right * @since 1.0.0 */ export const both = (left: E, right: A): These => ({ - _tag: "Both", + _tag: "@fp-ts/core/These/Both", left, right }) @@ -158,11 +158,11 @@ export const match = ( ) => (self: These): B | C | D => { switch (self._tag) { - case "Left": + case "@fp-ts/core/Either/Left": return onLeft(self.left) - case "Right": + case "@fp-ts/core/Either/Right": return onRight(self.right) - case "Both": + case "@fp-ts/core/These/Both": return onBoth(self.left, self.right) } } @@ -182,14 +182,15 @@ export const reverse: (self: These) => These = match( * @category guards * @since 1.0.0 */ -export const isLeft = (self: These): self is Left => self._tag === "Left" +export const isLeft = (self: These): self is Left => + self._tag === "@fp-ts/core/Either/Left" /** * @category guards * @since 1.0.0 */ export const isLeftOrBoth = (self: These): self is Left | Both => - self._tag !== "Right" + self._tag !== "@fp-ts/core/Either/Right" /** * Returns `true` if the these is an instance of `Right`, `false` otherwise @@ -197,14 +198,15 @@ export const isLeftOrBoth = (self: These): self is Left | Both(self: These): self is Right => self._tag === "Right" +export const isRight = (self: These): self is Right => + self._tag === "@fp-ts/core/Either/Right" /** * @category guards * @since 1.0.0 */ export const isRightOrBoth = (self: These): self is Right | Both => - self._tag !== "Left" + self._tag !== "@fp-ts/core/Either/Left" /** * Returns `true` if the these is an instance of `Both`, `false` otherwise @@ -212,7 +214,8 @@ export const isRightOrBoth = (self: These): self is Right | Both< * @category guards * @since 1.0.0 */ -export const isBoth = (self: These): self is Both => self._tag === "Both" +export const isBoth = (self: These): self is Both => + self._tag === "@fp-ts/core/These/Both" /** * Returns `true` if the specified value is an instance of `These`, `false` @@ -224,7 +227,8 @@ export const isBoth = (self: These): self is Both => self._tag export const isThese = (u: unknown): u is These => typeof u === "object" && u != null && "_tag" in u && - (u["_tag"] === "Left" || u["_tag"] === "Right" || u["_tag"] === "Both") + (u["_tag"] === "@fp-ts/core/Either/Left" || u["_tag"] === "@fp-ts/core/Either/Right" || + u["_tag"] === "@fp-ts/core/These/Both") /** * Constructs a new `These` from a function that might throw. diff --git a/src/internal/Either.ts b/src/internal/Either.ts index fbc5bce28..c8d2867d8 100644 --- a/src/internal/Either.ts +++ b/src/internal/Either.ts @@ -10,19 +10,21 @@ import type { Option } from "@fp-ts/core/Option" /** @internal */ export const isEither = (u: unknown): u is Either => typeof u === "object" && u != null && "_tag" in u && - (u["_tag"] === "Left" || u["_tag"] === "Right") + (u["_tag"] === "@fp-ts/core/Either/Left" || u["_tag"] === "@fp-ts/core/Either/Right") /** @internal */ -export const isLeft = (ma: Either): ma is Left => ma._tag === "Left" +export const isLeft = (ma: Either): ma is Left => + ma._tag === "@fp-ts/core/Either/Left" /** @internal */ -export const isRight = (ma: Either): ma is Right => ma._tag === "Right" +export const isRight = (ma: Either): ma is Right => + ma._tag === "@fp-ts/core/Either/Right" /** @internal */ -export const left = (e: E): Either => ({ _tag: "Left", left: e }) +export const left = (e: E): Either => ({ _tag: "@fp-ts/core/Either/Left", left: e }) /** @internal */ -export const right = (a: A): Either => ({ _tag: "Right", right: a }) +export const right = (a: A): Either => ({ _tag: "@fp-ts/core/Either/Right", right: a }) /** @internal */ export const getLeft = ( diff --git a/src/internal/Option.ts b/src/internal/Option.ts index c3a101ea6..04e3586ac 100644 --- a/src/internal/Option.ts +++ b/src/internal/Option.ts @@ -7,19 +7,19 @@ import type { None, Option, Some } from "@fp-ts/core/Option" /** @internal */ export const isOption = (u: unknown): u is Option => typeof u === "object" && u != null && "_tag" in u && - (u["_tag"] === "None" || u["_tag"] === "Some") + (u["_tag"] === "@fp-ts/core/Option/None" || u["_tag"] === "@fp-ts/core/Option/Some") /** @internal */ -export const isNone = (fa: Option): fa is None => fa._tag === "None" +export const isNone = (fa: Option): fa is None => fa._tag === "@fp-ts/core/Option/None" /** @internal */ -export const isSome = (fa: Option): fa is Some => fa._tag === "Some" +export const isSome = (fa: Option): fa is Some => fa._tag === "@fp-ts/core/Option/Some" /** @internal */ -export const none: Option = { _tag: "None" } +export const none: Option = { _tag: "@fp-ts/core/Option/None" } /** @internal */ -export const some = (a: A): Option => ({ _tag: "Some", value: a }) +export const some = (a: A): Option => ({ _tag: "@fp-ts/core/Option/Some", value: a }) /** @internal */ export const fromNullable = ( From a66f0f0ca6bdcad2cf466c817dcd92f6deb14d42 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 19:00:38 +0100 Subject: [PATCH 032/255] chore --- src/Either.ts | 2 +- src/Identity.ts | 2 +- src/Option.ts | 2 +- src/Predicate.ts | 2 +- src/ReadonlyArray.ts | 2 +- src/These.ts | 10 +++++----- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 42194e2c5..ebfb94b33 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -407,7 +407,7 @@ export const SemiProduct: semiProduct.SemiProduct = { */ export const andThenBind: ( name: Exclude, - fb: Either + that: Either ) => ( self: Either ) => Either = semiProduct diff --git a/src/Identity.ts b/src/Identity.ts index 41ba1275d..95b890460 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -282,7 +282,7 @@ export const SemiProduct: semiProduct.SemiProduct = { */ export const andThenBind: ( name: Exclude, - fb: Identity + that: Identity ) => ( self: Identity ) => Identity<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct diff --git a/src/Option.ts b/src/Option.ts index aa76952bc..d279adfb2 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -451,7 +451,7 @@ export const SemiProduct: semiProduct.SemiProduct = { */ export const andThenBind: ( name: Exclude, - fb: Option + that: Option ) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct.andThenBind(SemiProduct) diff --git a/src/Predicate.ts b/src/Predicate.ts index dce414810..17d73a020 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -185,7 +185,7 @@ export const Product: product_.Product = { */ export const andThenBind: ( name: Exclude, - self: Predicate + that: Predicate ) => ( self: Predicate ) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 2509e2860..8b7fa5a0b 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1736,7 +1736,7 @@ export const SemiProduct: semiProduct.SemiProduct = { */ export const andThenBind: ( name: Exclude, - fb: ReadonlyArray + that: ReadonlyArray ) => ( self: ReadonlyArray ) => ReadonlyArray<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct diff --git a/src/These.ts b/src/These.ts index 5ed4e4e80..88819b8a5 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1090,7 +1090,7 @@ export const productAll = ( */ export const andThenBind: ( name: Exclude, - fb: Validated + that: Validated ) => ( self: Validated ) => Validated = semiProduct @@ -1102,11 +1102,11 @@ export const andThenBind: ( */ export const andThenBindEither = ( name: Exclude, - fb: Either + that: Either ): ( self: Validated ) => Validated => - andThenBind(name, fromEither(fb)) + andThenBind(name, fromEither(that)) /** * @category do notation @@ -1114,11 +1114,11 @@ export const andThenBindEither = ( */ export const andThenBindThese = ( name: Exclude, - fb: These + that: These ): ( self: Validated ) => Validated => - andThenBind(name, fromThese(fb)) + andThenBind(name, fromThese(that)) /** * @since 1.0.0 From 157c09c5849445af3db04eda70d2432815b00b69 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 16 Jan 2023 19:04:51 +0100 Subject: [PATCH 033/255] Boolean: add not combinator --- .changeset/purple-cooks-destroy.md | 5 +++++ src/Boolean.ts | 6 ++++++ test/Boolean.ts | 5 +++++ 3 files changed, 16 insertions(+) create mode 100644 .changeset/purple-cooks-destroy.md diff --git a/.changeset/purple-cooks-destroy.md b/.changeset/purple-cooks-destroy.md new file mode 100644 index 000000000..3623a0b0c --- /dev/null +++ b/.changeset/purple-cooks-destroy.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Boolean: add not combinator diff --git a/src/Boolean.ts b/src/Boolean.ts index 7e9d8b8b1..da22ddc9e 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -27,6 +27,12 @@ export const and = (that: boolean) => (self: boolean): boolean => self && that */ export const or = (that: boolean) => (self: boolean): boolean => self || that +/** + * @category combinators + * @since 1.0.0 + */ +export const not = (self: boolean): boolean => !self + /** * Defines the match over a boolean value. * Takes two thunks `onTrue`, `onFalse` and a `boolean` value. diff --git a/test/Boolean.ts b/test/Boolean.ts index d9d7a3aae..ad34f13d9 100644 --- a/test/Boolean.ts +++ b/test/Boolean.ts @@ -31,6 +31,11 @@ describe.concurrent("Boolean", () => { deepStrictEqual(pipe(false, Boolean.or(false)), false) }) + it("not", () => { + deepStrictEqual(pipe(true, Boolean.not), false) + deepStrictEqual(pipe(false, Boolean.not), true) + }) + describe.concurrent("MonoidAll", () => { it("baseline", () => { deepStrictEqual(Boolean.MonoidAll.combineMany([true, true])(true), true) From 9b80f2b533a4a7a263abf20f7c1f8121ea41f22d Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 08:35:03 +0100 Subject: [PATCH 034/255] Chainable: remove readonly from bind return type --- src/Either.ts | 2 +- src/Identity.ts | 2 +- src/Option.ts | 4 ++-- src/These.ts | 6 +++--- src/typeclass/Chainable.ts | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index ebfb94b33..52b890345 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -335,7 +335,7 @@ export const bind: ( f: (a: A) => Either ) => ( self: Either -) => Either = chainable +) => Either = chainable .bind(Chainable) /** diff --git a/src/Identity.ts b/src/Identity.ts index 95b890460..744922601 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -217,7 +217,7 @@ export const bind: ( f: (a: A) => Identity ) => ( self: Identity -) => Identity<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable.bind( +) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable.bind( Chainable ) diff --git a/src/Option.ts b/src/Option.ts index d279adfb2..1e24144db 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -347,8 +347,8 @@ export const Chainable: chainable.Chainable = { export const bind: ( name: Exclude, f: (a: A) => Option -) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = - chainable.bind(Chainable) +) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable + .bind(Chainable) /** * Returns an effect that effectfully "peeks" at the success of this effect. diff --git a/src/These.ts b/src/These.ts index 88819b8a5..4cb30338c 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1259,7 +1259,7 @@ export const bind: ( f: (a: A) => Validated ) => ( self: Validated -) => Validated = chainable +) => Validated = chainable .bind(Chainable) /** @@ -1271,7 +1271,7 @@ export const bindEither = ( f: (a: A) => Either ): ( self: Validated -) => Validated => +) => Validated => bind(name, (a) => fromEither(f(a))) /** @@ -1283,7 +1283,7 @@ export const bindThese = ( f: (a: A) => These ): ( self: Validated -) => Validated => +) => Validated => bind(name, (a) => fromThese(f(a))) /** diff --git a/src/typeclass/Chainable.ts b/src/typeclass/Chainable.ts index 697a8fa7a..86ce4df76 100644 --- a/src/typeclass/Chainable.ts +++ b/src/typeclass/Chainable.ts @@ -56,7 +56,7 @@ export const bind = (F: Chainable) => R1 & R2, O1 | O2, E1 | E2, - { readonly [K in keyof A | N]: K extends keyof A ? A[K] : B } + { [K in keyof A | N]: K extends keyof A ? A[K] : B } > => F.flatMap(a => pipe( From a6e094e35df221921b9267f0865006d54524ffd3 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 08:37:32 +0100 Subject: [PATCH 035/255] Compactable: remove readonly from separate --- src/Option.ts | 4 ++-- src/typeclass/Compactable.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Option.ts b/src/Option.ts index 1e24144db..149d63675 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -749,8 +749,8 @@ export const Compactable: compactable.Compactable = { * @category filtering * @since 1.0.0 */ -export const separate: (self: Option>) => readonly [Option, Option] = - compactable.separate({ ...Covariant, ...Compactable }) +export const separate: (self: Option>) => [Option, Option] = compactable + .separate({ ...Covariant, ...Compactable }) /** * @category filtering diff --git a/src/typeclass/Compactable.ts b/src/typeclass/Compactable.ts index ef0c79de7..80de788d4 100644 --- a/src/typeclass/Compactable.ts +++ b/src/typeclass/Compactable.ts @@ -38,7 +38,7 @@ export const separate = ( ) => ( self: Kind> - ): readonly [Kind, Kind] => { + ): [Kind, Kind] => { return [ pipe(self, F.map(either.getLeft), F.compact), pipe(self, F.map(either.getRight), F.compact) From 8db1bb708a0ca4ac70849d5f91b5ed222339d23e Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 08:41:58 +0100 Subject: [PATCH 036/255] Filterable: remove readonly from partitionMap --- src/typeclass/Filterable.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typeclass/Filterable.ts b/src/typeclass/Filterable.ts index 03c5befeb..e749c2298 100644 --- a/src/typeclass/Filterable.ts +++ b/src/typeclass/Filterable.ts @@ -61,7 +61,7 @@ export const partitionMap = (F: Filterable) => (f: (a: A) => Either) => ( self: Kind - ): readonly [Kind, Kind] => { + ): [Kind, Kind] => { return [ pipe(self, F.filterMap((a) => either.getLeft(f(a)))), pipe(self, F.filterMap((a) => either.getRight(f(a)))) From 3af52aececa8f7550174f86143918940b1baca8d Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 08:44:59 +0100 Subject: [PATCH 037/255] Filterable: remove readonly from partition --- src/ReadonlyArray.ts | 4 ++-- src/typeclass/Filterable.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 8b7fa5a0b..6e6b3a496 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1542,10 +1542,10 @@ export const filterWithIndex: { export const partition: { (refinement: Refinement): ( self: ReadonlyArray - ) => readonly [ReadonlyArray, ReadonlyArray] + ) => [ReadonlyArray, ReadonlyArray] ( predicate: Predicate - ): (self: ReadonlyArray) => readonly [ReadonlyArray, ReadonlyArray] + ): (self: ReadonlyArray) => [ReadonlyArray, ReadonlyArray] } = filterable.partition(Filterable) /** diff --git a/src/typeclass/Filterable.ts b/src/typeclass/Filterable.ts index e749c2298..61f209229 100644 --- a/src/typeclass/Filterable.ts +++ b/src/typeclass/Filterable.ts @@ -76,14 +76,14 @@ export const partition: ( ) => { (refinement: (a: A) => a is B): ( self: Kind - ) => readonly [Kind, Kind] + ) => [Kind, Kind] (predicate: (a: A) => boolean): ( self: Kind - ) => readonly [Kind, Kind] + ) => [Kind, Kind] } = (Filterable: Filterable) => ( predicate: (a: A) => boolean ): (( self: Kind - ) => readonly [Kind, Kind]) => + ) => [Kind, Kind]) => partitionMap(Filterable)((b) => (predicate(b) ? either.right(b) : either.left(b))) From 0edf18c4a00407de126e995db611ce281f9e68b7 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 08:50:37 +0100 Subject: [PATCH 038/255] TraversableFilterable: remove readonly from traversePartitionMap, traversePartition --- src/ReadonlyArray.ts | 4 ++-- src/typeclass/TraversableFilterable.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 6e6b3a496..4006e7351 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1958,7 +1958,7 @@ export const traversePartitionMap: ( F: applicative.Applicative ) => ( f: (a: A) => Kind> -) => (self: ReadonlyArray) => Kind, ReadonlyArray]> = +) => (self: ReadonlyArray) => Kind, ReadonlyArray]> = traversableFilterable .traversePartitionMap({ ...Traversable, ...Covariant, ...Compactable }) @@ -1994,7 +1994,7 @@ export const traversePartition: ( predicate: (a: A) => Kind ) => ( self: ReadonlyArray -) => Kind, ReadonlyArray]> = traversableFilterable +) => Kind, ReadonlyArray]> = traversableFilterable .traversePartition(TraversableFilterable) /** diff --git a/src/typeclass/TraversableFilterable.ts b/src/typeclass/TraversableFilterable.ts index 2afc083c7..9c2b4198a 100644 --- a/src/typeclass/TraversableFilterable.ts +++ b/src/typeclass/TraversableFilterable.ts @@ -26,7 +26,7 @@ export interface TraversableFilterable extends TypeClass Kind> ) => ( self: Kind - ) => Kind, Kind]> + ) => Kind, Kind]> readonly traverseFilterMap: ( F: Applicative @@ -97,7 +97,7 @@ export const traversePartition = ( predicate: (a: A) => Kind ) => ( self: Kind - ) => Kind, Kind]>) => + ) => Kind, Kind]>) => (predicate) => T.traversePartitionMap(F)((b) => pipe( From 8bdff26996f8a1c166537f7294948300dc6ff5a5 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 08:56:19 +0100 Subject: [PATCH 039/255] Covariant: remove readonly from let --- src/Either.ts | 2 +- src/Identity.ts | 2 +- src/Option.ts | 4 ++-- src/These.ts | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 52b890345..64c78fc85 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -208,7 +208,7 @@ const let_: ( f: (a: A) => B ) => ( self: Either -) => Either = covariant.let( +) => Either = covariant.let( Covariant ) diff --git a/src/Identity.ts b/src/Identity.ts index 744922601..4a0fa2ef8 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -94,7 +94,7 @@ const let_: ( f: (a: A) => B ) => ( self: Identity -) => Identity<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant.let( +) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant.let( Covariant ) diff --git a/src/Option.ts b/src/Option.ts index 149d63675..d0fc017bf 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -227,8 +227,8 @@ export const Covariant: covariant.Covariant = { const let_: ( name: Exclude, f: (a: A) => B -) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = - covariant.let(Covariant) +) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant + .let(Covariant) export { /** diff --git a/src/These.ts b/src/These.ts index 4cb30338c..87ca2e258 100644 --- a/src/These.ts +++ b/src/These.ts @@ -687,7 +687,7 @@ const let_: ( f: (a: A) => B ) => ( self: These -) => These = covariant.let( +) => These = covariant.let( Covariant ) From d65f6c28b88bf248e92c605f64aa5ae212241e2c Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 14:17:17 +0100 Subject: [PATCH 040/255] bindTo: remove readonly --- src/Either.ts | 2 +- src/Identity.ts | 2 +- src/Option.ts | 2 +- src/ReadonlyArray.ts | 13 ++++++++++++- src/These.ts | 2 +- test/typeclass/TraversableFilterable.ts | 12 ++++++------ 6 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 64c78fc85..268d3d2b9 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -163,7 +163,7 @@ export const tupled: (self: Either) => Either = inv */ export const bindTo: ( name: N -) => (self: Either) => Either = invariant.bindTo(Invariant) +) => (self: Either) => Either = invariant.bindTo(Invariant) /** * @category instances diff --git a/src/Identity.ts b/src/Identity.ts index 4a0fa2ef8..80bc10f1f 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -78,7 +78,7 @@ export const tupled: (self: Identity) => Identity = invarian */ export const bindTo: ( name: N -) => (self: Identity) => Identity<{ readonly [K in N]: A }> = invariant.bindTo(Invariant) +) => (self: Identity) => Identity<{ [K in N]: A }> = invariant.bindTo(Invariant) /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index d0fc017bf..dce1aea2e 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -213,7 +213,7 @@ export const tupled: (self: Option) => Option = invariant.tu */ export const bindTo: ( name: N -) => (self: Option) => Option<{ readonly [K in N]: A }> = invariant.bindTo(Invariant) +) => (self: Option) => Option<{ [K in N]: A }> = invariant.bindTo(Invariant) /** * @category instances diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 4006e7351..96ad210fb 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -22,7 +22,7 @@ import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" import * as filterable from "@fp-ts/core/typeclass/Filterable" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" -import type * as invariant from "@fp-ts/core/typeclass/Invariant" +import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" import * as of_ from "@fp-ts/core/typeclass/Of" @@ -1299,6 +1299,17 @@ export const Invariant: invariant.Invariant = { imap } +/** + * @category do notation + * @since 1.0.0 + */ +export const bindTo: ( + name: N +) => (self: ReadonlyArray) => ReadonlyArray<{ [K in N]: A }> = invariant + .bindTo( + Invariant + ) + /** * @category instances * @since 1.0.0 diff --git a/src/These.ts b/src/These.ts index 87ca2e258..70e1dbed7 100644 --- a/src/These.ts +++ b/src/These.ts @@ -653,7 +653,7 @@ export const tupled: (self: These) => These = invar */ export const bindTo: ( name: N -) => (self: These) => These = invariant.bindTo(Invariant) +) => (self: These) => These = invariant.bindTo(Invariant) /** * @category mapping diff --git a/test/typeclass/TraversableFilterable.ts b/test/typeclass/TraversableFilterable.ts index 4b207fe9c..649bea03d 100644 --- a/test/typeclass/TraversableFilterable.ts +++ b/test/typeclass/TraversableFilterable.ts @@ -26,11 +26,11 @@ describe("TraversableFilterable", () => { const f = traversePartition((s: string) => s.length > 2 ? O.some(false) : s.length > 1 ? O.some(true) : O.none() ) - U.deepStrictEqual(f([]), O.some([[], []] as const)) - U.deepStrictEqual(f(["a"]), O.none()) - U.deepStrictEqual(f(["a", "aa"]), O.none()) - U.deepStrictEqual(f(["aa"]), O.some([[], ["aa"]] as const)) - U.deepStrictEqual(f(["aaa"]), O.some([["aaa"], []] as const)) - U.deepStrictEqual(f(["aaa", "aa"]), O.some([["aaa"], ["aa"]] as const)) + expect(f([])).toEqual(O.some([[], []])) + expect(f(["a"])).toEqual(O.none()) + expect(f(["a", "aa"])).toEqual(O.none()) + expect(f(["aa"])).toEqual(O.some([[], ["aa"]])) + expect(f(["aaa"])).toEqual(O.some([["aaa"], []])) + expect(f(["aaa", "aa"])).toEqual(O.some([["aaa"], ["aa"]])) }) }) From c76fce174951b69f794a2c658a617acbcd32ef1d Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 14:31:41 +0100 Subject: [PATCH 041/255] tupled: remove readonly --- src/Either.ts | 2 +- src/Identity.ts | 2 +- src/Option.ts | 2 +- src/Predicate.ts | 1 + src/ReadonlyArray.ts | 15 +++++++++++---- src/These.ts | 2 +- src/typeclass/Invariant.ts | 4 ++-- test/typeclass/Invariant.ts | 2 +- 8 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 268d3d2b9..2e714f857 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -153,7 +153,7 @@ export const Invariant: invariant.Invariant = { * @category mapping * @since 1.0.0 */ -export const tupled: (self: Either) => Either = invariant.tupled( +export const tupled: (self: Either) => Either = invariant.tupled( Invariant ) diff --git a/src/Identity.ts b/src/Identity.ts index 80bc10f1f..86fd42078 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -70,7 +70,7 @@ export const Invariant: invariant.Invariant = { /** * @since 1.0.0 */ -export const tupled: (self: Identity) => Identity = invariant.tupled(Invariant) +export const tupled: (self: Identity) => Identity<[A]> = invariant.tupled(Invariant) /** * @category do notation diff --git a/src/Option.ts b/src/Option.ts index dce1aea2e..98c886318 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -205,7 +205,7 @@ export const Invariant: invariant.Invariant = { /** * @since 1.0.0 */ -export const tupled: (self: Option) => Option = invariant.tupled(Invariant) +export const tupled: (self: Option) => Option<[A]> = invariant.tupled(Invariant) /** * @category do notation diff --git a/src/Predicate.ts b/src/Predicate.ts index 17d73a020..aac750baf 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -80,6 +80,7 @@ export const Invariant: invariant.Invariant = { /** * @since 1.0.0 */ +// @ts-expect-error export const tupled: (self: Predicate) => Predicate = invariant.tupled( Invariant ) diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 96ad210fb..1c24855c1 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1299,16 +1299,23 @@ export const Invariant: invariant.Invariant = { imap } +/** + * @category mapping + * @since 1.0.0 + */ +// @ts-expect-error +export const tupled: (self: ReadonlyArray) => Array<[A]> = invariant + .tupled(Invariant) + /** * @category do notation * @since 1.0.0 */ +// @ts-expect-error export const bindTo: ( name: N -) => (self: ReadonlyArray) => ReadonlyArray<{ [K in N]: A }> = invariant - .bindTo( - Invariant - ) +) => (self: ReadonlyArray) => Array<{ [K in N]: A }> = invariant + .bindTo(Invariant) /** * @category instances diff --git a/src/These.ts b/src/These.ts index 70e1dbed7..67b7e52ed 100644 --- a/src/These.ts +++ b/src/These.ts @@ -643,7 +643,7 @@ export const Invariant: invariant.Invariant = { * @category mapping * @since 1.0.0 */ -export const tupled: (self: These) => These = invariant.tupled( +export const tupled: (self: These) => These = invariant.tupled( Invariant ) diff --git a/src/typeclass/Invariant.ts b/src/typeclass/Invariant.ts index c0c41dfba..2b7c19265 100644 --- a/src/typeclass/Invariant.ts +++ b/src/typeclass/Invariant.ts @@ -46,5 +46,5 @@ export const bindTo = (F: Invariant) => */ export const tupled = ( F: Invariant -): ((self: Kind) => Kind) => - F.imap(a => [a] as const, ([a]) => a) +): ((self: Kind) => Kind) => + F.imap(a => [a], ([a]) => a) diff --git a/test/typeclass/Invariant.ts b/test/typeclass/Invariant.ts index c12bfc3b5..e10460ea9 100644 --- a/test/typeclass/Invariant.ts +++ b/test/typeclass/Invariant.ts @@ -38,7 +38,7 @@ describe("Invariant", () => { it("Covariant (Option)", () => { const tupled = _.tupled(O.Invariant) U.deepStrictEqual(pipe(O.none(), tupled), O.none()) - U.deepStrictEqual(pipe(O.some(1), tupled), O.some([1] as const)) + U.deepStrictEqual(pipe(O.some(1), tupled), O.some([1])) }) it("Contravariant (Predicate)", () => { From 1b0af3ea92e64665b1963a24b373c998738a79d4 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 15:06:05 +0100 Subject: [PATCH 042/255] Product, SemiProduct: remove readonly from typeclass members --- src/Either.ts | 6 ++-- src/Identity.ts | 6 ++-- src/Option.ts | 6 ++-- src/ReadonlyArray.ts | 21 +++++++----- src/These.ts | 6 ++-- src/typeclass/Monoid.ts | 2 +- src/typeclass/Product.ts | 2 +- src/typeclass/SemiProduct.ts | 12 +++---- src/typeclass/Semigroup.ts | 5 ++- test/Either.ts | 11 +++--- test/Option.ts | 11 +++--- test/These.ts | 43 +++++++++--------------- test/typeclass/NonEmptyTraversable.ts | 2 ++ test/typeclass/SemiProduct.ts | 46 ++++++++++++++------------ test/typeclass/Semigroup.ts | 5 ++- test/typeclass/TraversableWithIndex.ts | 1 + 16 files changed, 94 insertions(+), 91 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 2e714f857..0ab20f611 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -365,7 +365,7 @@ export const Monad: monad.Monad = { export const product = ( that: Either ) => - (self: Either): Either => + (self: Either): Either => isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self /** @@ -375,7 +375,7 @@ export const product = ( export const productMany = ( collection: Iterable> ) => - (self: Either): Either]> => { + (self: Either): Either]> => { if (isLeft(self)) { return self } @@ -428,7 +428,7 @@ export const productFlatten: ( */ export const productAll = ( collection: Iterable> -): Either> => { +): Either> => { const out: Array = [] for (const e of collection) { if (isLeft(e)) { diff --git a/src/Identity.ts b/src/Identity.ts index 86fd42078..8369aaf8b 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -256,13 +256,13 @@ export const Monad: monad.Monad = { */ export const product = ( that: Identity -) => (self: Identity): Identity => [self, that] +) => (self: Identity): Identity<[A, B]> => [self, that] /** * @since 1.0.0 */ export const productMany = (collection: Iterable>) => - (self: Identity): Identity]> => [self, ...collection] + (self: Identity): Identity<[A, ...Array]> => [self, ...collection] /** * @category instances @@ -300,7 +300,7 @@ export const productFlatten: ( /** * @since 1.0.0 */ -export const productAll = (collection: Iterable>): Identity> => +export const productAll = (collection: Iterable>): Identity> => readonlyArray.fromIterable(collection) /** diff --git a/src/Option.ts b/src/Option.ts index 98c886318..f0bd3a20e 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -412,14 +412,14 @@ export const Monad: monad.Monad = { export const product = ( that: Option ) => - (self: Option): Option => + (self: Option): Option<[A, B]> => isSome(self) && isSome(that) ? some([self.value, that.value]) : option.none /** * @since 1.0.0 */ export const productMany = (collection: Iterable>) => - (self: Option): Option]> => { + (self: Option): Option<[A, ...Array]> => { if (isNone(self)) { return option.none } @@ -466,7 +466,7 @@ export const productFlatten: ( /** * @since 1.0.0 */ -export const productAll = (collection: Iterable>): Option> => { +export const productAll = (collection: Iterable>): Option> => { const out: Array = [] for (const o of collection) { if (isNone(o)) { diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 1c24855c1..110b17af1 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1616,7 +1616,7 @@ export const partitionMapWithIndex = (f: (a: A, i: number) => Either(F: applicative.Applicative) => ( f: (a: A) => Kind - ): ((self: ReadonlyArray) => Kind>) => traverseWithIndex(F)(f) + ): ((self: ReadonlyArray) => Kind>) => traverseWithIndex(F)(f) /** * @category traversing @@ -1624,7 +1624,7 @@ export const traverse = (F: applicative.Applicative) => */ export const traverseWithIndex = (F: applicative.Applicative) => (f: (a: A, i: number) => Kind) => - (self: ReadonlyArray): Kind> => F.productAll(self.map(f)) + (self: ReadonlyArray): Kind> => F.productAll(self.map(f)) /** * @category traversing @@ -1635,7 +1635,7 @@ export const traverseNonEmpty = ( ) => ( f: (a: A) => Kind - ): ((self: NonEmptyReadonlyArray) => Kind>) => + ): ((self: NonEmptyReadonlyArray) => Kind>) => traverseNonEmptyWithIndex(F)(f) /** @@ -1646,7 +1646,7 @@ export const traverseNonEmptyWithIndex = ( F: semiApplicative.SemiApplicative ) => (f: (a: A, i: number) => Kind) => - (self: NonEmptyReadonlyArray): Kind> => { + (self: NonEmptyReadonlyArray): Kind> => { const fbs = pipe(self, mapNonEmptyWithIndex(f)) return pipe(headNonEmpty(fbs), F.productMany(tailNonEmpty(fbs))) } @@ -1655,18 +1655,23 @@ export const traverseNonEmptyWithIndex = ( * @category traversing * @since 1.0.0 */ +// @ts-expect-error export const sequence: ( F: applicative.Applicative ) => ( self: ReadonlyArray> -) => Kind> = traversable.sequence(traverse) +) => Kind> = + // @ts-expect-error + traversable.sequence(traverse) /** * @category instances * @since 1.0.0 */ export const Traversable: traversable.Traversable = { + // @ts-expect-error traverse, + // @ts-expect-error sequence } @@ -1691,7 +1696,7 @@ export const sequenceNonEmpty = ( F: semiApplicative.SemiApplicative ): (( self: NonEmptyReadonlyArray> -) => Kind>) => traverseNonEmpty(F)(identity) +) => Kind>) => traverseNonEmpty(F)(identity) /** * @since 1.0.0 @@ -1717,7 +1722,7 @@ export const product = ( */ export const productMany: ( collection: Iterable> -) => (self: ReadonlyArray) => ReadonlyArray> = semiProduct +) => (self: ReadonlyArray) => ReadonlyArray<[A, ...Array]> = semiProduct .productMany( Covariant, product @@ -1728,7 +1733,7 @@ export const productMany: ( */ export const productAll = ( collection: Iterable> -): ReadonlyArray> => { +): ReadonlyArray> => { const arrays = Array.from(collection) if (isEmpty(arrays)) { return empty() diff --git a/src/These.ts b/src/These.ts index 67b7e52ed..2d8de3069 100644 --- a/src/These.ts +++ b/src/These.ts @@ -961,7 +961,7 @@ export const filterMap = ( export const product = (that: Validated) => ( self: Validated - ): Validated => { + ): Validated => { if (isLeft(self)) { return self } @@ -991,7 +991,7 @@ export const productMany = ( ) => ( self: Validated - ): Validated]> => + ): Validated]> => pipe(self, product(productAll(collection)), map(([a, as]) => [a, ...as])) /** @@ -1062,7 +1062,7 @@ export const getFirstLeftSemigroup: ( */ export const productAll = ( collection: Iterable> -): Validated> => { +): Validated> => { const rights: Array = [] const lefts: Array = [] let isFatal = false diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index 160d0a8a9..a5ff1ecd1 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -79,5 +79,5 @@ export const tuple = >( ...monoids: { [K in keyof A]: Monoid } ): Monoid> => { const empty: A = monoids.map((m) => m.empty) as any - return fromSemigroup(semigroup.tuple(...monoids), empty) + return fromSemigroup(semigroup.tuple>(...monoids), empty) } diff --git a/src/typeclass/Product.ts b/src/typeclass/Product.ts index e6129ea94..9e849f17f 100644 --- a/src/typeclass/Product.ts +++ b/src/typeclass/Product.ts @@ -13,7 +13,7 @@ import type { SemiProduct } from "@fp-ts/core/typeclass/SemiProduct" export interface Product extends SemiProduct, Of { readonly productAll: ( collection: Iterable> - ) => Kind> + ) => Kind> } /** diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 833aa743c..2234c9b4e 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -16,11 +16,11 @@ export interface SemiProduct extends Invariant { that: Kind ) => ( self: Kind - ) => Kind + ) => Kind readonly productMany: ( collection: Iterable> - ) => (self: Kind) => Kind]> + ) => (self: Kind) => Kind]> } /** @@ -42,7 +42,7 @@ export const productComposition = ( FR1 & FR2, FO1 | FO2, FE1 | FE2, - Kind + Kind > => pipe(self, F.product(that), F.map(([ga, gb]) => pipe(ga, G.product(gb)))) /** @@ -59,7 +59,7 @@ export const productManyComposition = ( self: Kind> - ): Kind]>> => + ): Kind]>> => pipe( self, F.productMany(collection), @@ -82,13 +82,13 @@ export const productMany = ( (self: Kind) => { let out = pipe( self, - Covariant.map((a): readonly [A, ...Array] => [a]) + Covariant.map((a): [A, ...Array] => [a]) ) for (const fa of collection) { out = pipe( out, product(fa), - Covariant.map(([[head, ...tail], a]): readonly [A, ...Array] => [head, ...tail, a]) + Covariant.map(([[head, ...tail], a]): [A, ...Array] => [head, ...tail, a]) ) } return out diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index b49e76b28..35b442adf 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -205,7 +205,9 @@ export const Invariant: invariant.Invariant = { */ export const SemiProduct: semiProduct.SemiProduct = { ...Invariant, + // @ts-expect-error product: that => self => tuple(self, that), + // @ts-expect-error productMany: collection => self => tuple(self, ...collection) } @@ -216,5 +218,6 @@ export const SemiProduct: semiProduct.SemiProduct = { export const Product: product.Product = { ...SemiProduct, of: constant, - productAll: (collection: Iterable>) => tuple>(...collection) + // @ts-expect-error + productAll: (collection: Iterable>) => tuple(...collection) } diff --git a/test/Either.ts b/test/Either.ts index 83e429746..8b53175a5 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -381,17 +381,17 @@ describe.concurrent("Either", () => { }) it("product", () => { - deepStrictEqual(pipe(_.right(1), _.product(_.right("a"))), _.right([1, "a"] as const)) + deepStrictEqual(pipe(_.right(1), _.product(_.right("a"))), _.right([1, "a"])) deepStrictEqual(pipe(_.right(1), _.product(_.left("e2"))), _.left("e2")) deepStrictEqual(pipe(_.left("e1"), _.product(_.right("a"))), _.left("e1")) deepStrictEqual(pipe(_.left("e1"), _.product(_.left("2"))), _.left("e1")) }) it("productMany", () => { - deepStrictEqual(pipe(_.right(1), _.productMany([])), _.right([1] as const)) + deepStrictEqual(pipe(_.right(1), _.productMany([])), _.right([1])) deepStrictEqual( pipe(_.right(1), _.productMany([_.right(2), _.right(3)])), - _.right([1, 2, 3] as const) + _.right([1, 2, 3]) ) deepStrictEqual( pipe(_.right(1), _.productMany([_.left("e"), _.right(3)])), @@ -445,9 +445,8 @@ describe.concurrent("Either", () => { }) it("productFlatten", () => { - deepStrictEqual( - pipe(_.right(1), _.tupled, _.productFlatten(_.right("b"))), - _.right([1, "b"] as const) + expect(pipe(_.right(1), _.tupled, _.productFlatten(_.right("b")))).toEqual( + _.right([1, "b"]) ) }) diff --git a/test/Option.ts b/test/Option.ts index f0c9f641a..bb6d2283e 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -216,20 +216,20 @@ describe.concurrent("Option", () => { deepStrictEqual(pipe(_.none(), _.product(_.some("a"))), _.none()) deepStrictEqual( pipe(_.some(1), _.product(_.some("a"))), - _.some([1, "a"] as const) + _.some([1, "a"]) ) }) it("productMany", () => { deepStrictEqual(pipe(_.none(), _.SemiProduct.productMany([])), _.none()) - deepStrictEqual(pipe(_.some(1), _.SemiProduct.productMany([])), _.some([1] as const)) + deepStrictEqual(pipe(_.some(1), _.SemiProduct.productMany([])), _.some([1])) deepStrictEqual( pipe(_.some(1), _.SemiProduct.productMany([_.none() as _.Option])), _.none() ) deepStrictEqual( pipe(_.some(1), _.SemiProduct.productMany([_.some(2)])), - _.some([1, 2] as const) + _.some([1, 2]) ) }) @@ -503,9 +503,8 @@ describe.concurrent("Option", () => { }) it("productFlatten", () => { - deepStrictEqual( - pipe(_.some(1), _.tupled, _.productFlatten(_.some("b"))), - _.some([1, "b"] as const) + expect(pipe(_.some(1), _.tupled, _.productFlatten(_.some("b")))).toEqual( + _.some([1, "b"]) ) }) diff --git a/test/These.ts b/test/These.ts index 5dcd2eddb..79e276c98 100644 --- a/test/These.ts +++ b/test/These.ts @@ -274,15 +274,15 @@ describe("These", () => { const b = ["b"] as const const ab = ["a", "b"] as const - U.deepStrictEqual(pipe(_.right(1), _.product(_.right(2))), _.right([1, 2] as const)) + expect(pipe(_.right(1), _.product(_.right(2)))).toEqual(_.right([1, 2])) U.deepStrictEqual(pipe(_.right(1), _.product(_.left(b))), _.left(b)) - U.deepStrictEqual(pipe(_.right(1), _.product(_.both(b, 2))), _.both(b, [1, 2] as const)) + expect(pipe(_.right(1), _.product(_.both(b, 2)))).toEqual(_.both(b, [1, 2])) U.deepStrictEqual(pipe(_.left(a), _.product(_.right(2))), _.left(a)) U.deepStrictEqual(pipe(_.left(a), _.product(_.left(b))), _.left(a)) U.deepStrictEqual(pipe(_.left(a), _.product(_.both(b, 2))), _.left(a)) - U.deepStrictEqual(pipe(_.both(a, 1), _.product(_.right(2))), _.both(a, [1, 2] as const)) + expect(pipe(_.both(a, 1), _.product(_.right(2)))).toEqual(_.both(a, [1, 2])) expect(pipe(_.both(a, 1), _.product(_.left(b)))).toEqual(_.left(ab)) expect(pipe(_.both(a, 1), _.product(_.both(b, 2)))).toEqual(_.both(ab, [1, 2])) }) @@ -292,14 +292,15 @@ describe("These", () => { const b = ["b"] as const const ab = ["a", "b"] as const - U.deepStrictEqual(pipe(_.right(1), _.productMany([_.right(2)])), _.right([1, 2] as const)) + expect(pipe(_.right(1), _.productMany([_.right(2)]))).toEqual(_.right([1, 2])) U.deepStrictEqual( pipe(_.right(1), _.productMany([_.left(b)])), _.left(b) ) - U.deepStrictEqual( - pipe(_.right(1), _.productMany([_.both(b, 2)])), - _.both(b, [1, 2] as const) + expect( + pipe(_.right(1), _.productMany([_.both(b, 2)])) + ).toEqual( + _.both(b, [1, 2]) ) U.deepStrictEqual(pipe(_.left(a), _.productMany([_.right(2)])), _.left(a)) @@ -309,7 +310,7 @@ describe("These", () => { _.left(a) ) - U.deepStrictEqual(pipe(_.both(a, 1), _.productMany([_.right(2)])), _.both(a, [1, 2] as const)) + expect(pipe(_.both(a, 1), _.productMany([_.right(2)]))).toEqual(_.both(a, [1, 2])) expect(pipe(_.both(a, 1), _.productMany([_.left(b)]))).toEqual(_.left(ab)) expect(pipe(_.both(a, 1), _.productMany([_.both(b, 2)]))).toEqual( _.both(ab, [1, 2]) @@ -321,9 +322,9 @@ describe("These", () => { const b = ["b"] as const const ab = ["a", "b"] as const - U.deepStrictEqual(_.productAll([_.right(1), _.right(2)]), _.right([1, 2] as const)) + U.deepStrictEqual(_.productAll([_.right(1), _.right(2)]), _.right([1, 2])) U.deepStrictEqual(_.productAll([_.right(1), _.left(b)]), _.left(b)) - U.deepStrictEqual(_.productAll([_.right(1), _.both(b, 2)]), _.both(b, [1, 2] as const)) + U.deepStrictEqual(_.productAll([_.right(1), _.both(b, 2)]), _.both(b, [1, 2])) U.deepStrictEqual(_.productAll([_.left(a), _.right(2)]), _.left(a)) U.deepStrictEqual(_.productAll([_.left(a), _.left(b)]), _.left(a)) @@ -351,20 +352,8 @@ describe("These", () => { pipe(_.warn("e1", 2), _.flatMap(f)), _.warn("e1", 4) ) - U.deepStrictEqual( - pipe( - _.warn("e1", 1), - _.flatMap(f) - ), - _.left(["e1", "e3"] as const) - ) - U.deepStrictEqual( - pipe( - _.warn("e1", 6), - _.flatMap(f) - ), - _.both(["e1", "e2"] as const, 6) - ) + expect(pipe(_.warn("e1", 1), _.flatMap(f))).toEqual(_.left(["e1", "e3"])) + expect(pipe(_.warn("e1", 6), _.flatMap(f))).toEqual(_.both(["e1", "e2"], 6)) }) it("flatMapNullable", () => { @@ -435,7 +424,7 @@ describe("These", () => { it("getBoth", () => { U.deepStrictEqual(pipe(_.left("e"), _.getBoth), O.none()) U.deepStrictEqual(pipe(_.right(1), _.getBoth), O.none()) - U.deepStrictEqual(pipe(_.both("e", 1), _.getBoth), O.some(["e", 1] as const)) + expect(pipe(_.both("e", 1), _.getBoth)).toEqual(O.some(["e", 1])) }) it("getLeft", () => { @@ -627,7 +616,7 @@ describe("These", () => { it("fromEither", () => { U.deepStrictEqual(_.fromEither(E.right(1)), _.right(1)) - U.deepStrictEqual(_.fromEither(E.left("e")), _.left(["e"] as const)) + expect(_.fromEither(E.left("e"))).toEqual(_.left(["e"])) }) it("fromThese", () => { @@ -671,7 +660,7 @@ describe("These", () => { }) it("fromTuple", () => { - U.deepStrictEqual(pipe(["e", 1] as const, _.fromTuple), _.both("e", 1)) + expect(pipe(["e", 1] as [string, number], _.fromTuple)).toEqual(_.both("e", 1)) }) it("reverse", () => { diff --git a/test/typeclass/NonEmptyTraversable.ts b/test/typeclass/NonEmptyTraversable.ts index 666f074c6..73ddb23d9 100644 --- a/test/typeclass/NonEmptyTraversable.ts +++ b/test/typeclass/NonEmptyTraversable.ts @@ -5,7 +5,9 @@ import * as _ from "@fp-ts/core/test/limbo/NonEmptyTraversable" import * as U from "../util" const NonEmptyTraversable: _.NonEmptyTraversable = { + // @ts-expect-error traverseNonEmpty: RA.traverseNonEmpty, + // @ts-expect-error sequenceNonEmpty: F => self => pipe(self, RA.traverseNonEmpty(F)(identity)) } diff --git a/test/typeclass/SemiProduct.ts b/test/typeclass/SemiProduct.ts index aacea2833..29566f2e2 100644 --- a/test/typeclass/SemiProduct.ts +++ b/test/typeclass/SemiProduct.ts @@ -35,7 +35,7 @@ describe("SemiProduct", () => { const productManyFromAp = (collection: Iterable>) => ( self: Kind - ): Kind]> => { + ): Kind]> => { const args = [self, ...Array.from(collection)] const len = args.length const f = getCurriedTupleConstructor(len) @@ -52,8 +52,8 @@ describe("SemiProduct", () => { } const product = (that: ReadonlyArray) => - (self: ReadonlyArray): ReadonlyArray => { - const out: Array = [] + (self: ReadonlyArray): ReadonlyArray<[A, B]> => { + const out: Array<[A, B]> = [] for (const a of self) { for (const b of that) { out.push([a, b]) @@ -85,7 +85,7 @@ describe("SemiProduct", () => { U.deepStrictEqual(pipe([], product([O.none()])), []) U.deepStrictEqual(pipe([O.none()], product([])), []) U.deepStrictEqual(pipe([O.none()], product([O.none()])), [O.none()]) - U.deepStrictEqual(pipe([O.some(1)], product([O.some(2)])), [O.some([1, 2] as const)]) + expect(pipe([O.some(1)], product([O.some(2)]))).toEqual([O.some([1, 2])]) }) it("Option", () => { @@ -97,7 +97,7 @@ describe("SemiProduct", () => { U.deepStrictEqual(pipe(O.some(O.none()), product(O.some(O.some(2)))), O.some(O.none())) U.deepStrictEqual( pipe(O.some(O.some(1)), product(O.some(O.some(2)))), - O.some(O.some([1, 2] as const)) + O.some(O.some([1, 2])) ) }) }) @@ -105,23 +105,24 @@ describe("SemiProduct", () => { describe("productManyComposition", () => { it("ReadonlyArray", () => { const productMany = _.productManyComposition(RA.SemiApplicative, O.SemiProduct) - U.deepStrictEqual(pipe([O.some(1), O.none()], productMany([])), [ - O.some([1] as const), + expect(pipe([O.some(1), O.none()], productMany([]))).toEqual([ + O.some([1]), O.none() ]) - U.deepStrictEqual(pipe([O.some(1), O.none()], productMany([[O.some(2), O.none()]])), [ - O.some([1, 2] as const), + expect(pipe([O.some(1), O.none()], productMany([[O.some(2), O.none()]]))).toEqual([ + O.some([1, 2]), O.none(), O.none(), O.none() ]) - U.deepStrictEqual( - pipe([O.some(1), O.some(2)], productMany([[O.some(3), O.some(4)], [O.some(5)]])), + expect( + pipe([O.some(1), O.some(2)], productMany([[O.some(3), O.some(4)], [O.some(5)]])) + ).toEqual( [ - O.some([1, 3, 5] as const), - O.some([1, 4, 5] as const), - O.some([2, 3, 5] as const), - O.some([2, 4, 5] as const) + O.some([1, 3, 5]), + O.some([1, 4, 5]), + O.some([2, 3, 5]), + O.some([2, 4, 5]) ] ) }) @@ -130,7 +131,7 @@ describe("SemiProduct", () => { const productMany = _.productManyComposition(O.SemiApplicative, O.SemiProduct) U.deepStrictEqual(pipe(O.none(), productMany([])), O.none()) U.deepStrictEqual(pipe(O.some(O.none()), productMany([])), O.some(O.none())) - U.deepStrictEqual(pipe(O.some(O.some(1)), productMany([])), O.some(O.some([1] as const))) + U.deepStrictEqual(pipe(O.some(O.some(1)), productMany([])), O.some(O.some([1]))) U.deepStrictEqual(pipe(O.none(), productMany([O.none()])), O.none()) U.deepStrictEqual(pipe(O.some(O.none()), productMany([O.none()])), O.none()) U.deepStrictEqual(pipe(O.some(O.none()), productMany([O.some(O.none())])), O.some(O.none())) @@ -140,7 +141,7 @@ describe("SemiProduct", () => { ) U.deepStrictEqual( pipe(O.some(O.some(1)), productMany([O.some(O.some(2))])), - O.some(O.some([1, 2] as const)) + O.some(O.some([1, 2])) ) }) }) @@ -167,7 +168,7 @@ describe("SemiProduct", () => { it("Covariant (Option)", () => { const productFlatten = _.productFlatten(O.SemiProduct) U.deepStrictEqual(pipe(O.some([1, 2]), productFlatten(O.none())), O.none()) - U.deepStrictEqual(pipe(O.some([1, 2]), productFlatten(O.some(3))), O.some([1, 2, 3] as const)) + expect(pipe(O.some([1, 2]), productFlatten(O.some(3)))).toEqual(O.some([1, 2, 3])) }) it("Contravariant (Predicate)", () => { @@ -182,10 +183,11 @@ describe("SemiProduct", () => { describe("nonEmptyTuple", () => { it("Covariant (Option)", () => { const nonEmptyTuple = _.nonEmptyTuple(O.SemiProduct) - U.deepStrictEqual(nonEmptyTuple(O.some("a")), O.some(["a"] as const)) - U.deepStrictEqual( - nonEmptyTuple(O.some("a"), O.some(1), O.some(true)), - O.some(["a", 1, true] as const) + expect(nonEmptyTuple(O.some("a"))).toEqual(O.some(["a"])) + expect( + nonEmptyTuple(O.some("a"), O.some(1), O.some(true)) + ).toEqual( + O.some(["a", 1, true]) ) U.deepStrictEqual(nonEmptyTuple(O.some("a"), O.some(1), O.none()), O.none()) }) diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index b7b3d3999..be9986c23 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -138,7 +138,10 @@ describe("Semigroup", () => { String.Semigroup, _.SemiProduct.product(Number.SemigroupSum), _.SemiProduct.product(Number.SemigroupMultiply), - _.imap(([[a, b], c]) => [a, b, c] as const, ([a, b, c]) => [[a, b], c] as const) + _.imap( + ([[a, b], c]): [string, number, number] => [a, b, c], + ([a, b, c]): [[string, number], number] => [[a, b], c] + ) ) U.deepStrictEqual(pipe(["a", 2, 3], A.combine(["b", 3, 4])), ["ab", 5, 12]) }) diff --git a/test/typeclass/TraversableWithIndex.ts b/test/typeclass/TraversableWithIndex.ts index 0b7e83638..338e6d75a 100644 --- a/test/typeclass/TraversableWithIndex.ts +++ b/test/typeclass/TraversableWithIndex.ts @@ -5,6 +5,7 @@ import * as _ from "@fp-ts/core/test/limbo/TraversableWithIndex" import * as U from "../util" const TraversableWithIndex: _.TraversableWithIndex = { + // @ts-expect-error traverseWithIndex: RA.traverseWithIndex } From 1c11b0d40605704c736a5d8c42ccd5bc7b50f460 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 16:58:10 +0100 Subject: [PATCH 043/255] andThenBind: remove readonly --- src/Either.ts | 2 +- src/Identity.ts | 2 +- src/Option.ts | 4 ++-- src/These.ts | 6 +++--- src/typeclass/SemiProduct.ts | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 0ab20f611..3ad8d237b 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -410,7 +410,7 @@ export const andThenBind: ( that: Either ) => ( self: Either -) => Either = semiProduct +) => Either = semiProduct .andThenBind(SemiProduct) /** diff --git a/src/Identity.ts b/src/Identity.ts index 8369aaf8b..5a43015b3 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -285,7 +285,7 @@ export const andThenBind: ( that: Identity ) => ( self: Identity -) => Identity<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct +) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct .andThenBind(SemiProduct) /** diff --git a/src/Option.ts b/src/Option.ts index f0bd3a20e..e24a0702c 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -452,8 +452,8 @@ export const SemiProduct: semiProduct.SemiProduct = { export const andThenBind: ( name: Exclude, that: Option -) => (self: Option) => Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = - semiProduct.andThenBind(SemiProduct) +) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct + .andThenBind(SemiProduct) /** * @since 1.0.0 diff --git a/src/These.ts b/src/These.ts index 2d8de3069..2d4bd7de1 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1093,7 +1093,7 @@ export const andThenBind: ( that: Validated ) => ( self: Validated -) => Validated = semiProduct +) => Validated = semiProduct .andThenBind(SemiProduct) /** @@ -1105,7 +1105,7 @@ export const andThenBindEither = ( that: Either ): ( self: Validated -) => Validated => +) => Validated => andThenBind(name, fromEither(that)) /** @@ -1117,7 +1117,7 @@ export const andThenBindThese = ( that: These ): ( self: Validated -) => Validated => +) => Validated => andThenBind(name, fromThese(that)) /** diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 2234c9b4e..0faaaefee 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -109,7 +109,7 @@ export const andThenBind = (F: SemiProduct) => R1 & R2, O1 | O2, E1 | E2, - { readonly [K in keyof A | N]: K extends keyof A ? A[K] : B } + { [K in keyof A | N]: K extends keyof A ? A[K] : B } > => pipe( self, From 3f08bde61eb39cbc3a5207adc6dfdacfa6f60a90 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 17:07:45 +0100 Subject: [PATCH 044/255] productFlatten: remove readonly --- src/Either.ts | 2 +- src/Identity.ts | 5 ++--- src/Option.ts | 2 +- src/Predicate.ts | 8 ++++++++ src/ReadonlyArray.ts | 7 +++---- src/These.ts | 2 +- src/typeclass/SemiProduct.ts | 4 ++-- test/Predicate.ts | 1 + test/ReadonlyArray.ts | 2 ++ 9 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 3ad8d237b..d42e1ec62 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -420,7 +420,7 @@ export const productFlatten: ( that: Either ) => >( self: Either -) => Either = semiProduct +) => Either = semiProduct .productFlatten(SemiProduct) /** diff --git a/src/Identity.ts b/src/Identity.ts index 5a43015b3..62d1b9656 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -293,9 +293,8 @@ export const andThenBind: ( */ export const productFlatten: ( fb: Identity -) => >(self: Identity) => Identity = - semiProduct - .productFlatten(SemiProduct) +) => >(self: Identity) => Identity<[...A, B]> = semiProduct + .productFlatten(SemiProduct) /** * @since 1.0.0 diff --git a/src/Option.ts b/src/Option.ts index e24a0702c..e173c6a93 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -460,7 +460,7 @@ export const andThenBind: ( */ export const productFlatten: ( fb: Option -) => >(self: Option) => Option = semiProduct +) => >(self: Option) => Option<[...A, B]> = semiProduct .productFlatten(SemiProduct) /** diff --git a/src/Predicate.ts b/src/Predicate.ts index aac750baf..8d2934ffe 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -194,6 +194,14 @@ export const andThenBind: ( SemiProduct ) +/** + * @since 1.0.0 + */ +// @ts-expect-error +export const productFlatten: (that: Predicate) => >( + self: Predicate +) => Predicate = semiProduct.productFlatten(SemiProduct) + /** * @since 1.0.0 */ diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 110b17af1..d8e78af31 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -2136,11 +2136,10 @@ export const join: (sep: string) => (self: ReadonlyArray) => string = in /** * @since 1.0.0 */ -export const productFlatten: ( - that: ReadonlyArray -) => >( +// @ts-expect-error +export const productFlatten: (that: ReadonlyArray) => >( self: ReadonlyArray -) => ReadonlyArray = semiProduct.productFlatten(SemiProduct) +) => Array<[...A, B]> = semiProduct.productFlatten(SemiProduct) /** * @since 1.0.0 diff --git a/src/These.ts b/src/These.ts index 2d4bd7de1..b05c58f54 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1127,7 +1127,7 @@ export const productFlatten: ( that: Validated ) => >( self: Validated -) => Validated = semiProduct +) => Validated = semiProduct .productFlatten(SemiProduct) /** diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 0faaaefee..0b2d5b79b 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -129,11 +129,11 @@ export const productFlatten = (F: SemiProduct) => ) => >( self: Kind - ): Kind => + ): Kind => pipe( self, F.product(that), - F.imap(([a, b]) => [...a, b] as const, ab => [ab.slice(0, -1), ab[ab.length - 1]] as any) + F.imap(([a, b]) => [...a, b], ab => [ab.slice(0, -1), ab[ab.length - 1]] as any) ) /** diff --git a/test/Predicate.ts b/test/Predicate.ts index 7b272faa4..d727fa653 100644 --- a/test/Predicate.ts +++ b/test/Predicate.ts @@ -35,6 +35,7 @@ describe.concurrent("Predicate", () => { expect(_.product).exist expect(_.productMany).exist expect(_.andThenBind).exist + expect(_.productFlatten).exist expect(_.Product).exist expect(_.productAll).exist diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 550933a4e..a3e4022d3 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -15,6 +15,8 @@ describe.concurrent("ReadonlyArray", () => { it("instances and derived exports", () => { expect(RA.Invariant).exist expect(RA.imap).exist + expect(RA.tupled).exist + expect(RA.bindTo).exist expect(RA.Covariant).exist expect(RA.map).exist From 70933dd150e4c65e0d886cc72016711c84101f92 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 17:12:06 +0100 Subject: [PATCH 045/255] nonEmptyStruct: remove readonly --- src/typeclass/SemiProduct.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 0b2d5b79b..5af134638 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -163,7 +163,7 @@ export const nonEmptyStruct = (F: SemiProduct) => ([R[keyof R]] extends [Kind] ? R : never), ([R[keyof R]] extends [Kind] ? O : never), ([R[keyof R]] extends [Kind] ? E : never), - { readonly [K in keyof R]: [R[K]] extends [Kind] ? A : never } + { [K in keyof R]: [R[K]] extends [Kind] ? A : never } > => { const keys = Object.keys(fields) return pipe( From 3b986d02446caadddd745feee2dc5941418eeeaa Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 17:15:32 +0100 Subject: [PATCH 046/255] struct: remove readonly --- src/Either.ts | 2 +- src/Identity.ts | 5 ++--- src/Option.ts | 2 +- src/These.ts | 2 +- src/typeclass/Product.ts | 2 +- src/typeclass/Semigroup.ts | 4 +--- 6 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index d42e1ec62..0ae1c58e9 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -467,7 +467,7 @@ export const struct: >>( r: R ) => Either< [R[keyof R]] extends [Either] ? E : never, - { readonly [K in keyof R]: [R[K]] extends [Either] ? A : never } + { [K in keyof R]: [R[K]] extends [Either] ? A : never } > = product_ .struct(Product) diff --git a/src/Identity.ts b/src/Identity.ts index 62d1b9656..dfe99be9c 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -326,9 +326,8 @@ export const tuple: >>( */ export const struct: >>( r: R -) => Identity<{ readonly [K in keyof R]: [R[K]] extends [Identity] ? A : never }> = - product_ - .struct(Product) +) => Identity<{ [K in keyof R]: [R[K]] extends [Identity] ? A : never }> = product_ + .struct(Product) /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index e173c6a93..b48a4491b 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -500,7 +500,7 @@ export const tuple: >>( */ export const struct: >>( r: R -) => Option<{ readonly [K in keyof R]: [R[K]] extends [Option] ? A : never }> = product_ +) => Option<{ [K in keyof R]: [R[K]] extends [Option] ? A : never }> = product_ .struct(Product) /** diff --git a/src/These.ts b/src/These.ts index b05c58f54..8de9bb833 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1158,7 +1158,7 @@ export const struct: >>( r: R ) => Validated< [R[keyof R]] extends [Validated] ? E : never, - { readonly [K in keyof R]: [R[K]] extends [Validated] ? A : never } + { [K in keyof R]: [R[K]] extends [Validated] ? A : never } > = product_ .struct(Product) diff --git a/src/typeclass/Product.ts b/src/typeclass/Product.ts index 9e849f17f..bba168114 100644 --- a/src/typeclass/Product.ts +++ b/src/typeclass/Product.ts @@ -37,7 +37,7 @@ export const struct = (F: Product) => ([R[keyof R]] extends [Kind] ? R : never), ([R[keyof R]] extends [Kind] ? O : never), ([R[keyof R]] extends [Kind] ? E : never), - { readonly [K in keyof R]: [R[K]] extends [Kind] ? A : never } + { [K in keyof R]: [R[K]] extends [Kind] ? A : never } > => { const keys = Object.keys(fields) return pipe( diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 35b442adf..927bc76fb 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -110,9 +110,7 @@ export const reverse = (S: Semigroup): Semigroup => ({ * @since 1.0.0 */ export const struct = (semigroups: { readonly [K in keyof A]: Semigroup }): Semigroup< - { - readonly [K in keyof A]: A[K] - } + { readonly [K in keyof A]: A[K] } > => fromCombine((that) => (self) => { From f536a249a31f225825e976821b8abab96afc22ff Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 17:19:52 +0100 Subject: [PATCH 047/255] struct: remove readonly --- src/Either.ts | 2 +- src/Identity.ts | 6 +++--- src/Option.ts | 5 +++-- src/Predicate.ts | 3 +-- src/These.ts | 9 +++------ src/typeclass/Product.ts | 2 +- test/typeclass/Product.ts | 6 +++--- 7 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 0ae1c58e9..02861283c 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -456,7 +456,7 @@ export const tuple: >>( ...tuple: T ) => Either< [T[number]] extends [Either] ? E : never, - Readonly<{ [I in keyof T]: [T[I]] extends [Either] ? A : never }> + { [I in keyof T]: [T[I]] extends [Either] ? A : never } > = product_ .tuple(Product) diff --git a/src/Identity.ts b/src/Identity.ts index dfe99be9c..829d64c24 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -317,9 +317,9 @@ export const Product: product_.Product = { */ export const tuple: >>( ...tuple: T -) => Identity] ? A : never }>> = - product_ - .tuple(Product) +) => Identity<{ [I in keyof T]: [T[I]] extends [Identity] ? A : never }> = product_.tuple( + Product +) /** * @since 1.0.0 diff --git a/src/Option.ts b/src/Option.ts index b48a4491b..ad278b120 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -492,8 +492,9 @@ export const Product: product_.Product = { */ export const tuple: >>( ...tuple: T -) => Option] ? A : never }>> = product_ - .tuple(Product) +) => Option<{ [I in keyof T]: [T[I]] extends [Option] ? A : never }> = product_.tuple( + Product +) /** * @since 1.0.0 diff --git a/src/Predicate.ts b/src/Predicate.ts index 8d2934ffe..1477c59f9 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -208,8 +208,7 @@ export const productFlatten: (that: Predicate) => >>( ...predicates: T ) => Predicate] ? A : never }>> = - product_ - .tuple(Product) + product_.tuple(Product) /** * @since 1.0.0 diff --git a/src/These.ts b/src/These.ts index 8de9bb833..f87a565a2 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1143,13 +1143,10 @@ export const Product: product_.Product = { /** * @since 1.0.0 */ -export const tuple: >>( - ...tuple: T -) => Validated< +export const tuple: >>(...tuple: T) => Validated< [T[number]] extends [Validated] ? E : never, - Readonly<{ [I in keyof T]: [T[I]] extends [Validated] ? A : never }> -> = product_ - .tuple(Product) + { [I in keyof T]: [T[I]] extends [Validated] ? A : never } +> = product_.tuple(Product) /** * @since 1.0.0 diff --git a/src/typeclass/Product.ts b/src/typeclass/Product.ts index bba168114..bbbc4b640 100644 --- a/src/typeclass/Product.ts +++ b/src/typeclass/Product.ts @@ -25,7 +25,7 @@ export const tuple = (F: Product) => ([T[number]] extends [Kind] ? R : never), ([T[number]] extends [Kind] ? O : never), ([T[number]] extends [Kind] ? E : never), - Readonly<{ [I in keyof T]: [T[I]] extends [Kind] ? A : never }> + { [I in keyof T]: [T[I]] extends [Kind] ? A : never } > => F.productAll(components) as any /** diff --git a/test/typeclass/Product.ts b/test/typeclass/Product.ts index 3ae0590ff..76cc0e81c 100644 --- a/test/typeclass/Product.ts +++ b/test/typeclass/Product.ts @@ -12,11 +12,11 @@ describe("Product", () => { describe("tuple", () => { it("Covariant (Option)", () => { const tuple = _.tuple(O.Product) - U.deepStrictEqual(tuple(), O.some([] as const)) - U.deepStrictEqual(tuple(O.some("a")), O.some(["a"] as const)) + U.deepStrictEqual(tuple(), O.some([])) + U.deepStrictEqual(tuple(O.some("a")), O.some(["a"])) U.deepStrictEqual( tuple(O.some("a"), O.some(1), O.some(true)), - O.some(["a", 1, true] as const) + O.some(["a", 1, true]) ) U.deepStrictEqual(tuple(O.some("a"), O.some(1), O.none()), O.none()) }) From 43b849c2adbb8d8f9d94ed8a1672eeab617e197d Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 17:21:43 +0100 Subject: [PATCH 048/255] nonEmptyTuple: remove readonly --- src/typeclass/SemiProduct.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 5af134638..80c8a0efc 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -147,7 +147,7 @@ export const nonEmptyTuple = (F: SemiProduct) => ([T[number]] extends [Kind] ? R : never), ([T[number]] extends [Kind] ? O : never), ([T[number]] extends [Kind] ? E : never), - Readonly<{ [I in keyof T]: [T[I]] extends [Kind] ? A : never }> + { [I in keyof T]: [T[I]] extends [Kind] ? A : never } > => F.productMany(components.slice(1))(components[0]) as any type EnforceNonEmptyRecord = keyof R extends never ? never : R From c0fd4093af6019b54de7b001fec66d641bb41e56 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 17:51:41 +0100 Subject: [PATCH 049/255] Semigroup, Monoid: tuple: remove readonly --- dtslint/ts4.7/FlatMap.ts | 2 +- dtslint/ts4.7/Monoid.ts | 19 +++++++++++++++++++ dtslint/ts4.7/Product.ts | 4 ++-- dtslint/ts4.7/SemiAlternative.ts | 2 +- dtslint/ts4.7/SemiProduct.ts | 2 +- dtslint/ts4.7/Semigroup.ts | 19 +++++++++++++++++++ dtslint/ts4.7/tsconfig.json | 2 +- dtslint/ts4.7/tslint.json | 3 ++- src/typeclass/Monoid.ts | 26 +++++++++++++------------- src/typeclass/Semigroup.ts | 27 ++++++++++++--------------- 10 files changed, 71 insertions(+), 35 deletions(-) create mode 100644 dtslint/ts4.7/Monoid.ts create mode 100644 dtslint/ts4.7/Semigroup.ts diff --git a/dtslint/ts4.7/FlatMap.ts b/dtslint/ts4.7/FlatMap.ts index b3890d50b..fe241dd32 100644 --- a/dtslint/ts4.7/FlatMap.ts +++ b/dtslint/ts4.7/FlatMap.ts @@ -1,6 +1,6 @@ import * as _ from "@fp-ts/core/typeclass/FlatMap" import type { TypeLambda } from "@fp-ts/core/HKT" -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" interface RAW { (r: R): () => Promise diff --git a/dtslint/ts4.7/Monoid.ts b/dtslint/ts4.7/Monoid.ts new file mode 100644 index 000000000..a8e830cdc --- /dev/null +++ b/dtslint/ts4.7/Monoid.ts @@ -0,0 +1,19 @@ +import * as _ from "@fp-ts/core/typeclass/Monoid" +import * as Number from "@fp-ts/core/Number" +import * as String from "@fp-ts/core/String" + +// +// tuple +// + +// $ExpectType Monoid<[string, number]> +_.tuple( + String.Monoid, + Number.MonoidSum +) + +// $ExpectType Monoid +_.tuple( + String.Monoid, + Number.MonoidSum +) diff --git a/dtslint/ts4.7/Product.ts b/dtslint/ts4.7/Product.ts index 8287e5f69..68ee95b7f 100644 --- a/dtslint/ts4.7/Product.ts +++ b/dtslint/ts4.7/Product.ts @@ -15,10 +15,10 @@ declare const fc: RAW<{ c: boolean }, "c", boolean> export declare const Product: _.Product -// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", readonly [string, number, boolean]> +// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", [string, number, boolean]> _.tuple(Product)(fa, fb, fc) -// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", { readonly fa: string; readonly fb: number; readonly fc: boolean; }> +// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", { fa: string; fb: number; fc: boolean; }> _.struct(Product)({ fa, fb, fc }) _.tuple(Product)() // should allow empty tuple diff --git a/dtslint/ts4.7/SemiAlternative.ts b/dtslint/ts4.7/SemiAlternative.ts index 8ea619f71..e59f824d0 100644 --- a/dtslint/ts4.7/SemiAlternative.ts +++ b/dtslint/ts4.7/SemiAlternative.ts @@ -1,6 +1,6 @@ import * as _ from "@fp-ts/core/typeclass/SemiAlternative" import type { TypeLambda } from "@fp-ts/core/HKT" -import { pipe } from "@fp-ts/core/internal/Function" +import { pipe } from "@fp-ts/core/Function" interface RAW { (r: R): () => Promise diff --git a/dtslint/ts4.7/SemiProduct.ts b/dtslint/ts4.7/SemiProduct.ts index e4024d816..ea422d2d1 100644 --- a/dtslint/ts4.7/SemiProduct.ts +++ b/dtslint/ts4.7/SemiProduct.ts @@ -1,4 +1,4 @@ -import { OptionTypeLambda } from "@fp-ts/core/test/data/Option" +import { OptionTypeLambda } from "@fp-ts/core/Option" import * as _ from "@fp-ts/core/typeclass/SemiProduct" export declare const SemiProduct: _.SemiProduct diff --git a/dtslint/ts4.7/Semigroup.ts b/dtslint/ts4.7/Semigroup.ts new file mode 100644 index 000000000..854f4d468 --- /dev/null +++ b/dtslint/ts4.7/Semigroup.ts @@ -0,0 +1,19 @@ +import * as _ from "@fp-ts/core/typeclass/Semigroup" +import * as Number from "@fp-ts/core/Number" +import * as String from "@fp-ts/core/String" + +// +// tuple +// + +// $ExpectType Semigroup<[string, number]> +_.tuple( + String.Semigroup, + Number.SemigroupSum +) + +// $ExpectType Semigroup +_.tuple( + String.Semigroup, + Number.SemigroupSum +) diff --git a/dtslint/ts4.7/tsconfig.json b/dtslint/ts4.7/tsconfig.json index 109760a8d..0696bacfb 100644 --- a/dtslint/ts4.7/tsconfig.json +++ b/dtslint/ts4.7/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "noEmit": true, "strict": true, - "noImplicitAny": true, + "noImplicitAny": false, "noImplicitThis": true, "strictNullChecks": true, "strictFunctionTypes": true, diff --git a/dtslint/ts4.7/tslint.json b/dtslint/ts4.7/tslint.json index 222a6c998..1457aa8de 100644 --- a/dtslint/ts4.7/tslint.json +++ b/dtslint/ts4.7/tslint.json @@ -19,6 +19,7 @@ "no-relative-import-in-test": false, "no-null-undefined-union": false, "invalid-void": false, - "max-line-length": false + "max-line-length": false, + "no-useless-files": false } } diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index a5ff1ecd1..071447afe 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -54,7 +54,19 @@ export const max = (B: Bounded): Monoid => fromSemigroup(semigroup.max( export const reverse = (M: Monoid): Monoid => fromSemigroup(semigroup.reverse(M), M.empty) /** - * Given a struct of monoids returns a monoid for the struct. + * Given a tuple of `Monoid`s returns a `Monoid` for the tuple. + * + * @since 1.0.0 + */ +export const tuple = >( + ...monoids: { [K in keyof A]: Monoid } +): Monoid => { + const empty: A = monoids.map((m) => m.empty) as any + return fromSemigroup(semigroup.tuple(...monoids), empty) +} + +/** + * Given a struct of `Monoid`s returns a `Monoid` for the struct. * * @since 1.0.0 */ @@ -69,15 +81,3 @@ export const struct = ( } return fromSemigroup(semigroup.struct(monoids), empty) } - -/** - * Given a tuple of monoids returns a monoid for the tuple. - * - * @since 1.0.0 - */ -export const tuple = >( - ...monoids: { [K in keyof A]: Monoid } -): Monoid> => { - const empty: A = monoids.map((m) => m.empty) as any - return fromSemigroup(semigroup.tuple>(...monoids), empty) -} diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 927bc76fb..adaa273c2 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -105,7 +105,17 @@ export const reverse = (S: Semigroup): Semigroup => ({ }) /** - * Given a struct of associatives returns an associative for the struct. + * Given a tuple of `Semigroup`s returns a `Semigroup` for the tuple. + * + * @since 1.0.0 + */ +export const tuple = >( + ...semigroups: { readonly [K in keyof A]: Semigroup } +): Semigroup => + fromCombine((that) => (self) => semigroups.map((S, i) => S.combine(that[i])(self[i])) as any) + +/** + * Given a struct of `Semigroup`s returns a `Semigroup` for the struct. * * @since 1.0.0 */ @@ -124,16 +134,6 @@ export const struct = (semigroups: { readonly [K in keyof A]: Semigroup } ) -/** - * Given a tuple of associatives returns an associative for the tuple. - * - * @since 1.0.0 - */ -export const tuple = >( - ...semigroups: { readonly [K in keyof A]: Semigroup } -): Semigroup> => - fromCombine((that) => (self) => semigroups.map((S, i) => S.combine(that[i])(self[i])) as any) - /** * @since 1.0.0 */ @@ -203,9 +203,7 @@ export const Invariant: invariant.Invariant = { */ export const SemiProduct: semiProduct.SemiProduct = { ...Invariant, - // @ts-expect-error product: that => self => tuple(self, that), - // @ts-expect-error productMany: collection => self => tuple(self, ...collection) } @@ -216,6 +214,5 @@ export const SemiProduct: semiProduct.SemiProduct = { export const Product: product.Product = { ...SemiProduct, of: constant, - // @ts-expect-error - productAll: (collection: Iterable>) => tuple(...collection) + productAll: (collection: Iterable>) => tuple>(...collection) } From 7010e604de3cd4e08a3864125b194cf358324035 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 18:31:23 +0100 Subject: [PATCH 050/255] ReadonlyArray: remove useless instance --- src/ReadonlyArray.ts | 37 +++++---------------------- test/typeclass/NonEmptyTraversable.ts | 23 ++++++++++++++--- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index d8e78af31..b8931d03c 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -46,14 +46,6 @@ export interface ReadonlyArrayTypeLambda extends TypeLambda { readonly type: ReadonlyArray } -/** - * @category type lambdas - * @since 1.0.0 - */ -export interface NonEmptyReadonlyArrayTypeLambda extends TypeLambda { - readonly type: NonEmptyReadonlyArray -} - /** * @category models * @since 1.0.0 @@ -779,12 +771,8 @@ export const sortNonEmpty = (O: Order) => * @category sorting * @since 1.0.0 */ -export const sortBy = ( - ...orders: ReadonlyArray> -) => - ( - self: Iterable - ): Array => { +export const sortBy = (...orders: ReadonlyArray>) => + (self: Iterable): Array => { const input = fromIterable(self) return (isNonEmpty(input) ? sortByNonEmpty(...orders)(input) : []) } @@ -805,9 +793,8 @@ export const sortByNonEmpty = ( * * @since 1.0.0 */ -export const zip = ( - that: Iterable -): (self: Iterable) => Array<[A, B]> => zipWith(that, (a, b) => [a, b]) +export const zip = (that: Iterable): (self: Iterable) => Array<[A, B]> => + zipWith(that, (a, b) => [a, b]) /** * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results in a new `Array`. If one @@ -827,10 +814,7 @@ export const zipWith = (that: Iterable, f: (a: A, b: B) => C) => */ export const zipNonEmpty = (that: NonEmptyReadonlyArray) => (self: NonEmptyReadonlyArray): NonEmptyArray<[A, B]> => - pipe( - self, - zipNonEmptyWith(that, (a, b) => [a, b]) - ) + pipe(self, zipNonEmptyWith(that, (a, b) => [a, b])) /** * @since 1.0.0 @@ -850,9 +834,7 @@ export const zipNonEmptyWith = (that: NonEmptyReadonlyArray, f: (a: * * @since 1.0.0 */ -export const unzip = ( - self: Iterable<[A, B]> -): [Array, Array] => { +export const unzip = (self: Iterable<[A, B]>): [Array, Array] => { const input = fromIterable(self) return isNonEmpty(input) ? unzipNonEmpty(input) : [[], []] } @@ -2260,10 +2242,3 @@ export const liftOrder = (O: Order): Order> => return number.Order.compare(bLen)(aLen) } ) - -/** - * @category instances - * @since 1.0.0 - */ -export const NonEmptyCovariant: covariant.Covariant = covariant - .make(mapNonEmpty) diff --git a/test/typeclass/NonEmptyTraversable.ts b/test/typeclass/NonEmptyTraversable.ts index 73ddb23d9..050a96db9 100644 --- a/test/typeclass/NonEmptyTraversable.ts +++ b/test/typeclass/NonEmptyTraversable.ts @@ -1,16 +1,33 @@ import { identity, pipe } from "@fp-ts/core/Function" +import type { TypeLambda } from "@fp-ts/core/HKT" import * as O from "@fp-ts/core/Option" import * as RA from "@fp-ts/core/ReadonlyArray" import * as _ from "@fp-ts/core/test/limbo/NonEmptyTraversable" +import * as covariant from "@fp-ts/core/typeclass/Covariant" import * as U from "../util" -const NonEmptyTraversable: _.NonEmptyTraversable = { +const NonEmptyTraversable: _.NonEmptyTraversable = { // @ts-expect-error traverseNonEmpty: RA.traverseNonEmpty, // @ts-expect-error sequenceNonEmpty: F => self => pipe(self, RA.traverseNonEmpty(F)(identity)) } +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface NonEmptyReadonlyArrayTypeLambda extends TypeLambda { + readonly type: RA.NonEmptyReadonlyArray +} + +/** + * @category instances + * @since 1.0.0 + */ +export const NonEmptyCovariant: covariant.Covariant = covariant + .make(RA.mapNonEmpty) + describe("NonEmptyTraversable", () => { it("traverseNonEmptyComposition", () => { const traverseNonEmpty = _.traverseNonEmptyComposition( @@ -25,7 +42,7 @@ describe("NonEmptyTraversable", () => { it("traverseNonEmptyComposition", () => { const sequence = _.sequenceNonEmptyComposition( - { ...NonEmptyTraversable, ...RA.NonEmptyCovariant }, + { ...NonEmptyTraversable, ...NonEmptyCovariant }, NonEmptyTraversable )(O.SemiApplicative) U.deepStrictEqual(sequence([[O.some(1)]]), O.some([[1]] as const)) @@ -41,7 +58,7 @@ describe("NonEmptyTraversable", () => { }) it("sequenceNonEmpty", () => { - const sequenceNonEmpty = _.sequenceNonEmpty( + const sequenceNonEmpty = _.sequenceNonEmpty( NonEmptyTraversable.traverseNonEmpty )(O.SemiApplicative) U.deepStrictEqual(sequenceNonEmpty([O.none()]), O.none()) From 863f8114e013f390b4242f0d9468414d386a5a2c Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 17 Jan 2023 19:49:46 +0100 Subject: [PATCH 051/255] ReadonlyArray: remove readonly from imap, let, flap, as, flatten, bind, filter, partition, traverseTap, productMany, andThenBind, ap, lift2, lift3, traverseFilterMap, traversePartitionMap, traverseFilter, traversePartition --- src/ReadonlyArray.ts | 143 ++++++++++++++++-------------------------- test/ReadonlyArray.ts | 2 - 2 files changed, 55 insertions(+), 90 deletions(-) diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index b8931d03c..582ec3ec6 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1271,7 +1271,7 @@ export const Do: ReadonlyArray<{}> = of_.Do(Of) export const imap: ( to: (a: A) => B, from: (b: B) => A -) => (self: ReadonlyArray) => ReadonlyArray = covariant.imap(map) +) => (self: ReadonlyArray) => Array = covariant.imap(map) as any /** * @category instances @@ -1285,19 +1285,17 @@ export const Invariant: invariant.Invariant = { * @category mapping * @since 1.0.0 */ -// @ts-expect-error export const tupled: (self: ReadonlyArray) => Array<[A]> = invariant - .tupled(Invariant) + .tupled(Invariant) as any /** * @category do notation * @since 1.0.0 */ -// @ts-expect-error export const bindTo: ( name: N ) => (self: ReadonlyArray) => Array<{ [K in N]: A }> = invariant - .bindTo(Invariant) + .bindTo(Invariant) as any /** * @category instances @@ -1310,7 +1308,7 @@ const let_: ( f: (a: A) => B ) => ( self: ReadonlyArray -) => ReadonlyArray<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant.let(Covariant) +) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant.let(Covariant) as any export { /** @@ -1326,7 +1324,7 @@ export { */ export const flap: (a: A) => ( self: ReadonlyArray<(a: A) => B> -) => ReadonlyArray = covariant.flap(Covariant) +) => Array = covariant.flap(Covariant) as any /** * Maps the success value of this effect to the specified constant value. @@ -1334,9 +1332,9 @@ export const flap: (a: A) => ( * @category mapping * @since 1.0.0 */ -export const as: (b: B) => (self: ReadonlyArray) => ReadonlyArray = covariant.as( +export const as: (b: B) => (self: ReadonlyArray) => Array = covariant.as( Covariant -) +) as any /** * @category instances @@ -1404,8 +1402,8 @@ export const FlatMap: flatMap_.FlatMap = { * @category sequencing * @since 1.0.0 */ -export const flatten: (self: ReadonlyArray>) => ReadonlyArray = flatMap_ - .flatten(FlatMap) +export const flatten: (self: ReadonlyArray>) => Array = flatMap_ + .flatten(FlatMap) as any /** * @category sequencing @@ -1441,7 +1439,7 @@ export const bind: ( f: (a: A) => ReadonlyArray ) => ( self: ReadonlyArray -) => ReadonlyArray<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable.bind(Chainable) +) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable.bind(Chainable) as any /** * @category filtering @@ -1515,9 +1513,9 @@ export const Filterable: filterable.Filterable = { export const filter: { ( refinement: Refinement - ): (self: ReadonlyArray) => ReadonlyArray - (predicate: Predicate): (self: ReadonlyArray) => ReadonlyArray -} = filterable.filter(Filterable) + ): (self: ReadonlyArray) => Array + (predicate: Predicate): (self: ReadonlyArray) => Array +} = filterable.filter(Filterable) as any /** * @category filtering @@ -1542,11 +1540,11 @@ export const filterWithIndex: { export const partition: { (refinement: Refinement): ( self: ReadonlyArray - ) => [ReadonlyArray, ReadonlyArray] + ) => [Array, Array] ( predicate: Predicate - ): (self: ReadonlyArray) => [ReadonlyArray, ReadonlyArray] -} = filterable.partition(Filterable) + ): (self: ReadonlyArray) => [Array, Array] +} = filterable.partition(Filterable) as any /** * @category filtering @@ -1637,14 +1635,13 @@ export const traverseNonEmptyWithIndex = ( * @category traversing * @since 1.0.0 */ -// @ts-expect-error export const sequence: ( F: applicative.Applicative ) => ( self: ReadonlyArray> -) => Kind> = - // @ts-expect-error - traversable.sequence(traverse) +) => Kind> = traversable.sequence( + traverse as any +) as any /** * @category instances @@ -1665,10 +1662,8 @@ export const traverseTap: ( F: applicative.Applicative ) => ( f: (a: A) => Kind -) => (self: ReadonlyArray) => Kind> = traversable - .traverseTap( - Traversable - ) +) => (self: ReadonlyArray) => Kind> = traversable + .traverseTap(Traversable) as any /** * @category traversing @@ -1704,18 +1699,15 @@ export const product = ( */ export const productMany: ( collection: Iterable> -) => (self: ReadonlyArray) => ReadonlyArray<[A, ...Array]> = semiProduct - .productMany( - Covariant, - product - ) +) => (self: ReadonlyArray) => Array<[A, ...Array]> = semiProduct + .productMany(Covariant, product) as any /** * @since 1.0.0 */ export const productAll = ( collection: Iterable> -): ReadonlyArray> => { +): Array> => { const arrays = Array.from(collection) if (isEmpty(arrays)) { return empty() @@ -1744,8 +1736,8 @@ export const andThenBind: ( that: ReadonlyArray ) => ( self: ReadonlyArray -) => ReadonlyArray<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct - .andThenBind(SemiProduct) +) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct + .andThenBind(SemiProduct) as any /** * @category instances @@ -1761,9 +1753,9 @@ export const SemiApplicative: semiApplicative.SemiApplicative( fa: ReadonlyArray -) => (self: ReadonlyArray<(a: A) => B>) => ReadonlyArray = semiApplicative.ap( +) => (self: ReadonlyArray<(a: A) => B>) => Array = semiApplicative.ap( SemiApplicative -) +) as any /** * Lifts a binary function into `ReadonlyArray`. @@ -1773,9 +1765,9 @@ export const ap: ( */ export const lift2: ( f: (a: A, b: B) => C -) => (fa: ReadonlyArray, fb: ReadonlyArray) => ReadonlyArray = semiApplicative.lift2( +) => (fa: ReadonlyArray, fb: ReadonlyArray) => Array = semiApplicative.lift2( SemiApplicative -) +) as any /** * Lifts a ternary function into `ReadonlyArray`. @@ -1785,8 +1777,8 @@ export const lift2: ( */ export const lift3: ( f: (a: A, b: B, c: C) => D -) => (fa: ReadonlyArray, fb: ReadonlyArray, fc: ReadonlyArray) => ReadonlyArray = - semiApplicative.lift3(SemiApplicative) +) => (fa: ReadonlyArray, fb: ReadonlyArray, fc: ReadonlyArray) => Array = + semiApplicative.lift3(SemiApplicative) as any /** * @category lifting @@ -1874,11 +1866,8 @@ export const Foldable: foldable.Foldable = { * @category folding * @since 1.0.0 */ -export const foldMap: ( - M: Monoid -) => (f: (a: A) => M) => (self: ReadonlyArray) => M = foldable.foldMap( - Foldable -) +export const foldMap: (M: Monoid) => (f: (a: A) => M) => (self: ReadonlyArray) => M = + foldable.foldMap(Foldable) /** * @category folding @@ -1909,40 +1898,28 @@ export const foldMapNonEmptyWithIndex = (S: Semigroup) => * @category folding * @since 1.0.0 */ -export const reduceKind: ( - F: monad.Monad -) => ( +export const reduceKind: (F: monad.Monad) => ( b: B, f: (b: B, a: A) => Kind -) => (self: ReadonlyArray) => Kind = foldable.reduceKind( - Foldable -) +) => (self: ReadonlyArray) => Kind = foldable.reduceKind(Foldable) /** * @category folding * @since 1.0.0 */ -export const reduceRightKind: ( - F: monad.Monad -) => ( +export const reduceRightKind: (F: monad.Monad) => ( b: B, f: (b: B, a: A) => Kind ) => (self: ReadonlyArray) => Kind = foldable - .reduceRightKind( - Foldable - ) + .reduceRightKind(Foldable) /** * @category folding * @since 1.0.0 */ -export const foldMapKind: ( - F: Coproduct -) => ( +export const foldMapKind: (F: Coproduct) => ( f: (a: A) => Kind -) => (self: ReadonlyArray) => Kind = foldable.foldMapKind( - Foldable -) +) => (self: ReadonlyArray) => Kind = foldable.foldMapKind(Foldable) /** * @category filtering @@ -1952,8 +1929,8 @@ export const traverseFilterMap: ( F: applicative.Applicative ) => ( f: (a: A) => Kind> -) => (ta: ReadonlyArray) => Kind> = traversableFilterable - .traverseFilterMap({ ...Traversable, ...Compactable }) +) => (ta: ReadonlyArray) => Kind> = traversableFilterable + .traverseFilterMap({ ...Traversable, ...Compactable }) as any /** * @category filtering @@ -1963,9 +1940,8 @@ export const traversePartitionMap: ( F: applicative.Applicative ) => ( f: (a: A) => Kind> -) => (self: ReadonlyArray) => Kind, ReadonlyArray]> = - traversableFilterable - .traversePartitionMap({ ...Traversable, ...Covariant, ...Compactable }) +) => (self: ReadonlyArray) => Kind, Array]> = traversableFilterable + .traversePartitionMap({ ...Traversable, ...Covariant, ...Compactable }) as any /** * @category instances @@ -1974,7 +1950,9 @@ export const traversePartitionMap: ( export const TraversableFilterable: traversableFilterable.TraversableFilterable< ReadonlyArrayTypeLambda > = { + // @ts-expect-error traverseFilterMap, + // @ts-expect-error traversePartitionMap } @@ -1987,8 +1965,8 @@ export const traverseFilter: ( F: applicative.Applicative ) => ( predicate: (a: A) => Kind -) => (self: ReadonlyArray) => Kind> = traversableFilterable - .traverseFilter(TraversableFilterable) +) => (self: ReadonlyArray) => Kind> = traversableFilterable + .traverseFilter(TraversableFilterable) as any /** * @since 1.0.0 @@ -1999,8 +1977,8 @@ export const traversePartition: ( predicate: (a: A) => Kind ) => ( self: ReadonlyArray -) => Kind, ReadonlyArray]> = traversableFilterable - .traversePartition(TraversableFilterable) +) => Kind, Array]> = traversableFilterable + .traversePartition(TraversableFilterable) as any /** * @category lifting @@ -2064,7 +2042,7 @@ export const liftEither = , E, B>( */ export function every( refinement: Refinement -): Refinement, Array> +): Refinement, ReadonlyArray> export function every(predicate: Predicate): Predicate> export function every(predicate: Predicate): Predicate> { return (self) => self.every(predicate) @@ -2077,14 +2055,7 @@ export function every(predicate: Predicate): Predicate> { * @since 1.0.0 */ export const some = (predicate: Predicate) => - (self: ReadonlyArray): self is NonEmptyArray => self.some(predicate) - -/** - * Alias of [`some`](#some) - * - * @since 1.0.0 - */ -export const has = some + (self: ReadonlyArray): self is NonEmptyReadonlyArray => self.some(predicate) /** * Fold a data structure, accumulating values in some `Monoid`, combining adjacent elements @@ -2118,10 +2089,9 @@ export const join: (sep: string) => (self: ReadonlyArray) => string = in /** * @since 1.0.0 */ -// @ts-expect-error export const productFlatten: (that: ReadonlyArray) => >( self: ReadonlyArray -) => Array<[...A, B]> = semiProduct.productFlatten(SemiProduct) +) => Array<[...A, B]> = semiProduct.productFlatten(SemiProduct) as any /** * @since 1.0.0 @@ -2167,8 +2137,7 @@ export const unfold = (b: B, f: (b: B) => Option): Array< * @since 1.0.0 */ export const getUnionSemigroup = (equivalence: Equivalence): Semigroup> => - // @ts-expect-error - fromCombine(union(equivalence)) + fromCombine(union(equivalence)) as any /** * @category instances @@ -2190,9 +2159,7 @@ export const getUnionMonoid = (equivalence: Equivalence): Monoid( equivalence: Equivalence -): Semigroup> => - // @ts-expect-error - fromCombine(intersection(equivalence)) +): Semigroup> => fromCombine(intersection(equivalence)) as any /** * Returns a `Semigroup` for `ReadonlyArray`. diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index a3e4022d3..83f16cec9 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -1589,8 +1589,6 @@ describe.concurrent("ReadonlyArray", () => { const isPositive: Predicate = (n) => n > 0 deepStrictEqual(pipe([-1, -2, 3], RA.some(isPositive)), true) deepStrictEqual(pipe([-1, -2, -3], RA.some(isPositive)), false) - // has is an alias of some - deepStrictEqual(pipe([-1, -2, -3], RA.has(isPositive)), false) }) it("size", () => { From f4bd80f936f9719273a629d05543c9115fb0ab24 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 18 Jan 2023 16:13:23 +0100 Subject: [PATCH 052/255] rename `productFlatten` to `element` --- .changeset/blue-books-breathe.md | 5 +++++ src/Either.ts | 6 ++++-- src/Identity.ts | 6 ++++-- src/Option.ts | 6 ++++-- src/Predicate.ts | 7 ++++--- src/ReadonlyArray.ts | 6 ++++-- src/These.ts | 6 ++++-- src/typeclass/SemiProduct.ts | 4 +++- test/Either.ts | 4 ++-- test/Identity.ts | 2 +- test/Option.ts | 4 ++-- test/Predicate.ts | 2 +- test/ReadonlyArray.ts | 2 +- test/These.ts | 2 +- test/typeclass/SemiProduct.ts | 12 ++++++------ 15 files changed, 46 insertions(+), 28 deletions(-) create mode 100644 .changeset/blue-books-breathe.md diff --git a/.changeset/blue-books-breathe.md b/.changeset/blue-books-breathe.md new file mode 100644 index 000000000..fe1864618 --- /dev/null +++ b/.changeset/blue-books-breathe.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +rename `productFlatten` to `element` diff --git a/src/Either.ts b/src/Either.ts index 02861283c..98e084414 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -414,14 +414,16 @@ export const andThenBind: ( .andThenBind(SemiProduct) /** + * Adds an element to the end of a tuple. + * * @since 1.0.0 */ -export const productFlatten: ( +export const element: ( that: Either ) => >( self: Either ) => Either = semiProduct - .productFlatten(SemiProduct) + .element(SemiProduct) /** * @since 1.0.0 diff --git a/src/Identity.ts b/src/Identity.ts index 829d64c24..8e88771fd 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -289,12 +289,14 @@ export const andThenBind: ( .andThenBind(SemiProduct) /** + * Adds an element to the end of a tuple. + * * @since 1.0.0 */ -export const productFlatten: ( +export const element: ( fb: Identity ) => >(self: Identity) => Identity<[...A, B]> = semiProduct - .productFlatten(SemiProduct) + .element(SemiProduct) /** * @since 1.0.0 diff --git a/src/Option.ts b/src/Option.ts index ad278b120..1dc3b3724 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -456,12 +456,14 @@ export const andThenBind: ( .andThenBind(SemiProduct) /** + * Adds an element to the end of a tuple. + * * @since 1.0.0 */ -export const productFlatten: ( +export const element: ( fb: Option ) => >(self: Option) => Option<[...A, B]> = semiProduct - .productFlatten(SemiProduct) + .element(SemiProduct) /** * @since 1.0.0 diff --git a/src/Predicate.ts b/src/Predicate.ts index 1477c59f9..c21fb8d27 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -195,12 +195,13 @@ export const andThenBind: ( ) /** + * Adds an element to the end of a tuple. + * * @since 1.0.0 */ -// @ts-expect-error -export const productFlatten: (that: Predicate) => >( +export const element: (that: Predicate) => >( self: Predicate -) => Predicate = semiProduct.productFlatten(SemiProduct) +) => Predicate = semiProduct.element(SemiProduct) as any /** * @since 1.0.0 diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 582ec3ec6..0d6a44b02 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -2087,11 +2087,13 @@ export const join: (sep: string) => (self: ReadonlyArray) => string = in ) /** + * Adds an element to the end of a tuple. + * * @since 1.0.0 */ -export const productFlatten: (that: ReadonlyArray) => >( +export const element: (that: ReadonlyArray) => >( self: ReadonlyArray -) => Array<[...A, B]> = semiProduct.productFlatten(SemiProduct) as any +) => Array<[...A, B]> = semiProduct.element(SemiProduct) as any /** * @since 1.0.0 diff --git a/src/These.ts b/src/These.ts index f87a565a2..e9b1c9e71 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1121,14 +1121,16 @@ export const andThenBindThese = ( andThenBind(name, fromThese(that)) /** + * Adds an element to the end of a tuple. + * * @since 1.0.0 */ -export const productFlatten: ( +export const element: ( that: Validated ) => >( self: Validated ) => Validated = semiProduct - .productFlatten(SemiProduct) + .element(SemiProduct) /** * @category instances diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 80c8a0efc..2bcf5ddac 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -121,9 +121,11 @@ export const andThenBind = (F: SemiProduct) => ) /** + * Adds an element to the end of a tuple. + * * @since 1.0.0 */ -export const productFlatten = (F: SemiProduct) => +export const element = (F: SemiProduct) => ( that: Kind ) => diff --git a/test/Either.ts b/test/Either.ts index 8b53175a5..fe9844b2a 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -444,8 +444,8 @@ describe.concurrent("Either", () => { ) }) - it("productFlatten", () => { - expect(pipe(_.right(1), _.tupled, _.productFlatten(_.right("b")))).toEqual( + it("element", () => { + expect(pipe(_.right(1), _.tupled, _.element(_.right("b")))).toEqual( _.right([1, "b"]) ) }) diff --git a/test/Identity.ts b/test/Identity.ts index f840be294..fbc74fe38 100644 --- a/test/Identity.ts +++ b/test/Identity.ts @@ -41,7 +41,7 @@ describe.concurrent("Identity", () => { expect(_.product).exist expect(_.productMany).exist expect(_.andThenBind).exist - expect(_.productFlatten).exist + expect(_.element).exist expect(_.Product).exist expect(_.productAll).exist diff --git a/test/Option.ts b/test/Option.ts index bb6d2283e..74912d033 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -502,8 +502,8 @@ describe.concurrent("Option", () => { ) }) - it("productFlatten", () => { - expect(pipe(_.some(1), _.tupled, _.productFlatten(_.some("b")))).toEqual( + it("element", () => { + expect(pipe(_.some(1), _.tupled, _.element(_.some("b")))).toEqual( _.some([1, "b"]) ) }) diff --git a/test/Predicate.ts b/test/Predicate.ts index d727fa653..b675bf30f 100644 --- a/test/Predicate.ts +++ b/test/Predicate.ts @@ -35,7 +35,7 @@ describe.concurrent("Predicate", () => { expect(_.product).exist expect(_.productMany).exist expect(_.andThenBind).exist - expect(_.productFlatten).exist + expect(_.element).exist expect(_.Product).exist expect(_.productAll).exist diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 83f16cec9..66ac4a973 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -44,7 +44,7 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.product).exist expect(RA.productMany).exist expect(RA.andThenBind).exist - expect(RA.productFlatten).exist + expect(RA.element).exist expect(RA.Product).exist expect(RA.productAll).exist diff --git a/test/These.ts b/test/These.ts index 79e276c98..680bc8efd 100644 --- a/test/These.ts +++ b/test/These.ts @@ -47,7 +47,7 @@ describe("These", () => { expect(_.product).exist expect(_.productMany).exist expect(_.andThenBind).exist - expect(_.productFlatten).exist + expect(_.element).exist expect(_.Product).exist expect(_.productAll).exist diff --git a/test/typeclass/SemiProduct.ts b/test/typeclass/SemiProduct.ts index 29566f2e2..0befff78a 100644 --- a/test/typeclass/SemiProduct.ts +++ b/test/typeclass/SemiProduct.ts @@ -164,16 +164,16 @@ describe("SemiProduct", () => { }) }) - describe("productFlatten", () => { + describe("element", () => { it("Covariant (Option)", () => { - const productFlatten = _.productFlatten(O.SemiProduct) - U.deepStrictEqual(pipe(O.some([1, 2]), productFlatten(O.none())), O.none()) - expect(pipe(O.some([1, 2]), productFlatten(O.some(3)))).toEqual(O.some([1, 2, 3])) + const element = _.element(O.SemiProduct) + U.deepStrictEqual(pipe(O.some([1, 2]), element(O.none())), O.none()) + expect(pipe(O.some([1, 2]), element(O.some(3)))).toEqual(O.some([1, 2, 3])) }) it("Contravariant (Predicate)", () => { - const productFlatten = _.productFlatten(P.SemiProduct) - const p = pipe(P.tuple(String.isString, String.isString), productFlatten(Number.isNumber)) + const element = _.element(P.SemiProduct) + const p = pipe(P.tuple(String.isString, String.isString), element(Number.isNumber)) U.deepStrictEqual(p(["a", "b", 3]), true) U.deepStrictEqual(p(["a", "b", "c"]), false) U.deepStrictEqual(p([1, "b", 1]), false) From 359d869a9d301acd6ad78ee65052720cb863e901 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 19 Jan 2023 16:32:52 +0100 Subject: [PATCH 053/255] Order: add array combinator --- .changeset/green-kangaroos-report.md | 5 +++++ src/ReadonlyArray.ts | 25 +++++----------------- src/typeclass/Order.ts | 32 +++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 .changeset/green-kangaroos-report.md diff --git a/.changeset/green-kangaroos-report.md b/.changeset/green-kangaroos-report.md new file mode 100644 index 000000000..ef0285a57 --- /dev/null +++ b/.changeset/green-kangaroos-report.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Order: add array combinator diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 0d6a44b02..24a226902 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -8,7 +8,6 @@ import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" -import * as number from "@fp-ts/core/Number" import type { Option } from "@fp-ts/core/Option" import * as O from "@fp-ts/core/Option" import type { Predicate, Refinement } from "@fp-ts/core/Predicate" @@ -2188,26 +2187,12 @@ export const getMonoid = (): Monoid> => { } /** - * Derives an `Order` over the `ReadonlyArray` of a given element type from the `Order` of that type. The ordering between two such - * `ReadonlyArray`s is equal to: the first non equal comparison of each `ReadonlyArray`s elements taken pairwise in increasing order, in - * case of equality over all the pairwise elements; the longest `ReadonlyArray` is considered the greatest, if both `ReadonlyArray`s have - * the same length, the result is equality. + * This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. + * The returned `Order` compares two arrays by applying the given `Order` to each element in the arrays. + * If all elements are equal, the arrays are then compared based on their length. + * It is useful when you need to compare two arrays of the same type and you have a specific way of comparing each element of the array. * * @category lifting * @since 1.0.0 */ -export const liftOrder = (O: Order): Order> => - order.fromCompare((that) => - (self) => { - const aLen = self.length - const bLen = that.length - const len = Math.min(aLen, bLen) - for (let i = 0; i < len; i++) { - const o = O.compare(that[i])(self[i]) - if (o !== 0) { - return o - } - } - return number.Order.compare(bLen)(aLen) - } - ) +export const liftOrder: (O: Order) => Order> = order.array diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 571a872f6..c2623058a 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -2,6 +2,7 @@ * @since 1.0.0 */ import type { TypeLambda } from "@fp-ts/core/HKT" +import * as number from "@fp-ts/core/Number" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" @@ -37,8 +38,12 @@ export const fromCompare = (compare: Order["compare"]): Order => ({ }) /** - * Given a tuple of `Compare`s returns a `Compare` for the tuple. + * This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. + * The returned `Order` compares two tuples of the same type by applying the corresponding `Order` to each element in the tuple. + * It is useful when you need to compare two tuples of the same type and you have a specific way of comparing each element + * of the tuple. * + * @category combinators * @since 1.0.0 */ export const tuple = >( @@ -57,6 +62,31 @@ export const tuple = >( } ) +/** + * This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. + * The returned `Order` compares two arrays by applying the given `Order` to each element in the arrays. + * If all elements are equal, the arrays are then compared based on their length. + * It is useful when you need to compare two arrays of the same type and you have a specific way of comparing each element of the array. + * + * @category combinators + * @since 1.0.0 + */ +export const array = (O: Order): Order> => + fromCompare((that) => + (self) => { + const aLen = self.length + const bLen = that.length + const len = Math.min(aLen, bLen) + for (let i = 0; i < len; i++) { + const o = O.compare(that[i])(self[i]) + if (o !== 0) { + return o + } + } + return number.Order.compare(bLen)(aLen) + } + ) + /** * @since 1.0.0 */ From 32cc88615dbe0540df094f35d8cacfd1f99123e8 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 19 Jan 2023 17:19:03 +0100 Subject: [PATCH 054/255] Semigroup: add array, readonlyArray combinator --- .changeset/big-weeks-kiss.md | 5 +++ README.md | 3 +- data.md | 29 +++++++++++++ src/ReadonlyArray.ts | 2 +- src/typeclass/Semigroup.ts | 84 +++++++++++++++++++++++------------- test/typeclass/Semigroup.ts | 4 ++ Overview.md => typeclass.md | 0 7 files changed, 95 insertions(+), 32 deletions(-) create mode 100644 .changeset/big-weeks-kiss.md create mode 100644 data.md rename Overview.md => typeclass.md (100%) diff --git a/.changeset/big-weeks-kiss.md b/.changeset/big-weeks-kiss.md new file mode 100644 index 000000000..931923006 --- /dev/null +++ b/.changeset/big-weeks-kiss.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Semigroup: add array combinator diff --git a/README.md b/README.md index 364c07560..3de06454e 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,8 @@ npm install @fp-ts/core # Documentation -- [Typeclass overview](./Overview.md) +- [Typeclass overview](./typeclass.md) +- [Data overview](./data.md) - [API Reference](https://fp-ts.github.io/core/) # License diff --git a/data.md b/data.md new file mode 100644 index 000000000..e8eae4e1e --- /dev/null +++ b/data.md @@ -0,0 +1,29 @@ +# Data overview + +## tuples + +This section covers the various modules and combinators that work with tuples. + +| Module | Name | Given | To | +| ----------- | ------------- | --------------------------------------- | -------------------------------------- | +| Equivalence | tuple | `[Equivalence, Equivalence, ...]` | `Equivalence` | +| Order | tuple | `[Order, Order, ...]` | `Order` | +| Semigroup | tuple | `[Semigroup, Semigroup, ...]` | `Semigroup<[A, B, ...]>` | +| Monoid | tuple | `[Monoid, Monoid, ...]` | `Monoid<[A, B, ...]>` | +| SemiProduct | nonEmptyTuple | `[F, F, ...]` | `F<[A, B, ...]>` | +| Product | tuple | `[F, F, ...]` (can be empty) | `F<[A, B, ...]>` | +| Either | tuple | `[Either, Either, ...]` | `Either` | +| Option | tuple | `[Option, Option, ...]` | `Option<[A, B, ...]>` | +| Predicate | tuple | `[Predicate, Predicate, ...]` | `Predicate` | +| These | tuple | `[These, These, ...]` | `These` | + +## arrays + +This section covers the various modules and combinators that work with arrays. + +| Module | Name | Given | To | +| ----------- | ------------- | ---------------- | ------------------------------- | +| Equivalence | array | `Equivalence` | `Equivalence>` | +| Order | array | `Order` | `Order>` | +| Semigroup | array | `A` | `Semigroup>` | +| Semigroup | readonlyArray | `A` | `Semigroup>` | diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 24a226902..0083c5e82 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -2168,7 +2168,7 @@ export const getIntersectionSemigroup = ( * @category instances * @since 1.0.0 */ -export const getSemigroup = (): Semigroup> => fromCombine(appendAll) +export const getSemigroup: () => Semigroup> = semigroup.readonlyArray /** * Returns a `Monoid` for `ReadonlyArray`. diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index adaa273c2..fe3bcca48 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -61,6 +61,60 @@ export const fromCombine = (combine: Semigroup["combine"]): Semigroup = } }) +/** + * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. + * The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. + * It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. + * + * @category combinators + * @since 1.0.0 + */ +export const tuple = >( + ...semigroups: { readonly [K in keyof A]: Semigroup } +): Semigroup => + fromCombine((that) => (self) => semigroups.map((S, i) => S.combine(that[i])(self[i])) as any) + +/** + * Given a type `A`, this function creates and returns a `Semigroup` for `Array`. + * The returned `Semigroup` combines two arrays by concatenating them. + * + * @category combinators + * @since 1.0.0 + */ +export const array = (): Semigroup> => fromCombine(that => self => self.concat(that)) + +/** + * Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. + * The returned `Semigroup` combines two arrays by concatenating them. + * + * @category combinators + * @since 1.0.0 + */ +export const readonlyArray: () => Semigroup> = array as any + +/** + * This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. + * The returned `Semigroup` combines two structs of the same type by applying the corresponding `Semigroup` passed as arguments to each property in the struct. + * It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. + * + * @category combinators + * @since 1.0.0 + */ +export const struct = (semigroups: { readonly [K in keyof A]: Semigroup }): Semigroup< + { readonly [K in keyof A]: A[K] } +> => + fromCombine((that) => + (self) => { + const r = {} as any + for (const k in semigroups) { + if (Object.prototype.hasOwnProperty.call(semigroups, k)) { + r[k] = semigroups[k].combine(that[k])(self[k]) + } + } + return r + } + ) + /** * `Semigroup` that returns last minimum of elements. * @@ -104,36 +158,6 @@ export const reverse = (S: Semigroup): Semigroup => ({ } }) -/** - * Given a tuple of `Semigroup`s returns a `Semigroup` for the tuple. - * - * @since 1.0.0 - */ -export const tuple = >( - ...semigroups: { readonly [K in keyof A]: Semigroup } -): Semigroup => - fromCombine((that) => (self) => semigroups.map((S, i) => S.combine(that[i])(self[i])) as any) - -/** - * Given a struct of `Semigroup`s returns a `Semigroup` for the struct. - * - * @since 1.0.0 - */ -export const struct = (semigroups: { readonly [K in keyof A]: Semigroup }): Semigroup< - { readonly [K in keyof A]: A[K] } -> => - fromCombine((that) => - (self) => { - const r = {} as any - for (const k in semigroups) { - if (Object.prototype.hasOwnProperty.call(semigroups, k)) { - r[k] = semigroups[k].combine(that[k])(self[k]) - } - } - return r - } - ) - /** * @since 1.0.0 */ diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index be9986c23..537d82ce9 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -6,6 +6,10 @@ import * as _ from "@fp-ts/core/typeclass/Semigroup" import * as U from "../util" describe("Semigroup", () => { + it("exports", () => { + expect(_.array).exists + }) + it("reverse", () => { const A = _.reverse(String.Semigroup) U.deepStrictEqual(pipe("a", A.combine("b")), "ba") diff --git a/Overview.md b/typeclass.md similarity index 100% rename from Overview.md rename to typeclass.md From 38e48a3e785ba28f2b8ed6236169936bfebfdcc5 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 19 Jan 2023 17:28:22 +0100 Subject: [PATCH 055/255] Monoid: add array, readonlyArray combinators --- .changeset/popular-baboons-promise.md | 5 +++++ data.md | 2 ++ src/ReadonlyArray.ts | 11 ++--------- src/typeclass/Monoid.ts | 26 ++++++++++++++++++++++++++ test/typeclass/Monoid.ts | 4 ++++ 5 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 .changeset/popular-baboons-promise.md diff --git a/.changeset/popular-baboons-promise.md b/.changeset/popular-baboons-promise.md new file mode 100644 index 000000000..9446ae176 --- /dev/null +++ b/.changeset/popular-baboons-promise.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Monoid: add array, readonlyArray combinators diff --git a/data.md b/data.md index e8eae4e1e..7188d8485 100644 --- a/data.md +++ b/data.md @@ -27,3 +27,5 @@ This section covers the various modules and combinators that work with arrays. | Order | array | `Order` | `Order>` | | Semigroup | array | `A` | `Semigroup>` | | Semigroup | readonlyArray | `A` | `Semigroup>` | +| Monoid | array | `A` | `Monoid>` | +| Monoid | readonlyArray | `A` | `Monoid>` | diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 0083c5e82..cfdb335a8 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -24,6 +24,7 @@ import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" +import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as of_ from "@fp-ts/core/typeclass/Of" import * as order from "@fp-ts/core/typeclass/Order" import type { Order } from "@fp-ts/core/typeclass/Order" @@ -2176,15 +2177,7 @@ export const getSemigroup: () => Semigroup> = semigroup.read * @category instances * @since 1.0.0 */ -export const getMonoid = (): Monoid> => { - const S = getSemigroup() - return ({ - combine: S.combine, - combineMany: S.combineMany, - combineAll: (collection) => S.combineMany(collection)(empty()), - empty: empty() - }) -} +export const getMonoid: () => Monoid> = monoid.readonlyArray /** * This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index 071447afe..d574a2352 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -65,6 +65,32 @@ export const tuple = >( return fromSemigroup(semigroup.tuple(...monoids), empty) } +/** + * Given a type `A`, this function creates and returns a `Monoid` for `Array`. + * The returned `Monoid`'s empty value is the empty array. + * + * @category combinators + * @since 1.0.0 + */ +export const array = (): Monoid> => { + const S = semigroup.array() + return ({ + combine: S.combine, + combineMany: S.combineMany, + combineAll: (collection) => S.combineMany(collection)([]), + empty: [] + }) +} + +/** + * Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. + * The returned `Monoid`'s empty value is the empty array. + * + * @category combinators + * @since 1.0.0 + */ +export const readonlyArray: () => Monoid> = array as any + /** * Given a struct of `Monoid`s returns a `Monoid` for the struct. * diff --git a/test/typeclass/Monoid.ts b/test/typeclass/Monoid.ts index 4e9dbae21..1ce38fb06 100644 --- a/test/typeclass/Monoid.ts +++ b/test/typeclass/Monoid.ts @@ -5,6 +5,10 @@ import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as U from "../util" describe("Monoid", () => { + it("exports", () => { + expect(monoid.array).exists + }) + it("min", () => { const M = monoid.min(N.Bounded) U.deepStrictEqual(M.combineAll([]), +Infinity) From 9a818c502706e5655ffb914003492e66fa2d1449 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 19 Jan 2023 17:40:14 +0100 Subject: [PATCH 056/255] data.md: add struct section --- data.md | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/data.md b/data.md index 7188d8485..4decf1b9f 100644 --- a/data.md +++ b/data.md @@ -10,8 +10,8 @@ This section covers the various modules and combinators that work with tuples. | Order | tuple | `[Order, Order, ...]` | `Order` | | Semigroup | tuple | `[Semigroup, Semigroup, ...]` | `Semigroup<[A, B, ...]>` | | Monoid | tuple | `[Monoid, Monoid, ...]` | `Monoid<[A, B, ...]>` | -| SemiProduct | nonEmptyTuple | `[F, F, ...]` | `F<[A, B, ...]>` | -| Product | tuple | `[F, F, ...]` (can be empty) | `F<[A, B, ...]>` | +| SemiProduct | nonEmptyTuple | `[F, F, ...]` (cannot be empty) | `F<[A, B, ...]>` | +| Product | tuple | `[F, F, ...]` | `F<[A, B, ...]>` | | Either | tuple | `[Either, Either, ...]` | `Either` | | Option | tuple | `[Option, Option, ...]` | `Option<[A, B, ...]>` | | Predicate | tuple | `[Predicate, Predicate, ...]` | `Predicate` | @@ -21,11 +21,30 @@ This section covers the various modules and combinators that work with tuples. This section covers the various modules and combinators that work with arrays. -| Module | Name | Given | To | -| ----------- | ------------- | ---------------- | ------------------------------- | -| Equivalence | array | `Equivalence` | `Equivalence>` | -| Order | array | `Order` | `Order>` | -| Semigroup | array | `A` | `Semigroup>` | -| Semigroup | readonlyArray | `A` | `Semigroup>` | -| Monoid | array | `A` | `Monoid>` | -| Monoid | readonlyArray | `A` | `Monoid>` | +| Module | Name | Given | To | +| ------------- | ------------- | ---------------- | ------------------------------- | +| Equivalence | array | `Equivalence` | `Equivalence>` | +| Order | array | `Order` | `Order>` | +| Semigroup | array | `A` | `Semigroup>` | +| Semigroup | readonlyArray | `A` | `Semigroup>` | +| Monoid | array | `A` | `Monoid>` | +| Monoid | readonlyArray | `A` | `Monoid>` | +| ReadonlyArray | getSemigroup | `A` | `Semigroup>` | +| ReadonlyArray | getMonoid | `A` | `Monoid>` | + +## structs + +This section covers the various modules and combinators that work with structs. + +| Module | Name | Given | To | +| ----------- | -------------- | ----------------------------------------------- | ----------------------------------------- | +| Equivalence | struct | `{ a: Equivalence, b: Equivalence, ... }` | `Equivalence<{ a: A, b: B, ... }>` | +| Order | NA | NA | NA | +| Semigroup | struct | `{ a: Semigroup, b: Semigroup, ... }` | `Semigroup<{ a: A, b: B, ... }>` | +| Monoid | struct | `{ a: Monoid, b: Monoid, ... }` | `Monoid<{ a: A, b: B, ... }>` | +| SemiProduct | nonEmptyStruct | `{ a: F, b: F, ... }` (cannot be empty) | `F<{ a: A, b: B, ... }>` | +| Product | struct | `{ a: F, b: F, ... }` | `F<{ a: A, b: B, ... }>` | +| Either | struct | `{ a: Either, b: Either, ... }` | `Either` | +| Option | struct | `{ a: Option, b: Option, ... }` | `Option<{ a: A, b: B }>` | +| Predicate | struct | `{ a: Predicate, b: Predicate, ... }` | `Predicate>` | +| These | struct | `{ a: These, b: These, ... }` | `These` | From 4f998bad3588629b8d7fc476003ad37067be3f38 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 19 Jan 2023 17:58:04 +0100 Subject: [PATCH 057/255] data.md: add string section --- data.md | 15 +++++++++ src/Predicate.ts | 7 ++++ src/String.ts | 69 ++++++++++---------------------------- src/typeclass/Monoid.ts | 15 +++++++-- src/typeclass/Order.ts | 8 +++++ src/typeclass/Semigroup.ts | 8 +++++ 6 files changed, 68 insertions(+), 54 deletions(-) diff --git a/data.md b/data.md index 4decf1b9f..3f2321bb9 100644 --- a/data.md +++ b/data.md @@ -48,3 +48,18 @@ This section covers the various modules and combinators that work with structs. | Option | struct | `{ a: Option, b: Option, ... }` | `Option<{ a: A, b: B }>` | | Predicate | struct | `{ a: Predicate, b: Predicate, ... }` | `Predicate>` | | These | struct | `{ a: These, b: These, ... }` | `These` | + +## strings + +| Module | Name | Given | To | +| ----------- | ----------- | ----- | ----------------------------- | +| Equivalence | string | | `Equivalence` | +| Order | string | | `Order` | +| Semigroup | string | | `Semigroup` | +| Monoid | string | | `Monoid` | +| Predicate | isString | | `Refinement` | +| String | Equivalence | | `Equivalence` | +| String | Order | | `Order` | +| String | Semigroup | | `Semigroup` | +| String | Monoid | | `Monoid` | +| String | isString | | `Refinement` | diff --git a/src/Predicate.ts b/src/Predicate.ts index c21fb8d27..70a326370 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -35,6 +35,13 @@ export interface Refinement { (a: A): a is B } +/** + * @category guards + * @since 1.0.0 + */ +export const isString: Refinement = (u: unknown): u is string => + typeof u === "string" + /** * @category constructors * @since 1.0.0 diff --git a/src/String.ts b/src/String.ts index 950aca447..747df0de3 100644 --- a/src/String.ts +++ b/src/String.ts @@ -4,93 +4,58 @@ import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type { Refinement } from "@fp-ts/core/Predicate" +import * as predicate from "@fp-ts/core/Predicate" import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" -import type * as monoid from "@fp-ts/core/typeclass/Monoid" -import type * as order from "@fp-ts/core/typeclass/Order" +import * as monoid from "@fp-ts/core/typeclass/Monoid" +import * as order from "@fp-ts/core/typeclass/Order" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** + * @category guards * @since 1.0.0 */ -export const concat = (that: string) => (self: string): string => self + that +export const isString: Refinement = predicate.isString /** - * `string` semigroup under concatenation. - * - * @example - * import * as S from '@fp-ts/core/String' - * import { pipe } from '@fp-ts/core/Function' - * - * assert.deepStrictEqual(pipe('a', S.Semigroup.combine('b')), 'ab') - * * @category instances * @since 1.0.0 */ -export const Semigroup: semigroup.Semigroup = semigroup.fromCombine(concat) +export const Equivalence: equivalence.Equivalence = equivalence.string /** - * An empty `string`. - * + * @category instances * @since 1.0.0 */ -export const empty: "" = "" as const +export const Order: order.Order = order.string /** - * `string` monoid under concatenation. - * - * The `empty` value is `''`. - * - * @example - * import * as S from '@fp-ts/core/String' - * import { pipe } from '@fp-ts/core/Function' - * - * assert.deepStrictEqual(pipe('a', S.Monoid.combine('b')), 'ab') - * assert.deepStrictEqual(pipe('a', S.Monoid.combine(S.Monoid.empty)), 'a') + * `string` semigroup under concatenation. * * @category instances * @since 1.0.0 */ -export const Monoid: monoid.Monoid = { - ...Semigroup, - combineAll: (collection) => Semigroup.combineMany(collection)(empty), - empty -} +export const Semigroup: semigroup.Semigroup = semigroup.string /** + * `string` monoid under concatenation. + * + * The `empty` value is `''`. + * * @category instances * @since 1.0.0 */ -export const Equivalence: equivalence.Equivalence = equivalence.string +export const Monoid: monoid.Monoid = monoid.string /** - * @example - * import * as S from '@fp-ts/core/String' - * import { pipe } from '@fp-ts/core/Function' - * - * assert.deepStrictEqual(pipe('a', S.Order.compare('a')), 0) - * assert.deepStrictEqual(pipe('a', S.Order.compare('b')), -1) - * assert.deepStrictEqual(pipe('b', S.Order.compare('a')), 1) - * - * @category instances * @since 1.0.0 */ -export const Order: order.Order = { - compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 -} +export const empty: "" = "" as const /** - * @example - * import * as S from '@fp-ts/core/String' - * - * assert.deepStrictEqual(S.isString('a'), true) - * assert.deepStrictEqual(S.isString(1), false) - * - * @category guards * @since 1.0.0 */ -export const isString: Refinement = (u: unknown): u is string => - typeof u === "string" +export const concat: (that: string) => (self: string) => string = semigroup.string.combine /** * @example diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index d574a2352..be0bde9dd 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -15,8 +15,6 @@ export interface Monoid extends Semigroup { } /** - * Optimised. - * * @category constructors * @since 1.0.0 */ @@ -49,13 +47,25 @@ export const max = (B: Bounded): Monoid => fromSemigroup(semigroup.max( /** * The dual of a `Monoid`, obtained by swapping the arguments of `combine`. * + * @category combinators * @since 1.0.0 */ export const reverse = (M: Monoid): Monoid => fromSemigroup(semigroup.reverse(M), M.empty) +/** + * @category instances + * @since 1.0.0 + */ +export const string: Monoid = { + ...semigroup.string, + combineAll: (collection) => semigroup.string.combineMany(collection)(""), + empty: "" +} + /** * Given a tuple of `Monoid`s returns a `Monoid` for the tuple. * + * @category combinators * @since 1.0.0 */ export const tuple = >( @@ -94,6 +104,7 @@ export const readonlyArray: () => Monoid> = array as any /** * Given a struct of `Monoid`s returns a `Monoid` for the struct. * + * @category combinators * @since 1.0.0 */ export const struct = ( diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index c2623058a..40fa3c303 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -27,6 +27,14 @@ export interface OrderTypeLambda extends TypeLambda { readonly type: Order } +/** + * @category instances + * @since 1.0.0 + */ +export const string: Order = { + compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 +} + /** * Main constructor. * diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index fe3bcca48..b9bd739cf 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -61,6 +61,14 @@ export const fromCombine = (combine: Semigroup["combine"]): Semigroup = } }) +/** + * @category instances + * @since 1.0.0 + */ +export const string: Semigroup = fromCombine((that: string) => + (self: string): string => self + that +) + /** * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. * The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. From df5ae2437da777c77d80944ec0ad06d425ed2fb2 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 19 Jan 2023 18:24:53 +0100 Subject: [PATCH 058/255] data.md: add numbers section --- data.md | 20 ++++++++++++++ src/Number.ts | 56 +++++++++----------------------------- src/Predicate.ts | 7 +++++ src/typeclass/Bounded.ts | 10 +++++++ src/typeclass/Monoid.ts | 28 +++++++++++++++++++ src/typeclass/Order.ts | 11 ++++++-- src/typeclass/Semigroup.ts | 34 +++++++++++++++++++++++ 7 files changed, 121 insertions(+), 45 deletions(-) diff --git a/data.md b/data.md index 3f2321bb9..88fd116c1 100644 --- a/data.md +++ b/data.md @@ -63,3 +63,23 @@ This section covers the various modules and combinators that work with structs. | String | Semigroup | | `Semigroup` | | String | Monoid | | `Monoid` | | String | isString | | `Refinement` | + +## numbers + +| Module | Name | Given | To | +| ----------- | ----------------- | ----- | ----------------------------- | +| Equivalence | number | | `Equivalence` | +| Order | number | | `Order` | +| Bounded | number | | `Bounded` | +| Semigroup | numberSum | | `Semigroup` | +| Semigroup | numberMultiply | | `Semigroup` | +| Monoid | numberSum | | `Monoid` | +| Monoid | numberMultiply | | `Monoid` | +| Predicate | isNumber | | `Refinement` | +| Number | Equivalence | | `Equivalence` | +| Number | Order | | `Order` | +| Number | SemigroupSum | | `Semigroup` | +| Number | SemigroupMultiply | | `Semigroup` | +| Number | MonoidSum | | `Monoid` | +| Number | MonoidMultiply | | `Monoid` | +| Number | isNumber | | `Refinement` | diff --git a/src/Number.ts b/src/Number.ts index 54067783b..8aabd0ff6 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -3,28 +3,28 @@ */ import type { Ordering } from "@fp-ts/core/Ordering" import type { Refinement } from "@fp-ts/core/Predicate" -import type * as bounded from "@fp-ts/core/typeclass/Bounded" +import * as predicate from "@fp-ts/core/Predicate" +import * as bounded from "@fp-ts/core/typeclass/Bounded" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" -import type * as monoid from "@fp-ts/core/typeclass/Monoid" -import type * as order from "@fp-ts/core/typeclass/Order" +import * as monoid from "@fp-ts/core/typeclass/Monoid" +import * as order from "@fp-ts/core/typeclass/Order" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** * @category guards * @since 1.0.0 */ -export const isNumber: Refinement = (u: unknown): u is number => - typeof u === "number" +export const isNumber: Refinement = predicate.isNumber /** * @since 1.0.0 */ -export const sum = (that: number) => (self: number): number => self + that +export const sum: (that: number) => (self: number) => number = semigroup.numberSum.combine /** * @since 1.0.0 */ -export const multiply = (that: number) => (self: number): number => self * that +export const multiply: (that: number) => (self: number) => number = semigroup.numberMultiply.combine /** * @since 1.0.0 @@ -51,19 +51,13 @@ export const Equivalence: equivalence.Equivalence = equivalence.number * @category instances * @since 1.0.0 */ -export const Order: order.Order = { - compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 -} +export const Order: order.Order = order.number /** * @category instances * @since 1.0.0 */ -export const Bounded: bounded.Bounded = { - compare: Order.compare, - maxBound: Infinity, - minBound: -Infinity -} +export const Bounded: bounded.Bounded = bounded.number /** * `number` semigroup under addition. @@ -77,7 +71,7 @@ export const Bounded: bounded.Bounded = { * @category instances * @since 1.0.0 */ -export const SemigroupSum: semigroup.Semigroup = semigroup.fromCombine(sum) +export const SemigroupSum: semigroup.Semigroup = semigroup.numberSum /** * `number` semigroup under multiplication. @@ -91,23 +85,7 @@ export const SemigroupSum: semigroup.Semigroup = semigroup.fromCombine(s * @category instances * @since 1.0.0 */ -export const SemigroupMultiply: semigroup.Semigroup = { - combine: multiply, - combineMany: (collection) => - (self) => { - if (self === 0) { - return 0 - } - let out = self - for (const n of collection) { - if (n === 0) { - return 0 - } - out = out * n - } - return out - } -} +export const SemigroupMultiply: semigroup.Semigroup = semigroup.numberMultiply /** * `number` monoid under addition. @@ -117,11 +95,7 @@ export const SemigroupMultiply: semigroup.Semigroup = { * @category instances * @since 1.0.0 */ -export const MonoidSum: monoid.Monoid = { - ...SemigroupSum, - combineAll: (collection) => SemigroupSum.combineMany(collection)(0), - empty: 0 -} +export const MonoidSum: monoid.Monoid = monoid.numberSum /** * `number` monoid under multiplication. @@ -131,11 +105,7 @@ export const MonoidSum: monoid.Monoid = { * @category instances * @since 1.0.0 */ -export const MonoidMultiply: monoid.Monoid = { - ...SemigroupMultiply, - combineAll: (collection) => SemigroupMultiply.combineMany(collection)(1), - empty: 1 -} +export const MonoidMultiply: monoid.Monoid = monoid.numberMultiply /** * @since 1.0.0 diff --git a/src/Predicate.ts b/src/Predicate.ts index 70a326370..a4d24caa8 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -42,6 +42,13 @@ export interface Refinement { export const isString: Refinement = (u: unknown): u is string => typeof u === "string" +/** + * @category guards + * @since 1.0.0 + */ +export const isNumber: Refinement = (u: unknown): u is number => + typeof u === "number" + /** * @category constructors * @since 1.0.0 diff --git a/src/typeclass/Bounded.ts b/src/typeclass/Bounded.ts index 2459fa434..6d59f747f 100644 --- a/src/typeclass/Bounded.ts +++ b/src/typeclass/Bounded.ts @@ -22,6 +22,16 @@ export interface BoundedTypeLambda extends TypeLambda { readonly type: Bounded } +/** + * @category instances + * @since 1.0.0 + */ +export const number: Bounded = { + compare: order.number.compare, + maxBound: Infinity, + minBound: -Infinity +} + /** * Clamp a value between `minBound` and `maxBound` values. * diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index be0bde9dd..227b5e1b4 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -62,6 +62,34 @@ export const string: Monoid = { empty: "" } +/** + * `number` monoid under addition. + * + * The `empty` value is `0`. + * + * @category instances + * @since 1.0.0 + */ +export const numberSum: Monoid = { + ...semigroup.numberSum, + combineAll: (collection) => semigroup.numberSum.combineMany(collection)(0), + empty: 0 +} + +/** + * `number` monoid under multiplication. + * + * The `empty` value is `1`. + * + * @category instances + * @since 1.0.0 + */ +export const numberMultiply: Monoid = { + ...semigroup.numberMultiply, + combineAll: (collection) => semigroup.numberMultiply.combineMany(collection)(1), + empty: 1 +} + /** * Given a tuple of `Monoid`s returns a `Monoid` for the tuple. * diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 40fa3c303..89714a20c 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -2,7 +2,6 @@ * @since 1.0.0 */ import type { TypeLambda } from "@fp-ts/core/HKT" -import * as number from "@fp-ts/core/Number" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" @@ -35,6 +34,14 @@ export const string: Order = { compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 } +/** + * @category instances + * @since 1.0.0 + */ +export const number: Order = { + compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 +} + /** * Main constructor. * @@ -91,7 +98,7 @@ export const array = (O: Order): Order> => return o } } - return number.Order.compare(bLen)(aLen) + return number.compare(bLen)(aLen) } ) diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index b9bd739cf..f71897e9d 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -69,6 +69,40 @@ export const string: Semigroup = fromCombine((that: string) => (self: string): string => self + that ) +/** + * `number` semigroup under addition. + * + * @category instances + * @since 1.0.0 + */ +export const numberSum: Semigroup = fromCombine((that: number) => + (self: number): number => self + that +) + +/** + * `number` semigroup under multiplication. + * + * @category instances + * @since 1.0.0 + */ +export const numberMultiply: Semigroup = { + combine: (that: number) => (self: number): number => self * that, + combineMany: (collection) => + (self) => { + if (self === 0) { + return 0 + } + let out = self + for (const n of collection) { + if (n === 0) { + return 0 + } + out = out * n + } + return out + } +} + /** * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. * The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. From 26488b5383fd56163e8b3d0c1f207ff0b3c3fb0c Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 19 Jan 2023 18:58:59 +0100 Subject: [PATCH 059/255] data.md: add booleans section --- data.md | 19 +++++++ src/Boolean.ts | 100 ++++++++++++------------------------- src/Predicate.ts | 7 +++ src/typeclass/Monoid.ts | 28 +++++++++++ src/typeclass/Order.ts | 8 +++ src/typeclass/Semigroup.ts | 44 ++++++++++++++++ 6 files changed, 137 insertions(+), 69 deletions(-) diff --git a/data.md b/data.md index 88fd116c1..861e547c7 100644 --- a/data.md +++ b/data.md @@ -83,3 +83,22 @@ This section covers the various modules and combinators that work with structs. | Number | MonoidSum | | `Monoid` | | Number | MonoidMultiply | | `Monoid` | | Number | isNumber | | `Refinement` | + +## booleans + +| Module | Name | Given | To | +| ----------- | ----------- | ----- | ------------------------------ | +| Equivalence | boolean | | `Equivalence` | +| Order | boolean | | `Order` | +| Semigroup | booleanAny | | `Semigroup` | +| Semigroup | booleanAll | | `Semigroup` | +| Monoid | booleanAny | | `Monoid` | +| Monoid | booleanAll | | `Monoid` | +| Predicate | isBoolean | | `Refinement` | +| Boolean | Equivalence | | `Equivalence` | +| Boolean | Order | | `Order` | +| Boolean | booleanAny | | `Semigroup` | +| Boolean | booleanAll | | `Semigroup` | +| Boolean | booleanAny | | `Monoid` | +| Boolean | booleanAll | | `Monoid` | +| Boolean | isBoolean | | `Refinement` | diff --git a/src/Boolean.ts b/src/Boolean.ts index da22ddc9e..1b2b4e0c1 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -3,35 +3,17 @@ */ import type { LazyArg } from "@fp-ts/core/Function" import type { Refinement } from "@fp-ts/core/Predicate" +import * as predicate from "@fp-ts/core/Predicate" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" -import type * as monoid from "@fp-ts/core/typeclass/Monoid" -import type * as order from "@fp-ts/core/typeclass/Order" -import type * as semigroup from "@fp-ts/core/typeclass/Semigroup" +import * as monoid from "@fp-ts/core/typeclass/Monoid" +import * as order from "@fp-ts/core/typeclass/Order" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** * @category guards * @since 1.0.0 */ -export const isBoolean: Refinement = (u: unknown): u is boolean => - typeof u === "boolean" - -/** - * @category combinators - * @since 1.0.0 - */ -export const and = (that: boolean) => (self: boolean): boolean => self && that - -/** - * @category combinators - * @since 1.0.0 - */ -export const or = (that: boolean) => (self: boolean): boolean => self || that - -/** - * @category combinators - * @since 1.0.0 - */ -export const not = (self: boolean): boolean => !self +export const isBoolean: Refinement = predicate.isBoolean /** * Defines the match over a boolean value. @@ -57,6 +39,18 @@ export const not = (self: boolean): boolean => !self export const match = (onFalse: LazyArg, onTrue: LazyArg) => (value: boolean): A | B => value ? onTrue() : onFalse() +/** + * @category instances + * @since 1.0.0 + */ +export const Equivalence: equivalence.Equivalence = equivalence.boolean + +/** + * @category instances + * @since 1.0.0 + */ +export const Order: order.Order = order.boolean + /** * `boolean` semigroup under conjunction. * @@ -70,21 +64,7 @@ export const match = (onFalse: LazyArg, onTrue: LazyArg) => * @category instances * @since 1.0.0 */ -export const SemigroupAll: semigroup.Semigroup = { - combine: and, - combineMany: (collection) => - (self) => { - if (self === false) { - return false - } - for (const b of collection) { - if (b === false) { - return false - } - } - return true - } -} +export const SemigroupAll: semigroup.Semigroup = semigroup.booleanAll /** * `boolean` semigroup under disjunction. @@ -100,21 +80,7 @@ export const SemigroupAll: semigroup.Semigroup = { * @category instances * @since 1.0.0 */ -export const SemigroupAny: semigroup.Semigroup = { - combine: or, - combineMany: (collection) => - (self) => { - if (self === true) { - return true - } - for (const b of collection) { - if (b === true) { - return true - } - } - return false - } -} +export const SemigroupAny: semigroup.Semigroup = semigroup.booleanAny /** * `boolean` monoid under conjunction. @@ -124,11 +90,7 @@ export const SemigroupAny: semigroup.Semigroup = { * @category instances * @since 1.0.0 */ -export const MonoidAll: monoid.Monoid = { - ...SemigroupAll, - combineAll: (all) => SemigroupAll.combineMany(all)(true), - empty: true -} +export const MonoidAll: monoid.Monoid = monoid.booleanAll /** * `boolean` monoid under disjunction. @@ -138,22 +100,22 @@ export const MonoidAll: monoid.Monoid = { * @category instances * @since 1.0.0 */ -export const MonoidAny: monoid.Monoid = { - ...SemigroupAny, - combineAll: (all) => SemigroupAny.combineMany(all)(false), - empty: false -} +export const MonoidAny: monoid.Monoid = monoid.booleanAny /** - * @category instances + * @category combinators * @since 1.0.0 */ -export const Equivalence: equivalence.Equivalence = equivalence.boolean +export const and: (that: boolean) => (self: boolean) => boolean = semigroup.booleanAll.combine /** - * @category instances + * @category combinators * @since 1.0.0 */ -export const Order: order.Order = { - compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 -} +export const or: (that: boolean) => (self: boolean) => boolean = semigroup.booleanAny.combine + +/** + * @category combinators + * @since 1.0.0 + */ +export const not = (self: boolean): boolean => !self diff --git a/src/Predicate.ts b/src/Predicate.ts index a4d24caa8..4dd6a901f 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -49,6 +49,13 @@ export const isString: Refinement = (u: unknown): u is string = export const isNumber: Refinement = (u: unknown): u is number => typeof u === "number" +/** + * @category guards + * @since 1.0.0 + */ +export const isBoolean: Refinement = (u: unknown): u is boolean => + typeof u === "boolean" + /** * @category constructors * @since 1.0.0 diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index 227b5e1b4..79f953ac9 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -90,6 +90,34 @@ export const numberMultiply: Monoid = { empty: 1 } +/** + * `boolean` monoid under conjunction. + * + * The `empty` value is `true`. + * + * @category instances + * @since 1.0.0 + */ +export const booleanAll: Monoid = { + ...semigroup.booleanAll, + combineAll: (all) => semigroup.booleanAll.combineMany(all)(true), + empty: true +} + +/** + * `boolean` monoid under disjunction. + * + * The `empty` value is `false`. + * + * @category instances + * @since 1.0.0 + */ +export const booleanAny: Monoid = { + ...semigroup.booleanAny, + combineAll: (all) => semigroup.booleanAny.combineMany(all)(false), + empty: false +} + /** * Given a tuple of `Monoid`s returns a `Monoid` for the tuple. * diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 89714a20c..ed00a3556 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -42,6 +42,14 @@ export const number: Order = { compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 } +/** + * @category instances + * @since 1.0.0 + */ +export const boolean: Order = { + compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 +} + /** * Main constructor. * diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index f71897e9d..6139abb1b 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -103,6 +103,50 @@ export const numberMultiply: Semigroup = { } } +/** + * `boolean` semigroup under conjunction. + * + * @category instances + * @since 1.0.0 + */ +export const booleanAll: Semigroup = { + combine: (that: boolean) => (self: boolean): boolean => self && that, + combineMany: (collection) => + (self) => { + if (self === false) { + return false + } + for (const b of collection) { + if (b === false) { + return false + } + } + return true + } +} + +/** + * `boolean` semigroup under disjunction. + * + * @category instances + * @since 1.0.0 + */ +export const booleanAny: Semigroup = { + combine: (that: boolean) => (self: boolean): boolean => self || that, + combineMany: (collection) => + (self) => { + if (self === true) { + return true + } + for (const b of collection) { + if (b === true) { + return true + } + } + return false + } +} + /** * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. * The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. From 5723134f08c57f4bb54dd2d6b14ed451e8cf75bd Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 19 Jan 2023 19:03:51 +0100 Subject: [PATCH 060/255] Order: add bigint instance --- .changeset/nine-bags-end.md | 5 +++++ data.md | 13 +++++++++++++ src/typeclass/Order.ts | 8 ++++++++ test/typeclass/Order.ts | 8 ++++++++ 4 files changed, 34 insertions(+) create mode 100644 .changeset/nine-bags-end.md diff --git a/.changeset/nine-bags-end.md b/.changeset/nine-bags-end.md new file mode 100644 index 000000000..5ff72f442 --- /dev/null +++ b/.changeset/nine-bags-end.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Order: add bigint instance diff --git a/data.md b/data.md index 861e547c7..0dac7a028 100644 --- a/data.md +++ b/data.md @@ -102,3 +102,16 @@ This section covers the various modules and combinators that work with structs. | Boolean | booleanAny | | `Monoid` | | Boolean | booleanAll | | `Monoid` | | Boolean | isBoolean | | `Refinement` | + +## bigints + +| Module | Name | Given | To | +| ----------- | ------ | ----- | --------------------- | +| Equivalence | bigint | | `Equivalence` | +| Order | bigint | | `Order` | + +## symbols + +| Module | Name | Given | To | +| ----------- | ------ | ----- | --------------------- | +| Equivalence | symbol | | `Equivalence` | diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index ed00a3556..335929de6 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -50,6 +50,14 @@ export const boolean: Order = { compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 } +/** + * @category instances + * @since 1.0.0 + */ +export const bigint: Order = { + compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 +} + /** * Main constructor. * diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index 7910bbc90..3333f602f 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -7,6 +7,14 @@ import * as _ from "@fp-ts/core/typeclass/Order" import * as U from "../util" describe("Order", () => { + it("bigint", () => { + const O = _.bigint + expect(pipe(1n, _.lessThanOrEqualTo(O)(2n))).toBe(true) + expect(pipe(1n, _.lessThanOrEqualTo(O)(1n))).toBe(true) + expect(pipe(1n, _.lessThan(O)(1n))).toBe(false) + expect(pipe(1n, _.lessThanOrEqualTo(O)(0n))).toBe(false) + }) + it("tuple", () => { const O = _.tuple(string.Order, number.Order, boolean.Order) U.deepStrictEqual(pipe(["a", 1, true], O.compare(["b", 2, true])), -1) From 533fd2e3510fc50fe595856b2345be7ddbe342a3 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 19 Jan 2023 19:17:00 +0100 Subject: [PATCH 061/255] add ReadonlyRecord module --- .changeset/gold-teachers-admire.md | 5 ++++ data.md | 11 +++++++ dtslint/ts4.7/ReadonlyRecord.ts | 31 +++++++++++++++++++ src/ReadonlyRecord.ts | 48 ++++++++++++++++++++++++++++++ src/index.ts | 12 +++++++- src/typeclass/Equivalence.ts | 3 +- test/ReadonlyRecord.ts | 24 +++++++++++++++ 7 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 .changeset/gold-teachers-admire.md create mode 100644 dtslint/ts4.7/ReadonlyRecord.ts create mode 100644 src/ReadonlyRecord.ts create mode 100644 test/ReadonlyRecord.ts diff --git a/.changeset/gold-teachers-admire.md b/.changeset/gold-teachers-admire.md new file mode 100644 index 000000000..9ca396e17 --- /dev/null +++ b/.changeset/gold-teachers-admire.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add ReadonlyRecord module diff --git a/data.md b/data.md index 0dac7a028..f6d6cd587 100644 --- a/data.md +++ b/data.md @@ -49,6 +49,17 @@ This section covers the various modules and combinators that work with structs. | Predicate | struct | `{ a: Predicate, b: Predicate, ... }` | `Predicate>` | | These | struct | `{ a: These, b: These, ... }` | `These` | +## records + +This section covers the various modules and combinators that work with records. + +| Module | Name | Given | To | +| -------------- | ------------- | -------------------------------------------- | -------------------------------- | +| Equivalence | record | `Equivalence` | `Equivalence>` | +| ReadonlyRecord | get | `key: string`, `ReadonlyRecord` | `Option` | +| ReadonlyRecord | replaceOption | `key: string`, `B`, `ReadonlyRecord` | `Option>` | +| ReadonlyRecord | modifyOption | `key: string`, `A => B`, `ReadonlyRecord` | `Option>` | + ## strings | Module | Name | Given | To | diff --git a/dtslint/ts4.7/ReadonlyRecord.ts b/dtslint/ts4.7/ReadonlyRecord.ts new file mode 100644 index 000000000..2dd5d3362 --- /dev/null +++ b/dtslint/ts4.7/ReadonlyRecord.ts @@ -0,0 +1,31 @@ +import { pipe } from '@fp-ts/core/Function' +import * as _ from '@fp-ts/core/ReadonlyRecord' + +declare const r: Record + +// +// get +// + +// $ExpectType Option +pipe(r, _.get('a')) + +// +// replaceOption +// + +// $ExpectType Option> +pipe(r, _.replaceOption('a', 2)) + +// $ExpectType Option> +pipe(r, _.replaceOption('a', true)) + +// +// modifyOption +// + +// $ExpectType Option> +pipe(r, _.modifyOption('a', () => 2)) + +// $ExpectType Option> +pipe(r, _.modifyOption('a', () => true)) diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts new file mode 100644 index 000000000..a3f49e039 --- /dev/null +++ b/src/ReadonlyRecord.ts @@ -0,0 +1,48 @@ +/** + * @since 1.0.0 + */ + +import type { Option } from "@fp-ts/core/Option" +import * as O from "@fp-ts/core/Option" + +/** + * @category models + * @since 1.0.0 + */ +export interface ReadonlyRecord { + readonly [x: string]: A +} + +/** + * This function provides a safe way to read a value at a particular key from a record. + * + * @category getters + * @since 1.0.0 + */ +export const get = (key: string) => + (self: ReadonlyRecord): Option => + Object.prototype.hasOwnProperty.call(self, key) ? O.some(self[key]) : O.none() + +/** + * @since 1.0.0 + */ +export const replaceOption = ( + key: string, + b: B +): (self: ReadonlyRecord) => Option> => modifyOption(key, () => b) + +/** + * Apply a function to the element at the specified key, creating a new record, + * or return `None` if the key doesn't exist. + * + * @since 1.0.0 + */ +export const modifyOption = (key: string, f: (a: A) => B) => + (self: ReadonlyRecord): Option> => { + if (!Object.prototype.hasOwnProperty.call(self, key)) { + return O.none() + } + const out: Record = { ...self } + out[key] = f(self[key]) + return O.some(out) + } diff --git a/src/index.ts b/src/index.ts index 651a2e6f8..8fc085374 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,7 @@ import * as hkt from "@fp-ts/core/HKT" // ------------------------------------------------------------------------------------- -// typeclasses +// data types // ------------------------------------------------------------------------------------- import * as boolean from "@fp-ts/core/Boolean" @@ -21,8 +21,14 @@ import * as option from "@fp-ts/core/Option" import * as ordering from "@fp-ts/core/Ordering" import * as predicate from "@fp-ts/core/Predicate" import * as readonlyArray from "@fp-ts/core/ReadonlyArray" +import * as readonlyRecord from "@fp-ts/core/ReadonlyRecord" import * as string from "@fp-ts/core/String" import * as these from "@fp-ts/core/These" + +// ------------------------------------------------------------------------------------- +// typeclasses +// ------------------------------------------------------------------------------------- + import * as alternative from "@fp-ts/core/typeclass/Alternative" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" @@ -192,6 +198,10 @@ export { * @since 1.0.0 */ readonlyArray, + /** + * @since 1.0.0 + */ + readonlyRecord, /** * @category typeclass * @since 1.0.0 diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index ee2ee8fcf..6e6f5d38e 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -6,6 +6,7 @@ * @since 1.0.0 */ import type { TypeLambda } from "@fp-ts/core/HKT" +import type { ReadonlyRecord } from "@fp-ts/core/ReadonlyRecord" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" @@ -122,7 +123,7 @@ export const struct = ( */ export const record = ( equivalence: Equivalence -): Equivalence<{ readonly [x: string]: A }> => +): Equivalence> => (x, y) => { const keys = Object.keys(x) if (Object.keys(y).length !== keys.length) { diff --git a/test/ReadonlyRecord.ts b/test/ReadonlyRecord.ts new file mode 100644 index 000000000..c8127e047 --- /dev/null +++ b/test/ReadonlyRecord.ts @@ -0,0 +1,24 @@ +import { pipe } from "@fp-ts/core/Function" +import * as O from "@fp-ts/core/Option" +import * as RR from "@fp-ts/core/ReadonlyRecord" + +describe.concurrent("ReadonlyRecord", () => { + it("get", () => { + expect(pipe({}, RR.get("a"))).toEqual(O.none()) + expect(pipe({ a: 1 }, RR.get("a"))).toEqual(O.some(1)) + }) + + it("modifyOption", () => { + expect(pipe({}, RR.replaceOption("a", 2))).toEqual(O.none()) + expect(pipe({ a: 1 }, RR.replaceOption("a", 2))).toEqual(O.some({ a: 2 })) + expect(pipe({ a: 1 }, RR.replaceOption("a", true))).toEqual(O.some({ a: true })) + }) + + it("modifyOption", () => { + expect(pipe({}, RR.modifyOption("a", (n: number) => n + 1))).toEqual(O.none()) + expect(pipe({ a: 1 }, RR.modifyOption("a", (n: number) => n + 1))).toEqual(O.some({ a: 2 })) + expect(pipe({ a: 1 }, RR.modifyOption("a", (n: number) => String(n)))).toEqual( + O.some({ a: "1" }) + ) + }) +}) From 0e49a1f18816eea2074458852b8c4f39bc270b05 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 08:52:41 +0100 Subject: [PATCH 062/255] revert _tag changes --- src/Either.ts | 4 ++-- src/Option.ts | 4 ++-- src/These.ts | 31 ++++++++++++++----------------- src/internal/Either.ts | 12 +++++------- src/internal/Option.ts | 10 +++++----- 5 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 98e084414..a11d9e99a 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -45,7 +45,7 @@ import * as traversable from "@fp-ts/core/typeclass/Traversable" * @since 1.0.0 */ export type Left = { - readonly _tag: "@fp-ts/core/Either/Left" + readonly _tag: "Left" readonly left: E } @@ -54,7 +54,7 @@ export type Left = { * @since 1.0.0 */ export type Right = { - readonly _tag: "@fp-ts/core/Either/Right" + readonly _tag: "Right" readonly right: A } diff --git a/src/Option.ts b/src/Option.ts index 1dc3b3724..0d471a218 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -51,7 +51,7 @@ import * as traversable from "@fp-ts/core/typeclass/Traversable" * @since 1.0.0 */ export type None = { - readonly _tag: "@fp-ts/core/Option/None" + readonly _tag: "None" } /** @@ -59,7 +59,7 @@ export type None = { * @since 1.0.0 */ export type Some = { - readonly _tag: "@fp-ts/core/Option/Some" + readonly _tag: "Some" readonly value: A } diff --git a/src/These.ts b/src/These.ts index e9b1c9e71..b4b076a36 100644 --- a/src/These.ts +++ b/src/These.ts @@ -50,7 +50,7 @@ import * as traversable from "@fp-ts/core/typeclass/Traversable" * @since 1.0.0 */ export type Both = { - readonly _tag: "@fp-ts/core/These/Both" + readonly _tag: "Both" readonly left: E readonly right: A } @@ -87,13 +87,13 @@ export interface ValidatedTypeLambda extends TypeLambda { * @category constructors * @since 1.0.0 */ -export const left = (left: E): These => ({ _tag: "@fp-ts/core/Either/Left", left }) +export const left = (left: E): These => ({ _tag: "Left", left }) /** * @category constructors * @since 1.0.0 */ -export const right = (right: A): These => ({ _tag: "@fp-ts/core/Either/Right", right }) +export const right = (right: A): These => ({ _tag: "Right", right }) /** * Alias of `right`. @@ -108,7 +108,7 @@ export const of = right * @since 1.0.0 */ export const both = (left: E, right: A): These => ({ - _tag: "@fp-ts/core/These/Both", + _tag: "Both", left, right }) @@ -158,11 +158,11 @@ export const match = ( ) => (self: These): B | C | D => { switch (self._tag) { - case "@fp-ts/core/Either/Left": + case "Left": return onLeft(self.left) - case "@fp-ts/core/Either/Right": + case "Right": return onRight(self.right) - case "@fp-ts/core/These/Both": + case "Both": return onBoth(self.left, self.right) } } @@ -182,15 +182,14 @@ export const reverse: (self: These) => These = match( * @category guards * @since 1.0.0 */ -export const isLeft = (self: These): self is Left => - self._tag === "@fp-ts/core/Either/Left" +export const isLeft = (self: These): self is Left => self._tag === "Left" /** * @category guards * @since 1.0.0 */ export const isLeftOrBoth = (self: These): self is Left | Both => - self._tag !== "@fp-ts/core/Either/Right" + self._tag !== "Right" /** * Returns `true` if the these is an instance of `Right`, `false` otherwise @@ -198,15 +197,14 @@ export const isLeftOrBoth = (self: These): self is Left | Both(self: These): self is Right => - self._tag === "@fp-ts/core/Either/Right" +export const isRight = (self: These): self is Right => self._tag === "Right" /** * @category guards * @since 1.0.0 */ export const isRightOrBoth = (self: These): self is Right | Both => - self._tag !== "@fp-ts/core/Either/Left" + self._tag !== "Left" /** * Returns `true` if the these is an instance of `Both`, `false` otherwise @@ -214,8 +212,7 @@ export const isRightOrBoth = (self: These): self is Right | Both< * @category guards * @since 1.0.0 */ -export const isBoth = (self: These): self is Both => - self._tag === "@fp-ts/core/These/Both" +export const isBoth = (self: These): self is Both => self._tag === "Both" /** * Returns `true` if the specified value is an instance of `These`, `false` @@ -227,8 +224,8 @@ export const isBoth = (self: These): self is Both => export const isThese = (u: unknown): u is These => typeof u === "object" && u != null && "_tag" in u && - (u["_tag"] === "@fp-ts/core/Either/Left" || u["_tag"] === "@fp-ts/core/Either/Right" || - u["_tag"] === "@fp-ts/core/These/Both") + (u["_tag"] === "Left" || u["_tag"] === "Right" || + u["_tag"] === "Both") /** * Constructs a new `These` from a function that might throw. diff --git a/src/internal/Either.ts b/src/internal/Either.ts index c8d2867d8..fbc5bce28 100644 --- a/src/internal/Either.ts +++ b/src/internal/Either.ts @@ -10,21 +10,19 @@ import type { Option } from "@fp-ts/core/Option" /** @internal */ export const isEither = (u: unknown): u is Either => typeof u === "object" && u != null && "_tag" in u && - (u["_tag"] === "@fp-ts/core/Either/Left" || u["_tag"] === "@fp-ts/core/Either/Right") + (u["_tag"] === "Left" || u["_tag"] === "Right") /** @internal */ -export const isLeft = (ma: Either): ma is Left => - ma._tag === "@fp-ts/core/Either/Left" +export const isLeft = (ma: Either): ma is Left => ma._tag === "Left" /** @internal */ -export const isRight = (ma: Either): ma is Right => - ma._tag === "@fp-ts/core/Either/Right" +export const isRight = (ma: Either): ma is Right => ma._tag === "Right" /** @internal */ -export const left = (e: E): Either => ({ _tag: "@fp-ts/core/Either/Left", left: e }) +export const left = (e: E): Either => ({ _tag: "Left", left: e }) /** @internal */ -export const right = (a: A): Either => ({ _tag: "@fp-ts/core/Either/Right", right: a }) +export const right = (a: A): Either => ({ _tag: "Right", right: a }) /** @internal */ export const getLeft = ( diff --git a/src/internal/Option.ts b/src/internal/Option.ts index 04e3586ac..c3a101ea6 100644 --- a/src/internal/Option.ts +++ b/src/internal/Option.ts @@ -7,19 +7,19 @@ import type { None, Option, Some } from "@fp-ts/core/Option" /** @internal */ export const isOption = (u: unknown): u is Option => typeof u === "object" && u != null && "_tag" in u && - (u["_tag"] === "@fp-ts/core/Option/None" || u["_tag"] === "@fp-ts/core/Option/Some") + (u["_tag"] === "None" || u["_tag"] === "Some") /** @internal */ -export const isNone = (fa: Option): fa is None => fa._tag === "@fp-ts/core/Option/None" +export const isNone = (fa: Option): fa is None => fa._tag === "None" /** @internal */ -export const isSome = (fa: Option): fa is Some => fa._tag === "@fp-ts/core/Option/Some" +export const isSome = (fa: Option): fa is Some => fa._tag === "Some" /** @internal */ -export const none: Option = { _tag: "@fp-ts/core/Option/None" } +export const none: Option = { _tag: "None" } /** @internal */ -export const some = (a: A): Option => ({ _tag: "@fp-ts/core/Option/Some", value: a }) +export const some = (a: A): Option => ({ _tag: "Some", value: a }) /** @internal */ export const fromNullable = ( From bbe6b8fe884fe762525e9f7037971c2bcd9e811a Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 09:23:32 +0100 Subject: [PATCH 063/255] add Bigint module --- data.md | 19 ++++++++ src/Bigint.ts | 88 ++++++++++++++++++++++++++++++++++++++ src/Predicate.ts | 6 +++ src/index.ts | 5 +++ src/typeclass/Monoid.ts | 28 ++++++++++++ src/typeclass/Semigroup.ts | 34 +++++++++++++++ test/Bigint.ts | 61 ++++++++++++++++++++++++++ 7 files changed, 241 insertions(+) create mode 100644 src/Bigint.ts create mode 100644 test/Bigint.ts diff --git a/data.md b/data.md index f6d6cd587..59e946ffe 100644 --- a/data.md +++ b/data.md @@ -126,3 +126,22 @@ This section covers the various modules and combinators that work with records. | Module | Name | Given | To | | ----------- | ------ | ----- | --------------------- | | Equivalence | symbol | | `Equivalence` | + +## bigints + +| Module | Name | Given | To | +| ----------- | ----------------- | ----- | ----------------------------- | +| Equivalence | bigint | | `Equivalence` | +| Order | bigint | | `Order` | +| Semigroup | bigintSum | | `Semigroup` | +| Semigroup | bigintMultiply | | `Semigroup` | +| Monoid | bigintSum | | `Monoid` | +| Monoid | bigintMultiply | | `Monoid` | +| Predicate | isBigint | | `Refinement` | +| Bigint | Equivalence | | `Equivalence` | +| Bigint | Order | | `Order` | +| Bigint | SemigroupSum | | `Semigroup` | +| Bigint | SemigroupMultiply | | `Semigroup` | +| Bigint | MonoidSum | | `Monoid` | +| Bigint | MonoidMultiply | | `Monoid` | +| Bigint | isBigint | | `Refinement` | diff --git a/src/Bigint.ts b/src/Bigint.ts new file mode 100644 index 000000000..4c3095dce --- /dev/null +++ b/src/Bigint.ts @@ -0,0 +1,88 @@ +/** + * @since 1.0.0 + */ + +import * as predicate from "@fp-ts/core/Predicate" +import * as equivalence from "@fp-ts/core/typeclass/Equivalence" +import * as monoid from "@fp-ts/core/typeclass/Monoid" +import * as order from "@fp-ts/core/typeclass/Order" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" + +/** + * @category guards + * @since 1.0.0 + */ +export const isBigint: (u: unknown) => u is bigint = predicate.isBigInt + +/** + * @since 1.0.0 + */ +export const sum: (that: bigint) => (self: bigint) => bigint = semigroup.bigintSum.combine + +/** + * @since 1.0.0 + */ +export const multiply: (that: bigint) => (self: bigint) => bigint = semigroup.bigintMultiply.combine + +/** + * @since 1.0.0 + */ +export const sub = (that: bigint) => (self: bigint): bigint => self - that + +/** + * @since 1.0.0 + */ +export const increment = (n: bigint): bigint => n + 1n + +/** + * @since 1.0.0 + */ +export const decrement = (n: bigint): bigint => n - 1n + +/** + * @category instances + * @since 1.0.0 + */ +export const Equivalence: equivalence.Equivalence = equivalence.bigint + +/** + * @category instances + * @since 1.0.0 + */ +export const Order: order.Order = order.bigint + +/** + * `bigint` semigroup under addition. + * + * @category instances + * @since 1.0.0 + */ +export const SemigroupSum: semigroup.Semigroup = semigroup.bigintSum + +/** + * `bigint` semigroup under multiplication. + * + * @category instances + * @since 1.0.0 + */ +export const SemigroupMultiply: semigroup.Semigroup = semigroup.bigintMultiply + +/** + * `bigint` monoid under addition. + * + * The `empty` value is `0n`. + * + * @category instances + * @since 1.0.0 + */ +export const MonoidSum: monoid.Monoid = monoid.bigintSum + +/** + * `bigint` monoid under multiplication. + * + * The `empty` value is `1n`. + * + * @category instances + * @since 1.0.0 + */ +export const MonoidMultiply: monoid.Monoid = monoid.bigintMultiply diff --git a/src/Predicate.ts b/src/Predicate.ts index 4dd6a901f..9a34b85fc 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -56,6 +56,12 @@ export const isNumber: Refinement = (u: unknown): u is number = export const isBoolean: Refinement = (u: unknown): u is boolean => typeof u === "boolean" +/** + * @category guards + * @since 1.0.0 + */ +export const isBigInt = (u: unknown): u is bigint => typeof u === "bigint" + /** * @category constructors * @since 1.0.0 diff --git a/src/index.ts b/src/index.ts index 8fc085374..fc7d251ae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,6 +12,7 @@ import * as hkt from "@fp-ts/core/HKT" // data types // ------------------------------------------------------------------------------------- +import * as bigint from "@fp-ts/core/Bigint" import * as boolean from "@fp-ts/core/Boolean" import * as either from "@fp-ts/core/Either" import * as _function from "@fp-ts/core/Function" @@ -77,6 +78,10 @@ export { * @since 1.0.0 */ bicovariant, + /** + * @since 1.0.0 + */ + bigint, /** * @since 1.0.0 */ diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index 79f953ac9..55081696b 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -90,6 +90,34 @@ export const numberMultiply: Monoid = { empty: 1 } +/** + * `number` monoid under addition. + * + * The `bigint` value is `0n`. + * + * @category instances + * @since 1.0.0 + */ +export const bigintSum: Monoid = { + ...semigroup.bigintSum, + combineAll: (collection) => semigroup.bigintSum.combineMany(collection)(0n), + empty: 0n +} + +/** + * `bigint` monoid under multiplication. + * + * The `empty` value is `1n`. + * + * @category instances + * @since 1.0.0 + */ +export const bigintMultiply: Monoid = { + ...semigroup.bigintMultiply, + combineAll: (collection) => semigroup.bigintMultiply.combineMany(collection)(1n), + empty: 1n +} + /** * `boolean` monoid under conjunction. * diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 6139abb1b..6673755bb 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -103,6 +103,40 @@ export const numberMultiply: Semigroup = { } } +/** + * `bigint` semigroup under addition. + * + * @category instances + * @since 1.0.0 + */ +export const bigintSum: Semigroup = fromCombine((that: bigint) => + (self: bigint): bigint => self + that +) + +/** + * `bigint` semigroup under multiplication. + * + * @category instances + * @since 1.0.0 + */ +export const bigintMultiply: Semigroup = { + combine: (that: bigint) => (self: bigint): bigint => self * that, + combineMany: (collection) => + (self) => { + if (self === 0n) { + return 0n + } + let out = self + for (const n of collection) { + if (n === 0n) { + return 0n + } + out = out * n + } + return out + } +} + /** * `boolean` semigroup under conjunction. * diff --git a/test/Bigint.ts b/test/Bigint.ts new file mode 100644 index 000000000..cccc0bd48 --- /dev/null +++ b/test/Bigint.ts @@ -0,0 +1,61 @@ +import * as Bigint from "@fp-ts/core/Bigint" +import { pipe } from "@fp-ts/core/Function" +import { deepStrictEqual } from "@fp-ts/core/test/util" + +describe.concurrent("Bigint", () => { + it("isNumber", () => { + expect(Bigint.isBigint(1n)).toEqual(true) + expect(Bigint.isBigint(1)).toEqual(false) + expect(Bigint.isBigint("a")).toEqual(false) + expect(Bigint.isBigint(true)).toEqual(false) + }) + + it("sum", () => { + deepStrictEqual(Bigint.sum(1n)(2n), 3n) + }) + + it("sub", () => { + deepStrictEqual(Bigint.sub(1n)(2n), 1n) + }) + + it("multiply", () => { + deepStrictEqual(Bigint.multiply(3n)(2n), 6n) + }) + + it("increment", () => { + deepStrictEqual(Bigint.increment(2n), 3n) + }) + + it("decrement", () => { + deepStrictEqual(Bigint.decrement(2n), 1n) + }) + + it("Equivalence", () => { + expect(Bigint.Equivalence(1n, 1n)).toBe(true) + expect(Bigint.Equivalence(1n, 2n)).toBe(false) + }) + + it("Order", () => { + deepStrictEqual(pipe(1n, Bigint.Order.compare(2n)), -1) + deepStrictEqual(pipe(2n, Bigint.Order.compare(1n)), 1) + deepStrictEqual(pipe(2n, Bigint.Order.compare(2n)), 0) + }) + + it("SemigroupSum", () => { + deepStrictEqual(pipe(2n, Bigint.SemigroupSum.combine(3n)), 5n) + }) + + it("MonoidSum", () => { + deepStrictEqual(Bigint.MonoidSum.combineAll([1n, 2n, 3n]), 6n) + }) + + it("SemigroupMultiply", () => { + deepStrictEqual(pipe(2n, Bigint.SemigroupMultiply.combine(3n)), 6n) + deepStrictEqual(pipe(0n, Bigint.SemigroupMultiply.combineMany([1n, 2n, 3n])), 0n) + deepStrictEqual(pipe(2n, Bigint.SemigroupMultiply.combineMany([1n, 0n, 3n])), 0n) + }) + + it("MonoidMultiply", () => { + deepStrictEqual(Bigint.MonoidMultiply.combineAll([2n, 3n, 4n]), 24n) + }) +}) From 2536c4922a35bedd85b47290613e72c3a002b5c6 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 09:29:32 +0100 Subject: [PATCH 064/255] add Symbol module --- data.md | 8 +++++--- src/Predicate.ts | 6 ++++++ src/Symbol.ts | 11 +++++++++++ src/index.ts | 5 +++++ test/Bigint.ts | 2 +- test/Symbol.ts | 11 +++++++++++ 6 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 src/Symbol.ts create mode 100644 test/Symbol.ts diff --git a/data.md b/data.md index 59e946ffe..64e22438d 100644 --- a/data.md +++ b/data.md @@ -123,9 +123,11 @@ This section covers the various modules and combinators that work with records. ## symbols -| Module | Name | Given | To | -| ----------- | ------ | ----- | --------------------- | -| Equivalence | symbol | | `Equivalence` | +| Module | Name | Given | To | +| ----------- | -------- | ----- | ----------------------------- | +| Equivalence | symbol | | `Equivalence` | +| Predicate | isSymbol | | `Refinement` | +| Symbol | isSymbol | | `Refinement` | ## bigints diff --git a/src/Predicate.ts b/src/Predicate.ts index 9a34b85fc..755bd42c3 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -62,6 +62,12 @@ export const isBoolean: Refinement = (u: unknown): u is boolea */ export const isBigInt = (u: unknown): u is bigint => typeof u === "bigint" +/** + * @category guards + * @since 1.0.0 + */ +export const isSymbol = (u: unknown): u is symbol => typeof u === "symbol" + /** * @category constructors * @since 1.0.0 diff --git a/src/Symbol.ts b/src/Symbol.ts new file mode 100644 index 000000000..9abf22a9e --- /dev/null +++ b/src/Symbol.ts @@ -0,0 +1,11 @@ +/** + * @since 1.0.0 + */ + +import * as predicate from "@fp-ts/core/Predicate" + +/** + * @category guards + * @since 1.0.0 + */ +export const isSymbol: (u: unknown) => u is symbol = predicate.isSymbol diff --git a/src/index.ts b/src/index.ts index fc7d251ae..e4948f9e0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,6 +24,7 @@ import * as predicate from "@fp-ts/core/Predicate" import * as readonlyArray from "@fp-ts/core/ReadonlyArray" import * as readonlyRecord from "@fp-ts/core/ReadonlyRecord" import * as string from "@fp-ts/core/String" +import * as symbol from "@fp-ts/core/Symbol" import * as these from "@fp-ts/core/These" // ------------------------------------------------------------------------------------- @@ -236,6 +237,10 @@ export { * @since 1.0.0 */ string, + /** + * @since 1.0.0 + */ + symbol, /** * @since 1.0.0 */ diff --git a/test/Bigint.ts b/test/Bigint.ts index cccc0bd48..77a0fbb11 100644 --- a/test/Bigint.ts +++ b/test/Bigint.ts @@ -3,7 +3,7 @@ import { pipe } from "@fp-ts/core/Function" import { deepStrictEqual } from "@fp-ts/core/test/util" describe.concurrent("Bigint", () => { - it("isNumber", () => { + it("isBigint", () => { expect(Bigint.isBigint(1n)).toEqual(true) expect(Bigint.isBigint(1)).toEqual(false) expect(Bigint.isBigint("a")).toEqual(false) diff --git a/test/Symbol.ts b/test/Symbol.ts new file mode 100644 index 000000000..85b8cecd2 --- /dev/null +++ b/test/Symbol.ts @@ -0,0 +1,11 @@ +import * as S from "@fp-ts/core/Symbol" + +describe.concurrent("Symbol", () => { + it("isSymbol", () => { + expect(S.isSymbol(Symbol.for("@fp-ts/core/test/a"))).toEqual(true) + expect(S.isSymbol(1n)).toEqual(false) + expect(S.isSymbol(1)).toEqual(false) + expect(S.isSymbol("a")).toEqual(false) + expect(S.isSymbol(true)).toEqual(false) + }) +}) From c0571a512aa8b25231a157b6756b3dee508f2538 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 09:38:22 +0100 Subject: [PATCH 065/255] add Struct module --- src/Struct.ts | 31 +++++++++++++++++++++++++++++++ src/index.ts | 5 +++++ test/Struct.ts | 12 ++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 src/Struct.ts create mode 100644 test/Struct.ts diff --git a/src/Struct.ts b/src/Struct.ts new file mode 100644 index 000000000..25cbea7f1 --- /dev/null +++ b/src/Struct.ts @@ -0,0 +1,31 @@ +/** + * @since 1.0.0 + */ + +/** + * @since 1.0.0 + */ +export const pick = ]>( + ...keys: Keys +) => + (s: S): { [K in Keys[number]]: S[K] } => { + const out: any = {} + for (const k of keys) { + out[k] = s[k] + } + return out + } + +/** + * @since 1.0.0 + */ +export const omit = ]>( + ...keys: Keys +) => + (s: S): { [K in Exclude]: S[K] } => { + const out: any = { ...s } + for (const k of keys) { + delete out[k] + } + return out + } diff --git a/src/index.ts b/src/index.ts index e4948f9e0..4deb9f9c0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,6 +24,7 @@ import * as predicate from "@fp-ts/core/Predicate" import * as readonlyArray from "@fp-ts/core/ReadonlyArray" import * as readonlyRecord from "@fp-ts/core/ReadonlyRecord" import * as string from "@fp-ts/core/String" +import * as struct from "@fp-ts/core/Struct" import * as symbol from "@fp-ts/core/Symbol" import * as these from "@fp-ts/core/These" @@ -237,6 +238,10 @@ export { * @since 1.0.0 */ string, + /** + * @since 1.0.0 + */ + struct, /** * @since 1.0.0 */ diff --git a/test/Struct.ts b/test/Struct.ts new file mode 100644 index 000000000..66e2a3735 --- /dev/null +++ b/test/Struct.ts @@ -0,0 +1,12 @@ +import { pipe } from "@fp-ts/core/Function" +import * as S from "@fp-ts/core/Struct" + +describe.concurrent("Struct", () => { + it("pick", () => { + expect(pipe({ a: "a", b: 1, c: true }, S.pick("a", "b"))).toEqual({ a: "a", b: 1 }) + }) + + it("omit", () => { + expect(pipe({ a: "a", b: 1, c: true }, S.omit("c"))).toEqual({ a: "a", b: 1 }) + }) +}) From 0bd0d60454642d7b1692d923c2d240b747ac797b Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 12:18:58 +0100 Subject: [PATCH 066/255] add modules from @fp-ts/data --- .changeset/afraid-cars-lay.md | 5 ---- .changeset/big-weeks-kiss.md | 5 ---- .changeset/blue-books-breathe.md | 5 ---- .changeset/brave-poems-appear.md | 5 ---- .changeset/clean-goats-learn.md | 5 ---- .changeset/cyan-melons-own.md | 5 ---- .changeset/famous-parrots-shake.md | 5 ---- .changeset/four-garlics-wonder.md | 5 ---- .changeset/gold-teachers-admire.md | 5 ---- .changeset/green-kangaroos-report.md | 5 ---- .changeset/heavy-suns-buy.md | 5 ---- .changeset/modern-tomatoes-promise.md | 5 ++++ .changeset/nervous-schools-knock.md | 5 ---- .changeset/nine-bags-end.md | 5 ---- .changeset/olive-apes-suffer.md | 5 ---- .changeset/olive-pumas-trade.md | 5 ---- .changeset/pink-gorillas-sneeze.md | 5 ---- .changeset/polite-mice-begin.md | 5 ---- .changeset/popular-baboons-promise.md | 5 ---- .changeset/purple-cooks-destroy.md | 5 ---- .changeset/purple-meals-explode.md | 5 ---- .changeset/silver-experts-punch.md | 5 ---- .changeset/unlucky-chicken-try.md | 5 ---- .changeset/unlucky-knives-exercise.md | 5 ---- CHANGELOG.md | 38 +++++++++++++++++++++++++++ src/Struct.ts | 4 +++ 26 files changed, 47 insertions(+), 115 deletions(-) delete mode 100644 .changeset/afraid-cars-lay.md delete mode 100644 .changeset/big-weeks-kiss.md delete mode 100644 .changeset/blue-books-breathe.md delete mode 100644 .changeset/brave-poems-appear.md delete mode 100644 .changeset/clean-goats-learn.md delete mode 100644 .changeset/cyan-melons-own.md delete mode 100644 .changeset/famous-parrots-shake.md delete mode 100644 .changeset/four-garlics-wonder.md delete mode 100644 .changeset/gold-teachers-admire.md delete mode 100644 .changeset/green-kangaroos-report.md delete mode 100644 .changeset/heavy-suns-buy.md create mode 100644 .changeset/modern-tomatoes-promise.md delete mode 100644 .changeset/nervous-schools-knock.md delete mode 100644 .changeset/nine-bags-end.md delete mode 100644 .changeset/olive-apes-suffer.md delete mode 100644 .changeset/olive-pumas-trade.md delete mode 100644 .changeset/pink-gorillas-sneeze.md delete mode 100644 .changeset/polite-mice-begin.md delete mode 100644 .changeset/popular-baboons-promise.md delete mode 100644 .changeset/purple-cooks-destroy.md delete mode 100644 .changeset/purple-meals-explode.md delete mode 100644 .changeset/silver-experts-punch.md delete mode 100644 .changeset/unlucky-chicken-try.md delete mode 100644 .changeset/unlucky-knives-exercise.md diff --git a/.changeset/afraid-cars-lay.md b/.changeset/afraid-cars-lay.md deleted file mode 100644 index ea1e3c0ad..000000000 --- a/.changeset/afraid-cars-lay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add Either module diff --git a/.changeset/big-weeks-kiss.md b/.changeset/big-weeks-kiss.md deleted file mode 100644 index 931923006..000000000 --- a/.changeset/big-weeks-kiss.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -Semigroup: add array combinator diff --git a/.changeset/blue-books-breathe.md b/.changeset/blue-books-breathe.md deleted file mode 100644 index fe1864618..000000000 --- a/.changeset/blue-books-breathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -rename `productFlatten` to `element` diff --git a/.changeset/brave-poems-appear.md b/.changeset/brave-poems-appear.md deleted file mode 100644 index e0dd1b389..000000000 --- a/.changeset/brave-poems-appear.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add Option module diff --git a/.changeset/clean-goats-learn.md b/.changeset/clean-goats-learn.md deleted file mode 100644 index 2f4981c7f..000000000 --- a/.changeset/clean-goats-learn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add ReadonlyArray module diff --git a/.changeset/cyan-melons-own.md b/.changeset/cyan-melons-own.md deleted file mode 100644 index 7665266f3..000000000 --- a/.changeset/cyan-melons-own.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add Identity module diff --git a/.changeset/famous-parrots-shake.md b/.changeset/famous-parrots-shake.md deleted file mode 100644 index b73d5bcf9..000000000 --- a/.changeset/famous-parrots-shake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add missing readonly modifiers diff --git a/.changeset/four-garlics-wonder.md b/.changeset/four-garlics-wonder.md deleted file mode 100644 index 75dd1000b..000000000 --- a/.changeset/four-garlics-wonder.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add Predicate module diff --git a/.changeset/gold-teachers-admire.md b/.changeset/gold-teachers-admire.md deleted file mode 100644 index 9ca396e17..000000000 --- a/.changeset/gold-teachers-admire.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add ReadonlyRecord module diff --git a/.changeset/green-kangaroos-report.md b/.changeset/green-kangaroos-report.md deleted file mode 100644 index ef0285a57..000000000 --- a/.changeset/green-kangaroos-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -Order: add array combinator diff --git a/.changeset/heavy-suns-buy.md b/.changeset/heavy-suns-buy.md deleted file mode 100644 index 8c5199636..000000000 --- a/.changeset/heavy-suns-buy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add These module diff --git a/.changeset/modern-tomatoes-promise.md b/.changeset/modern-tomatoes-promise.md new file mode 100644 index 000000000..d40355a05 --- /dev/null +++ b/.changeset/modern-tomatoes-promise.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": minor +--- + +add modules from @fp-ts/data diff --git a/.changeset/nervous-schools-knock.md b/.changeset/nervous-schools-knock.md deleted file mode 100644 index 1defb228e..000000000 --- a/.changeset/nervous-schools-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -remove NonEmptyTraversable typeclass diff --git a/.changeset/nine-bags-end.md b/.changeset/nine-bags-end.md deleted file mode 100644 index 5ff72f442..000000000 --- a/.changeset/nine-bags-end.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -Order: add bigint instance diff --git a/.changeset/olive-apes-suffer.md b/.changeset/olive-apes-suffer.md deleted file mode 100644 index 54975c6ab..000000000 --- a/.changeset/olive-apes-suffer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add String module diff --git a/.changeset/olive-pumas-trade.md b/.changeset/olive-pumas-trade.md deleted file mode 100644 index 6a5413982..000000000 --- a/.changeset/olive-pumas-trade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add the prefix @fp-ts/core to the \_tag of the data types diff --git a/.changeset/pink-gorillas-sneeze.md b/.changeset/pink-gorillas-sneeze.md deleted file mode 100644 index 3b01876d4..000000000 --- a/.changeset/pink-gorillas-sneeze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add Number module diff --git a/.changeset/polite-mice-begin.md b/.changeset/polite-mice-begin.md deleted file mode 100644 index a4b66a2e5..000000000 --- a/.changeset/polite-mice-begin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add Equivalence module diff --git a/.changeset/popular-baboons-promise.md b/.changeset/popular-baboons-promise.md deleted file mode 100644 index 9446ae176..000000000 --- a/.changeset/popular-baboons-promise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -Monoid: add array, readonlyArray combinators diff --git a/.changeset/purple-cooks-destroy.md b/.changeset/purple-cooks-destroy.md deleted file mode 100644 index 3623a0b0c..000000000 --- a/.changeset/purple-cooks-destroy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -Boolean: add not combinator diff --git a/.changeset/purple-meals-explode.md b/.changeset/purple-meals-explode.md deleted file mode 100644 index 3af08023c..000000000 --- a/.changeset/purple-meals-explode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add CovariantWithIndex, FilterableWithIndex, TraversableFilterable modules diff --git a/.changeset/silver-experts-punch.md b/.changeset/silver-experts-punch.md deleted file mode 100644 index ec7026dc6..000000000 --- a/.changeset/silver-experts-punch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add Ordering module diff --git a/.changeset/unlucky-chicken-try.md b/.changeset/unlucky-chicken-try.md deleted file mode 100644 index 930cdd2ae..000000000 --- a/.changeset/unlucky-chicken-try.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add Function module diff --git a/.changeset/unlucky-knives-exercise.md b/.changeset/unlucky-knives-exercise.md deleted file mode 100644 index 7ef64bbad..000000000 --- a/.changeset/unlucky-knives-exercise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add Boolean module diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d1f2d4d9..e0c793b09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,43 @@ # @fp-ts/core +## next + +**Breaking changes** + +- `typeclass/Semiproduct` + - rename `productFlatten` to `element` + +**New Features** + +- `Boolean` + - add `not` combinator +- `Order` + - add `array` combinator + - add `bigint` instance +- `Monoid` + - add `array`, `readonlyArray` combinators +- `Semigroup` + - add `array`, `readonlyArray` combinators +- modules + - `typeclass/Equivalence` + - `typeclass/Filterable` + - `typeclass/TraversableFilterable` + - `Bigint` + - `Boolean` + - `Either` + - `Function` + - `Identity` + - `Number` + - `Option` + - `Ordering` + - `Predicate` + - `ReadonlyArray` + - `ReadonyRecord` + - `String` + - `Struct` + - `Symbol` + - `These` + ## 0.0.11 ### Patch Changes diff --git a/src/Struct.ts b/src/Struct.ts index 25cbea7f1..1efea549e 100644 --- a/src/Struct.ts +++ b/src/Struct.ts @@ -3,6 +3,8 @@ */ /** + * Create a new object by picking properties of an existing object. + * * @since 1.0.0 */ export const pick = ]>( @@ -17,6 +19,8 @@ export const pick = ]>( } /** + * Create a new object by omitting properties of an existing object. + * * @since 1.0.0 */ export const omit = ]>( From ec3f22201702f8853a8db15516b06f2871ff5b26 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 12:55:05 +0100 Subject: [PATCH 067/255] Order: make compare binary --- CHANGELOG.md | 4 +- src/Option.ts | 4 +- src/ReadonlyArray.ts | 2 +- src/typeclass/Order.ts | 104 +++++++++++++++----------------- src/typeclass/Semigroup.ts | 4 +- test/Bigint.ts | 6 +- test/Boolean.ts | 6 +- test/Number.ts | 6 +- test/Option.ts | 12 ++-- test/ReadonlyArray.ts | 34 +++++------ test/typeclass/Contravariant.ts | 6 +- test/typeclass/Order.ts | 54 ++++++++--------- 12 files changed, 118 insertions(+), 124 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0c793b09..809df28dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,10 @@ **Breaking changes** -- `typeclass/Semiproduct` +- `Semiproduct` - rename `productFlatten` to `element` +- `Order` + - make `compare` binary **New Features** diff --git a/src/Option.ts b/src/Option.ts index 0d471a218..0a5a352e3 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1139,8 +1139,8 @@ export const orElseSucceed = ( * @since 1.0.0 */ export const liftOrder = (O: Order): Order> => - order.fromCompare((that) => - (self) => isSome(self) ? (isSome(that) ? O.compare(that.value)(self.value) : 1) : -1 + order.fromCompare((self, that) => + isSome(self) ? (isSome(that) ? O.compare(self.value, that.value) : 1) : -1 ) /** diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index cfdb335a8..2fbcdee0b 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -751,7 +751,7 @@ export const lefts = (self: Iterable>): Array => { export const sort = (O: Order) => (self: Iterable): Array => { const out = Array.from(self) - out.sort((self, that) => O.compare(that)(self)) + out.sort(O.compare) return out } diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 335929de6..dc8321dff 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -15,7 +15,7 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Order { - readonly compare: (that: A) => (self: A) => -1 | 0 | 1 + readonly compare: (self: A, that: A) => -1 | 0 | 1 } /** @@ -31,7 +31,7 @@ export interface OrderTypeLambda extends TypeLambda { * @since 1.0.0 */ export const string: Order = { - compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 + compare: (self, that) => self < that ? -1 : self > that ? 1 : 0 } /** @@ -39,7 +39,7 @@ export const string: Order = { * @since 1.0.0 */ export const number: Order = { - compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 + compare: (self, that) => self < that ? -1 : self > that ? 1 : 0 } /** @@ -47,7 +47,7 @@ export const number: Order = { * @since 1.0.0 */ export const boolean: Order = { - compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 + compare: (self, that) => self < that ? -1 : self > that ? 1 : 0 } /** @@ -55,7 +55,7 @@ export const boolean: Order = { * @since 1.0.0 */ export const bigint: Order = { - compare: (that) => (self) => self < that ? -1 : self > that ? 1 : 0 + compare: (self, that) => self < that ? -1 : self > that ? 1 : 0 } /** @@ -65,7 +65,7 @@ export const bigint: Order = { * @since 1.0.0 */ export const fromCompare = (compare: Order["compare"]): Order => ({ - compare: that => self => self === that ? 0 : compare(that)(self) + compare: (self, that) => self === that ? 0 : compare(self, that) }) /** @@ -80,18 +80,16 @@ export const fromCompare = (compare: Order["compare"]): Order => ({ export const tuple = >( ...orders: { readonly [K in keyof A]: Order } ): Order> => - fromCompare(that => - self => { - let i = 0 - for (; i < orders.length - 1; i++) { - const r = orders[i].compare(that[i])(self[i]) - if (r !== 0) { - return r - } + fromCompare((self, that) => { + let i = 0 + for (; i < orders.length - 1; i++) { + const r = orders[i].compare(self[i], that[i]) + if (r !== 0) { + return r } - return orders[i].compare(that[i])(self[i]) } - ) + return orders[i].compare(self[i], that[i]) + }) /** * This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. @@ -103,32 +101,30 @@ export const tuple = >( * @since 1.0.0 */ export const array = (O: Order): Order> => - fromCompare((that) => - (self) => { - const aLen = self.length - const bLen = that.length - const len = Math.min(aLen, bLen) - for (let i = 0; i < len; i++) { - const o = O.compare(that[i])(self[i]) - if (o !== 0) { - return o - } + fromCompare((self, that) => { + const aLen = self.length + const bLen = that.length + const len = Math.min(aLen, bLen) + for (let i = 0; i < len; i++) { + const o = O.compare(self[i], that[i]) + if (o !== 0) { + return o } - return number.compare(bLen)(aLen) } - ) + return number.compare(aLen, bLen) + }) /** * @since 1.0.0 */ export const reverse = (O: Order): Order => - fromCompare(that => self => O.compare(self)(that)) + fromCompare((self, that) => O.compare(that, self)) /** * @since 1.0.0 */ export const contramap = (f: (b: B) => A) => - (self: Order): Order => fromCompare((b2) => (b1) => self.compare(f(b2))(f(b1))) + (self: Order): Order => fromCompare((b1, b2) => self.compare(f(b1), f(b2))) /** * @category instances @@ -137,35 +133,31 @@ export const contramap = (f: (b: B) => A) => export const getSemigroup = (): Semigroup> => ({ combine: (O2) => (O1) => - fromCompare(that => - self => { - const out = O1.compare(that)(self) - if (out !== 0) { - return out - } - return O2.compare(that)(self) + fromCompare((self, that) => { + const out = O1.compare(self, that) + if (out !== 0) { + return out } - ), + return O2.compare(self, that) + }), combineMany: (collection) => (self) => - fromCompare(a2 => - a1 => { - let out = self.compare(a2)(a1) + fromCompare((a1, a2) => { + let out = self.compare(a1, a2) + if (out !== 0) { + return out + } + for (const O of collection) { + out = O.compare(a1, a2) if (out !== 0) { return out } - for (const O of collection) { - out = O.compare(a2)(a1) - if (out !== 0) { - return out - } - } - return out } - ) + return out + }) }) -const empty: Order = fromCompare(() => () => 0) +const empty: Order = fromCompare(() => 0) /** * @category instances @@ -214,14 +206,14 @@ export const Product: product.Product = { * * @since 1.0.0 */ -export const lessThan = (O: Order) => (that: A) => (self: A) => O.compare(that)(self) === -1 +export const lessThan = (O: Order) => (that: A) => (self: A) => O.compare(self, that) === -1 /** * Test whether one value is _strictly greater than_ another. * * @since 1.0.0 */ -export const greaterThan = (O: Order) => (that: A) => (self: A) => O.compare(that)(self) === 1 +export const greaterThan = (O: Order) => (that: A) => (self: A) => O.compare(self, that) === 1 /** * Test whether one value is _non-strictly less than_ another. @@ -229,7 +221,7 @@ export const greaterThan = (O: Order) => (that: A) => (self: A) => O.compa * @since 1.0.0 */ export const lessThanOrEqualTo = (O: Order) => - (that: A) => (self: A) => O.compare(that)(self) !== 1 + (that: A) => (self: A) => O.compare(self, that) !== 1 /** * Test whether one value is _non-strictly greater than_ another. @@ -237,7 +229,7 @@ export const lessThanOrEqualTo = (O: Order) => * @since 1.0.0 */ export const greaterThanOrEqualTo = (O: Order) => - (that: A) => (self: A) => O.compare(that)(self) !== -1 + (that: A) => (self: A) => O.compare(self, that) !== -1 /** * Take the minimum of two values. If they are considered equal, the first argument is chosen. @@ -245,7 +237,7 @@ export const greaterThanOrEqualTo = (O: Order) => * @since 1.0.0 */ export const min = (O: Order) => - (that: A) => (self: A): A => self === that || O.compare(that)(self) < 1 ? self : that + (that: A) => (self: A): A => self === that || O.compare(self, that) < 1 ? self : that /** * Take the maximum of two values. If they are considered equal, the first argument is chosen. @@ -253,7 +245,7 @@ export const min = (O: Order) => * @since 1.0.0 */ export const max = (O: Order) => - (that: A) => (self: A): A => self === that || O.compare(that)(self) > -1 ? self : that + (that: A) => (self: A): A => self === that || O.compare(self, that) > -1 ? self : that /** * Clamp a value between a minimum and a maximum. diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 6673755bb..ec36c5743 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -242,7 +242,7 @@ export const struct = (semigroups: { readonly [K in keyof A]: Semigroup * @since 1.0.0 */ export const min = (O: Order): Semigroup => - fromCombine((that) => (self) => O.compare(that)(self) === -1 ? self : that) + fromCombine((that) => (self) => O.compare(self, that) === -1 ? self : that) /** * `Semigroup` that returns last maximum of elements. @@ -251,7 +251,7 @@ export const min = (O: Order): Semigroup => * @since 1.0.0 */ export const max = (O: Order): Semigroup => - fromCombine((that) => (self) => O.compare(that)(self) === 1 ? self : that) + fromCombine((that) => (self) => O.compare(self, that) === 1 ? self : that) /** * @category constructors diff --git a/test/Bigint.ts b/test/Bigint.ts index 77a0fbb11..164731dc9 100644 --- a/test/Bigint.ts +++ b/test/Bigint.ts @@ -36,9 +36,9 @@ describe.concurrent("Bigint", () => { }) it("Order", () => { - deepStrictEqual(pipe(1n, Bigint.Order.compare(2n)), -1) - deepStrictEqual(pipe(2n, Bigint.Order.compare(1n)), 1) - deepStrictEqual(pipe(2n, Bigint.Order.compare(2n)), 0) + deepStrictEqual(Bigint.Order.compare(1n, 2n), -1) + deepStrictEqual(Bigint.Order.compare(2n, 1n), 1) + deepStrictEqual(Bigint.Order.compare(2n, 2n), 0) }) it("SemigroupSum", () => { diff --git a/test/Boolean.ts b/test/Boolean.ts index ad34f13d9..8367ba376 100644 --- a/test/Boolean.ts +++ b/test/Boolean.ts @@ -83,8 +83,8 @@ describe.concurrent("Boolean", () => { }) it("Order", () => { - deepStrictEqual(pipe(false, Boolean.Order.compare(true)), -1) - deepStrictEqual(pipe(true, Boolean.Order.compare(false)), 1) - deepStrictEqual(pipe(true, Boolean.Order.compare(true)), 0) + deepStrictEqual(Boolean.Order.compare(false, true), -1) + deepStrictEqual(Boolean.Order.compare(true, false), 1) + deepStrictEqual(Boolean.Order.compare(true, true), 0) }) }) diff --git a/test/Number.ts b/test/Number.ts index a68aa5692..85a945f04 100644 --- a/test/Number.ts +++ b/test/Number.ts @@ -35,9 +35,9 @@ describe.concurrent("Number", () => { }) it("Order", () => { - deepStrictEqual(pipe(1, Number.Order.compare(2)), -1) - deepStrictEqual(pipe(2, Number.Order.compare(1)), 1) - deepStrictEqual(pipe(2, Number.Order.compare(2)), 0) + deepStrictEqual(Number.Order.compare(1, 2), -1) + deepStrictEqual(Number.Order.compare(2, 1), 1) + deepStrictEqual(Number.Order.compare(2, 2), 0) }) it("Bounded", () => { diff --git a/test/Option.ts b/test/Option.ts index 74912d033..3cde1acdf 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -357,12 +357,12 @@ describe.concurrent("Option", () => { it("liftOrder", () => { const OS = _.liftOrder(S.Order) - deepStrictEqual(pipe(_.none(), OS.compare(_.none())), 0) - deepStrictEqual(pipe(_.some("a"), OS.compare(_.none())), 1) - deepStrictEqual(pipe(_.none(), OS.compare(_.some("a"))), -1) - deepStrictEqual(pipe(_.some("a"), OS.compare(_.some("a"))), 0) - deepStrictEqual(pipe(_.some("a"), OS.compare(_.some("b"))), -1) - deepStrictEqual(pipe(_.some("b"), OS.compare(_.some("a"))), 1) + deepStrictEqual(OS.compare(_.none(), _.none()), 0) + deepStrictEqual(OS.compare(_.some("a"), _.none()), 1) + deepStrictEqual(OS.compare(_.none(), _.some("a")), -1) + deepStrictEqual(OS.compare(_.some("a"), _.some("a")), 0) + deepStrictEqual(OS.compare(_.some("a"), _.some("b")), -1) + deepStrictEqual(OS.compare(_.some("b"), _.some("a")), 1) }) it("flatMapNullable", () => { diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 66ac4a973..ba9cbc34c 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -1055,28 +1055,28 @@ describe.concurrent("ReadonlyArray", () => { it("liftOrder", () => { const O = RA.liftOrder(String.Order) - deepStrictEqual(O.compare([])([]), 0) - deepStrictEqual(O.compare(["a"])(["a"]), 0) + deepStrictEqual(O.compare([], []), 0) + deepStrictEqual(O.compare(["a"], ["a"]), 0) - deepStrictEqual(O.compare(["b"])(["a"]), -1) - deepStrictEqual(O.compare(["a"])(["b"]), 1) + deepStrictEqual(O.compare(["a"], ["b"]), -1) + deepStrictEqual(O.compare(["b"], ["a"]), 1) - deepStrictEqual(O.compare(["a"])([]), -1) - deepStrictEqual(O.compare([])(["a"]), 1) - deepStrictEqual(O.compare(["a", "a"])(["a"]), -1) - deepStrictEqual(O.compare(["a", "a"])(["b"]), 1) + deepStrictEqual(O.compare([], ["a"]), -1) + deepStrictEqual(O.compare(["a"], []), 1) + deepStrictEqual(O.compare(["a"], ["a", "a"]), -1) + deepStrictEqual(O.compare(["b"], ["a", "a"]), 1) - deepStrictEqual(O.compare(["a", "a"])(["a", "a"]), 0) - deepStrictEqual(O.compare(["a", "b"])(["a", "b"]), 0) + deepStrictEqual(O.compare(["a", "a"], ["a", "a"]), 0) + deepStrictEqual(O.compare(["a", "b"], ["a", "b"]), 0) - deepStrictEqual(O.compare(["a", "a"])(["a", "b"]), 1) - deepStrictEqual(O.compare(["a", "b"])(["a", "a"]), -1) + deepStrictEqual(O.compare(["a", "b"], ["a", "a"]), 1) + deepStrictEqual(O.compare(["a", "a"], ["a", "b"]), -1) - deepStrictEqual(O.compare(["a", "b"])(["b", "a"]), 1) - deepStrictEqual(O.compare(["b", "a"])(["a", "a"]), -1) - deepStrictEqual(O.compare(["b", "a"])(["a", "b"]), -1) - deepStrictEqual(O.compare(["b", "b"])(["b", "a"]), -1) - deepStrictEqual(O.compare(["b", "a"])(["b", "b"]), 1) + deepStrictEqual(O.compare(["b", "a"], ["a", "b"]), 1) + deepStrictEqual(O.compare(["a", "a"], ["b", "a"]), -1) + deepStrictEqual(O.compare(["a", "b"], ["b", "a"]), -1) + deepStrictEqual(O.compare(["b", "a"], ["b", "b"]), -1) + deepStrictEqual(O.compare(["b", "b"], ["b", "a"]), 1) }) it("isEmpty", () => { diff --git a/test/typeclass/Contravariant.ts b/test/typeclass/Contravariant.ts index de754eb91..5f8e50fd5 100644 --- a/test/typeclass/Contravariant.ts +++ b/test/typeclass/Contravariant.ts @@ -21,8 +21,8 @@ describe("Contravariant", () => { )( S.Order ) - U.deepStrictEqual(pipe(["a"], O.compare(["b"])), -1) - U.deepStrictEqual(pipe(["a"], O.compare(["a"])), 0) - U.deepStrictEqual(pipe(["b"], O.compare(["a"])), 1) + U.deepStrictEqual(O.compare(["a"], ["b"]), -1) + U.deepStrictEqual(O.compare(["a"], ["a"]), 0) + U.deepStrictEqual(O.compare(["b"], ["a"]), 1) }) }) diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index 3333f602f..aca17cdde 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -17,25 +17,25 @@ describe("Order", () => { it("tuple", () => { const O = _.tuple(string.Order, number.Order, boolean.Order) - U.deepStrictEqual(pipe(["a", 1, true], O.compare(["b", 2, true])), -1) - U.deepStrictEqual(pipe(["a", 1, true], O.compare(["a", 2, true])), -1) - U.deepStrictEqual(pipe(["a", 1, true], O.compare(["a", 1, false])), 1) + U.deepStrictEqual(O.compare(["a", 1, true], ["b", 2, true]), -1) + U.deepStrictEqual(O.compare(["a", 1, true], ["a", 2, true]), -1) + U.deepStrictEqual(O.compare(["a", 1, true], ["a", 1, false]), 1) }) it("Contravariant", () => { const O = pipe(number.Order, _.Contravariant.contramap((s: string) => s.length)) - U.deepStrictEqual(pipe("a", O.compare("b")), 0) - U.deepStrictEqual(pipe("a", O.compare("bb")), -1) - U.deepStrictEqual(pipe("aa", O.compare("b")), 1) + U.deepStrictEqual(O.compare("a", "b"), 0) + U.deepStrictEqual(O.compare("a", "bb"), -1) + U.deepStrictEqual(O.compare("aa", "b"), 1) }) it("Invariant", () => { const O = _.Invariant.imap((s: string) => [s], ([s]) => s)( string.Order ) - U.deepStrictEqual(pipe(["a"], O.compare(["b"])), -1) - U.deepStrictEqual(pipe(["a"], O.compare(["a"])), 0) - U.deepStrictEqual(pipe(["b"], O.compare(["a"])), 1) + U.deepStrictEqual(O.compare(["a"], ["b"]), -1) + U.deepStrictEqual(O.compare(["a"], ["a"]), 0) + U.deepStrictEqual(O.compare(["b"], ["a"]), 1) }) it("getSemigroup", () => { @@ -132,9 +132,9 @@ describe("Order", () => { it("reverse", () => { const O = _.reverse(number.Order) - U.deepStrictEqual(pipe(1, O.compare(2)), 1) - U.deepStrictEqual(pipe(2, O.compare(1)), -1) - U.deepStrictEqual(pipe(2, O.compare(2)), 0) + U.deepStrictEqual(O.compare(1, 2), 1) + U.deepStrictEqual(O.compare(2, 1), -1) + U.deepStrictEqual(O.compare(2, 2), 0) }) it("lessThan", () => { @@ -201,10 +201,10 @@ describe("Order", () => { string.Order, _.SemiProduct.product(number.Order) ) - U.deepStrictEqual(pipe(["a", 1], O.compare(["a", 2])), -1) - U.deepStrictEqual(pipe(["a", 1], O.compare(["a", 1])), 0) - U.deepStrictEqual(pipe(["a", 1], O.compare(["a", 0])), 1) - U.deepStrictEqual(pipe(["a", 1], O.compare(["b", 1])), -1) + U.deepStrictEqual(O.compare(["a", 1], ["a", 2]), -1) + U.deepStrictEqual(O.compare(["a", 1], ["a", 1]), 0) + U.deepStrictEqual(O.compare(["a", 1], ["a", 0]), 1) + U.deepStrictEqual(O.compare(["a", 1], ["b", 1]), -1) }) it("productMany", () => { @@ -212,29 +212,29 @@ describe("Order", () => { string.Order, _.SemiProduct.productMany([string.Order, string.Order]) ) - U.deepStrictEqual(pipe(["a", "b"], O.compare(["a", "c"])), -1) - U.deepStrictEqual(pipe(["a", "b"], O.compare(["a", "b"])), 0) - U.deepStrictEqual(pipe(["a", "b"], O.compare(["a", "a"])), 1) - U.deepStrictEqual(pipe(["a", "b"], O.compare(["b", "a"])), -1) + U.deepStrictEqual(O.compare(["a", "b"], ["a", "c"]), -1) + U.deepStrictEqual(O.compare(["a", "b"], ["a", "b"]), 0) + U.deepStrictEqual(O.compare(["a", "b"], ["a", "a"]), 1) + U.deepStrictEqual(O.compare(["a", "b"], ["b", "a"]), -1) }) }) describe("Product", () => { it("of", () => { const O = _.Product.of("a") - U.deepStrictEqual(pipe("b", O.compare("a")), 0) - U.deepStrictEqual(pipe("a", O.compare("a")), 0) - U.deepStrictEqual(pipe("a", O.compare("b")), 0) + U.deepStrictEqual(O.compare("b", "a"), 0) + U.deepStrictEqual(O.compare("a", "a"), 0) + U.deepStrictEqual(O.compare("a", "b"), 0) }) it("productAll", () => { const O = pipe( _.Product.productAll([string.Order, string.Order, string.Order]) ) - U.deepStrictEqual(pipe(["a", "b"], O.compare(["a", "c"])), -1) - U.deepStrictEqual(pipe(["a", "b"], O.compare(["a", "b"])), 0) - U.deepStrictEqual(pipe(["a", "b"], O.compare(["a", "a"])), 1) - U.deepStrictEqual(pipe(["a", "b"], O.compare(["b", "a"])), -1) + U.deepStrictEqual(O.compare(["a", "b"], ["a", "c"]), -1) + U.deepStrictEqual(O.compare(["a", "b"], ["a", "b"]), 0) + U.deepStrictEqual(O.compare(["a", "b"], ["a", "a"]), 1) + U.deepStrictEqual(O.compare(["a", "b"], ["b", "a"]), -1) }) }) }) From 5eef6a9224ca60e09cf4f133873a0eddcebbf470 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 14:28:18 +0100 Subject: [PATCH 068/255] Semigroup: make combine binary --- CHANGELOG.md | 2 + src/Bigint.ts | 6 ++- src/Boolean.ts | 6 ++- src/Function.ts | 2 +- src/Identity.ts | 2 +- src/Number.ts | 6 ++- src/Option.ts | 9 ++--- src/Ordering.ts | 2 +- src/Predicate.ts | 7 ++-- src/ReadonlyArray.ts | 13 ++++--- src/String.ts | 3 +- src/typeclass/Equivalence.ts | 2 +- src/typeclass/Order.ts | 17 ++++---- src/typeclass/SemiApplicative.ts | 2 +- src/typeclass/SemiCoproduct.ts | 3 +- src/typeclass/Semigroup.ts | 64 +++++++++++++------------------ test/Bigint.ts | 4 +- test/Function.ts | 8 ++-- test/Number.ts | 4 +- test/Option.ts | 10 ++--- test/Ordering.ts | 20 +++++----- test/Predicate.ts | 8 ++-- test/ReadonlyArray.ts | 28 +++++++------- test/String.ts | 2 +- test/typeclass/Applicative.ts | 9 ++--- test/typeclass/Coproduct.ts | 15 ++++---- test/typeclass/Equivalence.ts | 2 +- test/typeclass/Invariant.ts | 12 +++--- test/typeclass/Monoid.ts | 10 ++--- test/typeclass/Order.ts | 4 +- test/typeclass/Product.ts | 9 ++--- test/typeclass/SemiApplicative.ts | 8 ++-- test/typeclass/SemiCoproduct.ts | 9 ++--- test/typeclass/SemiProduct.ts | 4 +- test/typeclass/Semigroup.ts | 20 +++++----- 35 files changed, 164 insertions(+), 168 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 809df28dd..44cd53a15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ **Breaking changes** +- `Semigroup` + - make `combine` binary - `Semiproduct` - rename `productFlatten` to `element` - `Order` diff --git a/src/Bigint.ts b/src/Bigint.ts index 4c3095dce..9860f19a3 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -17,12 +17,14 @@ export const isBigint: (u: unknown) => u is bigint = predicate.isBigInt /** * @since 1.0.0 */ -export const sum: (that: bigint) => (self: bigint) => bigint = semigroup.bigintSum.combine +export const sum = (that: bigint) => + (self: bigint): bigint => semigroup.bigintSum.combine(self, that) /** * @since 1.0.0 */ -export const multiply: (that: bigint) => (self: bigint) => bigint = semigroup.bigintMultiply.combine +export const multiply = (that: bigint) => + (self: bigint): bigint => semigroup.bigintMultiply.combine(self, that) /** * @since 1.0.0 diff --git a/src/Boolean.ts b/src/Boolean.ts index 1b2b4e0c1..bd07985dd 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -106,13 +106,15 @@ export const MonoidAny: monoid.Monoid = monoid.booleanAny * @category combinators * @since 1.0.0 */ -export const and: (that: boolean) => (self: boolean) => boolean = semigroup.booleanAll.combine +export const and = (that: boolean) => + (self: boolean): boolean => semigroup.booleanAll.combine(self, that) /** * @category combinators * @since 1.0.0 */ -export const or: (that: boolean) => (self: boolean) => boolean = semigroup.booleanAny.combine +export const or = (that: boolean) => + (self: boolean): boolean => semigroup.booleanAny.combine(self, that) /** * @category combinators diff --git a/src/Function.ts b/src/Function.ts index 6326f46fc..109a6c259 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -49,7 +49,7 @@ export const compose: (bc: (b: B) => C) => (ab: (a: A) => B) => (a: A) */ export const getSemigroup = (Semigroup: semigroup.Semigroup) => (): semigroup.Semigroup<(a: A) => S> => - semigroup.fromCombine((that) => (self) => (a) => Semigroup.combine(that(a))(self(a))) + semigroup.fromCombine((self, that) => (a) => Semigroup.combine(self(a), that(a))) /** * Unary functions form a monoid as long as you can provide a monoid for the codomain. diff --git a/src/Identity.ts b/src/Identity.ts index 8e88771fd..59cd59f0b 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -404,7 +404,7 @@ export const getSemiCoproduct = ( S: Semigroup ): semiCoproduct.SemiCoproduct> => ({ imap: Invariant.imap, - coproduct: S.combine, + coproduct: (that) => (self) => S.combine(self, that), coproductMany: S.combineMany }) diff --git a/src/Number.ts b/src/Number.ts index 8aabd0ff6..49ddd27eb 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -19,12 +19,14 @@ export const isNumber: Refinement = predicate.isNumber /** * @since 1.0.0 */ -export const sum: (that: number) => (self: number) => number = semigroup.numberSum.combine +export const sum = (that: number) => + (self: number): number => semigroup.numberSum.combine(self, that) /** * @since 1.0.0 */ -export const multiply: (that: number) => (self: number) => number = semigroup.numberMultiply.combine +export const multiply = (that: number) => + (self: number): number => semigroup.numberMultiply.combine(self, that) /** * @since 1.0.0 diff --git a/src/Option.ts b/src/Option.ts index 0a5a352e3..9c4477cfa 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -543,23 +543,22 @@ export const SemiApplicative: semiApplicative.SemiApplicative export const getMonoid = ( Semigroup: Semigroup ): Monoid> => { - const combine = (that: Option) => - (self: Option): Option => - isNone(self) ? that : isNone(that) ? self : some(Semigroup.combine(that.value)(self.value)) + const combine = (self: Option, that: Option): Option => + isNone(self) ? that : isNone(that) ? self : some(Semigroup.combine(self.value, that.value)) return ({ combine, combineMany: (others) => (start) => { let c = start for (const o of others) { - c = combine(o)(c) + c = combine(c, o) } return c }, combineAll: (collection: Iterable>): Option => { let c: Option = option.none for (const o of collection) { - c = combine(o)(c) + c = combine(c, o) } return c }, diff --git a/src/Ordering.ts b/src/Ordering.ts index 9e9cc526a..67ccf3917 100644 --- a/src/Ordering.ts +++ b/src/Ordering.ts @@ -31,7 +31,7 @@ export const match = ( * @since 1.0.0 */ export const Semigroup: semigroup.Semigroup = { - combine: (that) => (self) => self !== 0 ? self : that, + combine: (self, that) => self !== 0 ? self : that, combineMany: (collection) => (self) => { let ordering = self diff --git a/src/Predicate.ts b/src/Predicate.ts index 755bd42c3..fb3fe7e63 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { constFalse, constTrue } from "@fp-ts/core/Function" +import { constFalse, constTrue, pipe } from "@fp-ts/core/Function" import type { TypeLambda } from "@fp-ts/core/HKT" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" @@ -274,7 +274,8 @@ export const and = (that: Predicate) => * @category instances * @since 1.0.0 */ -export const getSemigroupAny = (): semigroup.Semigroup> => semigroup.fromCombine(or) +export const getSemigroupAny = (): semigroup.Semigroup> => + semigroup.fromCombine((self, that) => pipe(self, or(that))) /** * @category instances @@ -295,7 +296,7 @@ export const getMonoidAny = (): monoid.Monoid> => { * @since 1.0.0 */ export const getSemigroupAll = (): semigroup.Semigroup> => - semigroup.fromCombine(and) + semigroup.fromCombine((self, that) => pipe(self, and(that))) /** * @category instances diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 2fbcdee0b..f3689b551 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1876,7 +1876,7 @@ export const foldMap: (M: Monoid) => (f: (a: A) => M) => (self: Readonl export const foldMapWithIndex = (Monoid: Monoid) => (f: (a: A, i: number) => M) => (self: ReadonlyArray): M => - self.reduce((m, a, i) => Monoid.combine(f(a, i))(m), Monoid.empty) + self.reduce((m, a, i) => Monoid.combine(m, f(a, i)), Monoid.empty) /** * @category folding @@ -1892,7 +1892,7 @@ export const foldMapNonEmpty = (S: Semigroup) => export const foldMapNonEmptyWithIndex = (S: Semigroup) => (f: (a: A, i: number) => S) => (self: NonEmptyReadonlyArray): S => - tailNonEmpty(self).reduce((s, a, i) => S.combine(f(a, i + 1))(s), f(headNonEmpty(self), 0)) + tailNonEmpty(self).reduce((s, a, i) => S.combine(s, f(a, i + 1)), f(headNonEmpty(self), 0)) /** * @category folding @@ -2107,7 +2107,7 @@ export const extend = ( */ export const min = (O: Order): ((self: NonEmptyReadonlyArray) => A) => { const S = semigroup.min(O) - return (self) => self.reduce((a, acc) => S.combine(acc)(a)) + return (self) => self.reduce(S.combine) } /** @@ -2115,7 +2115,7 @@ export const min = (O: Order): ((self: NonEmptyReadonlyArray) => A) => */ export const max = (O: Order): ((self: NonEmptyReadonlyArray) => A) => { const S = semigroup.max(O) - return (self) => self.reduce((a, acc) => S.combine(acc)(a)) + return (self) => self.reduce(S.combine) } /** @@ -2139,7 +2139,7 @@ export const unfold = (b: B, f: (b: B) => Option): Array< * @since 1.0.0 */ export const getUnionSemigroup = (equivalence: Equivalence): Semigroup> => - fromCombine(union(equivalence)) as any + fromCombine((self, that) => pipe(self, union(equivalence)(that))) /** * @category instances @@ -2161,7 +2161,8 @@ export const getUnionMonoid = (equivalence: Equivalence): Monoid( equivalence: Equivalence -): Semigroup> => fromCombine(intersection(equivalence)) as any +): Semigroup> => + fromCombine((self, that) => pipe(self, intersection(equivalence)(that))) /** * Returns a `Semigroup` for `ReadonlyArray`. diff --git a/src/String.ts b/src/String.ts index 747df0de3..54d974db4 100644 --- a/src/String.ts +++ b/src/String.ts @@ -55,7 +55,8 @@ export const empty: "" = "" as const /** * @since 1.0.0 */ -export const concat: (that: string) => (self: string) => string = semigroup.string.combine +export const concat = (that: string) => + (self: string): string => semigroup.string.combine(self, that) /** * @example diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 6e6f5d38e..018949791 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -142,7 +142,7 @@ export const record = ( * @since 2.10.0 */ export const getSemigroup = (): Semigroup> => ({ - combine: (that) => (self) => (x, y) => self(x, y) && that(x, y), + combine: (self, that) => (x, y) => self(x, y) && that(x, y), combineMany: (collection) => self => (x, y) => { diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index dc8321dff..1f42f37d9 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -131,15 +131,14 @@ export const contramap = (f: (b: B) => A) => * @since 1.0.0 */ export const getSemigroup = (): Semigroup> => ({ - combine: (O2) => - (O1) => - fromCompare((self, that) => { - const out = O1.compare(self, that) - if (out !== 0) { - return out - } - return O2.compare(self, that) - }), + combine: (O1, O2) => + fromCompare((self, that) => { + const out = O1.compare(self, that) + if (out !== 0) { + return out + } + return O2.compare(self, that) + }), combineMany: (collection) => (self) => fromCompare((a1, a2) => { diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 064dc041b..a83b700f2 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -20,7 +20,7 @@ export interface SemiApplicative extends SemiProduct, C */ export const liftSemigroup = (F: SemiApplicative) => (S: Semigroup): Semigroup> => ({ - combine: that => self => pipe(self, F.product(that), F.map(([a1, a2]) => S.combine(a2)(a1))), + combine: (self, that) => pipe(self, F.product(that), F.map(([a1, a2]) => S.combine(a1, a2))), combineMany: collection => self => pipe( diff --git a/src/typeclass/SemiCoproduct.ts b/src/typeclass/SemiCoproduct.ts index d13d6e044..c1523d660 100644 --- a/src/typeclass/SemiCoproduct.ts +++ b/src/typeclass/SemiCoproduct.ts @@ -1,6 +1,7 @@ /** * @since 1.0.0 */ +import { pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" @@ -28,6 +29,6 @@ export const getSemigroup = (F: SemiCoproduct) => (): Semigroup< Kind > => ({ - combine: F.coproduct, + combine: (self, that) => pipe(self, F.coproduct(that)), combineMany: F.coproductMany }) diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index ec36c5743..4d14c9f94 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -31,7 +31,7 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Semigroup { - readonly combine: (that: A) => (self: A) => A + readonly combine: (self: A, that: A) => A readonly combineMany: (collection: Iterable) => (self: A) => A } @@ -55,7 +55,7 @@ export const fromCombine = (combine: Semigroup["combine"]): Semigroup = (self) => { let out: A = self for (const a of collection) { - out = combine(a)(out) + out = combine(out, a) } return out } @@ -65,9 +65,7 @@ export const fromCombine = (combine: Semigroup["combine"]): Semigroup = * @category instances * @since 1.0.0 */ -export const string: Semigroup = fromCombine((that: string) => - (self: string): string => self + that -) +export const string: Semigroup = fromCombine((self, that) => self + that) /** * `number` semigroup under addition. @@ -75,9 +73,7 @@ export const string: Semigroup = fromCombine((that: string) => * @category instances * @since 1.0.0 */ -export const numberSum: Semigroup = fromCombine((that: number) => - (self: number): number => self + that -) +export const numberSum: Semigroup = fromCombine((self, that) => self + that) /** * `number` semigroup under multiplication. @@ -86,7 +82,7 @@ export const numberSum: Semigroup = fromCombine((that: number) => * @since 1.0.0 */ export const numberMultiply: Semigroup = { - combine: (that: number) => (self: number): number => self * that, + combine: (self, that) => self * that, combineMany: (collection) => (self) => { if (self === 0) { @@ -109,9 +105,7 @@ export const numberMultiply: Semigroup = { * @category instances * @since 1.0.0 */ -export const bigintSum: Semigroup = fromCombine((that: bigint) => - (self: bigint): bigint => self + that -) +export const bigintSum: Semigroup = fromCombine((self, that) => self + that) /** * `bigint` semigroup under multiplication. @@ -120,7 +114,7 @@ export const bigintSum: Semigroup = fromCombine((that: bigint) => * @since 1.0.0 */ export const bigintMultiply: Semigroup = { - combine: (that: bigint) => (self: bigint): bigint => self * that, + combine: (self, that) => self * that, combineMany: (collection) => (self) => { if (self === 0n) { @@ -144,7 +138,7 @@ export const bigintMultiply: Semigroup = { * @since 1.0.0 */ export const booleanAll: Semigroup = { - combine: (that: boolean) => (self: boolean): boolean => self && that, + combine: (self, that) => self && that, combineMany: (collection) => (self) => { if (self === false) { @@ -166,7 +160,7 @@ export const booleanAll: Semigroup = { * @since 1.0.0 */ export const booleanAny: Semigroup = { - combine: (that: boolean) => (self: boolean): boolean => self || that, + combine: (self, that) => self || that, combineMany: (collection) => (self) => { if (self === true) { @@ -192,7 +186,7 @@ export const booleanAny: Semigroup = { export const tuple = >( ...semigroups: { readonly [K in keyof A]: Semigroup } ): Semigroup => - fromCombine((that) => (self) => semigroups.map((S, i) => S.combine(that[i])(self[i])) as any) + fromCombine((self, that) => semigroups.map((S, i) => S.combine(self[i], that[i])) as any) /** * Given a type `A`, this function creates and returns a `Semigroup` for `Array`. @@ -201,7 +195,7 @@ export const tuple = >( * @category combinators * @since 1.0.0 */ -export const array = (): Semigroup> => fromCombine(that => self => self.concat(that)) +export const array = (): Semigroup> => fromCombine((self, that) => self.concat(that)) /** * Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. @@ -223,17 +217,15 @@ export const readonlyArray: () => Semigroup> = array as any export const struct = (semigroups: { readonly [K in keyof A]: Semigroup }): Semigroup< { readonly [K in keyof A]: A[K] } > => - fromCombine((that) => - (self) => { - const r = {} as any - for (const k in semigroups) { - if (Object.prototype.hasOwnProperty.call(semigroups, k)) { - r[k] = semigroups[k].combine(that[k])(self[k]) - } + fromCombine((self, that) => { + const r = {} as any + for (const k in semigroups) { + if (Object.prototype.hasOwnProperty.call(semigroups, k)) { + r[k] = semigroups[k].combine(self[k], that[k]) } - return r } - ) + return r + }) /** * `Semigroup` that returns last minimum of elements. @@ -242,7 +234,7 @@ export const struct = (semigroups: { readonly [K in keyof A]: Semigroup * @since 1.0.0 */ export const min = (O: Order): Semigroup => - fromCombine((that) => (self) => O.compare(self, that) === -1 ? self : that) + fromCombine((self, that) => O.compare(self, that) === -1 ? self : that) /** * `Semigroup` that returns last maximum of elements. @@ -251,14 +243,14 @@ export const min = (O: Order): Semigroup => * @since 1.0.0 */ export const max = (O: Order): Semigroup => - fromCombine((that) => (self) => O.compare(self, that) === 1 ? self : that) + fromCombine((self, that) => O.compare(self, that) === 1 ? self : that) /** * @category constructors * @since 1.0.0 */ export const constant = (a: A): Semigroup => ({ - combine: () => () => a, + combine: () => a, combineMany: () => () => a }) @@ -268,12 +260,12 @@ export const constant = (a: A): Semigroup => ({ * @since 1.0.0 */ export const reverse = (S: Semigroup): Semigroup => ({ - combine: (that) => (self) => S.combine(self)(that), + combine: (self, that) => S.combine(that, self), combineMany: (collection) => (self) => { const reversed = Array.from(collection).reverse() return reversed.length > 0 ? - S.combine(self)(S.combineMany(reversed.slice(1))(reversed[0])) : + S.combine(S.combineMany(reversed.slice(1))(reversed[0]), self) : self } }) @@ -283,9 +275,7 @@ export const reverse = (S: Semigroup): Semigroup => ({ */ export const intercalate = (separator: A) => (S: Semigroup): Semigroup => - fromCombine( - (that) => S.combineMany([separator, that]) - ) + fromCombine((self, that) => S.combineMany([separator, that])(self)) /** * Always return the first argument. @@ -294,7 +284,7 @@ export const intercalate = (separator: A) => * @since 1.0.0 */ export const first = (): Semigroup => ({ - combine: () => a => a, + combine: (a) => a, combineMany: () => a => a }) @@ -305,7 +295,7 @@ export const first = (): Semigroup => ({ * @since 1.0.0 */ export const last = (): Semigroup => ({ - combine: second => () => second, + combine: (_, second) => second, combineMany: collection => self => { let a: A = self @@ -323,7 +313,7 @@ export const imap = ( from: (b: B) => A ) => (S: Semigroup): Semigroup => ({ - combine: that => self => to(S.combine(from(that))(from(self))), + combine: (self, that) => to(S.combine(from(self), from(that))), combineMany: (collection) => self => to( diff --git a/test/Bigint.ts b/test/Bigint.ts index 164731dc9..02f76c44f 100644 --- a/test/Bigint.ts +++ b/test/Bigint.ts @@ -42,7 +42,7 @@ describe.concurrent("Bigint", () => { }) it("SemigroupSum", () => { - deepStrictEqual(pipe(2n, Bigint.SemigroupSum.combine(3n)), 5n) + deepStrictEqual(Bigint.SemigroupSum.combine(2n, 3n), 5n) }) it("MonoidSum", () => { @@ -50,7 +50,7 @@ describe.concurrent("Bigint", () => { }) it("SemigroupMultiply", () => { - deepStrictEqual(pipe(2n, Bigint.SemigroupMultiply.combine(3n)), 6n) + deepStrictEqual(Bigint.SemigroupMultiply.combine(2n, 3n), 6n) deepStrictEqual(pipe(0n, Bigint.SemigroupMultiply.combineMany([1n, 2n, 3n])), 0n) deepStrictEqual(pipe(2n, Bigint.SemigroupMultiply.combineMany([1n, 0n, 3n])), 0n) }) diff --git a/test/Function.ts b/test/Function.ts index 6f9c6e5e9..2bbcc7d75 100644 --- a/test/Function.ts +++ b/test/Function.ts @@ -11,7 +11,7 @@ describe.concurrent("Function", () => { it("getSemigroup", () => { const S = Function.getSemigroup(Number.SemigroupSum)() const f = (s: string) => s === "a" ? 0 : 1 - const g = Function.pipe(size, S.combine(f)) + const g = S.combine(size, f) deepStrictEqual(g(""), 1) deepStrictEqual(g("a"), 1) deepStrictEqual(g("b"), 2) @@ -21,12 +21,12 @@ describe.concurrent("Function", () => { it("getMonoid", () => { const M = Function.getMonoid(Number.MonoidSum)() const f = (s: string) => s === "a" ? 0 : 1 - const g = Function.pipe(size, M.combine(f)) + const g = M.combine(size, f) deepStrictEqual(g(""), 1) deepStrictEqual(g("a"), 1) deepStrictEqual(g("b"), 2) - deepStrictEqual(Function.pipe(size, M.combine(M.empty))("a"), 1) - deepStrictEqual(Function.pipe(M.empty, M.combine(size))("a"), 1) + deepStrictEqual(M.combine(size, M.empty)("a"), 1) + deepStrictEqual(M.combine(M.empty, size)("a"), 1) deepStrictEqual(M.combineAll([size, size])("a"), 2) }) diff --git a/test/Number.ts b/test/Number.ts index 85a945f04..7f7cf69ea 100644 --- a/test/Number.ts +++ b/test/Number.ts @@ -46,7 +46,7 @@ describe.concurrent("Number", () => { }) it("SemigroupSum", () => { - deepStrictEqual(pipe(2, Number.SemigroupSum.combine(3)), 5) + deepStrictEqual(Number.SemigroupSum.combine(2, 3), 5) }) it("MonoidSum", () => { @@ -54,7 +54,7 @@ describe.concurrent("Number", () => { }) it("SemigroupMultiply", () => { - deepStrictEqual(pipe(2, Number.SemigroupMultiply.combine(3)), 6) + deepStrictEqual(Number.SemigroupMultiply.combine(2, 3), 6) deepStrictEqual(pipe(0, Number.SemigroupMultiply.combineMany([1, 2, 3])), 0) deepStrictEqual(pipe(2, Number.SemigroupMultiply.combineMany([1, 0, 3])), 0) }) diff --git a/test/Option.ts b/test/Option.ts index 3cde1acdf..b897eeaf9 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -409,11 +409,11 @@ describe.concurrent("Option", () => { it("getMonoid", () => { const M = _.getMonoid(S.Semigroup) - deepStrictEqual(pipe(_.none(), M.combine(_.none())), _.none()) - deepStrictEqual(pipe(_.none(), M.combine(_.some("a"))), _.some("a")) - deepStrictEqual(pipe(_.some("a"), M.combine(_.none())), _.some("a")) - deepStrictEqual(pipe(_.some("b"), M.combine(_.some("a"))), _.some("ba")) - deepStrictEqual(pipe(_.some("a"), M.combine(_.some("b"))), _.some("ab")) + deepStrictEqual(M.combine(_.none(), _.none()), _.none()) + deepStrictEqual(M.combine(_.none(), _.some("a")), _.some("a")) + deepStrictEqual(M.combine(_.some("a"), _.none()), _.some("a")) + deepStrictEqual(M.combine(_.some("b"), _.some("a")), _.some("ba")) + deepStrictEqual(M.combine(_.some("a"), _.some("b")), _.some("ab")) deepStrictEqual(pipe(_.some("a"), M.combineMany([_.some("b")])), _.some("ab")) deepStrictEqual(pipe(_.none(), M.combineMany([_.some("b")])), _.some("b")) diff --git a/test/Ordering.ts b/test/Ordering.ts index 55580eaec..091af1c5a 100644 --- a/test/Ordering.ts +++ b/test/Ordering.ts @@ -21,10 +21,10 @@ describe("Ordering", () => { }) it("Semigroup", () => { - deepStrictEqual(pipe(0, _.Semigroup.combine(0)), 0) - deepStrictEqual(pipe(0, _.Semigroup.combine(1)), 1) - deepStrictEqual(pipe(1, _.Semigroup.combine(-1)), 1) - deepStrictEqual(pipe(-1, _.Semigroup.combine(1)), -1) + deepStrictEqual(_.Semigroup.combine(0, 0), 0) + deepStrictEqual(_.Semigroup.combine(0, 1), 1) + deepStrictEqual(_.Semigroup.combine(1, -1), 1) + deepStrictEqual(_.Semigroup.combine(-1, 1), -1) deepStrictEqual(pipe(0, _.Semigroup.combineMany([])), 0) deepStrictEqual(pipe(1, _.Semigroup.combineMany([])), 1) @@ -36,11 +36,11 @@ describe("Ordering", () => { }) it("Monoid", () => { - deepStrictEqual(pipe(_.Monoid.empty, _.Monoid.combine(0)), 0) - deepStrictEqual(pipe(_.Monoid.empty, _.Monoid.combine(1)), 1) - deepStrictEqual(pipe(_.Monoid.empty, _.Monoid.combine(-1)), -1) - deepStrictEqual(pipe(0, _.Monoid.combine(_.Monoid.empty)), 0) - deepStrictEqual(pipe(1, _.Monoid.combine(_.Monoid.empty)), 1) - deepStrictEqual(pipe(-1, _.Monoid.combine(_.Monoid.empty)), -1) + deepStrictEqual(_.Monoid.combine(_.Monoid.empty, 0), 0) + deepStrictEqual(_.Monoid.combine(_.Monoid.empty, 1), 1) + deepStrictEqual(_.Monoid.combine(_.Monoid.empty, -1), -1) + deepStrictEqual(_.Monoid.combine(0, _.Monoid.empty), 0) + deepStrictEqual(_.Monoid.combine(1, _.Monoid.empty), 1) + deepStrictEqual(_.Monoid.combine(-1, _.Monoid.empty), -1) }) }) diff --git a/test/Predicate.ts b/test/Predicate.ts index b675bf30f..269e68f27 100644 --- a/test/Predicate.ts +++ b/test/Predicate.ts @@ -115,7 +115,7 @@ describe.concurrent("Predicate", () => { it("getSemigroupAny", () => { const S = _.getSemigroupAny() - const predicate = pipe(isPositive, S.combine(isNegative)) + const predicate = S.combine(isPositive, isNegative) deepStrictEqual(predicate(0), false) deepStrictEqual(predicate(-1), true) deepStrictEqual(predicate(1), true) @@ -123,7 +123,7 @@ describe.concurrent("Predicate", () => { it("getMonoidAny", () => { const M = _.getMonoidAny() - const predicate = pipe(isPositive, M.combine(M.empty)) + const predicate = M.combine(isPositive, M.empty) deepStrictEqual(predicate(0), isPositive(0)) deepStrictEqual(predicate(-1), isPositive(-1)) deepStrictEqual(predicate(1), isPositive(1)) @@ -131,7 +131,7 @@ describe.concurrent("Predicate", () => { it("getSemigroupAll", () => { const S = _.getSemigroupAll() - const predicate = pipe(isPositive, S.combine(isLessThan2)) + const predicate = S.combine(isPositive, isLessThan2) deepStrictEqual(predicate(0), false) deepStrictEqual(predicate(-2), false) deepStrictEqual(predicate(1), true) @@ -139,7 +139,7 @@ describe.concurrent("Predicate", () => { it("getMonoidAll", () => { const M = _.getMonoidAll() - const predicate = pipe(isPositive, M.combine(M.empty)) + const predicate = M.combine(isPositive, M.empty) deepStrictEqual(predicate(0), isPositive(0)) deepStrictEqual(predicate(-1), isPositive(-1)) deepStrictEqual(predicate(1), isPositive(1)) diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index ba9cbc34c..89b7281e9 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -1045,10 +1045,10 @@ describe.concurrent("ReadonlyArray", () => { it("getMonoid", () => { const M = RA.getMonoid() - deepStrictEqual(M.combine([3, 4])([1, 2]), [1, 2, 3, 4]) + deepStrictEqual(M.combine([1, 2], [3, 4]), [1, 2, 3, 4]) const x = [1, 2] - deepStrictEqual(M.combine(M.empty)(x), x) - deepStrictEqual(M.combine(x)(M.empty), x) + deepStrictEqual(M.combine(x, M.empty), x) + deepStrictEqual(M.combine(M.empty, x), x) deepStrictEqual(M.combineAll([[1, 2], [3, 4, 5], [5, 6, 7, 1]]), [1, 2, 3, 4, 5, 5, 6, 7, 1]) }) @@ -1460,12 +1460,12 @@ describe.concurrent("ReadonlyArray", () => { it("getSemigroup", () => { const S = RA.getSemigroup() - expect(pipe([1, 2], S.combine([2, 3]))).toEqual([1, 2, 2, 3]) + expect(S.combine([1, 2], [2, 3])).toEqual([1, 2, 2, 3]) }) it("getUnionSemigroup", () => { const S = RA.getUnionSemigroup(Number.Equivalence) - expect(pipe([1, 2], S.combine([2, 3]))).toEqual([1, 2, 3]) + expect(S.combine([1, 2], [2, 3])).toEqual([1, 2, 3]) }) it("intersection", () => { @@ -1485,22 +1485,22 @@ describe.concurrent("ReadonlyArray", () => { it("getUnionMonoid", () => { const M = RA.getUnionMonoid(Number.Equivalence) const two: ReadonlyArray = [1, 2] - deepStrictEqual(M.combine([3, 4])(two), [1, 2, 3, 4]) - deepStrictEqual(M.combine([2, 3])(two), [1, 2, 3]) - deepStrictEqual(M.combine([1, 2])(two), [1, 2]) + deepStrictEqual(M.combine(two, [3, 4]), [1, 2, 3, 4]) + deepStrictEqual(M.combine(two, [2, 3]), [1, 2, 3]) + deepStrictEqual(M.combine(two, [1, 2]), [1, 2]) - deepStrictEqual(M.combine(two)(M.empty), two) - deepStrictEqual(M.combine(M.empty)(two), two) - deepStrictEqual(M.combine(M.empty)(M.empty), M.empty) + deepStrictEqual(M.combine(M.empty, two), two) + deepStrictEqual(M.combine(two, M.empty), two) + deepStrictEqual(M.combine(M.empty, M.empty), M.empty) deepStrictEqual(M.combineAll([[1, 2], [3, 4, 5], [5, 6, 7, 1]]), [1, 2, 3, 4, 5, 6, 7]) }) it("getIntersectionSemigroup", () => { const S = RA.getIntersectionSemigroup(Number.Equivalence) - deepStrictEqual(S.combine([1, 2])([3, 4]), []) - deepStrictEqual(S.combine([1, 2])([2, 3]), [2]) - deepStrictEqual(S.combine([1, 2])([1, 2]), [1, 2]) + deepStrictEqual(S.combine([3, 4], [1, 2]), []) + deepStrictEqual(S.combine([2, 3], [1, 2]), [2]) + deepStrictEqual(S.combine([1, 2], [1, 2]), [1, 2]) }) it("should be safe when calling map with a binary function", () => { diff --git a/test/String.ts b/test/String.ts index 31f099c75..fba32f3c7 100644 --- a/test/String.ts +++ b/test/String.ts @@ -15,7 +15,7 @@ describe.concurrent("String", () => { }) it("Semigroup", () => { - expect(String.Semigroup.combine("b")("a")).toEqual("ab") + expect(String.Semigroup.combine("a", "b")).toEqual("ab") expect(String.Semigroup.combineMany(["b", "c"])("a")).toEqual("abc") expect(String.Semigroup.combineMany([])("a")).toEqual("a") }) diff --git a/test/typeclass/Applicative.ts b/test/typeclass/Applicative.ts index c62252223..fb426b75d 100644 --- a/test/typeclass/Applicative.ts +++ b/test/typeclass/Applicative.ts @@ -1,4 +1,3 @@ -import { pipe } from "@fp-ts/core/Function" import * as N from "@fp-ts/core/Number" import * as O from "@fp-ts/core/Option" import * as _ from "@fp-ts/core/typeclass/Applicative" @@ -8,9 +7,9 @@ describe("Applicative", () => { it("liftMonoid", () => { const liftMonoid = _.liftMonoid(O.Applicative) const M = liftMonoid(N.MonoidSum) - U.deepStrictEqual(pipe(O.none(), M.combine(O.none())), O.none()) - U.deepStrictEqual(pipe(O.some(1), M.combine(O.none())), O.none()) - U.deepStrictEqual(pipe(O.none(), M.combine(O.some(2))), O.none()) - U.deepStrictEqual(pipe(O.some(1), M.combine(O.some(2))), O.some(3)) + U.deepStrictEqual(M.combine(O.none(), O.none()), O.none()) + U.deepStrictEqual(M.combine(O.some(1), O.none()), O.none()) + U.deepStrictEqual(M.combine(O.none(), O.some(2)), O.none()) + U.deepStrictEqual(M.combine(O.some(1), O.some(2)), O.some(3)) }) }) diff --git a/test/typeclass/Coproduct.ts b/test/typeclass/Coproduct.ts index 0a138b74e..93c2fe019 100644 --- a/test/typeclass/Coproduct.ts +++ b/test/typeclass/Coproduct.ts @@ -1,4 +1,3 @@ -import { pipe } from "@fp-ts/core/Function" import * as O from "@fp-ts/core/Option" import * as _ from "@fp-ts/core/typeclass/Coproduct" import * as U from "../util" @@ -6,13 +5,13 @@ import * as U from "../util" describe("Coproduct", () => { it("getMonoid", () => { const M = _.getMonoid(O.Alternative)() - U.deepStrictEqual(pipe(O.none(), M.combine(O.none())), O.none()) - U.deepStrictEqual(pipe(O.some(1), M.combine(O.none())), O.some(1)) - U.deepStrictEqual(pipe(O.none(), M.combine(O.some(2))), O.some(2)) - U.deepStrictEqual(pipe(O.some(1), M.combine(O.some(2))), O.some(1)) + U.deepStrictEqual(M.combine(O.none(), O.none()), O.none()) + U.deepStrictEqual(M.combine(O.some(1), O.none()), O.some(1)) + U.deepStrictEqual(M.combine(O.none(), O.some(2)), O.some(2)) + U.deepStrictEqual(M.combine(O.some(1), O.some(2)), O.some(1)) - U.deepStrictEqual(pipe(M.empty, M.combine(O.none())), O.none()) - U.deepStrictEqual(pipe(M.empty, M.combine(O.some(2))), O.some(2)) - U.deepStrictEqual(pipe(O.some(1), M.combine(M.empty)), O.some(1)) + U.deepStrictEqual(M.combine(M.empty, O.none()), O.none()) + U.deepStrictEqual(M.combine(M.empty, O.some(2)), O.some(2)) + U.deepStrictEqual(M.combine(O.some(1), M.empty), O.some(1)) }) }) diff --git a/test/typeclass/Equivalence.ts b/test/typeclass/Equivalence.ts index 6411c8247..1df2bc0f2 100644 --- a/test/typeclass/Equivalence.ts +++ b/test/typeclass/Equivalence.ts @@ -102,7 +102,7 @@ describe("Equivalence", () => { const S = _.getSemigroup() const E0: _.Equivalence = _.contramap((x: T) => x[0])(_.string) const E1: _.Equivalence = _.contramap((x: T) => x[1])(_.number) - const eqE0E1 = pipe(E0, S.combine(E1)) + const eqE0E1 = S.combine(E0, E1) expect(eqE0E1(["a", 1, true], ["a", 1, true])).toEqual(true) expect(eqE0E1(["a", 1, true], ["a", 1, false])).toEqual(true) expect(eqE0E1(["a", 1, true], ["b", 1, true])).toEqual(false) diff --git a/test/typeclass/Invariant.ts b/test/typeclass/Invariant.ts index e10460ea9..f1572662d 100644 --- a/test/typeclass/Invariant.ts +++ b/test/typeclass/Invariant.ts @@ -9,13 +9,13 @@ import * as U from "../util" describe("Invariant", () => { it("imapComposition", () => { const imap = _.imapComposition(semigroup.Invariant, O.Invariant) - const S = pipe(O.getMonoid(String.Semigroup), imap(s => [s] as const, ([s]) => s)) - U.deepStrictEqual(pipe(O.none(), S.combine(O.none())), O.none()) - U.deepStrictEqual(pipe(O.none(), S.combine(O.some(["b"]))), O.some(["b"] as const)) - U.deepStrictEqual(pipe(O.some(["a"] as const), S.combine(O.none())), O.some(["a"] as const)) + const S = pipe(O.getMonoid(String.Semigroup), imap(s => [s], ([s]) => s)) + U.deepStrictEqual(S.combine(O.none(), O.none()), O.none()) + U.deepStrictEqual(S.combine(O.none(), O.some(["b"])), O.some(["b"])) + U.deepStrictEqual(S.combine(O.some(["a"]), O.none()), O.some(["a"])) U.deepStrictEqual( - pipe(O.some(["a"] as const), S.combine(O.some(["b"]))), - O.some(["ab"] as const) + S.combine(O.some(["a"]), O.some(["b"])), + O.some(["ab"]) ) }) diff --git a/test/typeclass/Monoid.ts b/test/typeclass/Monoid.ts index 1ce38fb06..d44612787 100644 --- a/test/typeclass/Monoid.ts +++ b/test/typeclass/Monoid.ts @@ -25,9 +25,9 @@ describe("Monoid", () => { it("reverse", () => { const M = monoid.reverse(String.Monoid) - U.deepStrictEqual(pipe("a", M.combine("b")), "ba") - U.deepStrictEqual(pipe("a", M.combine(M.empty)), "a") - U.deepStrictEqual(pipe(M.empty, M.combine("a")), "a") + U.deepStrictEqual(M.combine("a", "b"), "ba") + U.deepStrictEqual(M.combine("a", M.empty), "a") + U.deepStrictEqual(M.combine(M.empty, "a"), "a") U.deepStrictEqual(pipe("a", M.combineMany([])), "a") U.deepStrictEqual(pipe("a", M.combineMany(["b", "c", "d"])), "dcba") U.deepStrictEqual(pipe("a", M.combineMany([M.empty])), "a") @@ -41,7 +41,7 @@ describe("Monoid", () => { age: N.MonoidSum }) U.deepStrictEqual(M.empty, { name: "", age: 0 }) - U.deepStrictEqual(pipe({ name: "a", age: 10 }, M.combine({ name: "b", age: 20 })), { + U.deepStrictEqual(M.combine({ name: "a", age: 10 }, { name: "b", age: 20 }), { name: "ab", age: 30 }) @@ -60,6 +60,6 @@ describe("Monoid", () => { N.MonoidSum ) U.deepStrictEqual(M.empty, ["", 0]) - U.deepStrictEqual(pipe(["a", 10], M.combine(["b", 20])), ["ab", 30]) + U.deepStrictEqual(M.combine(["a", 10], ["b", 20]), ["ab", 30]) }) }) diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index aca17cdde..4e03f51ba 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -55,13 +55,13 @@ describe("Order", () => { string.Order, _.contramap((x: T) => x[1]) ) - U.deepStrictEqual(sort(pipe(sortByFst, S.combine(sortBySnd)))(tuples), [ + U.deepStrictEqual(sort(S.combine(sortByFst, sortBySnd))(tuples), [ [1, "b"], [1, "c"], [2, "a"], [2, "c"] ]) - U.deepStrictEqual(sort(pipe(sortBySnd, S.combine(sortByFst)))(tuples), [ + U.deepStrictEqual(sort(S.combine(sortBySnd, sortByFst))(tuples), [ [2, "a"], [1, "b"], [1, "c"], diff --git a/test/typeclass/Product.ts b/test/typeclass/Product.ts index 76cc0e81c..2f917c38d 100644 --- a/test/typeclass/Product.ts +++ b/test/typeclass/Product.ts @@ -1,5 +1,4 @@ import * as Boolean from "@fp-ts/core/Boolean" -import { pipe } from "@fp-ts/core/Function" import * as Number from "@fp-ts/core/Number" import * as O from "@fp-ts/core/Option" import * as P from "@fp-ts/core/Predicate" @@ -23,9 +22,9 @@ describe("Product", () => { it("Invariant (Semigroup)", () => { const tuple = _.tuple(semigroup.Product) - U.deepStrictEqual(pipe([], tuple().combine([])), []) + U.deepStrictEqual(tuple().combine([], []), []) const S = tuple(String.Semigroup, Number.SemigroupSum) - U.deepStrictEqual(pipe(["a", 2], S.combine(["b", 3])), ["ab", 5]) + U.deepStrictEqual(S.combine(["a", 2], ["b", 3]), ["ab", 5]) }) it("Contravariant (Predicate)", () => { @@ -54,9 +53,9 @@ describe("Product", () => { it("Invariant (Semigroup)", () => { const struct = _.struct(semigroup.Product) - U.deepStrictEqual(pipe({}, struct({}).combine({})), {}) + U.deepStrictEqual(struct({}).combine({}, {}), {}) const S = struct({ x: String.Semigroup, y: Number.SemigroupSum }) - U.deepStrictEqual(pipe({ x: "a", y: 2 }, S.combine({ x: "b", y: 3 })), { x: "ab", y: 5 }) + U.deepStrictEqual(S.combine({ x: "a", y: 2 }, { x: "b", y: 3 }), { x: "ab", y: 5 }) }) it("Contravariant (Predicate)", () => { diff --git a/test/typeclass/SemiApplicative.ts b/test/typeclass/SemiApplicative.ts index fad3732da..2bec885af 100644 --- a/test/typeclass/SemiApplicative.ts +++ b/test/typeclass/SemiApplicative.ts @@ -33,10 +33,10 @@ describe("SemiApplicative", () => { it("liftSemigroup", () => { const liftSemigroup = _.liftSemigroup(O.SemiApplicative) const S = liftSemigroup(String.Semigroup) - U.deepStrictEqual(pipe(O.none(), S.combine(O.none())), O.none()) - U.deepStrictEqual(pipe(O.none(), S.combine(O.some("b"))), O.none()) - U.deepStrictEqual(pipe(O.some("a"), S.combine(O.none())), O.none()) - U.deepStrictEqual(pipe(O.some("a"), S.combine(O.some("b"))), O.some("ab")) + U.deepStrictEqual(S.combine(O.none(), O.none()), O.none()) + U.deepStrictEqual(S.combine(O.none(), O.some("b")), O.none()) + U.deepStrictEqual(S.combine(O.some("a"), O.none()), O.none()) + U.deepStrictEqual(S.combine(O.some("a"), O.some("b")), O.some("ab")) U.deepStrictEqual(pipe(O.some("a"), S.combineMany([O.some("b"), O.some("c")])), O.some("abc")) }) diff --git a/test/typeclass/SemiCoproduct.ts b/test/typeclass/SemiCoproduct.ts index 1049fd717..29ca03bf3 100644 --- a/test/typeclass/SemiCoproduct.ts +++ b/test/typeclass/SemiCoproduct.ts @@ -1,14 +1,13 @@ import * as E from "@fp-ts/core/Either" -import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/typeclass/SemiCoproduct" import * as U from "../util" describe("SemiCoproduct", () => { it("getSemigroup", () => { const S = _.getSemigroup(E.SemiCoproduct)() - U.deepStrictEqual(pipe(E.right(1), S.combine(E.right(2))), E.right(1)) - U.deepStrictEqual(pipe(E.left("a"), S.combine(E.right(2))), E.right(2)) - U.deepStrictEqual(pipe(E.right(1), S.combine(E.left("b"))), E.right(1)) - U.deepStrictEqual(pipe(E.left("a"), S.combine(E.left("b"))), E.left("b")) + U.deepStrictEqual(S.combine(E.right(1), E.right(2)), E.right(1)) + U.deepStrictEqual(S.combine(E.left("a"), E.right(2)), E.right(2)) + U.deepStrictEqual(S.combine(E.right(1), E.left("b")), E.right(1)) + U.deepStrictEqual(S.combine(E.left("a"), E.left("b")), E.left("b")) }) }) diff --git a/test/typeclass/SemiProduct.ts b/test/typeclass/SemiProduct.ts index 0befff78a..29c875655 100644 --- a/test/typeclass/SemiProduct.ts +++ b/test/typeclass/SemiProduct.ts @@ -195,7 +195,7 @@ describe("SemiProduct", () => { it("Invariant (Semigroup)", () => { const nonEmptyTuple = _.nonEmptyTuple(semigroup.SemiProduct) const S = nonEmptyTuple(String.Semigroup, Number.SemigroupSum) - U.deepStrictEqual(pipe(["a", 2], S.combine(["b", 3])), ["ab", 5]) + U.deepStrictEqual(S.combine(["a", 2], ["b", 3]), ["ab", 5]) }) it("Contravariant (Predicate)", () => { @@ -223,7 +223,7 @@ describe("SemiProduct", () => { it("Invariant (Semigroup)", () => { const nonEmptyStruct = _.nonEmptyStruct(semigroup.Product) const S = nonEmptyStruct({ x: String.Semigroup, y: Number.SemigroupSum }) - U.deepStrictEqual(pipe({ x: "a", y: 2 }, S.combine({ x: "b", y: 3 })), { x: "ab", y: 5 }) + U.deepStrictEqual(S.combine({ x: "a", y: 2 }, { x: "b", y: 3 }), { x: "ab", y: 5 }) }) it("Contravariant (Predicate)", () => { diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index 537d82ce9..127d9d94f 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -12,7 +12,7 @@ describe("Semigroup", () => { it("reverse", () => { const A = _.reverse(String.Semigroup) - U.deepStrictEqual(pipe("a", A.combine("b")), "ba") + U.deepStrictEqual(A.combine("a", "b"), "ba") U.deepStrictEqual(pipe("a", A.combineMany([])), "a") U.deepStrictEqual(pipe("a", A.combineMany(["b"])), "ba") U.deepStrictEqual(pipe("a", A.combineMany(["b", "c", "d"])), "dcba") @@ -20,14 +20,14 @@ describe("Semigroup", () => { it("constant", () => { const A = _.constant("-") - U.deepStrictEqual(pipe("a", A.combine("b")), "-") + U.deepStrictEqual(A.combine("a", "b"), "-") U.deepStrictEqual(pipe("a", A.combineMany([])), "-") U.deepStrictEqual(pipe("a", A.combineMany(["b", "c", "d"])), "-") }) it("intercalate", () => { const A = pipe(String.Semigroup, _.intercalate("|")) - U.deepStrictEqual(pipe("a", A.combine("b")), "a|b") + U.deepStrictEqual(A.combine("a", "b"), "a|b") U.deepStrictEqual(pipe("a", A.combineMany([])), "a") U.deepStrictEqual(pipe("a", A.combineMany(["b"])), "a|b") U.deepStrictEqual(pipe("a", A.combineMany(["b", "c", "d"])), "a|b|c|d") @@ -70,7 +70,7 @@ describe("Semigroup", () => { name: String.Semigroup, age: Number.SemigroupSum }) - U.deepStrictEqual(pipe({ name: "a", age: 10 }, A.combine({ name: "b", age: 20 })), { + U.deepStrictEqual(A.combine({ name: "a", age: 10 }, { name: "b", age: 20 }), { name: "ab", age: 30 }) @@ -96,7 +96,7 @@ describe("Semigroup", () => { String.Semigroup, Number.SemigroupSum ) - U.deepStrictEqual(pipe(["a", 10], A.combine(["b", 20])), ["ab", 30]) + U.deepStrictEqual(A.combine(["a", 10], ["b", 20]), ["ab", 30]) U.deepStrictEqual(pipe(["a", 10], A.combineMany([])), ["a", 10]) U.deepStrictEqual(pipe(["a", 10], A.combineMany([["b", 20]])), ["ab", 30]) U.deepStrictEqual(pipe(["a", 10], A.combineMany([["b", 20], ["c", 30]])), ["abc", 60]) @@ -104,14 +104,14 @@ describe("Semigroup", () => { it("first", () => { const A = _.first() - U.deepStrictEqual(pipe(1, A.combine(2)), 1) + U.deepStrictEqual(A.combine(1, 2), 1) U.deepStrictEqual(pipe(1, A.combineMany([])), 1) U.deepStrictEqual(pipe(1, A.combineMany([2, 3, 4, 5, 6])), 1) }) it("last", () => { const A = _.last() - U.deepStrictEqual(pipe(1, A.combine(2)), 2) + U.deepStrictEqual(A.combine(1, 2), 2) U.deepStrictEqual(pipe(1, A.combineMany([])), 1) U.deepStrictEqual(pipe(1, A.combineMany([2, 3, 4, 5, 6])), 6) }) @@ -119,7 +119,7 @@ describe("Semigroup", () => { it("imap", () => { const imap = _.imap const To = imap((s: string) => [s], ([s]) => s)(String.Semigroup) - U.deepStrictEqual(pipe(["a"], To.combine(["b"])), ["ab"]) + U.deepStrictEqual(To.combine(["a"], ["b"]), ["ab"]) U.deepStrictEqual(pipe(["a"], To.combineMany([])), ["a"]) U.deepStrictEqual(pipe(["a"], To.combineMany([["b"]])), ["ab"]) U.deepStrictEqual(pipe(["a"], To.combineMany([["b"], ["c"]])), ["abc"]) @@ -147,7 +147,7 @@ describe("Semigroup", () => { ([a, b, c]): [[string, number], number] => [[a, b], c] ) ) - U.deepStrictEqual(pipe(["a", 2, 3], A.combine(["b", 3, 4])), ["ab", 5, 12]) + U.deepStrictEqual(A.combine(["a", 2, 3], ["b", 3, 4]), ["ab", 5, 12]) }) it("productMany", () => { @@ -155,6 +155,6 @@ describe("Semigroup", () => { String.Semigroup, _.SemiProduct.productMany([String.Semigroup, String.Semigroup]) ) - U.deepStrictEqual(pipe(["a", "b", "c"], A.combine(["d", "e", "f"])), ["ad", "be", "cf"]) + U.deepStrictEqual(A.combine(["a", "b", "c"], ["d", "e", "f"]), ["ad", "be", "cf"]) }) }) From 706194bbf68a562a96f250331cbf608b975910ac Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 15:00:11 +0100 Subject: [PATCH 069/255] Semigroup: make combineMany binary --- CHANGELOG.md | 1 + src/Function.ts | 6 +- src/Identity.ts | 2 +- src/Option.ts | 15 ++-- src/Ordering.ts | 17 ++-- src/Predicate.ts | 4 +- src/ReadonlyArray.ts | 6 +- src/typeclass/Equivalence.ts | 19 ++--- src/typeclass/Monoid.ts | 18 ++-- src/typeclass/Order.ts | 23 +++--- src/typeclass/SemiApplicative.ts | 13 ++- src/typeclass/SemiCoproduct.ts | 2 +- src/typeclass/Semigroup.ts | 133 ++++++++++++++---------------- test/Bigint.ts | 5 +- test/Boolean.ts | 12 +-- test/Function.ts | 2 +- test/Number.ts | 5 +- test/Option.ts | 6 +- test/Ordering.ts | 15 ++-- test/String.ts | 4 +- test/typeclass/Equivalence.ts | 2 +- test/typeclass/Monoid.ts | 9 +- test/typeclass/Order.ts | 8 +- test/typeclass/SemiApplicative.ts | 2 +- test/typeclass/SemiCoproduct.ts | 1 + test/typeclass/Semigroup.ts | 119 +++++++++++++------------- 26 files changed, 210 insertions(+), 239 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44cd53a15..28dde2d23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - `Semigroup` - make `combine` binary + - make `combineMany` binary - `Semiproduct` - rename `productFlatten` to `element` - `Order` diff --git a/src/Function.ts b/src/Function.ts index 109a6c259..ebe780f4e 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -79,11 +79,7 @@ export const getMonoid = (Monoid: monoid.Monoid) => (): monoid.Monoid<(a: A) => M> => { const S = getSemigroup(Monoid)() const empty = () => Monoid.empty - return ({ - ...S, - combineAll: (collection) => S.combineMany(collection)(empty), - empty - }) + return ({ ...S, combineAll: (collection) => S.combineMany(empty, collection), empty }) } /** diff --git a/src/Identity.ts b/src/Identity.ts index 59cd59f0b..3a87f7966 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -405,7 +405,7 @@ export const getSemiCoproduct = ( ): semiCoproduct.SemiCoproduct> => ({ imap: Invariant.imap, coproduct: (that) => (self) => S.combine(self, that), - coproductMany: S.combineMany + coproductMany: (collection) => (self) => S.combineMany(self, collection) }) /** diff --git a/src/Option.ts b/src/Option.ts index 9c4477cfa..368dcad20 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -547,14 +547,13 @@ export const getMonoid = ( isNone(self) ? that : isNone(that) ? self : some(Semigroup.combine(self.value, that.value)) return ({ combine, - combineMany: (others) => - (start) => { - let c = start - for (const o of others) { - c = combine(c, o) - } - return c - }, + combineMany: (self, collection) => { + let c = self + for (const o of collection) { + c = combine(c, o) + } + return c + }, combineAll: (collection: Iterable>): Option => { let c: Option = option.none for (const o of collection) { diff --git a/src/Ordering.ts b/src/Ordering.ts index 67ccf3917..65782eefe 100644 --- a/src/Ordering.ts +++ b/src/Ordering.ts @@ -32,19 +32,18 @@ export const match = ( */ export const Semigroup: semigroup.Semigroup = { combine: (self, that) => self !== 0 ? self : that, - combineMany: (collection) => - (self) => { - let ordering = self + combineMany: (self, collection) => { + let ordering = self + if (ordering !== 0) { + return ordering + } + for (ordering of collection) { if (ordering !== 0) { return ordering } - for (ordering of collection) { - if (ordering !== 0) { - return ordering - } - } - return ordering } + return ordering + } } /** diff --git a/src/Predicate.ts b/src/Predicate.ts index fb3fe7e63..3bae8a9c8 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -286,7 +286,7 @@ export const getMonoidAny = (): monoid.Monoid> => { return ({ combine: S.combine, combineMany: S.combineMany, - combineAll: (collection) => S.combineMany(collection)(constFalse), + combineAll: (collection) => S.combineMany(constFalse, collection), empty: constFalse }) } @@ -307,7 +307,7 @@ export const getMonoidAll = (): monoid.Monoid> => { return ({ combine: S.combine, combineMany: S.combineMany, - combineAll: (collection) => S.combineMany(collection)(constTrue), + combineAll: (collection) => S.combineMany(constTrue, collection), empty: constTrue }) } diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index f3689b551..2a944f518 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -2077,7 +2077,7 @@ export const intercalateNonEmpty = ( ) => (middle: A) => (self: NonEmptyReadonlyArray): A => - semigroup.intercalate(middle)(S).combineMany(tailNonEmpty(self))(headNonEmpty(self)) + semigroup.intercalate(middle)(S).combineMany(headNonEmpty(self), tailNonEmpty(self)) /** * @since 1.0.0 @@ -2150,8 +2150,8 @@ export const getUnionMonoid = (equivalence: Equivalence): Monoid S.combineMany(collection)(empty()), - empty: empty() + combineAll: (collection) => S.combineMany([], collection), + empty: [] }) } diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 018949791..3929cb0e7 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -143,19 +143,18 @@ export const record = ( */ export const getSemigroup = (): Semigroup> => ({ combine: (self, that) => (x, y) => self(x, y) && that(x, y), - combineMany: (collection) => - self => - (x, y) => { - if (!self(x, y)) { + combineMany: (self, collection) => + (x, y) => { + if (!self(x, y)) { + return false + } + for (const equivalence of collection) { + if (!equivalence(x, y)) { return false } - for (const equivalence of collection) { - if (!equivalence(x, y)) { - return false - } - } - return true } + return true + } }) const empty: Equivalence = () => true diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index 55081696b..fd2c7cfa0 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -21,7 +21,7 @@ export interface Monoid extends Semigroup { export const fromSemigroup = (S: Semigroup, empty: Monoid["empty"]): Monoid => ({ ...S, empty, - combineAll: collection => S.combineMany(collection)(empty) + combineAll: collection => S.combineMany(empty, collection) }) /** @@ -58,7 +58,7 @@ export const reverse = (M: Monoid): Monoid => fromSemigroup(semigroup.r */ export const string: Monoid = { ...semigroup.string, - combineAll: (collection) => semigroup.string.combineMany(collection)(""), + combineAll: (collection) => semigroup.string.combineMany("", collection), empty: "" } @@ -72,7 +72,7 @@ export const string: Monoid = { */ export const numberSum: Monoid = { ...semigroup.numberSum, - combineAll: (collection) => semigroup.numberSum.combineMany(collection)(0), + combineAll: (collection) => semigroup.numberSum.combineMany(0, collection), empty: 0 } @@ -86,7 +86,7 @@ export const numberSum: Monoid = { */ export const numberMultiply: Monoid = { ...semigroup.numberMultiply, - combineAll: (collection) => semigroup.numberMultiply.combineMany(collection)(1), + combineAll: (collection) => semigroup.numberMultiply.combineMany(1, collection), empty: 1 } @@ -100,7 +100,7 @@ export const numberMultiply: Monoid = { */ export const bigintSum: Monoid = { ...semigroup.bigintSum, - combineAll: (collection) => semigroup.bigintSum.combineMany(collection)(0n), + combineAll: (collection) => semigroup.bigintSum.combineMany(0n, collection), empty: 0n } @@ -114,7 +114,7 @@ export const bigintSum: Monoid = { */ export const bigintMultiply: Monoid = { ...semigroup.bigintMultiply, - combineAll: (collection) => semigroup.bigintMultiply.combineMany(collection)(1n), + combineAll: (collection) => semigroup.bigintMultiply.combineMany(1n, collection), empty: 1n } @@ -128,7 +128,7 @@ export const bigintMultiply: Monoid = { */ export const booleanAll: Monoid = { ...semigroup.booleanAll, - combineAll: (all) => semigroup.booleanAll.combineMany(all)(true), + combineAll: (collection) => semigroup.booleanAll.combineMany(true, collection), empty: true } @@ -142,7 +142,7 @@ export const booleanAll: Monoid = { */ export const booleanAny: Monoid = { ...semigroup.booleanAny, - combineAll: (all) => semigroup.booleanAny.combineMany(all)(false), + combineAll: (collection) => semigroup.booleanAny.combineMany(false, collection), empty: false } @@ -171,7 +171,7 @@ export const array = (): Monoid> => { return ({ combine: S.combine, combineMany: S.combineMany, - combineAll: (collection) => S.combineMany(collection)([]), + combineAll: (collection) => S.combineMany([], collection), empty: [] }) } diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 1f42f37d9..3158a1821 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -139,21 +139,20 @@ export const getSemigroup = (): Semigroup> => ({ } return O2.compare(self, that) }), - combineMany: (collection) => - (self) => - fromCompare((a1, a2) => { - let out = self.compare(a1, a2) + combineMany: (self, collection) => + fromCompare((a1, a2) => { + let out = self.compare(a1, a2) + if (out !== 0) { + return out + } + for (const O of collection) { + out = O.compare(a1, a2) if (out !== 0) { return out } - for (const O of collection) { - out = O.compare(a1, a2) - if (out !== 0) { - return out - } - } - return out - }) + } + return out + }) }) const empty: Order = fromCompare(() => 0) diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index a83b700f2..063707118 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -21,13 +21,12 @@ export interface SemiApplicative extends SemiProduct, C export const liftSemigroup = (F: SemiApplicative) => (S: Semigroup): Semigroup> => ({ combine: (self, that) => pipe(self, F.product(that), F.map(([a1, a2]) => S.combine(a1, a2))), - combineMany: collection => - self => - pipe( - self, - F.productMany(collection), - F.map(([head, ...tail]) => pipe(head, S.combineMany(tail))) - ) + combineMany: (self, collection) => + pipe( + self, + F.productMany(collection), + F.map(([head, ...tail]) => S.combineMany(head, tail)) + ) }) /** diff --git a/src/typeclass/SemiCoproduct.ts b/src/typeclass/SemiCoproduct.ts index c1523d660..c659b3408 100644 --- a/src/typeclass/SemiCoproduct.ts +++ b/src/typeclass/SemiCoproduct.ts @@ -30,5 +30,5 @@ export const getSemigroup = (F: SemiCoproduct) => Kind > => ({ combine: (self, that) => pipe(self, F.coproduct(that)), - combineMany: F.coproductMany + combineMany: (self, collection) => pipe(self, F.coproductMany(collection)) }) diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 4d14c9f94..464ed4d4a 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -21,6 +21,7 @@ * @since 1.0.0 */ import type { TypeLambda } from "@fp-ts/core/HKT" +import { fromIterable } from "@fp-ts/core/internal/ReadonlyArray" import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Order } from "@fp-ts/core/typeclass/Order" import type * as product from "@fp-ts/core/typeclass/Product" @@ -32,7 +33,7 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" */ export interface Semigroup { readonly combine: (self: A, that: A) => A - readonly combineMany: (collection: Iterable) => (self: A) => A + readonly combineMany: (self: A, collection: Iterable) => A } /** @@ -51,14 +52,13 @@ export interface SemigroupTypeLambda extends TypeLambda { */ export const fromCombine = (combine: Semigroup["combine"]): Semigroup => ({ combine, - combineMany: (collection) => - (self) => { - let out: A = self - for (const a of collection) { - out = combine(out, a) - } - return out + combineMany: (self, collection) => { + let out: A = self + for (const a of collection) { + out = combine(out, a) } + return out + } }) /** @@ -83,20 +83,19 @@ export const numberSum: Semigroup = fromCombine((self, that) => self + t */ export const numberMultiply: Semigroup = { combine: (self, that) => self * that, - combineMany: (collection) => - (self) => { - if (self === 0) { + combineMany: (self, collection) => { + if (self === 0) { + return 0 + } + let out = self + for (const n of collection) { + if (n === 0) { return 0 } - let out = self - for (const n of collection) { - if (n === 0) { - return 0 - } - out = out * n - } - return out + out = out * n } + return out + } } /** @@ -115,20 +114,19 @@ export const bigintSum: Semigroup = fromCombine((self, that) => self + t */ export const bigintMultiply: Semigroup = { combine: (self, that) => self * that, - combineMany: (collection) => - (self) => { - if (self === 0n) { + combineMany: (self, collection) => { + if (self === 0n) { + return 0n + } + let out = self + for (const n of collection) { + if (n === 0n) { return 0n } - let out = self - for (const n of collection) { - if (n === 0n) { - return 0n - } - out = out * n - } - return out + out = out * n } + return out + } } /** @@ -139,18 +137,17 @@ export const bigintMultiply: Semigroup = { */ export const booleanAll: Semigroup = { combine: (self, that) => self && that, - combineMany: (collection) => - (self) => { - if (self === false) { + combineMany: (self, collection) => { + if (self === false) { + return false + } + for (const b of collection) { + if (b === false) { return false } - for (const b of collection) { - if (b === false) { - return false - } - } - return true } + return true + } } /** @@ -161,18 +158,17 @@ export const booleanAll: Semigroup = { */ export const booleanAny: Semigroup = { combine: (self, that) => self || that, - combineMany: (collection) => - (self) => { - if (self === true) { + combineMany: (self, collection) => { + if (self === true) { + return true + } + for (const b of collection) { + if (b === true) { return true } - for (const b of collection) { - if (b === true) { - return true - } - } - return false } + return false + } } /** @@ -251,7 +247,7 @@ export const max = (O: Order): Semigroup => */ export const constant = (a: A): Semigroup => ({ combine: () => a, - combineMany: () => () => a + combineMany: () => a }) /** @@ -261,13 +257,12 @@ export const constant = (a: A): Semigroup => ({ */ export const reverse = (S: Semigroup): Semigroup => ({ combine: (self, that) => S.combine(that, self), - combineMany: (collection) => - (self) => { - const reversed = Array.from(collection).reverse() - return reversed.length > 0 ? - S.combine(S.combineMany(reversed.slice(1))(reversed[0]), self) : - self - } + combineMany: (self, collection) => { + const reversed = Array.from(collection).reverse() + return reversed.length > 0 ? + S.combine(S.combineMany(reversed[0], reversed.slice(1)), self) : + self + } }) /** @@ -275,7 +270,7 @@ export const reverse = (S: Semigroup): Semigroup => ({ */ export const intercalate = (separator: A) => (S: Semigroup): Semigroup => - fromCombine((self, that) => S.combineMany([separator, that])(self)) + fromCombine((self, that) => S.combineMany(self, [separator, that])) /** * Always return the first argument. @@ -285,7 +280,7 @@ export const intercalate = (separator: A) => */ export const first = (): Semigroup => ({ combine: (a) => a, - combineMany: () => a => a + combineMany: (a) => a }) /** @@ -296,13 +291,12 @@ export const first = (): Semigroup => ({ */ export const last = (): Semigroup => ({ combine: (_, second) => second, - combineMany: collection => - self => { - let a: A = self - // eslint-disable-next-line no-empty - for (a of collection) {} - return a - } + combineMany: (self, collection) => { + let a: A = self + // eslint-disable-next-line no-empty + for (a of collection) {} + return a + } }) /** @@ -314,13 +308,8 @@ export const imap = ( ) => (S: Semigroup): Semigroup => ({ combine: (self, that) => to(S.combine(from(self), from(that))), - combineMany: (collection) => - self => - to( - S.combineMany( - (Array.isArray(collection) ? collection : Array.from(collection)).map(from) - )(from(self)) - ) + combineMany: (self, collection) => + to(S.combineMany(from(self), (fromIterable(collection)).map(from))) }) /** diff --git a/test/Bigint.ts b/test/Bigint.ts index 02f76c44f..94468621e 100644 --- a/test/Bigint.ts +++ b/test/Bigint.ts @@ -1,5 +1,4 @@ import * as Bigint from "@fp-ts/core/Bigint" -import { pipe } from "@fp-ts/core/Function" import { deepStrictEqual } from "@fp-ts/core/test/util" describe.concurrent("Bigint", () => { @@ -51,8 +50,8 @@ describe.concurrent("Bigint", () => { it("SemigroupMultiply", () => { deepStrictEqual(Bigint.SemigroupMultiply.combine(2n, 3n), 6n) - deepStrictEqual(pipe(0n, Bigint.SemigroupMultiply.combineMany([1n, 2n, 3n])), 0n) - deepStrictEqual(pipe(2n, Bigint.SemigroupMultiply.combineMany([1n, 0n, 3n])), 0n) + deepStrictEqual(Bigint.SemigroupMultiply.combineMany(0n, [1n, 2n, 3n]), 0n) + deepStrictEqual(Bigint.SemigroupMultiply.combineMany(2n, [1n, 0n, 3n]), 0n) }) it("MonoidMultiply", () => { diff --git a/test/Boolean.ts b/test/Boolean.ts index 8367ba376..39bd328cb 100644 --- a/test/Boolean.ts +++ b/test/Boolean.ts @@ -38,9 +38,9 @@ describe.concurrent("Boolean", () => { describe.concurrent("MonoidAll", () => { it("baseline", () => { - deepStrictEqual(Boolean.MonoidAll.combineMany([true, true])(true), true) - deepStrictEqual(Boolean.MonoidAll.combineMany([true, false])(true), false) - deepStrictEqual(Boolean.MonoidAll.combineMany([true, false])(false), false) + deepStrictEqual(Boolean.MonoidAll.combineMany(true, [true, true]), true) + deepStrictEqual(Boolean.MonoidAll.combineMany(true, [true, false]), false) + deepStrictEqual(Boolean.MonoidAll.combineMany(false, [true, false]), false) deepStrictEqual(Boolean.MonoidAll.combineAll([true, true, true]), true) deepStrictEqual(Boolean.MonoidAll.combineAll([true, true, false]), false) }) @@ -54,9 +54,9 @@ describe.concurrent("Boolean", () => { describe.concurrent("MonoidAny", () => { it("baseline", () => { - deepStrictEqual(Boolean.MonoidAny.combineMany([true, true])(true), true) - deepStrictEqual(Boolean.MonoidAny.combineMany([true, false])(true), true) - deepStrictEqual(Boolean.MonoidAny.combineMany([false, false])(false), false) + deepStrictEqual(Boolean.MonoidAny.combineMany(true, [true, true]), true) + deepStrictEqual(Boolean.MonoidAny.combineMany(true, [true, false]), true) + deepStrictEqual(Boolean.MonoidAny.combineMany(false, [false, false]), false) deepStrictEqual(Boolean.MonoidAny.combineAll([true, true, true]), true) deepStrictEqual(Boolean.MonoidAny.combineAll([true, true, false]), true) deepStrictEqual(Boolean.MonoidAny.combineAll([false, false, false]), false) diff --git a/test/Function.ts b/test/Function.ts index 2bbcc7d75..969d19b27 100644 --- a/test/Function.ts +++ b/test/Function.ts @@ -15,7 +15,7 @@ describe.concurrent("Function", () => { deepStrictEqual(g(""), 1) deepStrictEqual(g("a"), 1) deepStrictEqual(g("b"), 2) - deepStrictEqual(S.combineMany([size, size])(size)("a"), 3) + deepStrictEqual(S.combineMany(size, [size, size])("a"), 3) }) it("getMonoid", () => { diff --git a/test/Number.ts b/test/Number.ts index 7f7cf69ea..a3f6c334e 100644 --- a/test/Number.ts +++ b/test/Number.ts @@ -1,4 +1,3 @@ -import { pipe } from "@fp-ts/core/Function" import * as Number from "@fp-ts/core/Number" import { deepStrictEqual } from "@fp-ts/core/test/util" @@ -55,8 +54,8 @@ describe.concurrent("Number", () => { it("SemigroupMultiply", () => { deepStrictEqual(Number.SemigroupMultiply.combine(2, 3), 6) - deepStrictEqual(pipe(0, Number.SemigroupMultiply.combineMany([1, 2, 3])), 0) - deepStrictEqual(pipe(2, Number.SemigroupMultiply.combineMany([1, 0, 3])), 0) + deepStrictEqual(Number.SemigroupMultiply.combineMany(0, [1, 2, 3]), 0) + deepStrictEqual(Number.SemigroupMultiply.combineMany(2, [1, 0, 3]), 0) }) it("MonoidMultiply", () => { diff --git a/test/Option.ts b/test/Option.ts index b897eeaf9..93f1da94b 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -415,9 +415,9 @@ describe.concurrent("Option", () => { deepStrictEqual(M.combine(_.some("b"), _.some("a")), _.some("ba")) deepStrictEqual(M.combine(_.some("a"), _.some("b")), _.some("ab")) - deepStrictEqual(pipe(_.some("a"), M.combineMany([_.some("b")])), _.some("ab")) - deepStrictEqual(pipe(_.none(), M.combineMany([_.some("b")])), _.some("b")) - deepStrictEqual(pipe(_.some("a"), M.combineMany([_.none()])), _.some("a")) + deepStrictEqual(M.combineMany(_.some("a"), [_.some("b")]), _.some("ab")) + deepStrictEqual(M.combineMany(_.none(), [_.some("b")]), _.some("b")) + deepStrictEqual(M.combineMany(_.some("a"), [_.none()]), _.some("a")) deepStrictEqual(pipe(M.combineAll([])), _.none()) deepStrictEqual(pipe(M.combineAll([_.some("a")])), _.some("a")) diff --git a/test/Ordering.ts b/test/Ordering.ts index 091af1c5a..5f2682083 100644 --- a/test/Ordering.ts +++ b/test/Ordering.ts @@ -1,4 +1,3 @@ -import { pipe } from "@fp-ts/core/Function" import * as _ from "@fp-ts/core/Ordering" import { deepStrictEqual } from "./util" @@ -26,13 +25,13 @@ describe("Ordering", () => { deepStrictEqual(_.Semigroup.combine(1, -1), 1) deepStrictEqual(_.Semigroup.combine(-1, 1), -1) - deepStrictEqual(pipe(0, _.Semigroup.combineMany([])), 0) - deepStrictEqual(pipe(1, _.Semigroup.combineMany([])), 1) - deepStrictEqual(pipe(-1, _.Semigroup.combineMany([])), -1) - deepStrictEqual(pipe(0, _.Semigroup.combineMany([0, 0, 0])), 0) - deepStrictEqual(pipe(0, _.Semigroup.combineMany([0, 0, 1])), 1) - deepStrictEqual(pipe(1, _.Semigroup.combineMany([0, 0, -1])), 1) - deepStrictEqual(pipe(-1, _.Semigroup.combineMany([0, 0, 1])), -1) + deepStrictEqual(_.Semigroup.combineMany(0, []), 0) + deepStrictEqual(_.Semigroup.combineMany(1, []), 1) + deepStrictEqual(_.Semigroup.combineMany(-1, []), -1) + deepStrictEqual(_.Semigroup.combineMany(0, [0, 0, 0]), 0) + deepStrictEqual(_.Semigroup.combineMany(0, [0, 0, 1]), 1) + deepStrictEqual(_.Semigroup.combineMany(1, [0, 0, -1]), 1) + deepStrictEqual(_.Semigroup.combineMany(-1, [0, 0, 1]), -1) }) it("Monoid", () => { diff --git a/test/String.ts b/test/String.ts index fba32f3c7..db96267c7 100644 --- a/test/String.ts +++ b/test/String.ts @@ -16,8 +16,8 @@ describe.concurrent("String", () => { it("Semigroup", () => { expect(String.Semigroup.combine("a", "b")).toEqual("ab") - expect(String.Semigroup.combineMany(["b", "c"])("a")).toEqual("abc") - expect(String.Semigroup.combineMany([])("a")).toEqual("a") + expect(String.Semigroup.combineMany("a", ["b", "c"])).toEqual("abc") + expect(String.Semigroup.combineMany("a", [])).toEqual("a") }) it("Monoid", () => { diff --git a/test/typeclass/Equivalence.ts b/test/typeclass/Equivalence.ts index 1df2bc0f2..2eaaf393d 100644 --- a/test/typeclass/Equivalence.ts +++ b/test/typeclass/Equivalence.ts @@ -108,7 +108,7 @@ describe("Equivalence", () => { expect(eqE0E1(["a", 1, true], ["b", 1, true])).toEqual(false) expect(eqE0E1(["a", 1, true], ["a", 2, false])).toEqual(false) const E2: _.Equivalence = _.contramap((x: T) => x[2])(_.boolean) - const eqE0E1E2 = S.combineMany([E1, E2])(E0) + const eqE0E1E2 = S.combineMany(E0, [E1, E2]) expect(eqE0E1E2(["a", 1, true], ["a", 1, true])).toEqual(true) expect(eqE0E1E2(["a", 1, true], ["b", 1, true])).toEqual(false) expect(eqE0E1E2(["a", 1, true], ["a", 2, true])).toEqual(false) diff --git a/test/typeclass/Monoid.ts b/test/typeclass/Monoid.ts index d44612787..c8bec081a 100644 --- a/test/typeclass/Monoid.ts +++ b/test/typeclass/Monoid.ts @@ -1,4 +1,3 @@ -import { pipe } from "@fp-ts/core/Function" import * as N from "@fp-ts/core/Number" import * as String from "@fp-ts/core/String" import * as monoid from "@fp-ts/core/typeclass/Monoid" @@ -28,10 +27,10 @@ describe("Monoid", () => { U.deepStrictEqual(M.combine("a", "b"), "ba") U.deepStrictEqual(M.combine("a", M.empty), "a") U.deepStrictEqual(M.combine(M.empty, "a"), "a") - U.deepStrictEqual(pipe("a", M.combineMany([])), "a") - U.deepStrictEqual(pipe("a", M.combineMany(["b", "c", "d"])), "dcba") - U.deepStrictEqual(pipe("a", M.combineMany([M.empty])), "a") - U.deepStrictEqual(pipe(M.empty, M.combineMany(["a"])), "a") + U.deepStrictEqual(M.combineMany("a", []), "a") + U.deepStrictEqual(M.combineMany("a", ["b", "c", "d"]), "dcba") + U.deepStrictEqual(M.combineMany("a", [M.empty]), "a") + U.deepStrictEqual(M.combineMany(M.empty, ["a"]), "a") }) describe("struct", () => { diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index 4e03f51ba..1f4c8edca 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -67,13 +67,13 @@ describe("Order", () => { [1, "c"], [2, "c"] ]) - U.deepStrictEqual(sort(pipe(sortBySnd, S.combineMany([])))(tuples), [ + U.deepStrictEqual(sort(S.combineMany(sortBySnd, []))(tuples), [ [2, "a"], [1, "b"], [2, "c"], [1, "c"] ]) - U.deepStrictEqual(sort(pipe(sortBySnd, S.combineMany([sortByFst])))(tuples), [ + U.deepStrictEqual(sort(S.combineMany(sortBySnd, [sortByFst]))(tuples), [ [2, "a"], [1, "b"], [1, "c"], @@ -98,13 +98,13 @@ describe("Order", () => { string.Order, _.contramap((x: T) => x[1]) ) - U.deepStrictEqual(sort(pipe(M.empty, M.combineMany([sortByFst, sortBySnd])))(tuples), [ + U.deepStrictEqual(sort(M.combineMany(M.empty, [sortByFst, sortBySnd]))(tuples), [ [1, "b"], [1, "c"], [2, "a"], [2, "c"] ]) - U.deepStrictEqual(sort(pipe(sortBySnd, M.combineMany([sortByFst, M.empty])))(tuples), [ + U.deepStrictEqual(sort(M.combineMany(sortBySnd, [sortByFst, M.empty]))(tuples), [ [2, "a"], [1, "b"], [1, "c"], diff --git a/test/typeclass/SemiApplicative.ts b/test/typeclass/SemiApplicative.ts index 2bec885af..a7ca047c9 100644 --- a/test/typeclass/SemiApplicative.ts +++ b/test/typeclass/SemiApplicative.ts @@ -38,7 +38,7 @@ describe("SemiApplicative", () => { U.deepStrictEqual(S.combine(O.some("a"), O.none()), O.none()) U.deepStrictEqual(S.combine(O.some("a"), O.some("b")), O.some("ab")) - U.deepStrictEqual(pipe(O.some("a"), S.combineMany([O.some("b"), O.some("c")])), O.some("abc")) + U.deepStrictEqual(S.combineMany(O.some("a"), [O.some("b"), O.some("c")]), O.some("abc")) }) it("lift2", () => { diff --git a/test/typeclass/SemiCoproduct.ts b/test/typeclass/SemiCoproduct.ts index 29ca03bf3..7ac9c273b 100644 --- a/test/typeclass/SemiCoproduct.ts +++ b/test/typeclass/SemiCoproduct.ts @@ -9,5 +9,6 @@ describe("SemiCoproduct", () => { U.deepStrictEqual(S.combine(E.left("a"), E.right(2)), E.right(2)) U.deepStrictEqual(S.combine(E.right(1), E.left("b")), E.right(1)) U.deepStrictEqual(S.combine(E.left("a"), E.left("b")), E.left("b")) + U.deepStrictEqual(S.combineMany(E.left("a"), [E.left("b")]), E.left("b")) }) }) diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index 127d9d94f..65b13bb47 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -11,79 +11,79 @@ describe("Semigroup", () => { }) it("reverse", () => { - const A = _.reverse(String.Semigroup) - U.deepStrictEqual(A.combine("a", "b"), "ba") - U.deepStrictEqual(pipe("a", A.combineMany([])), "a") - U.deepStrictEqual(pipe("a", A.combineMany(["b"])), "ba") - U.deepStrictEqual(pipe("a", A.combineMany(["b", "c", "d"])), "dcba") + const S = _.reverse(String.Semigroup) + U.deepStrictEqual(S.combine("a", "b"), "ba") + U.deepStrictEqual(S.combineMany("a", []), "a") + U.deepStrictEqual(S.combineMany("a", ["b"]), "ba") + U.deepStrictEqual(S.combineMany("a", ["b", "c", "d"]), "dcba") }) it("constant", () => { - const A = _.constant("-") - U.deepStrictEqual(A.combine("a", "b"), "-") - U.deepStrictEqual(pipe("a", A.combineMany([])), "-") - U.deepStrictEqual(pipe("a", A.combineMany(["b", "c", "d"])), "-") + const S = _.constant("-") + U.deepStrictEqual(S.combine("a", "b"), "-") + U.deepStrictEqual(S.combineMany("a", []), "-") + U.deepStrictEqual(S.combineMany("a", ["b", "c", "d"]), "-") }) it("intercalate", () => { - const A = pipe(String.Semigroup, _.intercalate("|")) - U.deepStrictEqual(A.combine("a", "b"), "a|b") - U.deepStrictEqual(pipe("a", A.combineMany([])), "a") - U.deepStrictEqual(pipe("a", A.combineMany(["b"])), "a|b") - U.deepStrictEqual(pipe("a", A.combineMany(["b", "c", "d"])), "a|b|c|d") + const S = pipe(String.Semigroup, _.intercalate("|")) + U.deepStrictEqual(S.combine("a", "b"), "a|b") + U.deepStrictEqual(S.combineMany("a", []), "a") + U.deepStrictEqual(S.combineMany("a", ["b"]), "a|b") + U.deepStrictEqual(S.combineMany("a", ["b", "c", "d"]), "a|b|c|d") }) describe("min", () => { it("should return the minimum", () => { - const A = _.min(Number.Order) - U.deepStrictEqual(pipe(1, A.combineMany([])), 1) - U.deepStrictEqual(pipe(1, A.combineMany([3, 2])), 1) + const S = _.min(Number.Order) + U.deepStrictEqual(S.combineMany(1, []), 1) + U.deepStrictEqual(S.combineMany(1, [3, 2]), 1) }) it("should return the last minimum", () => { type Item = { a: number } const A = _.min(pipe(Number.Order, order.contramap((_: Item) => _.a))) const item: Item = { a: 1 } - U.strictEqual(pipe({ a: 2 }, A.combineMany([{ a: 1 }, item])), item) - U.strictEqual(pipe(item, A.combineMany([])), item) + U.strictEqual(A.combineMany({ a: 2 }, [{ a: 1 }, item]), item) + U.strictEqual(A.combineMany(item, []), item) }) }) describe("max", () => { it("should return the maximum", () => { - const A = _.max(Number.Order) - U.deepStrictEqual(pipe(1, A.combineMany([])), 1) - U.deepStrictEqual(pipe(1, A.combineMany([3, 2])), 3) + const S = _.max(Number.Order) + U.deepStrictEqual(S.combineMany(1, []), 1) + U.deepStrictEqual(S.combineMany(1, [3, 2]), 3) }) it("should return the last minimum", () => { type Item = { a: number } - const A = _.max(pipe(Number.Order, order.contramap((_: Item) => _.a))) + const S = _.max(pipe(Number.Order, order.contramap((_: Item) => _.a))) const item: Item = { a: 2 } - U.strictEqual(pipe({ a: 1 }, A.combineMany([{ a: 2 }, item])), item) - U.strictEqual(pipe(item, A.combineMany([])), item) + U.strictEqual(S.combineMany({ a: 1 }, [{ a: 2 }, item]), item) + U.strictEqual(S.combineMany(item, []), item) }) }) it("struct", () => { - const A = _.struct({ + const S = _.struct({ name: String.Semigroup, age: Number.SemigroupSum }) - U.deepStrictEqual(A.combine({ name: "a", age: 10 }, { name: "b", age: 20 }), { + U.deepStrictEqual(S.combine({ name: "a", age: 10 }, { name: "b", age: 20 }), { name: "ab", age: 30 }) - U.deepStrictEqual(pipe({ name: "a", age: 10 }, A.combineMany([])), { + U.deepStrictEqual(S.combineMany({ name: "a", age: 10 }, []), { name: "a", age: 10 }) - U.deepStrictEqual(pipe({ name: "a", age: 10 }, A.combineMany([{ name: "b", age: 20 }])), { + U.deepStrictEqual(S.combineMany({ name: "a", age: 10 }, [{ name: "b", age: 20 }]), { name: "ab", age: 30 }) U.deepStrictEqual( - pipe({ name: "a", age: 10 }, A.combineMany([{ name: "b", age: 20 }, { name: "c", age: 30 }])), + S.combineMany({ name: "a", age: 10 }, [{ name: "b", age: 20 }, { name: "c", age: 30 }]), { name: "abc", age: 60 @@ -92,53 +92,46 @@ describe("Semigroup", () => { }) it("tuple", () => { - const A = _.tuple( + const S = _.tuple( String.Semigroup, Number.SemigroupSum ) - U.deepStrictEqual(A.combine(["a", 10], ["b", 20]), ["ab", 30]) - U.deepStrictEqual(pipe(["a", 10], A.combineMany([])), ["a", 10]) - U.deepStrictEqual(pipe(["a", 10], A.combineMany([["b", 20]])), ["ab", 30]) - U.deepStrictEqual(pipe(["a", 10], A.combineMany([["b", 20], ["c", 30]])), ["abc", 60]) + U.deepStrictEqual(S.combine(["a", 10], ["b", 20]), ["ab", 30]) + U.deepStrictEqual(S.combineMany(["a", 10], []), ["a", 10]) + U.deepStrictEqual(S.combineMany(["a", 10], [["b", 20]]), ["ab", 30]) + U.deepStrictEqual(S.combineMany(["a", 10], [["b", 20], ["c", 30]]), ["abc", 60]) }) it("first", () => { - const A = _.first() - U.deepStrictEqual(A.combine(1, 2), 1) - U.deepStrictEqual(pipe(1, A.combineMany([])), 1) - U.deepStrictEqual(pipe(1, A.combineMany([2, 3, 4, 5, 6])), 1) + const S = _.first() + U.deepStrictEqual(S.combine(1, 2), 1) + U.deepStrictEqual(S.combineMany(1, []), 1) + U.deepStrictEqual(S.combineMany(1, [2, 3, 4, 5, 6]), 1) }) it("last", () => { - const A = _.last() - U.deepStrictEqual(A.combine(1, 2), 2) - U.deepStrictEqual(pipe(1, A.combineMany([])), 1) - U.deepStrictEqual(pipe(1, A.combineMany([2, 3, 4, 5, 6])), 6) + const S = _.last() + U.deepStrictEqual(S.combine(1, 2), 2) + U.deepStrictEqual(S.combineMany(1, []), 1) + U.deepStrictEqual(S.combineMany(1, [2, 3, 4, 5, 6]), 6) }) it("imap", () => { const imap = _.imap - const To = imap((s: string) => [s], ([s]) => s)(String.Semigroup) - U.deepStrictEqual(To.combine(["a"], ["b"]), ["ab"]) - U.deepStrictEqual(pipe(["a"], To.combineMany([])), ["a"]) - U.deepStrictEqual(pipe(["a"], To.combineMany([["b"]])), ["ab"]) - U.deepStrictEqual(pipe(["a"], To.combineMany([["b"], ["c"]])), ["abc"]) - - U.deepStrictEqual( - pipe( - ["a"], - _.Invariant.imap((s: string) => [s], ([s]) => s)(String.Semigroup).combineMany([["b"], [ - "c" - ]]) - ), - ["abc"] - ) + const S1 = imap((s: string) => [s], ([s]) => s)(String.Semigroup) + U.deepStrictEqual(S1.combine(["a"], ["b"]), ["ab"]) + U.deepStrictEqual(S1.combineMany(["a"], []), ["a"]) + U.deepStrictEqual(S1.combineMany(["a"], [["b"]]), ["ab"]) + U.deepStrictEqual(S1.combineMany(["a"], [["b"], ["c"]]), ["abc"]) // should handle an Iterable - U.deepStrictEqual(pipe(["a"], To.combineMany(new Set([["b"], ["c"]]))), ["abc"]) + U.deepStrictEqual(S1.combineMany(["a"], new Set([["b"], ["c"]])), ["abc"]) + + const S2 = pipe(String.Semigroup, _.Invariant.imap((s: string) => [s], ([s]) => s)) + U.deepStrictEqual(S2.combineMany(["a"], [["b"], ["c"]]), ["abc"]) }) it("product", () => { - const A = pipe( + const S = pipe( String.Semigroup, _.SemiProduct.product(Number.SemigroupSum), _.SemiProduct.product(Number.SemigroupMultiply), @@ -147,14 +140,14 @@ describe("Semigroup", () => { ([a, b, c]): [[string, number], number] => [[a, b], c] ) ) - U.deepStrictEqual(A.combine(["a", 2, 3], ["b", 3, 4]), ["ab", 5, 12]) + U.deepStrictEqual(S.combine(["a", 2, 3], ["b", 3, 4]), ["ab", 5, 12]) }) it("productMany", () => { - const A = pipe( + const S = pipe( String.Semigroup, _.SemiProduct.productMany([String.Semigroup, String.Semigroup]) ) - U.deepStrictEqual(A.combine(["a", "b", "c"], ["d", "e", "f"]), ["ad", "be", "cf"]) + U.deepStrictEqual(S.combine(["a", "b", "c"], ["d", "e", "f"]), ["ad", "be", "cf"]) }) }) From 51cc3291d0b5f3ede35442df86143201c4eb231f Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 15:52:08 +0100 Subject: [PATCH 070/255] SemiProduct: make product binary --- CHANGELOG.md | 3 +- src/Either.ts | 23 ++---------- src/Identity.ts | 19 ++-------- src/Option.ts | 22 ++--------- src/Predicate.ts | 22 ++--------- src/ReadonlyArray.ts | 43 +++++++++------------- src/These.ts | 57 ++++++++++++----------------- src/typeclass/Equivalence.ts | 2 +- src/typeclass/Order.ts | 2 +- src/typeclass/SemiApplicative.ts | 14 +++---- src/typeclass/SemiProduct.ts | 34 +++++++---------- src/typeclass/Semigroup.ts | 2 +- test/Either.ts | 35 ++++++++++-------- test/Identity.ts | 6 +-- test/Option.ts | 12 +++--- test/Predicate.ts | 12 +++--- test/ReadonlyArray.ts | 28 ++++++-------- test/These.ts | 63 +++++++++++++++++--------------- test/typeclass/Equivalence.ts | 4 +- test/typeclass/Order.ts | 4 +- test/typeclass/SemiProduct.ts | 38 ++++++++++--------- test/typeclass/Semigroup.ts | 7 ++-- 22 files changed, 186 insertions(+), 266 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28dde2d23..56617abaf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,8 @@ - `Semigroup` - make `combine` binary - make `combineMany` binary -- `Semiproduct` +- `SemiProduct` + - make `product` binary - rename `productFlatten` to `element` - `Order` - make `compare` binary diff --git a/src/Either.ts b/src/Either.ts index a11d9e99a..059954922 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -359,20 +359,7 @@ export const Monad: monad.Monad = { ...FlatMap } -/** - * @since 1.0.0 - */ -export const product = ( - that: Either -) => - (self: Either): Either => - isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self - -/** - * @category error handling - * @since 1.0.0 - */ -export const productMany = ( +const productMany = ( collection: Iterable> ) => (self: Either): Either]> => { @@ -395,7 +382,8 @@ export const productMany = ( */ export const SemiProduct: semiProduct.SemiProduct = { ...Invariant, - product, + product: (self, that) => + isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self, productMany } @@ -425,10 +413,7 @@ export const element: ( ) => Either = semiProduct .element(SemiProduct) -/** - * @since 1.0.0 - */ -export const productAll = ( +const productAll = ( collection: Iterable> ): Either> => { const out: Array = [] diff --git a/src/Identity.ts b/src/Identity.ts index 3a87f7966..2e453e453 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -251,17 +251,7 @@ export const Monad: monad.Monad = { ...FlatMap } -/** - * @since 1.0.0 - */ -export const product = ( - that: Identity -) => (self: Identity): Identity<[A, B]> => [self, that] - -/** - * @since 1.0.0 - */ -export const productMany = (collection: Iterable>) => +const productMany = (collection: Iterable>) => (self: Identity): Identity<[A, ...Array]> => [self, ...collection] /** @@ -270,7 +260,7 @@ export const productMany = (collection: Iterable>) => */ export const SemiProduct: semiProduct.SemiProduct = { ...Invariant, - product, + product: (self, that) => [self, that], productMany } @@ -298,10 +288,7 @@ export const element: ( ) => >(self: Identity) => Identity<[...A, B]> = semiProduct .element(SemiProduct) -/** - * @since 1.0.0 - */ -export const productAll = (collection: Iterable>): Identity> => +const productAll = (collection: Iterable>): Identity> => readonlyArray.fromIterable(collection) /** diff --git a/src/Option.ts b/src/Option.ts index 368dcad20..ed68076fd 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -406,19 +406,7 @@ export const Monad: monad.Monad = { ...FlatMap } -/** - * @since 1.0.0 - */ -export const product = ( - that: Option -) => - (self: Option): Option<[A, B]> => - isSome(self) && isSome(that) ? some([self.value, that.value]) : option.none - -/** - * @since 1.0.0 - */ -export const productMany = (collection: Iterable>) => +const productMany = (collection: Iterable>) => (self: Option): Option<[A, ...Array]> => { if (isNone(self)) { return option.none @@ -439,7 +427,8 @@ export const productMany = (collection: Iterable>) => */ export const SemiProduct: semiProduct.SemiProduct = { ...Invariant, - product, + product: (self, that) => + isSome(self) && isSome(that) ? some([self.value, that.value]) : option.none, productMany } @@ -465,10 +454,7 @@ export const element: ( ) => >(self: Option) => Option<[...A, B]> = semiProduct .element(SemiProduct) -/** - * @since 1.0.0 - */ -export const productAll = (collection: Iterable>): Option> => { +const productAll = (collection: Iterable>): Option> => { const out: Array = [] for (const o of collection) { if (isNone(o)) { diff --git a/src/Predicate.ts b/src/Predicate.ts index 3bae8a9c8..4aac24a4b 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -151,16 +151,7 @@ export const Do: Predicate<{}> = of_.Do(Of) */ export const unit: Predicate = of_.unit(Of) -/** - * @since 1.0.0 - */ -export const product = (that: Predicate) => - (self: Predicate): Predicate => ([a, b]) => self(a) && that(b) - -/** - * @since 1.0.0 - */ -export const productMany = (collection: Iterable>) => +const productMany = (collection: Iterable>) => (self: Predicate): Predicate]> => { return ([head, ...tail]) => { if (self(head) === false) { @@ -182,14 +173,11 @@ export const productMany = (collection: Iterable>) => */ export const SemiProduct: semiProduct.SemiProduct = { imap, - product, + product: (self, that) => ([a, b]) => self(a) && that(b), productMany } -/** - * @since 1.0.0 - */ -export const productAll = ( +const productAll = ( collection: Iterable> ): Predicate> => (as) => { @@ -207,9 +195,7 @@ export const productAll = ( * @since 1.0.0 */ export const Product: product_.Product = { - imap, - product, - productMany, + ...SemiProduct, of, productAll } diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 2a944f518..9af39fe13 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1675,37 +1675,30 @@ export const sequenceNonEmpty = ( self: NonEmptyReadonlyArray> ) => Kind>) => traverseNonEmpty(F)(identity) -/** - * @since 1.0.0 - */ -export const product = ( +const product = ( + self: ReadonlyArray, that: ReadonlyArray -) => - (self: ReadonlyArray): Array<[A, B]> => { - if (isEmpty(self) || isEmpty(that)) { - return empty() - } - const out: Array<[A, B]> = [] - for (let i = 0; i < self.length; i++) { - for (let j = 0; j < that.length; j++) { - out.push([self[i], that[j]]) - } +): Array<[A, B]> => { + if (isEmpty(self) || isEmpty(that)) { + return empty() + } + const out: Array<[A, B]> = [] + for (let i = 0; i < self.length; i++) { + for (let j = 0; j < that.length; j++) { + out.push([self[i], that[j]]) } - return out } + return out +} -/** - * @since 1.0.0 - */ -export const productMany: ( +const productMany: ( collection: Iterable> -) => (self: ReadonlyArray) => Array<[A, ...Array]> = semiProduct - .productMany(Covariant, product) as any +) => (self: ReadonlyArray) => Array<[A, ...Array]> = semiProduct.productMany( + Covariant, + product +) as any -/** - * @since 1.0.0 - */ -export const productAll = ( +const productAll = ( collection: Iterable> ): Array> => { const arrays = Array.from(collection) diff --git a/src/These.ts b/src/These.ts index b4b076a36..01eb8ed30 100644 --- a/src/These.ts +++ b/src/These.ts @@ -952,44 +952,36 @@ export const filterMap = ( return option.isNone(ob) ? left(onNone()) : both(self.left, ob.value) } -/** - * @since 1.0.0 - */ -export const product = (that: Validated) => - ( - self: Validated - ): Validated => { - if (isLeft(self)) { - return self - } - if (isRight(self)) { - if (isLeft(that)) { - return that - } - if (isRight(that)) { - return right([self.right, that.right]) - } - return both(that.left, [self.right, that.right]) - } +const product = ( + self: Validated, + that: Validated +): Validated => { + if (isLeft(self)) { + return self + } + if (isRight(self)) { if (isLeft(that)) { - return left(RA.appendAllNonEmpty(that.left)(self.left)) + return that } if (isRight(that)) { - return both(self.left, [self.right, that.right]) + return right([self.right, that.right]) } - return both(RA.appendAllNonEmpty(that.left)(self.left), [self.right, that.right]) + return both(that.left, [self.right, that.right]) + } + if (isLeft(that)) { + return left(RA.appendAllNonEmpty(that.left)(self.left)) } + if (isRight(that)) { + return both(self.left, [self.right, that.right]) + } + return both(RA.appendAllNonEmpty(that.left)(self.left), [self.right, that.right]) +} -/** - * @since 1.0.0 - */ -export const productMany = ( +const productMany = ( collection: Iterable> ) => - ( - self: Validated - ): Validated]> => - pipe(self, product(productAll(collection)), map(([a, as]) => [a, ...as])) + (self: Validated): Validated]> => + pipe(product(self, productAll(collection)), map(([a, as]) => [a, ...as])) /** * @category instances @@ -1054,10 +1046,7 @@ export const getFirstLeftSemigroup: ( ) => Semigroup> = semiApplicative .liftSemigroup(SemiApplicative) -/** - * @since 1.0.0 - */ -export const productAll = ( +const productAll = ( collection: Iterable> ): Validated> => { const rights: Array = [] diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 3929cb0e7..d13ba4380 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -195,7 +195,7 @@ export const Invariant: invariant.Invariant = { */ export const SemiProduct: semiProduct.SemiProduct = { imap: Contravariant.imap, - product: that => self => tuple(self, that), + product: tuple, productMany: collection => self => tuple(self, ...collection) } diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 3158a1821..a52386b74 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -185,7 +185,7 @@ export const Invariant: invariant.Invariant = { */ export const SemiProduct: semiProduct.SemiProduct = { imap: Contravariant.imap, - product: that => self => tuple(self, that), + product: tuple, productMany: collection => self => tuple(self, ...collection) } diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 063707118..2a31677d7 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -20,7 +20,7 @@ export interface SemiApplicative extends SemiProduct, C */ export const liftSemigroup = (F: SemiApplicative) => (S: Semigroup): Semigroup> => ({ - combine: (self, that) => pipe(self, F.product(that), F.map(([a1, a2]) => S.combine(a1, a2))), + combine: (self, that) => pipe(F.product(self, that), F.map(([a1, a2]) => S.combine(a1, a2))), combineMany: (self, collection) => pipe( self, @@ -38,7 +38,7 @@ export const ap = (F: SemiApplicative) => ) => ( self: Kind B> - ): Kind => pipe(self, F.product(fa), F.map(([f, a]) => f(a))) + ): Kind => pipe(F.product(self, fa), F.map(([f, a]) => f(a))) /** * @since 1.0.0 @@ -49,7 +49,7 @@ export const andThenDiscard = (F: SemiApplicative) => ) => ( self: Kind - ): Kind => pipe(self, F.product(that), F.map(([a]) => a)) + ): Kind => pipe(F.product(self, that), F.map(([a]) => a)) /** * @since 1.0.0 @@ -60,7 +60,7 @@ export const andThen = (F: SemiApplicative) => ) => ( self: Kind - ): Kind => pipe(self, F.product(that), F.map(([_, a]) => a)) + ): Kind => pipe(F.product(self, that), F.map(([_, a]) => a)) /** * Lifts a binary function into `F`. @@ -72,7 +72,7 @@ export const lift2 = (F: SemiApplicative) => ( fa: Kind, fb: Kind - ): Kind => pipe(fa, F.product(fb), F.map(([a, b]) => f(a, b))) + ): Kind => pipe(F.product(fa, fb), F.map(([a, b]) => f(a, b))) /** * Lifts a ternary function into 'F'. @@ -87,8 +87,6 @@ export const lift3 = (F: SemiApplicative) => fc: Kind ): Kind => pipe( - fa, - F.product(fb), - F.product(fc), + F.product(F.product(fa, fb), fc), F.map(([[a, b], c]) => f(a, b, c)) ) diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 2bcf5ddac..6fec78bdb 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -12,10 +12,9 @@ import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" * @since 1.0.0 */ export interface SemiProduct extends Invariant { - readonly product: ( + readonly product: ( + self: Kind, that: Kind - ) => ( - self: Kind ) => Kind readonly productMany: ( @@ -32,18 +31,16 @@ export const productComposition = ( F: SemiApplicative, G: SemiProduct ) => - ( + ( + self: Kind>, that: Kind> - ) => - ( - self: Kind> - ): Kind< - F, - FR1 & FR2, - FO1 | FO2, - FE1 | FE2, - Kind - > => pipe(self, F.product(that), F.map(([ga, gb]) => pipe(ga, G.product(gb)))) + ): Kind< + F, + FR1 & FR2, + FO1 | FO2, + FE1 | FE2, + Kind + > => pipe(F.product(self, that), F.map(([ga, gb]) => G.product(ga, gb))) /** * Returns a default `productMany` composition. @@ -86,8 +83,7 @@ export const productMany = ( ) for (const fa of collection) { out = pipe( - out, - product(fa), + product(out, fa), Covariant.map(([[head, ...tail], a]): [A, ...Array] => [head, ...tail, a]) ) } @@ -112,8 +108,7 @@ export const andThenBind = (F: SemiProduct) => { [K in keyof A | N]: K extends keyof A ? A[K] : B } > => pipe( - self, - F.product(that), + F.product(self, that), F.imap( ([a, b]) => Object.assign({}, a, { [name]: b }) as any, ({ [name]: b, ...rest }) => [rest, b] as any @@ -133,8 +128,7 @@ export const element = (F: SemiProduct) => self: Kind ): Kind => pipe( - self, - F.product(that), + F.product(self, that), F.imap(([a, b]) => [...a, b], ab => [ab.slice(0, -1), ab[ab.length - 1]] as any) ) diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 464ed4d4a..a72572d5e 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -326,7 +326,7 @@ export const Invariant: invariant.Invariant = { */ export const SemiProduct: semiProduct.SemiProduct = { ...Invariant, - product: that => self => tuple(self, that), + product: tuple, productMany: collection => self => tuple(self, ...collection) } diff --git a/test/Either.ts b/test/Either.ts index fe9844b2a..37b709857 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -44,10 +44,8 @@ describe.concurrent("Either", () => { expect(_.Monad).exist expect(_.SemiProduct).exist - expect(_.product).exist expect(_.Product).exist - expect(_.productAll).exist expect(_.tuple).exist expect(_.struct).exist @@ -381,36 +379,41 @@ describe.concurrent("Either", () => { }) it("product", () => { - deepStrictEqual(pipe(_.right(1), _.product(_.right("a"))), _.right([1, "a"])) - deepStrictEqual(pipe(_.right(1), _.product(_.left("e2"))), _.left("e2")) - deepStrictEqual(pipe(_.left("e1"), _.product(_.right("a"))), _.left("e1")) - deepStrictEqual(pipe(_.left("e1"), _.product(_.left("2"))), _.left("e1")) + const product = _.SemiProduct.product + deepStrictEqual(product(_.right(1), _.right("a")), _.right([1, "a"])) + deepStrictEqual(product(_.right(1), _.left("e2")), _.left("e2")) + deepStrictEqual(product(_.left("e1"), _.right("a")), _.left("e1")) + deepStrictEqual(product(_.left("e1"), _.left("2")), _.left("e1")) }) it("productMany", () => { - deepStrictEqual(pipe(_.right(1), _.productMany([])), _.right([1])) + const productMany: ( + collection: Iterable<_.Either> + ) => (self: _.Either) => _.Either]> = _.SemiProduct.productMany + + deepStrictEqual(pipe(_.right(1), productMany([])), _.right([1])) deepStrictEqual( - pipe(_.right(1), _.productMany([_.right(2), _.right(3)])), + pipe(_.right(1), productMany([_.right(2), _.right(3)])), _.right([1, 2, 3]) ) deepStrictEqual( - pipe(_.right(1), _.productMany([_.left("e"), _.right(3)])), - _.left("e") - ) - deepStrictEqual( - pipe(_.left("e"), _.productMany([_.right(2), _.right(3)])), + pipe(_.right(1), productMany([_.left("e"), _.right(3)])), _.left("e") ) + expect( + pipe(_.left("e"), productMany([_.right(2), _.right(3)])) + ).toEqual(_.left("e")) }) it("productAll", () => { - deepStrictEqual(_.productAll([]), _.right([])) + const productAll = _.Product.productAll + deepStrictEqual(productAll([]), _.right([])) deepStrictEqual( - _.productAll([_.right(1), _.right(2), _.right(3)]), + productAll([_.right(1), _.right(2), _.right(3)]), _.right([1, 2, 3]) ) deepStrictEqual( - _.productAll([_.left("e"), _.right(2), _.right(3)]), + productAll([_.left("e"), _.right(2), _.right(3)]), _.left("e") ) }) diff --git a/test/Identity.ts b/test/Identity.ts index fbc74fe38..8f130aa9b 100644 --- a/test/Identity.ts +++ b/test/Identity.ts @@ -38,13 +38,10 @@ describe.concurrent("Identity", () => { expect(_.Monad).exist expect(_.SemiProduct).exist - expect(_.product).exist - expect(_.productMany).exist expect(_.andThenBind).exist expect(_.element).exist expect(_.Product).exist - expect(_.productAll).exist expect(_.tuple).exist expect(_.struct).exist @@ -100,7 +97,8 @@ describe.concurrent("Identity", () => { }) it("product", () => { - U.deepStrictEqual(pipe("a", _.product("b")), ["a", "b"]) + const product = _.SemiProduct.product + U.deepStrictEqual(product("a", "b"), ["a", "b"]) }) it("getSemiCoproduct", () => { diff --git a/test/Option.ts b/test/Option.ts index 93f1da94b..cd3e30016 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -42,11 +42,8 @@ describe.concurrent("Option", () => { expect(_.Monad).exist expect(_.SemiProduct).exist - expect(_.product).exist - expect(_.productMany).exist expect(_.Product).exist - expect(_.productAll).exist expect(_.tuple).exist expect(_.struct).exist @@ -211,11 +208,12 @@ describe.concurrent("Option", () => { }) it("product", () => { - deepStrictEqual(pipe(_.none(), _.product(_.none())), _.none()) - deepStrictEqual(pipe(_.some(1), _.product(_.none())), _.none()) - deepStrictEqual(pipe(_.none(), _.product(_.some("a"))), _.none()) + const product = _.SemiProduct.product + deepStrictEqual(product(_.none(), _.none()), _.none()) + deepStrictEqual(product(_.some(1), _.none()), _.none()) + deepStrictEqual(product(_.none(), _.some("a")), _.none()) deepStrictEqual( - pipe(_.some(1), _.product(_.some("a"))), + product(_.some(1), _.some("a")), _.some([1, "a"]) ) }) diff --git a/test/Predicate.ts b/test/Predicate.ts index 269e68f27..9298ca40c 100644 --- a/test/Predicate.ts +++ b/test/Predicate.ts @@ -32,13 +32,10 @@ describe.concurrent("Predicate", () => { expect(_.Do).exist expect(_.SemiProduct).exist - expect(_.product).exist - expect(_.productMany).exist expect(_.andThenBind).exist expect(_.element).exist expect(_.Product).exist - expect(_.productAll).exist expect(_.tuple).exist expect(_.struct).exist }) @@ -69,7 +66,8 @@ describe.concurrent("Predicate", () => { }) it("product", () => { - const p = pipe(isPositive, _.product(isNegative)) + const product = _.SemiProduct.product + const p = product(isPositive, isNegative) deepStrictEqual(p([1, -1]), true) deepStrictEqual(p([1, 1]), false) deepStrictEqual(p([-1, -1]), false) @@ -77,7 +75,8 @@ describe.concurrent("Predicate", () => { }) it("productMany", () => { - const p = pipe(isPositive, _.productMany([isNegative])) + const productMany = _.SemiProduct.productMany + const p = pipe(isPositive, productMany([isNegative])) deepStrictEqual(p([1, -1]), true) deepStrictEqual(p([1, 1]), false) deepStrictEqual(p([-1, -1]), false) @@ -85,7 +84,8 @@ describe.concurrent("Predicate", () => { }) it("productAll", () => { - const p = _.productAll([isPositive, isNegative]) + const productAll = _.Product.productAll + const p = productAll([isPositive, isNegative]) deepStrictEqual(p([1, -1]), true) deepStrictEqual(p([1, 1]), false) deepStrictEqual(p([-1, -1]), false) diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 89b7281e9..0784ea741 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -7,7 +7,6 @@ import * as RA from "@fp-ts/core/ReadonlyArray" import * as String from "@fp-ts/core/String" import { deepStrictEqual, double, strictEqual } from "@fp-ts/core/test/util" import * as Order from "@fp-ts/core/typeclass/Order" -import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as assert from "assert" import * as fc from "fast-check" @@ -41,15 +40,10 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.Monad).exist expect(RA.SemiProduct).exist - expect(RA.product).exist - expect(RA.productMany).exist expect(RA.andThenBind).exist expect(RA.element).exist expect(RA.Product).exist - expect(RA.productAll).exist - // expect(ReadonlyArray.tuple).exist - // expect(ReadonlyArray.struct).exist expect(RA.SemiApplicative).exist expect(RA.liftSemigroup).exist @@ -1608,9 +1602,10 @@ describe.concurrent("ReadonlyArray", () => { }) test("product", () => { - expect(pipe([], RA.product(["a", "b"]))).toEqual([]) - expect(pipe([1, 2], RA.product([]))).toEqual([]) - expect(pipe([1, 2], RA.product(["a", "b"]))).toEqual([ + const product = RA.SemiProduct.product + expect(product([], ["a", "b"])).toEqual([]) + expect(product([1, 2], [])).toEqual([]) + expect(product([1, 2], ["a", "b"])).toEqual([ [1, "a"], [1, "b"], [2, "a"], @@ -1619,10 +1614,10 @@ describe.concurrent("ReadonlyArray", () => { }) test("productMany", () => { - const productMany = semiProduct.productMany(RA.Covariant, RA.product) + const productMany = RA.SemiProduct.productMany expect(pipe( [], - RA.productMany([ + productMany([ [2], [4, 5], [8, 9, 10] @@ -1637,14 +1632,14 @@ describe.concurrent("ReadonlyArray", () => { )) expect(pipe( [1, 2, 3], - RA.productMany([]) + productMany([]) )).toEqual(pipe( [1, 2, 3], productMany([]) )) expect(pipe( [1, 2, 3], - RA.productMany([ + productMany([ [2], [4, 5], [8, 9, 10] @@ -1660,9 +1655,10 @@ describe.concurrent("ReadonlyArray", () => { }) test("productAll", () => { - expect(RA.productAll([])).toEqual([]) - expect(RA.productAll([[1, 2, 3]])).toEqual([[1], [2], [3]]) - expect(RA.productAll([[1, 2, 3], [4, 5]])).toEqual([[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [ + const productAll = RA.Product.productAll + expect(productAll([])).toEqual([]) + expect(productAll([[1, 2, 3]])).toEqual([[1], [2], [3]]) + expect(productAll([[1, 2, 3], [4, 5]])).toEqual([[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [ 3, 5 ]]) diff --git a/test/These.ts b/test/These.ts index 680bc8efd..2b9792baa 100644 --- a/test/These.ts +++ b/test/These.ts @@ -44,13 +44,10 @@ describe("These", () => { expect(_.Monad).exist expect(_.SemiProduct).exist - expect(_.product).exist - expect(_.productMany).exist expect(_.andThenBind).exist expect(_.element).exist expect(_.Product).exist - expect(_.productAll).exist expect(_.tuple).exist expect(_.struct).exist @@ -274,17 +271,18 @@ describe("These", () => { const b = ["b"] as const const ab = ["a", "b"] as const - expect(pipe(_.right(1), _.product(_.right(2)))).toEqual(_.right([1, 2])) - U.deepStrictEqual(pipe(_.right(1), _.product(_.left(b))), _.left(b)) - expect(pipe(_.right(1), _.product(_.both(b, 2)))).toEqual(_.both(b, [1, 2])) + const product = _.SemiProduct.product + expect(product(_.right(1), _.right(2))).toEqual(_.right([1, 2])) + U.deepStrictEqual(product(_.right(1), _.left(b)), _.left(b)) + expect(product(_.right(1), _.both(b, 2))).toEqual(_.both(b, [1, 2])) - U.deepStrictEqual(pipe(_.left(a), _.product(_.right(2))), _.left(a)) - U.deepStrictEqual(pipe(_.left(a), _.product(_.left(b))), _.left(a)) - U.deepStrictEqual(pipe(_.left(a), _.product(_.both(b, 2))), _.left(a)) + U.deepStrictEqual(product(_.left(a), _.right(2)), _.left(a)) + U.deepStrictEqual(product(_.left(a), _.left(b)), _.left(a)) + U.deepStrictEqual(product(_.left(a), _.both(b, 2)), _.left(a)) - expect(pipe(_.both(a, 1), _.product(_.right(2)))).toEqual(_.both(a, [1, 2])) - expect(pipe(_.both(a, 1), _.product(_.left(b)))).toEqual(_.left(ab)) - expect(pipe(_.both(a, 1), _.product(_.both(b, 2)))).toEqual(_.both(ab, [1, 2])) + expect(product(_.both(a, 1), _.right(2))).toEqual(_.both(a, [1, 2])) + expect(product(_.both(a, 1), _.left(b))).toEqual(_.left(ab)) + expect(product(_.both(a, 1), _.both(b, 2))).toEqual(_.both(ab, [1, 2])) }) it("productMany", () => { @@ -292,27 +290,31 @@ describe("These", () => { const b = ["b"] as const const ab = ["a", "b"] as const - expect(pipe(_.right(1), _.productMany([_.right(2)]))).toEqual(_.right([1, 2])) + const productMany: ( + collection: Iterable<_.Validated> + ) => (self: _.Validated) => _.Validated]> = _.SemiProduct.productMany + + expect(pipe(_.right(1), productMany([_.right(2)]))).toEqual(_.right([1, 2])) U.deepStrictEqual( - pipe(_.right(1), _.productMany([_.left(b)])), + pipe(_.right(1), productMany([_.left(b)])), _.left(b) ) expect( - pipe(_.right(1), _.productMany([_.both(b, 2)])) + pipe(_.right(1), productMany([_.both(b, 2)])) ).toEqual( _.both(b, [1, 2]) ) - U.deepStrictEqual(pipe(_.left(a), _.productMany([_.right(2)])), _.left(a)) - U.deepStrictEqual(pipe(_.left(a), _.productMany([_.left(b)])), _.left(a)) + U.deepStrictEqual(pipe(_.left(a), productMany([_.right(2)])), _.left(a)) + U.deepStrictEqual(pipe(_.left(a), productMany([_.left(b)])), _.left(a)) U.deepStrictEqual( - pipe(_.left(a), _.productMany([_.both(b, 2)])), + pipe(_.left(a), productMany([_.both(b, 2)])), _.left(a) ) - expect(pipe(_.both(a, 1), _.productMany([_.right(2)]))).toEqual(_.both(a, [1, 2])) - expect(pipe(_.both(a, 1), _.productMany([_.left(b)]))).toEqual(_.left(ab)) - expect(pipe(_.both(a, 1), _.productMany([_.both(b, 2)]))).toEqual( + expect(pipe(_.both(a, 1), productMany([_.right(2)]))).toEqual(_.both(a, [1, 2])) + expect(pipe(_.both(a, 1), productMany([_.left(b)]))).toEqual(_.left(ab)) + expect(pipe(_.both(a, 1), productMany([_.both(b, 2)]))).toEqual( _.both(ab, [1, 2]) ) }) @@ -322,17 +324,18 @@ describe("These", () => { const b = ["b"] as const const ab = ["a", "b"] as const - U.deepStrictEqual(_.productAll([_.right(1), _.right(2)]), _.right([1, 2])) - U.deepStrictEqual(_.productAll([_.right(1), _.left(b)]), _.left(b)) - U.deepStrictEqual(_.productAll([_.right(1), _.both(b, 2)]), _.both(b, [1, 2])) + const productAll = _.Product.productAll + U.deepStrictEqual(productAll([_.right(1), _.right(2)]), _.right([1, 2])) + U.deepStrictEqual(productAll([_.right(1), _.left(b)]), _.left(b)) + U.deepStrictEqual(productAll([_.right(1), _.both(b, 2)]), _.both(b, [1, 2])) - U.deepStrictEqual(_.productAll([_.left(a), _.right(2)]), _.left(a)) - U.deepStrictEqual(_.productAll([_.left(a), _.left(b)]), _.left(a)) - U.deepStrictEqual(_.productAll([_.left(a), _.both(b, 2)]), _.left(a)) + U.deepStrictEqual(productAll([_.left(a), _.right(2)]), _.left(a)) + U.deepStrictEqual(productAll([_.left(a), _.left(b)]), _.left(a)) + U.deepStrictEqual(productAll([_.left(a), _.both(b, 2)]), _.left(a)) - U.deepStrictEqual(_.productAll([_.both(a, 1), _.right(2)]), _.both(a, [1, 2])) - expect(_.productAll([_.both(a, 1), _.left(b)])).toEqual(_.left(ab)) - expect(_.productAll([_.both(a, 1), _.both(b, 2)])).toEqual(_.both(ab, [1, 2])) + U.deepStrictEqual(productAll([_.both(a, 1), _.right(2)]), _.both(a, [1, 2])) + expect(productAll([_.both(a, 1), _.left(b)])).toEqual(_.left(ab)) + expect(productAll([_.both(a, 1), _.both(b, 2)])).toEqual(_.both(ab, [1, 2])) }) it("flatMap", () => { diff --git a/test/typeclass/Equivalence.ts b/test/typeclass/Equivalence.ts index 2eaaf393d..2668fd960 100644 --- a/test/typeclass/Equivalence.ts +++ b/test/typeclass/Equivalence.ts @@ -137,9 +137,9 @@ describe("Equivalence", () => { }) it("SemiProduct/product", () => { - const eq = pipe( + const eq = _.SemiProduct.product( _.string, - _.SemiProduct.product(_.string) + _.string ) expect(eq(["a", "b"], ["a", "b"])).toEqual(true) expect(eq(["a", "b"], ["a", "c"])).toEqual(false) diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index 1f4c8edca..bf41c8e08 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -197,9 +197,9 @@ describe("Order", () => { describe("SemiProduct", () => { it("product", () => { - const O = pipe( + const O = _.SemiProduct.product( string.Order, - _.SemiProduct.product(number.Order) + number.Order ) U.deepStrictEqual(O.compare(["a", 1], ["a", 2]), -1) U.deepStrictEqual(O.compare(["a", 1], ["a", 1]), 0) diff --git a/test/typeclass/SemiProduct.ts b/test/typeclass/SemiProduct.ts index 29c875655..3595e6223 100644 --- a/test/typeclass/SemiProduct.ts +++ b/test/typeclass/SemiProduct.ts @@ -51,16 +51,18 @@ describe("SemiProduct", () => { U.deepStrictEqual(actual, expected) } - const product = (that: ReadonlyArray) => - (self: ReadonlyArray): ReadonlyArray<[A, B]> => { - const out: Array<[A, B]> = [] - for (const a of self) { - for (const b of that) { - out.push([a, b]) - } + const product = ( + self: ReadonlyArray, + that: ReadonlyArray + ): ReadonlyArray<[A, B]> => { + const out: Array<[A, B]> = [] + for (const a of self) { + for (const b of that) { + out.push([a, b]) } - return out } + return out + } const productMany = _.productMany( RA.Covariant, @@ -82,21 +84,21 @@ describe("SemiProduct", () => { describe("productComposition", () => { it("ReadonlyArray", () => { const product = _.productComposition(RA.SemiApplicative, O.SemiProduct) - U.deepStrictEqual(pipe([], product([O.none()])), []) - U.deepStrictEqual(pipe([O.none()], product([])), []) - U.deepStrictEqual(pipe([O.none()], product([O.none()])), [O.none()]) - expect(pipe([O.some(1)], product([O.some(2)]))).toEqual([O.some([1, 2])]) + U.deepStrictEqual(product([], [O.none()]), []) + U.deepStrictEqual(product([O.none()], []), []) + U.deepStrictEqual(product([O.none()], [O.none()]), [O.none()]) + expect(product([O.some(1)], [O.some(2)])).toEqual([O.some([1, 2])]) }) it("Option", () => { const product = _.productComposition(O.SemiApplicative, O.SemiProduct) - U.deepStrictEqual(pipe(O.none(), product(O.none())), O.none()) - U.deepStrictEqual(pipe(O.some(O.none()), product(O.none())), O.none()) - U.deepStrictEqual(pipe(O.some(O.some(1)), product(O.none())), O.none()) - U.deepStrictEqual(pipe(O.some(O.some(1)), product(O.some(O.none()))), O.some(O.none())) - U.deepStrictEqual(pipe(O.some(O.none()), product(O.some(O.some(2)))), O.some(O.none())) + U.deepStrictEqual(product(O.none(), O.none()), O.none()) + U.deepStrictEqual(product(O.some(O.none()), O.none()), O.none()) + U.deepStrictEqual(product(O.some(O.some(1)), O.none()), O.none()) + U.deepStrictEqual(product(O.some(O.some(1)), O.some(O.none())), O.some(O.none())) + U.deepStrictEqual(product(O.some(O.none()), O.some(O.some(2))), O.some(O.none())) U.deepStrictEqual( - pipe(O.some(O.some(1)), product(O.some(O.some(2)))), + product(O.some(O.some(1)), O.some(O.some(2))), O.some(O.some([1, 2])) ) }) diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index 65b13bb47..46ebaa0ee 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -132,9 +132,10 @@ describe("Semigroup", () => { it("product", () => { const S = pipe( - String.Semigroup, - _.SemiProduct.product(Number.SemigroupSum), - _.SemiProduct.product(Number.SemigroupMultiply), + _.SemiProduct.product( + _.SemiProduct.product(String.Semigroup, Number.SemigroupSum), + Number.SemigroupMultiply + ), _.imap( ([[a, b], c]): [string, number, number] => [a, b, c], ([a, b, c]): [[string, number], number] => [[a, b], c] From 5bb38975a1b754bfe681e41e59bf66255b47e521 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 16:12:31 +0100 Subject: [PATCH 071/255] SemiProduct: make productMany binary --- CHANGELOG.md | 1 + src/Either.ts | 24 ++++++++--------- src/Identity.ts | 6 +++-- src/Option.ts | 24 +++++++++-------- src/Predicate.ts | 24 +++++++++-------- src/ReadonlyArray.ts | 14 +++++----- src/These.ts | 6 ++--- src/typeclass/Equivalence.ts | 2 +- src/typeclass/Order.ts | 2 +- src/typeclass/SemiApplicative.ts | 3 +-- src/typeclass/SemiProduct.ts | 46 +++++++++++++++----------------- src/typeclass/Semigroup.ts | 2 +- test/Either.ts | 11 ++++---- test/Identity.ts | 2 +- test/Option.ts | 15 ++++------- test/Predicate.ts | 2 +- test/ReadonlyArray.ts | 41 ---------------------------- test/These.ts | 21 ++++++++------- test/typeclass/Equivalence.ts | 5 +--- test/typeclass/Order.ts | 5 +--- test/typeclass/SemiProduct.ts | 24 ++++++++--------- test/typeclass/Semigroup.ts | 5 +--- 22 files changed, 117 insertions(+), 168 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56617abaf..0ff608fec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - make `combineMany` binary - `SemiProduct` - make `product` binary + - make `productMany` binary - rename `productFlatten` to `element` - `Order` - make `compare` binary diff --git a/src/Either.ts b/src/Either.ts index 059954922..c9b7cf5db 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -360,21 +360,21 @@ export const Monad: monad.Monad = { } const productMany = ( + self: Either, collection: Iterable> -) => - (self: Either): Either]> => { - if (isLeft(self)) { - return self - } - const out: [A, ...Array] = [self.right] - for (const e of collection) { - if (isLeft(e)) { - return e - } - out.push(e.right) +): Either]> => { + if (isLeft(self)) { + return self + } + const out: [A, ...Array] = [self.right] + for (const e of collection) { + if (isLeft(e)) { + return e } - return right(out) + out.push(e.right) } + return right(out) +} /** * @category instances diff --git a/src/Identity.ts b/src/Identity.ts index 2e453e453..f65883432 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -251,8 +251,10 @@ export const Monad: monad.Monad = { ...FlatMap } -const productMany = (collection: Iterable>) => - (self: Identity): Identity<[A, ...Array]> => [self, ...collection] +const productMany = ( + self: Identity, + collection: Iterable> +): Identity<[A, ...Array]> => [self, ...collection] /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index ed68076fd..a2d2e70a9 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -406,20 +406,22 @@ export const Monad: monad.Monad = { ...FlatMap } -const productMany = (collection: Iterable>) => - (self: Option): Option<[A, ...Array]> => { - if (isNone(self)) { +const productMany = ( + self: Option, + collection: Iterable> +): Option<[A, ...Array]> => { + if (isNone(self)) { + return option.none + } + const out: [A, ...Array] = [self.value] + for (const o of collection) { + if (isNone(o)) { return option.none } - const out: [A, ...Array] = [self.value] - for (const o of collection) { - if (isNone(o)) { - return option.none - } - out.push(o.value) - } - return some(out) + out.push(o.value) } + return some(out) +} /** * @category instances diff --git a/src/Predicate.ts b/src/Predicate.ts index 4aac24a4b..55c0042e4 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -151,21 +151,23 @@ export const Do: Predicate<{}> = of_.Do(Of) */ export const unit: Predicate = of_.unit(Of) -const productMany = (collection: Iterable>) => - (self: Predicate): Predicate]> => { - return ([head, ...tail]) => { - if (self(head) === false) { +const productMany = ( + self: Predicate, + collection: Iterable> +): Predicate]> => { + return ([head, ...tail]) => { + if (self(head) === false) { + return false + } + const predicates = readonlyArray.fromIterable(collection) + for (let i = 0; i < predicates.length; i++) { + if (predicates[i](tail[i]) === false) { return false } - const predicates = readonlyArray.fromIterable(collection) - for (let i = 0; i < predicates.length; i++) { - if (predicates[i](tail[i]) === false) { - return false - } - } - return true } + return true } +} /** * @category instances diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 9af39fe13..fbec99624 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1627,8 +1627,8 @@ export const traverseNonEmptyWithIndex = ( ) => (f: (a: A, i: number) => Kind) => (self: NonEmptyReadonlyArray): Kind> => { - const fbs = pipe(self, mapNonEmptyWithIndex(f)) - return pipe(headNonEmpty(fbs), F.productMany(tailNonEmpty(fbs))) + const [head, ...tail] = pipe(self, mapNonEmptyWithIndex(f)) + return F.productMany(head, tail) } /** @@ -1692,8 +1692,9 @@ const product = ( } const productMany: ( + self: ReadonlyArray, collection: Iterable> -) => (self: ReadonlyArray) => Array<[A, ...Array]> = semiProduct.productMany( +) => Array<[A, ...Array]> = semiProduct.productMany( Covariant, product ) as any @@ -1701,11 +1702,8 @@ const productMany: ( const productAll = ( collection: Iterable> ): Array> => { - const arrays = Array.from(collection) - if (isEmpty(arrays)) { - return empty() - } - return productMany(arrays.slice(1))(arrays[0]) + const arrays = fromIterable(collection) + return isEmpty(arrays) ? empty() : productMany(arrays[0], arrays.slice(1)) } /** diff --git a/src/These.ts b/src/These.ts index 01eb8ed30..25e1ea22d 100644 --- a/src/These.ts +++ b/src/These.ts @@ -978,10 +978,10 @@ const product = ( } const productMany = ( + self: Validated, collection: Iterable> -) => - (self: Validated): Validated]> => - pipe(product(self, productAll(collection)), map(([a, as]) => [a, ...as])) +): Validated]> => + pipe(product(self, productAll(collection)), map(([a, as]) => [a, ...as])) /** * @category instances diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index d13ba4380..78146c738 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -196,7 +196,7 @@ export const Invariant: invariant.Invariant = { export const SemiProduct: semiProduct.SemiProduct = { imap: Contravariant.imap, product: tuple, - productMany: collection => self => tuple(self, ...collection) + productMany: (self, collection) => tuple(self, ...collection) } /** diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index a52386b74..85b762d09 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -186,7 +186,7 @@ export const Invariant: invariant.Invariant = { export const SemiProduct: semiProduct.SemiProduct = { imap: Contravariant.imap, product: tuple, - productMany: collection => self => tuple(self, ...collection) + productMany: (self, collection) => tuple(self, ...collection) } /** diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 2a31677d7..48098ba35 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -23,8 +23,7 @@ export const liftSemigroup = (F: SemiApplicative) => combine: (self, that) => pipe(F.product(self, that), F.map(([a1, a2]) => S.combine(a1, a2))), combineMany: (self, collection) => pipe( - self, - F.productMany(collection), + F.productMany(self, collection), F.map(([head, ...tail]) => S.combineMany(head, tail)) ) }) diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 6fec78bdb..f16678bbd 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -18,8 +18,9 @@ export interface SemiProduct extends Invariant { ) => Kind readonly productMany: ( + self: Kind, collection: Iterable> - ) => (self: Kind) => Kind]> + ) => Kind]> } /** @@ -52,16 +53,13 @@ export const productManyComposition = ) => ( + self: Kind>, collection: Iterable>> - ) => - ( - self: Kind> - ): Kind]>> => - pipe( - self, - F.productMany(collection), - F.map(([ga, ...gas]) => pipe(ga, G.productMany(gas))) - ) + ): Kind]>> => + pipe( + F.productMany(self, collection), + F.map(([ga, ...gas]) => G.productMany(ga, gas)) + ) /** * Returns a default `productMany` implementation (useful for tests). @@ -74,21 +72,21 @@ export const productMany = ( product: SemiProduct["product"] ): SemiProduct["productMany"] => ( + self: Kind, collection: Iterable> - ) => - (self: Kind) => { - let out = pipe( - self, - Covariant.map((a): [A, ...Array] => [a]) + ) => { + let out = pipe( + self, + Covariant.map((a): [A, ...Array] => [a]) + ) + for (const fa of collection) { + out = pipe( + product(out, fa), + Covariant.map(([[head, ...tail], a]): [A, ...Array] => [head, ...tail, a]) ) - for (const fa of collection) { - out = pipe( - product(out, fa), - Covariant.map(([[head, ...tail], a]): [A, ...Array] => [head, ...tail, a]) - ) - } - return out } + return out + } /** * @since 1.0.0 @@ -144,7 +142,7 @@ export const nonEmptyTuple = (F: SemiProduct) => ([T[number]] extends [Kind] ? O : never), ([T[number]] extends [Kind] ? E : never), { [I in keyof T]: [T[I]] extends [Kind] ? A : never } - > => F.productMany(components.slice(1))(components[0]) as any + > => F.productMany(components[0], components.slice(1)) as any type EnforceNonEmptyRecord = keyof R extends never ? never : R @@ -163,7 +161,7 @@ export const nonEmptyStruct = (F: SemiProduct) => > => { const keys = Object.keys(fields) return pipe( - F.productMany(keys.slice(1).map(k => fields[k]))(fields[keys[0]]), + F.productMany(fields[keys[0]], keys.slice(1).map(k => fields[k])), F.imap(([value, ...values]) => { const out: any = { [keys[0]]: value } for (let i = 0; i < values.length; i++) { diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index a72572d5e..abb2b3cea 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -327,7 +327,7 @@ export const Invariant: invariant.Invariant = { export const SemiProduct: semiProduct.SemiProduct = { ...Invariant, product: tuple, - productMany: collection => self => tuple(self, ...collection) + productMany: (self, collection) => tuple(self, ...collection) } /** diff --git a/test/Either.ts b/test/Either.ts index 37b709857..88f135658 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -388,20 +388,21 @@ describe.concurrent("Either", () => { it("productMany", () => { const productMany: ( + self: _.Either, collection: Iterable<_.Either> - ) => (self: _.Either) => _.Either]> = _.SemiProduct.productMany + ) => _.Either]> = _.SemiProduct.productMany - deepStrictEqual(pipe(_.right(1), productMany([])), _.right([1])) + deepStrictEqual(productMany(_.right(1), []), _.right([1])) deepStrictEqual( - pipe(_.right(1), productMany([_.right(2), _.right(3)])), + productMany(_.right(1), [_.right(2), _.right(3)]), _.right([1, 2, 3]) ) deepStrictEqual( - pipe(_.right(1), productMany([_.left("e"), _.right(3)])), + productMany(_.right(1), [_.left("e"), _.right(3)]), _.left("e") ) expect( - pipe(_.left("e"), productMany([_.right(2), _.right(3)])) + productMany(_.left("e"), [_.right(2), _.right(3)]) ).toEqual(_.left("e")) }) diff --git a/test/Identity.ts b/test/Identity.ts index 8f130aa9b..77006ee89 100644 --- a/test/Identity.ts +++ b/test/Identity.ts @@ -81,7 +81,7 @@ describe.concurrent("Identity", () => { }) it("SemiProduct", () => { - U.deepStrictEqual(pipe("a", _.SemiProduct.productMany(["b", "c"])), ["a", "b", "c"]) + U.deepStrictEqual(_.SemiProduct.productMany("a", ["b", "c"]), ["a", "b", "c"]) }) it("Product", () => { diff --git a/test/Option.ts b/test/Option.ts index cd3e30016..ef147d596 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -219,16 +219,11 @@ describe.concurrent("Option", () => { }) it("productMany", () => { - deepStrictEqual(pipe(_.none(), _.SemiProduct.productMany([])), _.none()) - deepStrictEqual(pipe(_.some(1), _.SemiProduct.productMany([])), _.some([1])) - deepStrictEqual( - pipe(_.some(1), _.SemiProduct.productMany([_.none() as _.Option])), - _.none() - ) - deepStrictEqual( - pipe(_.some(1), _.SemiProduct.productMany([_.some(2)])), - _.some([1, 2]) - ) + const productMany = _.SemiProduct.productMany + deepStrictEqual(productMany(_.none(), []), _.none()) + deepStrictEqual(productMany(_.some(1), []), _.some([1])) + deepStrictEqual(productMany(_.some(1), [_.none()]), _.none()) + deepStrictEqual(productMany(_.some(1), [_.some(2)]), _.some([1, 2])) }) it("productAll", () => { diff --git a/test/Predicate.ts b/test/Predicate.ts index 9298ca40c..5825f3879 100644 --- a/test/Predicate.ts +++ b/test/Predicate.ts @@ -76,7 +76,7 @@ describe.concurrent("Predicate", () => { it("productMany", () => { const productMany = _.SemiProduct.productMany - const p = pipe(isPositive, productMany([isNegative])) + const p = productMany(isPositive, [isNegative]) deepStrictEqual(p([1, -1]), true) deepStrictEqual(p([1, 1]), false) deepStrictEqual(p([-1, -1]), false) diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 0784ea741..b6a4e9dfe 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -1613,47 +1613,6 @@ describe.concurrent("ReadonlyArray", () => { ]) }) - test("productMany", () => { - const productMany = RA.SemiProduct.productMany - expect(pipe( - [], - productMany([ - [2], - [4, 5], - [8, 9, 10] - ]) - )).toEqual(pipe( - [], - productMany([ - [2], - [4, 5], - [8, 9, 10] - ]) - )) - expect(pipe( - [1, 2, 3], - productMany([]) - )).toEqual(pipe( - [1, 2, 3], - productMany([]) - )) - expect(pipe( - [1, 2, 3], - productMany([ - [2], - [4, 5], - [8, 9, 10] - ]) - )).toEqual(pipe( - [1, 2, 3], - productMany([ - [2], - [4, 5], - [8, 9, 10] - ]) - )) - }) - test("productAll", () => { const productAll = RA.Product.productAll expect(productAll([])).toEqual([]) diff --git a/test/These.ts b/test/These.ts index 2b9792baa..eaed39a55 100644 --- a/test/These.ts +++ b/test/These.ts @@ -291,30 +291,31 @@ describe("These", () => { const ab = ["a", "b"] as const const productMany: ( + self: _.Validated, collection: Iterable<_.Validated> - ) => (self: _.Validated) => _.Validated]> = _.SemiProduct.productMany + ) => _.Validated]> = _.SemiProduct.productMany - expect(pipe(_.right(1), productMany([_.right(2)]))).toEqual(_.right([1, 2])) + expect(productMany(_.right(1), [_.right(2)])).toEqual(_.right([1, 2])) U.deepStrictEqual( - pipe(_.right(1), productMany([_.left(b)])), + productMany(_.right(1), [_.left(b)]), _.left(b) ) expect( - pipe(_.right(1), productMany([_.both(b, 2)])) + productMany(_.right(1), [_.both(b, 2)]) ).toEqual( _.both(b, [1, 2]) ) - U.deepStrictEqual(pipe(_.left(a), productMany([_.right(2)])), _.left(a)) - U.deepStrictEqual(pipe(_.left(a), productMany([_.left(b)])), _.left(a)) + U.deepStrictEqual(productMany(_.left(a), [_.right(2)]), _.left(a)) + U.deepStrictEqual(productMany(_.left(a), [_.left(b)]), _.left(a)) U.deepStrictEqual( - pipe(_.left(a), productMany([_.both(b, 2)])), + productMany(_.left(a), [_.both(b, 2)]), _.left(a) ) - expect(pipe(_.both(a, 1), productMany([_.right(2)]))).toEqual(_.both(a, [1, 2])) - expect(pipe(_.both(a, 1), productMany([_.left(b)]))).toEqual(_.left(ab)) - expect(pipe(_.both(a, 1), productMany([_.both(b, 2)]))).toEqual( + expect(productMany(_.both(a, 1), [_.right(2)])).toEqual(_.both(a, [1, 2])) + expect(productMany(_.both(a, 1), [_.left(b)])).toEqual(_.left(ab)) + expect(productMany(_.both(a, 1), [_.both(b, 2)])).toEqual( _.both(ab, [1, 2]) ) }) diff --git a/test/typeclass/Equivalence.ts b/test/typeclass/Equivalence.ts index 2668fd960..8bef6a0b1 100644 --- a/test/typeclass/Equivalence.ts +++ b/test/typeclass/Equivalence.ts @@ -146,10 +146,7 @@ describe("Equivalence", () => { }) it("SemiProduct/productMany", () => { - const eq = pipe( - _.string, - _.SemiProduct.productMany([_.string]) - ) + const eq = _.SemiProduct.productMany(_.string, [_.string]) expect(eq(["a"], ["a"])).toEqual(true) expect(eq(["a"], ["b"])).toEqual(false) expect(eq(["a"], ["a", "b"])).toEqual(false) diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index bf41c8e08..1d82bb7bb 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -208,10 +208,7 @@ describe("Order", () => { }) it("productMany", () => { - const O = pipe( - string.Order, - _.SemiProduct.productMany([string.Order, string.Order]) - ) + const O = _.SemiProduct.productMany(string.Order, [string.Order, string.Order]) U.deepStrictEqual(O.compare(["a", "b"], ["a", "c"]), -1) U.deepStrictEqual(O.compare(["a", "b"], ["a", "b"]), 0) U.deepStrictEqual(O.compare(["a", "b"], ["a", "a"]), 1) diff --git a/test/typeclass/SemiProduct.ts b/test/typeclass/SemiProduct.ts index 3595e6223..57a00fbdc 100644 --- a/test/typeclass/SemiProduct.ts +++ b/test/typeclass/SemiProduct.ts @@ -45,7 +45,7 @@ describe("SemiProduct", () => { } return fas } - const actual = pipe(self, SemiApplicative.productMany(collection)) + const actual = SemiApplicative.productMany(self, collection) const expected = pipe(self, productManyFromAp(collection)) // console.log(expected) U.deepStrictEqual(actual, expected) @@ -107,18 +107,18 @@ describe("SemiProduct", () => { describe("productManyComposition", () => { it("ReadonlyArray", () => { const productMany = _.productManyComposition(RA.SemiApplicative, O.SemiProduct) - expect(pipe([O.some(1), O.none()], productMany([]))).toEqual([ + expect(productMany([O.some(1), O.none()], [])).toEqual([ O.some([1]), O.none() ]) - expect(pipe([O.some(1), O.none()], productMany([[O.some(2), O.none()]]))).toEqual([ + expect(productMany([O.some(1), O.none()], [[O.some(2), O.none()]])).toEqual([ O.some([1, 2]), O.none(), O.none(), O.none() ]) expect( - pipe([O.some(1), O.some(2)], productMany([[O.some(3), O.some(4)], [O.some(5)]])) + productMany([O.some(1), O.some(2)], [[O.some(3), O.some(4)], [O.some(5)]]) ).toEqual( [ O.some([1, 3, 5]), @@ -131,18 +131,18 @@ describe("SemiProduct", () => { it("Option", () => { const productMany = _.productManyComposition(O.SemiApplicative, O.SemiProduct) - U.deepStrictEqual(pipe(O.none(), productMany([])), O.none()) - U.deepStrictEqual(pipe(O.some(O.none()), productMany([])), O.some(O.none())) - U.deepStrictEqual(pipe(O.some(O.some(1)), productMany([])), O.some(O.some([1]))) - U.deepStrictEqual(pipe(O.none(), productMany([O.none()])), O.none()) - U.deepStrictEqual(pipe(O.some(O.none()), productMany([O.none()])), O.none()) - U.deepStrictEqual(pipe(O.some(O.none()), productMany([O.some(O.none())])), O.some(O.none())) + U.deepStrictEqual(productMany(O.none(), []), O.none()) + U.deepStrictEqual(productMany(O.some(O.none()), []), O.some(O.none())) + U.deepStrictEqual(productMany(O.some(O.some(1)), []), O.some(O.some([1]))) + U.deepStrictEqual(productMany(O.none(), [O.none()]), O.none()) + U.deepStrictEqual(productMany(O.some(O.none()), [O.none()]), O.none()) + U.deepStrictEqual(productMany(O.some(O.none()), [O.some(O.none())]), O.some(O.none())) U.deepStrictEqual( - pipe(O.some(O.none()), productMany([O.some(O.some("a"))])), + productMany(O.some(O.none()), [O.some(O.some("a"))]), O.some(O.none()) ) U.deepStrictEqual( - pipe(O.some(O.some(1)), productMany([O.some(O.some(2))])), + productMany(O.some(O.some(1)), [O.some(O.some(2))]), O.some(O.some([1, 2])) ) }) diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index 46ebaa0ee..2612c7890 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -145,10 +145,7 @@ describe("Semigroup", () => { }) it("productMany", () => { - const S = pipe( - String.Semigroup, - _.SemiProduct.productMany([String.Semigroup, String.Semigroup]) - ) + const S = _.SemiProduct.productMany(String.Semigroup, [String.Semigroup, String.Semigroup]) U.deepStrictEqual(S.combine(["a", "b", "c"], ["d", "e", "f"]), ["ad", "be", "cf"]) }) }) From 97ce466871eae2d9273d383135db04cc6f3fa065 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 16:21:30 +0100 Subject: [PATCH 072/255] SemiCoproduct: make coproduct binary --- CHANGELOG.md | 2 ++ src/Either.ts | 2 +- src/Identity.ts | 2 +- src/Option.ts | 13 ++----------- src/These.ts | 2 +- src/typeclass/Foldable.ts | 5 +---- src/typeclass/SemiCoproduct.ts | 7 +++---- src/typeclass/Semigroup.ts | 4 ++-- test/Either.ts | 9 +++++---- test/Identity.ts | 4 ++-- test/Option.ts | 19 +++++++++---------- test/These.ts | 13 +++++++------ 12 files changed, 36 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ff608fec..71c616c58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ - `Semigroup` - make `combine` binary - make `combineMany` binary +- `SemiCoproduct` + - make `coproduct` binary - `SemiProduct` - make `product` binary - make `productMany` binary diff --git a/src/Either.ts b/src/Either.ts index c9b7cf5db..d4b2d37c1 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -564,7 +564,7 @@ export const firstSuccessOf = (collection: Iterable>) => */ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { ...Invariant, - coproduct: (that) => (self) => isRight(self) ? self : that, + coproduct: (self, that) => isRight(self) ? self : that, coproductMany: firstSuccessOf } diff --git a/src/Identity.ts b/src/Identity.ts index f65883432..a0b3f8062 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -393,7 +393,7 @@ export const getSemiCoproduct = ( S: Semigroup ): semiCoproduct.SemiCoproduct> => ({ imap: Invariant.imap, - coproduct: (that) => (self) => S.combine(self, that), + coproduct: (self, that) => S.combine(self, that), coproductMany: (collection) => (self) => S.combineMany(self, collection) }) diff --git a/src/Option.ts b/src/Option.ts index a2d2e70a9..af2524d3f 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -615,12 +615,6 @@ export const getFirstNoneMonoid: (M: Monoid) => Monoid> = applic Applicative ) -/** - * @since 1.0.0 - */ -export const coproduct = (that: Option) => - (self: Option): Option => isSome(self) ? self : that - /** * @category error handling * @since 1.0.0 @@ -645,7 +639,7 @@ export const firstSomeOf = (collection: Iterable>) => */ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { ...Invariant, - coproduct, + coproduct: (self, that) => isSome(self) ? self : that, coproductMany: firstSomeOf } @@ -667,10 +661,7 @@ export const coproductEither = (that: Option) => (self: Option): Option> => isNone(self) ? pipe(that, map(either.right)) : pipe(self, map(either.left)) -/** - * @since 1.0.0 - */ -export const coproductAll = (collection: Iterable>): Option => { +const coproductAll = (collection: Iterable>): Option => { const options = readonlyArray.fromIterable(collection) return options.length > 0 ? SemiCoproduct.coproductMany(options.slice(1))(options[0]) : diff --git a/src/These.ts b/src/These.ts index 25e1ea22d..51d2fec40 100644 --- a/src/These.ts +++ b/src/These.ts @@ -879,7 +879,7 @@ export const firstRightOrBothOf = (collection: Iterable>) => */ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { ...Invariant, - coproduct: (that) => (self) => isRightOrBoth(self) ? self : that, + coproduct: (self, that) => isRightOrBoth(self) ? self : that, coproductMany: firstRightOrBothOf } diff --git a/src/typeclass/Foldable.ts b/src/typeclass/Foldable.ts index 408c7406b..73bb55e9a 100644 --- a/src/typeclass/Foldable.ts +++ b/src/typeclass/Foldable.ts @@ -108,7 +108,4 @@ export const foldMapKind = (F: Foldable) => ( f: (a: A) => Kind ): (self: Kind) => Kind => - F.reduce>( - G.zero(), - (gb, a) => pipe(gb, G.coproduct(f(a))) - ) + F.reduce>(G.zero(), (gb, a) => G.coproduct(gb, f(a))) diff --git a/src/typeclass/SemiCoproduct.ts b/src/typeclass/SemiCoproduct.ts index c659b3408..e49e160b3 100644 --- a/src/typeclass/SemiCoproduct.ts +++ b/src/typeclass/SemiCoproduct.ts @@ -11,10 +11,9 @@ import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" * @since 1.0.0 */ export interface SemiCoproduct extends Invariant { - readonly coproduct: ( + readonly coproduct: ( + self: Kind, that: Kind - ) => ( - self: Kind ) => Kind readonly coproductMany: ( @@ -29,6 +28,6 @@ export const getSemigroup = (F: SemiCoproduct) => (): Semigroup< Kind > => ({ - combine: (self, that) => pipe(self, F.coproduct(that)), + combine: F.coproduct, combineMany: (self, collection) => pipe(self, F.coproductMany(collection)) }) diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index abb2b3cea..ea3916963 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -3,8 +3,8 @@ * * ```ts * export interface Semigroup { - * combine: (that: A) => (self: A) => A - * combineMany: (collection: Iterable) => (self: A) => A + * combine: (self: A, that: A) => A + * combineMany: (self: A, collection: Iterable) => A * } * ``` * diff --git a/test/Either.ts b/test/Either.ts index 88f135658..19b9c6788 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -420,10 +420,11 @@ describe.concurrent("Either", () => { }) it("coproduct", () => { - deepStrictEqual(pipe(_.right(1), _.SemiCoproduct.coproduct(_.right(2))), _.right(1)) - deepStrictEqual(pipe(_.right(1), _.SemiCoproduct.coproduct(_.left("e2"))), _.right(1)) - deepStrictEqual(pipe(_.left("e1"), _.SemiCoproduct.coproduct(_.right(2))), _.right(2)) - deepStrictEqual(pipe(_.left("e1"), _.SemiCoproduct.coproduct(_.left("e2"))), _.left("e2")) + const coproduct = _.SemiCoproduct.coproduct + deepStrictEqual(coproduct(_.right(1), _.right(2)), _.right(1)) + deepStrictEqual(coproduct(_.right(1), _.left("e2")), _.right(1)) + deepStrictEqual(coproduct(_.left("e1"), _.right(2)), _.right(2)) + deepStrictEqual(coproduct(_.left("e1"), _.left("e2")), _.left("e2")) }) it("coproductMany", () => { diff --git a/test/Identity.ts b/test/Identity.ts index 77006ee89..0a39f52f0 100644 --- a/test/Identity.ts +++ b/test/Identity.ts @@ -103,13 +103,13 @@ describe.concurrent("Identity", () => { it("getSemiCoproduct", () => { const F = _.getSemiCoproduct(String.Semigroup) - U.deepStrictEqual(pipe("a", F.coproduct("b")), "ab") + U.deepStrictEqual(F.coproduct("a", "b"), "ab") U.deepStrictEqual(pipe("a", F.coproductMany(["b", "c"])), "abc") }) it("getSemiAlternative", () => { const F = _.getSemiAlternative(String.Semigroup) - U.deepStrictEqual(pipe("a", F.coproduct("b")), "ab") + U.deepStrictEqual(F.coproduct("a", "b"), "ab") U.deepStrictEqual(pipe("a", F.coproductMany(["b", "c"])), "abc") }) diff --git a/test/Option.ts b/test/Option.ts index ef147d596..98401c6b1 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -60,10 +60,8 @@ describe.concurrent("Option", () => { expect(_.SemiCoproduct).exist expect(_.getFirstSomeSemigroup).exist // getSemigroup - expect(_.coproduct).exist expect(_.Coproduct).exist - expect(_.coproductAll).exist expect(_.SemiAlternative).exist @@ -197,10 +195,11 @@ describe.concurrent("Option", () => { }) it("coproductAll", () => { - deepStrictEqual(_.coproductAll([]), _.none()) - deepStrictEqual(_.coproductAll([_.some(1)]), _.some(1)) - deepStrictEqual(_.coproductAll([_.none(), _.some(1)]), _.some(1)) - deepStrictEqual(_.coproductAll([_.some(1), _.some(2)]), _.some(1)) + const coproductAll = _.Coproduct.coproductAll + deepStrictEqual(coproductAll([]), _.none()) + deepStrictEqual(coproductAll([_.some(1)]), _.some(1)) + deepStrictEqual(coproductAll([_.none(), _.some(1)]), _.some(1)) + deepStrictEqual(coproductAll([_.some(1), _.some(2)]), _.some(1)) }) it("unit", () => { @@ -236,10 +235,10 @@ describe.concurrent("Option", () => { it("SemiCoproduct", () => { const coproduct = _.SemiCoproduct.coproduct - deepStrictEqual(pipe(_.none(), coproduct(_.none())), _.none()) - deepStrictEqual(pipe(_.none(), coproduct(_.some(2))), _.some(2)) - deepStrictEqual(pipe(_.some(1), coproduct(_.none())), _.some(1)) - deepStrictEqual(pipe(_.some(1), coproduct(_.some(2))), _.some(1)) + deepStrictEqual(coproduct(_.none(), _.none()), _.none()) + deepStrictEqual(coproduct(_.none(), _.some(2)), _.some(2)) + deepStrictEqual(coproduct(_.some(1), _.none()), _.some(1)) + deepStrictEqual(coproduct(_.some(1), _.some(2)), _.some(1)) const coproductMany = _.SemiCoproduct.coproductMany deepStrictEqual(pipe(_.none(), coproductMany([])), _.none()) diff --git a/test/These.ts b/test/These.ts index eaed39a55..ffbdd0dd1 100644 --- a/test/These.ts +++ b/test/These.ts @@ -767,16 +767,17 @@ describe("These", () => { }) it("coproduct", () => { - U.deepStrictEqual(pipe(_.right(1), _.SemiCoproduct.coproduct(_.right(2))), _.right(1)) - U.deepStrictEqual(pipe(_.right(1), _.SemiCoproduct.coproduct(_.left("e2"))), _.right(1)) - U.deepStrictEqual(pipe(_.left("e1"), _.SemiCoproduct.coproduct(_.right(2))), _.right(2)) - U.deepStrictEqual(pipe(_.left("e1"), _.SemiCoproduct.coproduct(_.left("e2"))), _.left("e2")) + const coproduct = _.SemiCoproduct.coproduct + U.deepStrictEqual(coproduct(_.right(1), _.right(2)), _.right(1)) + U.deepStrictEqual(coproduct(_.right(1), _.left("e2")), _.right(1)) + U.deepStrictEqual(coproduct(_.left("e1"), _.right(2)), _.right(2)) + U.deepStrictEqual(coproduct(_.left("e1"), _.left("e2")), _.left("e2")) U.deepStrictEqual( - pipe(_.both("e1", 1), _.SemiCoproduct.coproduct(_.right(2))), + coproduct(_.both("e1", 1), _.right(2)), _.both("e1", 1) ) U.deepStrictEqual( - pipe(_.both("e1", 1), _.SemiCoproduct.coproduct(_.left("e2"))), + coproduct(_.both("e1", 1), _.left("e2")), _.both("e1", 1) ) }) From be970806bf0ecfed3f5c4d813e9736a53fcffb4e Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 16:29:29 +0100 Subject: [PATCH 073/255] SemiCoproduct: make coproductMany binary --- CHANGELOG.md | 1 + src/Either.ts | 2 +- src/Identity.ts | 4 ++-- src/Option.ts | 16 +++++++--------- src/These.ts | 2 +- src/typeclass/SemiCoproduct.ts | 11 +++++------ test/Either.ts | 21 +++++---------------- test/Identity.ts | 4 ++-- test/Option.ts | 12 ++++++------ test/These.ts | 20 ++++++++++++-------- 10 files changed, 42 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71c616c58..1222b62be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - make `combineMany` binary - `SemiCoproduct` - make `coproduct` binary + - make `coproductMany` binary - `SemiProduct` - make `product` binary - make `productMany` binary diff --git a/src/Either.ts b/src/Either.ts index d4b2d37c1..c0f6e5127 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -565,7 +565,7 @@ export const firstSuccessOf = (collection: Iterable>) => export const SemiCoproduct: semiCoproduct.SemiCoproduct = { ...Invariant, coproduct: (self, that) => isRight(self) ? self : that, - coproductMany: firstSuccessOf + coproductMany: (self, collection) => pipe(self, firstSuccessOf(collection)) } /** diff --git a/src/Identity.ts b/src/Identity.ts index a0b3f8062..e694c6248 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -393,8 +393,8 @@ export const getSemiCoproduct = ( S: Semigroup ): semiCoproduct.SemiCoproduct> => ({ imap: Invariant.imap, - coproduct: (self, that) => S.combine(self, that), - coproductMany: (collection) => (self) => S.combineMany(self, collection) + coproduct: S.combine, + coproductMany: S.combineMany }) /** diff --git a/src/Option.ts b/src/Option.ts index af2524d3f..47a09a263 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -640,7 +640,7 @@ export const firstSomeOf = (collection: Iterable>) => export const SemiCoproduct: semiCoproduct.SemiCoproduct = { ...Invariant, coproduct: (self, that) => isSome(self) ? self : that, - coproductMany: firstSomeOf + coproductMany: (self, collection) => pipe(self, firstSomeOf(collection)) } /** @@ -661,13 +661,6 @@ export const coproductEither = (that: Option) => (self: Option): Option> => isNone(self) ? pipe(that, map(either.right)) : pipe(self, map(either.left)) -const coproductAll = (collection: Iterable>): Option => { - const options = readonlyArray.fromIterable(collection) - return options.length > 0 ? - SemiCoproduct.coproductMany(options.slice(1))(options[0]) : - option.none -} - /** * @category instances * @since 1.0.0 @@ -675,7 +668,12 @@ const coproductAll = (collection: Iterable>): Option => { export const Coproduct: coproduct_.Coproduct = { ...SemiCoproduct, zero: none, - coproductAll + coproductAll: collection => { + const options = readonlyArray.fromIterable(collection) + return options.length > 0 ? + SemiCoproduct.coproductMany(options[0], options.slice(1)) : + option.none + } } /** diff --git a/src/These.ts b/src/These.ts index 51d2fec40..f7569d8b0 100644 --- a/src/These.ts +++ b/src/These.ts @@ -880,7 +880,7 @@ export const firstRightOrBothOf = (collection: Iterable>) => export const SemiCoproduct: semiCoproduct.SemiCoproduct = { ...Invariant, coproduct: (self, that) => isRightOrBoth(self) ? self : that, - coproductMany: firstRightOrBothOf + coproductMany: (self, collection) => pipe(self, firstRightOrBothOf(collection)) } /** diff --git a/src/typeclass/SemiCoproduct.ts b/src/typeclass/SemiCoproduct.ts index e49e160b3..57d85526d 100644 --- a/src/typeclass/SemiCoproduct.ts +++ b/src/typeclass/SemiCoproduct.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { pipe } from "@fp-ts/core/Function" + import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" @@ -17,17 +17,16 @@ export interface SemiCoproduct extends Invariant { ) => Kind readonly coproductMany: ( + self: Kind, collection: Iterable> - ) => (self: Kind) => Kind + ) => Kind } /** * @since 1.0.0 */ export const getSemigroup = (F: SemiCoproduct) => - (): Semigroup< - Kind - > => ({ + (): Semigroup> => ({ combine: F.coproduct, - combineMany: (self, collection) => pipe(self, F.coproductMany(collection)) + combineMany: F.coproductMany }) diff --git a/test/Either.ts b/test/Either.ts index 19b9c6788..8dd940be3 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -428,25 +428,14 @@ describe.concurrent("Either", () => { }) it("coproductMany", () => { - deepStrictEqual(pipe(_.right(1), _.SemiCoproduct.coproductMany([_.right(2)])), _.right(1)) + const coproductMany = _.SemiCoproduct.coproductMany + deepStrictEqual(coproductMany(_.right(1), [_.right(2)]), _.right(1)) deepStrictEqual( - pipe( - _.right(1) as _.Either, - _.SemiCoproduct.coproductMany([_.left("e2") as _.Either]) - ), + coproductMany(_.right(1), [_.left("e2")]), _.right(1) ) - deepStrictEqual( - pipe( - _.left("e1") as _.Either, - _.SemiCoproduct.coproductMany([_.right(2) as _.Either]) - ), - _.right(2) - ) - deepStrictEqual( - pipe(_.left("e1"), _.SemiCoproduct.coproductMany([_.left("e2")])), - _.left("e2") - ) + deepStrictEqual(coproductMany(_.left("e1"), [_.right(2)]), _.right(2)) + deepStrictEqual(coproductMany(_.left("e1"), [_.left("e2")]), _.left("e2")) }) it("element", () => { diff --git a/test/Identity.ts b/test/Identity.ts index 0a39f52f0..4bde2fe48 100644 --- a/test/Identity.ts +++ b/test/Identity.ts @@ -104,13 +104,13 @@ describe.concurrent("Identity", () => { it("getSemiCoproduct", () => { const F = _.getSemiCoproduct(String.Semigroup) U.deepStrictEqual(F.coproduct("a", "b"), "ab") - U.deepStrictEqual(pipe("a", F.coproductMany(["b", "c"])), "abc") + U.deepStrictEqual(F.coproductMany("a", ["b", "c"]), "abc") }) it("getSemiAlternative", () => { const F = _.getSemiAlternative(String.Semigroup) U.deepStrictEqual(F.coproduct("a", "b"), "ab") - U.deepStrictEqual(pipe("a", F.coproductMany(["b", "c"])), "abc") + U.deepStrictEqual(F.coproductMany("a", ["b", "c"]), "abc") }) it("reduce", () => { diff --git a/test/Option.ts b/test/Option.ts index 98401c6b1..ef5480f09 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -241,12 +241,12 @@ describe.concurrent("Option", () => { deepStrictEqual(coproduct(_.some(1), _.some(2)), _.some(1)) const coproductMany = _.SemiCoproduct.coproductMany - deepStrictEqual(pipe(_.none(), coproductMany([])), _.none()) - deepStrictEqual(pipe(_.none(), coproductMany([_.none()])), _.none()) - deepStrictEqual(pipe(_.none(), coproductMany([_.some(2)])), _.some(2)) - deepStrictEqual(pipe(_.some(1), coproductMany([])), _.some(1)) - deepStrictEqual(pipe(_.some(1), coproductMany([_.none() as _.Option])), _.some(1)) - deepStrictEqual(pipe(_.some(1), coproductMany([_.some(2)])), _.some(1)) + deepStrictEqual(coproductMany(_.none(), []), _.none()) + deepStrictEqual(coproductMany(_.none(), [_.none()]), _.none()) + deepStrictEqual(coproductMany(_.none(), [_.some(2)]), _.some(2)) + deepStrictEqual(coproductMany(_.some(1), []), _.some(1)) + deepStrictEqual(coproductMany(_.some(1), [_.none() as _.Option]), _.some(1)) + deepStrictEqual(coproductMany(_.some(1), [_.some(2)]), _.some(1)) }) it("fromIterable", () => { diff --git a/test/These.ts b/test/These.ts index ffbdd0dd1..66bb5b609 100644 --- a/test/These.ts +++ b/test/These.ts @@ -772,14 +772,18 @@ describe("These", () => { U.deepStrictEqual(coproduct(_.right(1), _.left("e2")), _.right(1)) U.deepStrictEqual(coproduct(_.left("e1"), _.right(2)), _.right(2)) U.deepStrictEqual(coproduct(_.left("e1"), _.left("e2")), _.left("e2")) - U.deepStrictEqual( - coproduct(_.both("e1", 1), _.right(2)), - _.both("e1", 1) - ) - U.deepStrictEqual( - coproduct(_.both("e1", 1), _.left("e2")), - _.both("e1", 1) - ) + U.deepStrictEqual(coproduct(_.both("e1", 1), _.right(2)), _.both("e1", 1)) + U.deepStrictEqual(coproduct(_.both("e1", 1), _.left("e2")), _.both("e1", 1)) + }) + + it("coproduct", () => { + const coproductMany = _.SemiCoproduct.coproductMany + U.deepStrictEqual(coproductMany(_.right(1), [_.right(2)]), _.right(1)) + U.deepStrictEqual(coproductMany(_.right(1), [_.left("e2")]), _.right(1)) + U.deepStrictEqual(coproductMany(_.left("e1"), [_.right(2)]), _.right(2)) + U.deepStrictEqual(coproductMany(_.left("e1"), [_.left("e2")]), _.left("e2")) + U.deepStrictEqual(coproductMany(_.both("e1", 1), [_.right(2)]), _.both("e1", 1)) + U.deepStrictEqual(coproductMany(_.both("e1", 1), [_.left("e2")]), _.both("e1", 1)) }) it("compact", () => { From 4ffabfaa97c1ef338388ca942570fcde1fe28abe Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 20 Jan 2023 17:16:44 +0100 Subject: [PATCH 074/255] add Tuple module --- CHANGELOG.md | 3 ++- data.md | 30 ++++++++++++++--------- dtslint/ts4.7/Tuple.ts | 4 +++ src/ReadonlyArray.ts | 9 ------- src/Tuple.ts | 55 ++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 7 +++++- test/ReadonlyArray.ts | 1 - test/Tuple.ts | 17 +++++++++++++ 8 files changed, 102 insertions(+), 24 deletions(-) create mode 100644 dtslint/ts4.7/Tuple.ts create mode 100644 src/Tuple.ts create mode 100644 test/Tuple.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1222b62be..e61d75168 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ - add `array`, `readonlyArray` combinators - `Semigroup` - add `array`, `readonlyArray` combinators -- modules +- new modules - `typeclass/Equivalence` - `typeclass/Filterable` - `typeclass/TraversableFilterable` @@ -47,6 +47,7 @@ - `Struct` - `Symbol` - `These` + - `Tuple` ## 0.0.11 diff --git a/data.md b/data.md index 64e22438d..c55fe8867 100644 --- a/data.md +++ b/data.md @@ -4,18 +4,24 @@ This section covers the various modules and combinators that work with tuples. -| Module | Name | Given | To | -| ----------- | ------------- | --------------------------------------- | -------------------------------------- | -| Equivalence | tuple | `[Equivalence, Equivalence, ...]` | `Equivalence` | -| Order | tuple | `[Order, Order, ...]` | `Order` | -| Semigroup | tuple | `[Semigroup, Semigroup, ...]` | `Semigroup<[A, B, ...]>` | -| Monoid | tuple | `[Monoid, Monoid, ...]` | `Monoid<[A, B, ...]>` | -| SemiProduct | nonEmptyTuple | `[F, F, ...]` (cannot be empty) | `F<[A, B, ...]>` | -| Product | tuple | `[F, F, ...]` | `F<[A, B, ...]>` | -| Either | tuple | `[Either, Either, ...]` | `Either` | -| Option | tuple | `[Option, Option, ...]` | `Option<[A, B, ...]>` | -| Predicate | tuple | `[Predicate, Predicate, ...]` | `Predicate` | -| These | tuple | `[These, These, ...]` | `These` | +| Module | Name | Given | To | +| ----------- | --------------- | --------------------------------------- | -------------------------------------- | +| Equivalence | tuple | `[Equivalence, Equivalence, ...]` | `Equivalence` | +| Order | tuple | `[Order, Order, ...]` | `Order` | +| Semigroup | tuple | `[Semigroup, Semigroup, ...]` | `Semigroup<[A, B, ...]>` | +| Monoid | tuple | `[Monoid, Monoid, ...]` | `Monoid<[A, B, ...]>` | +| SemiProduct | nonEmptyTuple | `[F, F, ...]` (cannot be empty) | `F<[A, B, ...]>` | +| Product | tuple | `[F, F, ...]` | `F<[A, B, ...]>` | +| Either | tuple | `[Either, Either, ...]` | `Either` | +| Option | tuple | `[Option, Option, ...]` | `Option<[A, B, ...]>` | +| Predicate | tuple | `[Predicate, Predicate, ...]` | `Predicate` | +| These | tuple | `[These, These, ...]` | `These` | +| Tuple | getEquivalence | `[Equivalence, Equivalence, ...]` | `Equivalence` | +| Tuple | getOrder | `[Order, Order, ...]` | `Order` | +| Tuple | getSemigroup | `[Semigroup, Semigroup, ...]` | `Semigroup<[A, B, ...]>` | +| Tuple | getMonoid | `[Monoid, Monoid, ...]` | `Monoid<[A, B, ...]>` | +| Tuple | nonEmptyProduct | `[F, F, ...]` (cannot be empty) | `F<[A, B, ...]>` | +| Tuple | product | `[F, F, ...]` | `F<[A, B, ...]>` | ## arrays diff --git a/dtslint/ts4.7/Tuple.ts b/dtslint/ts4.7/Tuple.ts new file mode 100644 index 000000000..ffe7ae68b --- /dev/null +++ b/dtslint/ts4.7/Tuple.ts @@ -0,0 +1,4 @@ +import * as T from '@fp-ts/core/Tuple' + +// $ExpectType [string, number, boolean] +T.tuple('a', 1, true) diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index fbec99624..16d096338 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -2077,15 +2077,6 @@ export const join: (sep: string) => (self: ReadonlyArray) => string = in string.Monoid ) -/** - * Adds an element to the end of a tuple. - * - * @since 1.0.0 - */ -export const element: (that: ReadonlyArray) => >( - self: ReadonlyArray -) => Array<[...A, B]> = semiProduct.element(SemiProduct) as any - /** * @since 1.0.0 */ diff --git a/src/Tuple.ts b/src/Tuple.ts new file mode 100644 index 000000000..50872e69b --- /dev/null +++ b/src/Tuple.ts @@ -0,0 +1,55 @@ +/** + * @since 1.0.0 + */ +import * as RA from "@fp-ts/core/ReadonlyArray" +import * as equivalence from "@fp-ts/core/typeclass/Equivalence" +import * as monoid from "@fp-ts/core/typeclass/Monoid" +import * as order from "@fp-ts/core/typeclass/Order" +import * as _product from "@fp-ts/core/typeclass/Product" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" + +/** + * @category constructors + * @since 1.0.0 + */ +export const tuple = >(...elements: A): A => elements + +/** + * Adds an element to the end of a tuple. + * + * @since 1.0.0 + */ +export const element: (that: ReadonlyArray) => >( + self: ReadonlyArray +) => Array<[...A, B]> = semiProduct.element(RA.SemiProduct) as any + +/** + * @since 1.0.0 + */ +export const getEquivalence = equivalence.tuple + +/** + * @since 1.0.0 + */ +export const getOrder = order.tuple + +/** + * @since 1.0.0 + */ +export const getSemigroup = semigroup.tuple + +/** + * @since 1.0.0 + */ +export const getMonoid = monoid.tuple + +/** + * @since 1.0.0 + */ +export const nonEmptyProduct = semiProduct.nonEmptyTuple + +/** + * @since 1.0.0 + */ +export const product = _product.tuple diff --git a/src/index.ts b/src/index.ts index 4deb9f9c0..03150d21a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,6 +27,7 @@ import * as string from "@fp-ts/core/String" import * as struct from "@fp-ts/core/Struct" import * as symbol from "@fp-ts/core/Symbol" import * as these from "@fp-ts/core/These" +import * as tuple from "@fp-ts/core/Tuple" // ------------------------------------------------------------------------------------- // typeclasses @@ -259,5 +260,9 @@ export { * @category typeclass * @since 1.0.0 */ - traversableFilterable + traversableFilterable, + /** + * @since 1.0.0 + */ + tuple } diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index b6a4e9dfe..366631809 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -41,7 +41,6 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.SemiProduct).exist expect(RA.andThenBind).exist - expect(RA.element).exist expect(RA.Product).exist diff --git a/test/Tuple.ts b/test/Tuple.ts new file mode 100644 index 000000000..9a1212646 --- /dev/null +++ b/test/Tuple.ts @@ -0,0 +1,17 @@ +import * as T from "@fp-ts/core/Tuple" + +describe.concurrent("Tuple", () => { + it("exports", () => { + expect(T.element).exists + expect(T.getEquivalence).exists + expect(T.getOrder).exists + expect(T.getSemigroup).exists + expect(T.getMonoid).exists + expect(T.nonEmptyProduct).exists + expect(T.product).exists + }) + + it("tuple", () => { + expect(T.tuple("a", 1, true)).toEqual(["a", 1, true]) + }) +}) From 31bb44ad697576d61c0635172ac62f04bea9ca4a Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 21 Jan 2023 09:56:28 +0100 Subject: [PATCH 075/255] more docs --- CHANGELOG.md | 1 + Either.md | 141 ++++++++++++++++++++++++++++++++++++++++++ Option.md | 120 +++++++++++++++++++++++++++++++++++ src/Bigint.ts | 4 ++ src/Boolean.ts | 4 ++ src/Either.ts | 18 +++--- src/Number.ts | 4 ++ src/Option.ts | 4 -- src/ReadonlyArray.ts | 2 + src/ReadonlyRecord.ts | 2 + src/String.ts | 4 ++ src/Struct.ts | 2 + src/Tuple.ts | 2 + 13 files changed, 294 insertions(+), 14 deletions(-) create mode 100644 Either.md create mode 100644 Option.md diff --git a/CHANGELOG.md b/CHANGELOG.md index e61d75168..d91339d5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ **Breaking changes** +- remove `NonEmptyTraversable` module - `Semigroup` - make `combine` binary - make `combineMany` binary diff --git a/Either.md b/Either.md new file mode 100644 index 000000000..1b1bf3953 --- /dev/null +++ b/Either.md @@ -0,0 +1,141 @@ +# The `Either` data type + +The `Either` data type is a powerful and flexible tool for handling potentially failed computations in functional programming. It can be found in the `@fp-ts/core/Either` module, and it has two variants, `Left` and `Right`, which can be used to represent different outcomes. + +The `Left` variant is used to represent a failure, and it can contain useful information such as an error message or a failure code. The `Right` variant, on the other hand, is used to represent a successful outcome, and it can contain the result of the computation. + +Unlike the `Option` type, `Either` allows you to attach additional information to the failure case, making it more informative. +In this usage, `None` is replaced with a `Left` which can contain useful information. `Right` takes the place of `Some`. + +## Definition + +The `Either` data type is the union of two members: `Left` and `Right`. The way chosen by the `@fp-ts/core` library to model this union in TypeScript is to use a feature of the language called [Discriminating Unions](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions): + +> A common technique for working with unions is to have a single field which uses literal types which you can use to let TypeScript narrow down the possible current type + +Here's the complete definition of the `Either` type: + +```ts +export type Left = { + readonly _tag: "Left"; + readonly left: E; +}; + +export type Right = { + readonly _tag: "Right"; + readonly right: A; +}; + +export type Either = Left | Right; +``` + +## Using `Either` + +To create an instance of `Either`, you can use the `right` and `left` constructors, which construct a new `Either` holding a `Right` or `Left` value respectively. + +```ts +import { left, right } from "@fp-ts/core/Either"; + +const success: Either = right(1); +const failure: Either = left("error message"); +``` + +You can also use the `fromOption` function to convert an `Option` to an `Either`. + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { fromOption } from "@fp-ts/core/Either"; +import { none, some } from "@fp-ts/core/Option"; + +const success: Either = pipe( + some(1), + fromOption("error message") +); +const failure: Either = pipe( + none(), + fromOption("error message") +); +``` + +The `fromOption` function requires an argument because it needs to know what value to use for the `Left` variant of the `Either` type when given a `None`. In the example, the argument "error message" is used as the value for the `Left` variant when `None` is encountered. This allows `Either` to provide more information about why a failure occurred. + +## Working with `Either` + +Once you have an instance of `Either`, you can use the various functions provided in the `@fp-ts/core/Either` module to work with it. + +The `map` and `mapLeft` functions can be used to transform the `Right` and `Left` values respectively. + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { left, right, map, mapLeft } from "@fp-ts/core/Either"; + +const success: Either = pipe( + right(1), + map((x) => x + 1) +); // right(2) + +const failure: Either = pipe( + left("error message"), + mapLeft((x) => x + "!") +); // left("error message!") +``` + +## Handling failing computations + +Let's see how to use the `Either` data type to model a computation that can fail, such as a function that can throw an exception based on certain conditions. Let's take the case of the following function: + +```ts +function parseNumber(s: string): number { + const n = parseFloat(s); + if (isNaN(n)) { + throw new Error(`Cannot parse '${s}' as a number`); + } + return n; +} +``` + +An alternative to throwing an exception is to always return a value, but this value will be of type `Either` instead of `number`, with the following interpretation: + +- if `parseNumber` returns a `Left` value, it means that the computation failed, and the `Left` contains an error message or other information about the failure +- if the result is instead a `Right` value, it means that the computation succeeded and the computed value is wrapped inside the `Right` + +Let's see how we can rewrite the `parseNumber` function without throwing exceptions and using the `Either` data type instead: + +```ts +import { Either, left, right } from "@fp-ts/core/Either"; + +function parseNumber(s: string): Either { + const n = parseFloat(s); + return isNaN(n) ? left(`Cannot parse '${s}' as a number`) : right(n); +} + +console.log(parseNumber("2")); // right(2) +console.log(parseNumber("Not a number")); // left("Cannot parse 'Not a number' as a number") +``` + +## Pattern matching + +The `match` function allows us to match on the `Left` and `Right` cases of an `Either` value and provide different actions for each. + +We can use the `match` function to handle the `Either` value returned by `parseNumber` and decide what to do based on whether it's a `Left` or a `Right`. + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { match } from "@fp-ts/core/Either"; + +// parseNumber returns an Either +const result = parseNumber("Not a number"); + +// Using pipe and match to pattern match on the result +const output = pipe( + result, + match( + // If the result is a Left, return an error string + (error) => `Error: ${error}`, + // If the result is a Right, return a string with the number + (n) => `The number is ${n}` + ) +); + +console.log(output); // Output: Error: Cannot parse 'Not a number' as a number +``` diff --git a/Option.md b/Option.md new file mode 100644 index 000000000..02086f9cf --- /dev/null +++ b/Option.md @@ -0,0 +1,120 @@ +# The `Option` data type + +The `Option` data type is a powerful and flexible tool for handling potentially failed computations in functional programming. It can be found in the `@fp-ts/core/Option` module, and it has two variants, `None` and `Some`, which can be used to represent different outcomes. + +There are two possible interpretations of the `Option` data type: + +1. as a representation of the result of a computation that can fail or return a value of type `A` +2. as a representation of an optional value of type `A` + +In the first of these two interpretations, the `None` union member represents the result of a computation that has failed and therefore was not able to return any value, while the `Some` union member represents the result of a computation that has succeeded and was able to return a value of type `A`. + +In the second of these two interpretations, the `None` union member represents the absence of the value, while the `Some` union member represents the presence of the value of type `A` + +## Definition + +The `Option` data type is the union of two members: `None` and `Some`. The way chosen by the `@fp-ts/core` library to model this union in TypeScript is to use a feature of the language called [Discriminating Unions](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions): + +> A common technique for working with unions is to have a single field which uses literal types which you can use to let TypeScript narrow down the possible current type + +Here's the complete definition of the `Option` type: + +```ts +export type None = { + readonly _tag: "None"; +}; + +export type Some = { + readonly _tag: "Some"; + readonly value: A; +}; + +export type Option = None | Some; +``` + +## Using `Option` + +To create an instance of `Option`, you can use the `some` and `none` constructors, which construct a new `Option` holding a `Some` or `None` value respectively. + +```ts +import { none, some } from "@fp-ts/core/Either"; + +const success: Option = some(1); +const failure: Option = none(); +``` + +## Working with `Option` + +Once you have an instance of `Option`, you can use the various functions provided in the `@fp-ts/core/Option` module to work with it. + +The `map` function can be used to transform the `Some` values. + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { some, map } from "@fp-ts/core/Option"; + +const success: Option = pipe( + some(1), + map((x) => x + 1) +); // some(2) +``` + +## Handling failing computations + +Let's see how to use the `Option` data type to model a computation that can fail, such as a function that can throw an exception based on certain conditions. Let's take the case of the following function: + +```ts +function parseNumber(s: string): number { + const n = parseFloat(s); + if (isNaN(n)) { + throw new Error(); + } + return n; +} +``` + +An alternative to throwing an exception is to always return a value, but this value will be of type `Option` instead of `number`, with the following interpretation: + +- if `parseNumber` returns a `None` value, it means that the computation failed +- if the result is instead a `Some` value, it means that the computation succeeded and the computed value is wrapped inside the `Some` + +Let's see how we can rewrite the `parseNumber` function without throwing exceptions and using the `Option` data type instead: + +```ts +import { Option, none, some } from "@fp-ts/core/Option"; + +function parseNumber(s: string): Option { + const n = parseFloat(s); + return isNaN(n) ? none() : some(n); +} + +console.log(parseNumber("2")); // some(2) +console.log(parseNumber("Not a number")); // none() +``` + +## Pattern matching + +The `match` function allows us to match on the `None` and `Some` cases of an `Option` value and provide different actions for each. + +We can use the `match` function to handle the `Option` value returned by `parseNumber` and decide what to do based on whether it's a `None` or a `Some`. + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { match } from "@fp-ts/core/Option"; + +// parseNumber returns an Option +const result = parseNumber("Not a number"); + +// Using pipe and match to pattern match on the result +const output = pipe( + result, + match( + // If the result is a None, return an error string + () => `Error: ${error}`, + // If the result is a Some, return a string with the number + (n) => `The number is ${n}` + ) +); + +console.log(output); // Output: Error: Cannot parse 'Not a number' as a number +``` diff --git a/src/Bigint.ts b/src/Bigint.ts index 9860f19a3..6248af689 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -1,4 +1,8 @@ /** + * This module provides utility functions and type class instances for working with the `bigint` type in TypeScript. + * It includes functions for basic arithmetic operations, as well as type class instances for + * `Equivalence`, `Order`, `Semigroup`, and `Monoid`. + * * @since 1.0.0 */ diff --git a/src/Boolean.ts b/src/Boolean.ts index bd07985dd..f3e6e4743 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -1,4 +1,8 @@ /** + * This module provides utility functions and type class instances for working with the `boolean` type in TypeScript. + * It includes functions for basic boolean operations, as well as type class instances for + * `Equivalence`, `Order`, `Semigroup`, and `Monoid`. + * * @since 1.0.0 */ import type { LazyArg } from "@fp-ts/core/Function" diff --git a/src/Either.ts b/src/Either.ts index c0f6e5127..29b339d7d 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1,15 +1,13 @@ /** - * ```ts - * type Either = Left | Right - * ``` + * The `Either` data type is a powerful and flexible tool for handling potentially failed computations. + * It has two variants, `Left` and `Right`, which can be used to represent different outcomes. * - * Represents a value of one of two possible types (a disjoint union). + * The `Left` variant is used to represent a failure, and it can contain useful information such as an error message + * or a failure code. The `Right` variant is used to represent a successful outcome, and it can contain the result + * of the computation. * - * An instance of `Either` is either an instance of `Left` or `Right`. - * - * A common use of `Either` is as an alternative to `Option` for dealing with possible missing values. In this usage, - * `None` is replaced with a `Left` which can contain useful information. `Right` takes the place of `Some`. Convention - * dictates that `Left` is used for failure and `Right` is used for success. + * Unlike `Option`, `Either` allows you to attach additional information to the failure case, making it more + * informative than a simple `null` or `undefined`. * * @since 1.0.0 */ @@ -1004,7 +1002,7 @@ export const fromIterable = (onEmpty: LazyArg) => * import * as O from '@fp-ts/core/Option' * * assert.deepStrictEqual(pipe(O.some(1), E.fromOption(() => 'error')), E.right(1)) - * assert.deepStrictEqual(pipe(O.none, E.fromOption(() => 'error')), E.left('error')) + * assert.deepStrictEqual(pipe(O.none(), E.fromOption(() => 'error')), E.left('error')) * * @category conversions * @since 1.0.0 diff --git a/src/Number.ts b/src/Number.ts index 49ddd27eb..c5a4b5f9f 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -1,4 +1,8 @@ /** + * This module provides utility functions and type class instances for working with the `number` type in TypeScript. + * It includes functions for basic arithmetic operations, as well as type class instances for + * `Equivalence`, `Order`, `Semigroup`, and `Monoid`. + * * @since 1.0.0 */ import type { Ordering } from "@fp-ts/core/Ordering" diff --git a/src/Option.ts b/src/Option.ts index 47a09a263..479c75e30 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1,8 +1,4 @@ /** - * ```ts - * type Option = None | Some - * ``` - * * The `Option` type can be interpreted in a few ways: * * 1) `Option` is a container for an optional value of type `A`. If the value of type `A` is present, the `Option` is diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 16d096338..7a41e7939 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1,4 +1,6 @@ /** + * This module provides utility functions for working with arrays in TypeScript. + * * @since 1.0.0 */ import type { Either } from "@fp-ts/core/Either" diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index a3f49e039..9936e7372 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -1,4 +1,6 @@ /** + * This module provides utility functions for working with records in TypeScript. + * * @since 1.0.0 */ diff --git a/src/String.ts b/src/String.ts index 54d974db4..0a3a89b21 100644 --- a/src/String.ts +++ b/src/String.ts @@ -1,4 +1,8 @@ /** + * This module provides utility functions and type class instances for working with the `string` type in TypeScript. + * It includes functions for basic string manipulation, as well as type class instances for + * `Equivalence`, `Order`, `Semigroup`, and `Monoid`. + * * @since 1.0.0 */ diff --git a/src/Struct.ts b/src/Struct.ts index 1efea549e..deceeb29f 100644 --- a/src/Struct.ts +++ b/src/Struct.ts @@ -1,4 +1,6 @@ /** + * This module provides utility functions for working with structs in TypeScript. + * * @since 1.0.0 */ diff --git a/src/Tuple.ts b/src/Tuple.ts index 50872e69b..ccfea26e3 100644 --- a/src/Tuple.ts +++ b/src/Tuple.ts @@ -1,4 +1,6 @@ /** + * This module provides utility functions for working with tuples in TypeScript. + * * @since 1.0.0 */ import * as RA from "@fp-ts/core/ReadonlyArray" From bb51b0408595af625d3ce014b13d140bd7af7f07 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 21 Jan 2023 10:16:46 +0100 Subject: [PATCH 076/255] Order: add struct --- data.md | 30 ++++++++++++++---------- src/Struct.ts | 36 ++++++++++++++++++++++++++++ src/typeclass/Order.ts | 21 +++++++++++++++++ test/Struct.ts | 9 +++++++ test/typeclass/Order.ts | 52 +++++++++++++++++++++-------------------- 5 files changed, 111 insertions(+), 37 deletions(-) diff --git a/data.md b/data.md index c55fe8867..7d753d734 100644 --- a/data.md +++ b/data.md @@ -42,18 +42,24 @@ This section covers the various modules and combinators that work with arrays. This section covers the various modules and combinators that work with structs. -| Module | Name | Given | To | -| ----------- | -------------- | ----------------------------------------------- | ----------------------------------------- | -| Equivalence | struct | `{ a: Equivalence, b: Equivalence, ... }` | `Equivalence<{ a: A, b: B, ... }>` | -| Order | NA | NA | NA | -| Semigroup | struct | `{ a: Semigroup, b: Semigroup, ... }` | `Semigroup<{ a: A, b: B, ... }>` | -| Monoid | struct | `{ a: Monoid, b: Monoid, ... }` | `Monoid<{ a: A, b: B, ... }>` | -| SemiProduct | nonEmptyStruct | `{ a: F, b: F, ... }` (cannot be empty) | `F<{ a: A, b: B, ... }>` | -| Product | struct | `{ a: F, b: F, ... }` | `F<{ a: A, b: B, ... }>` | -| Either | struct | `{ a: Either, b: Either, ... }` | `Either` | -| Option | struct | `{ a: Option, b: Option, ... }` | `Option<{ a: A, b: B }>` | -| Predicate | struct | `{ a: Predicate, b: Predicate, ... }` | `Predicate>` | -| These | struct | `{ a: These, b: These, ... }` | `These` | +| Module | Name | Given | To | +| ----------- | --------------- | ----------------------------------------------- | ----------------------------------------- | +| Equivalence | struct | `{ a: Equivalence, b: Equivalence, ... }` | `Equivalence<{ a: A, b: B, ... }>` | +| Order | struct | `{ a: Order, b: Order, ... }` | `Order<{ a: A, b: B, ... }>` | +| Semigroup | struct | `{ a: Semigroup, b: Semigroup, ... }` | `Semigroup<{ a: A, b: B, ... }>` | +| Monoid | struct | `{ a: Monoid, b: Monoid, ... }` | `Monoid<{ a: A, b: B, ... }>` | +| SemiProduct | nonEmptyStruct | `{ a: F, b: F, ... }` (cannot be empty) | `F<{ a: A, b: B, ... }>` | +| Product | struct | `{ a: F, b: F, ... }` | `F<{ a: A, b: B, ... }>` | +| Either | struct | `{ a: Either, b: Either, ... }` | `Either` | +| Option | struct | `{ a: Option, b: Option, ... }` | `Option<{ a: A, b: B }>` | +| Predicate | struct | `{ a: Predicate, b: Predicate, ... }` | `Predicate>` | +| These | struct | `{ a: These, b: These, ... }` | `These` | +| Struct | getEquivalence | `{ a: Equivalence, b: Equivalence, ... }` | `Equivalence<{ a: A, b: B, ... }>` | +| Struct | getOrder | `{ a: Order, b: Order, ... }` | `Order<{ a: A, b: B, ... }>` | +| Struct | getSemigroup | `{ a: Semigroup, b: Semigroup, ... }` | `Semigroup<{ a: A, b: B, ... }>` | +| Struct | getMonoid | `{ a: Monoid, b: Monoid, ... }` | `Monoid<{ a: A, b: B, ... }>` | +| Struct | nonEmptyProduct | `{ a: F, b: F, ... }` (cannot be empty) | `F<{ a: A, b: B, ... }>` | +| Struct | product | `{ a: F, b: F, ... }` | `F<{ a: A, b: B, ... }>` | ## records diff --git a/src/Struct.ts b/src/Struct.ts index deceeb29f..053d7eec1 100644 --- a/src/Struct.ts +++ b/src/Struct.ts @@ -3,6 +3,12 @@ * * @since 1.0.0 */ +import * as equivalence from "@fp-ts/core/typeclass/Equivalence" +import * as monoid from "@fp-ts/core/typeclass/Monoid" +import * as order from "@fp-ts/core/typeclass/Order" +import * as _product from "@fp-ts/core/typeclass/Product" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** * Create a new object by picking properties of an existing object. @@ -35,3 +41,33 @@ export const omit = ]>( } return out } + +/** + * @since 1.0.0 + */ +export const getEquivalence = equivalence.struct + +/** + * @since 1.0.0 + */ +export const getOrder = order.struct + +/** + * @since 1.0.0 + */ +export const getSemigroup = semigroup.struct + +/** + * @since 1.0.0 + */ +export const getMonoid = monoid.struct + +/** + * @since 1.0.0 + */ +export const nonEmptyProduct = semiProduct.nonEmptyStruct + +/** + * @since 1.0.0 + */ +export const product = _product.struct diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 85b762d09..0adbb5945 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -114,6 +114,27 @@ export const array = (O: Order): Order> => return number.compare(aLen, bLen) }) +/** + * This function creates and returns a new `Order` for a struct of values based on the given `Order`s + * for each property in the struct. + * + * @category combinators + * @since 1.0.0 + */ +export const struct = (orders: { readonly [K in keyof A]: Order }): Order< + { readonly [K in keyof A]: A[K] } +> => ({ + compare: (self, that) => { + for (const key of Object.keys(orders)) { + const o = orders[key].compare(self[key], that[key]) + if (o !== 0) { + return o + } + } + return 0 + } +}) + /** * @since 1.0.0 */ diff --git a/test/Struct.ts b/test/Struct.ts index 66e2a3735..a9526236b 100644 --- a/test/Struct.ts +++ b/test/Struct.ts @@ -2,6 +2,15 @@ import { pipe } from "@fp-ts/core/Function" import * as S from "@fp-ts/core/Struct" describe.concurrent("Struct", () => { + it("exports", () => { + expect(S.getEquivalence).exists + expect(S.getOrder).exists + expect(S.getSemigroup).exists + expect(S.getMonoid).exists + expect(S.nonEmptyProduct).exists + expect(S.product).exists + }) + it("pick", () => { expect(pipe({ a: "a", b: 1, c: true }, S.pick("a", "b"))).toEqual({ a: "a", b: 1 }) }) diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index 1d82bb7bb..9e59bcfb1 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -1,8 +1,5 @@ -import * as boolean from "@fp-ts/core/Boolean" import { pipe } from "@fp-ts/core/Function" -import * as number from "@fp-ts/core/Number" import { sort } from "@fp-ts/core/ReadonlyArray" -import * as string from "@fp-ts/core/String" import * as _ from "@fp-ts/core/typeclass/Order" import * as U from "../util" @@ -16,14 +13,22 @@ describe("Order", () => { }) it("tuple", () => { - const O = _.tuple(string.Order, number.Order, boolean.Order) + const O = _.tuple(_.string, _.number, _.boolean) U.deepStrictEqual(O.compare(["a", 1, true], ["b", 2, true]), -1) U.deepStrictEqual(O.compare(["a", 1, true], ["a", 2, true]), -1) U.deepStrictEqual(O.compare(["a", 1, true], ["a", 1, false]), 1) }) + it("struct", () => { + const O = _.struct({ a: _.string, b: _.number, c: _.boolean }) + U.deepStrictEqual(O.compare({ a: "a", b: 1, c: true }, { a: "b", b: 2, c: true }), -1) + U.deepStrictEqual(O.compare({ a: "a", b: 1, c: true }, { a: "a", b: 2, c: true }), -1) + U.deepStrictEqual(O.compare({ a: "a", b: 1, c: true }, { a: "a", b: 1, c: false }), 1) + U.deepStrictEqual(O.compare({ a: "a", b: 1, c: true }, { a: "a", b: 1, c: true }), 0) + }) + it("Contravariant", () => { - const O = pipe(number.Order, _.Contravariant.contramap((s: string) => s.length)) + const O = pipe(_.number, _.Contravariant.contramap((s: string) => s.length)) U.deepStrictEqual(O.compare("a", "b"), 0) U.deepStrictEqual(O.compare("a", "bb"), -1) U.deepStrictEqual(O.compare("aa", "b"), 1) @@ -31,7 +36,7 @@ describe("Order", () => { it("Invariant", () => { const O = _.Invariant.imap((s: string) => [s], ([s]) => s)( - string.Order + _.string ) U.deepStrictEqual(O.compare(["a"], ["b"]), -1) U.deepStrictEqual(O.compare(["a"], ["a"]), 0) @@ -48,11 +53,11 @@ describe("Order", () => { ] const S = _.getSemigroup() const sortByFst = pipe( - number.Order, + _.number, _.contramap((x: T) => x[0]) ) const sortBySnd = pipe( - string.Order, + _.string, _.contramap((x: T) => x[1]) ) U.deepStrictEqual(sort(S.combine(sortByFst, sortBySnd))(tuples), [ @@ -91,11 +96,11 @@ describe("Order", () => { ] const M = _.getMonoid() const sortByFst = pipe( - number.Order, + _.number, _.contramap((x: T) => x[0]) ) const sortBySnd = pipe( - string.Order, + _.string, _.contramap((x: T) => x[1]) ) U.deepStrictEqual(sort(M.combineMany(M.empty, [sortByFst, sortBySnd]))(tuples), [ @@ -113,7 +118,7 @@ describe("Order", () => { }) it("clamp", () => { - const clamp = _.clamp(number.Order) + const clamp = _.clamp(_.number) U.deepStrictEqual(clamp(1, 10)(2), 2) U.deepStrictEqual(clamp(1, 10)(10), 10) U.deepStrictEqual(clamp(1, 10)(20), 10) @@ -122,7 +127,7 @@ describe("Order", () => { }) it("between", () => { - const between = _.between(number.Order) + const between = _.between(_.number) U.deepStrictEqual(between(1, 10)(2), true) U.deepStrictEqual(between(1, 10)(10), true) U.deepStrictEqual(between(1, 10)(20), false) @@ -131,35 +136,35 @@ describe("Order", () => { }) it("reverse", () => { - const O = _.reverse(number.Order) + const O = _.reverse(_.number) U.deepStrictEqual(O.compare(1, 2), 1) U.deepStrictEqual(O.compare(2, 1), -1) U.deepStrictEqual(O.compare(2, 2), 0) }) it("lessThan", () => { - const lessThan = _.lessThan(number.Order) + const lessThan = _.lessThan(_.number) U.deepStrictEqual(pipe(0, lessThan(1)), true) U.deepStrictEqual(pipe(1, lessThan(1)), false) U.deepStrictEqual(pipe(2, lessThan(1)), false) }) it("lessThanOrEqualTo", () => { - const lessThanOrEqualTo = _.lessThanOrEqualTo(number.Order) + const lessThanOrEqualTo = _.lessThanOrEqualTo(_.number) U.deepStrictEqual(pipe(0, lessThanOrEqualTo(1)), true) U.deepStrictEqual(pipe(1, lessThanOrEqualTo(1)), true) U.deepStrictEqual(pipe(2, lessThanOrEqualTo(1)), false) }) it("greaterThan", () => { - const greaterThan = _.greaterThan(number.Order) + const greaterThan = _.greaterThan(_.number) U.deepStrictEqual(pipe(0, greaterThan(1)), false) U.deepStrictEqual(pipe(1, greaterThan(1)), false) U.deepStrictEqual(pipe(2, greaterThan(1)), true) }) it("greaterThanOrEqualTo", () => { - const greaterThanOrEqualTo = _.greaterThanOrEqualTo(number.Order) + const greaterThanOrEqualTo = _.greaterThanOrEqualTo(_.number) U.deepStrictEqual(pipe(0, greaterThanOrEqualTo(1)), false) U.deepStrictEqual(pipe(1, greaterThanOrEqualTo(1)), true) U.deepStrictEqual(pipe(2, greaterThanOrEqualTo(1)), true) @@ -169,7 +174,7 @@ describe("Order", () => { type A = { a: number } const min = _.min( pipe( - number.Order, + _.number, _.contramap((a: A) => a.a) ) ) @@ -184,7 +189,7 @@ describe("Order", () => { type A = { a: number } const max = _.max( pipe( - number.Order, + _.number, _.contramap((a: A) => a.a) ) ) @@ -197,10 +202,7 @@ describe("Order", () => { describe("SemiProduct", () => { it("product", () => { - const O = _.SemiProduct.product( - string.Order, - number.Order - ) + const O = _.SemiProduct.product(_.string, _.number) U.deepStrictEqual(O.compare(["a", 1], ["a", 2]), -1) U.deepStrictEqual(O.compare(["a", 1], ["a", 1]), 0) U.deepStrictEqual(O.compare(["a", 1], ["a", 0]), 1) @@ -208,7 +210,7 @@ describe("Order", () => { }) it("productMany", () => { - const O = _.SemiProduct.productMany(string.Order, [string.Order, string.Order]) + const O = _.SemiProduct.productMany(_.string, [_.string, _.string]) U.deepStrictEqual(O.compare(["a", "b"], ["a", "c"]), -1) U.deepStrictEqual(O.compare(["a", "b"], ["a", "b"]), 0) U.deepStrictEqual(O.compare(["a", "b"], ["a", "a"]), 1) @@ -226,7 +228,7 @@ describe("Order", () => { it("productAll", () => { const O = pipe( - _.Product.productAll([string.Order, string.Order, string.Order]) + _.Product.productAll([_.string, _.string, _.string]) ) U.deepStrictEqual(O.compare(["a", "b"], ["a", "c"]), -1) U.deepStrictEqual(O.compare(["a", "b"], ["a", "b"]), 0) From a047735c3a6abf3537fb66f8cde38eff8d3895dd Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 21 Jan 2023 10:47:16 +0100 Subject: [PATCH 077/255] Number: add SemigroupMin, SemigroupMax, MonoidMin, MonoidMax --- data.md | 4 ++++ src/Number.ts | 48 +++++++++++++++++++++++++++++++--------- src/Predicate.ts | 3 +-- src/Struct.ts | 4 ++-- src/Tuple.ts | 4 ++-- src/typeclass/Bounded.ts | 21 ++++++++++++++++++ test/Number.ts | 22 +++++++++++++----- 7 files changed, 85 insertions(+), 21 deletions(-) diff --git a/data.md b/data.md index 7d753d734..ca819e536 100644 --- a/data.md +++ b/data.md @@ -103,8 +103,12 @@ This section covers the various modules and combinators that work with records. | Number | Order | | `Order` | | Number | SemigroupSum | | `Semigroup` | | Number | SemigroupMultiply | | `Semigroup` | +| Number | SemigroupMax | | `Semigroup` | +| Number | SemigroupMin | | `Semigroup` | | Number | MonoidSum | | `Monoid` | | Number | MonoidMultiply | | `Monoid` | +| Number | MonoidMax | | `Monoid` | +| Number | MonoidMin | | `Monoid` | | Number | isNumber | | `Refinement` | ## booleans diff --git a/src/Number.ts b/src/Number.ts index c5a4b5f9f..c67370659 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -6,7 +6,6 @@ * @since 1.0.0 */ import type { Ordering } from "@fp-ts/core/Ordering" -import type { Refinement } from "@fp-ts/core/Predicate" import * as predicate from "@fp-ts/core/Predicate" import * as bounded from "@fp-ts/core/typeclass/Bounded" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" @@ -18,7 +17,7 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" * @category guards * @since 1.0.0 */ -export const isNumber: Refinement = predicate.isNumber +export const isNumber = predicate.isNumber /** * @since 1.0.0 @@ -35,7 +34,12 @@ export const multiply = (that: number) => /** * @since 1.0.0 */ -export const sub = (that: number) => (self: number): number => self - that +export const subtract = (that: number) => (self: number): number => self - that + +/** + * @since 1.0.0 + */ +export const divide = (that: number) => (self: number): number => self / that /** * @since 1.0.0 @@ -51,19 +55,19 @@ export const decrement = (n: number): number => n - 1 * @category instances * @since 1.0.0 */ -export const Equivalence: equivalence.Equivalence = equivalence.number +export const Equivalence = equivalence.number /** * @category instances * @since 1.0.0 */ -export const Order: order.Order = order.number +export const Order = order.number /** * @category instances * @since 1.0.0 */ -export const Bounded: bounded.Bounded = bounded.number +export const Bounded = bounded.number /** * `number` semigroup under addition. @@ -77,7 +81,19 @@ export const Bounded: bounded.Bounded = bounded.number * @category instances * @since 1.0.0 */ -export const SemigroupSum: semigroup.Semigroup = semigroup.numberSum +export const SemigroupSum = semigroup.numberSum + +/** + * @category instances + * @since 1.0.0 + */ +export const SemigroupMax = semigroup.max(Order) + +/** + * @category instances + * @since 1.0.0 + */ +export const SemigroupMin = semigroup.min(Order) /** * `number` semigroup under multiplication. @@ -91,7 +107,7 @@ export const SemigroupSum: semigroup.Semigroup = semigroup.numberSum * @category instances * @since 1.0.0 */ -export const SemigroupMultiply: semigroup.Semigroup = semigroup.numberMultiply +export const SemigroupMultiply = semigroup.numberMultiply /** * `number` monoid under addition. @@ -101,7 +117,7 @@ export const SemigroupMultiply: semigroup.Semigroup = semigroup.numberMu * @category instances * @since 1.0.0 */ -export const MonoidSum: monoid.Monoid = monoid.numberSum +export const MonoidSum = monoid.numberSum /** * `number` monoid under multiplication. @@ -111,7 +127,19 @@ export const MonoidSum: monoid.Monoid = monoid.numberSum * @category instances * @since 1.0.0 */ -export const MonoidMultiply: monoid.Monoid = monoid.numberMultiply +export const MonoidMultiply = monoid.numberMultiply + +/** + * @category instances + * @since 1.0.0 + */ +export const MonoidMax = bounded.max(Bounded) + +/** + * @category instances + * @since 1.0.0 + */ +export const MonoidMin = bounded.min(Bounded) /** * @since 1.0.0 diff --git a/src/Predicate.ts b/src/Predicate.ts index 55c0042e4..2f55da2a7 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -238,8 +238,7 @@ export const tuple: >>( export const struct: >>( predicates: R ) => Predicate<{ readonly [K in keyof R]: [R[K]] extends [Predicate] ? A : never }> = - product_ - .struct(Product) + product_.struct(Product) /** * @since 1.0.0 diff --git a/src/Struct.ts b/src/Struct.ts index 053d7eec1..c4294f1c9 100644 --- a/src/Struct.ts +++ b/src/Struct.ts @@ -6,7 +6,7 @@ import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as order from "@fp-ts/core/typeclass/Order" -import * as _product from "@fp-ts/core/typeclass/Product" +import * as product_ from "@fp-ts/core/typeclass/Product" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" @@ -70,4 +70,4 @@ export const nonEmptyProduct = semiProduct.nonEmptyStruct /** * @since 1.0.0 */ -export const product = _product.struct +export const product = product_.struct diff --git a/src/Tuple.ts b/src/Tuple.ts index ccfea26e3..6b072345c 100644 --- a/src/Tuple.ts +++ b/src/Tuple.ts @@ -7,7 +7,7 @@ import * as RA from "@fp-ts/core/ReadonlyArray" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as order from "@fp-ts/core/typeclass/Order" -import * as _product from "@fp-ts/core/typeclass/Product" +import * as product_ from "@fp-ts/core/typeclass/Product" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" @@ -54,4 +54,4 @@ export const nonEmptyProduct = semiProduct.nonEmptyTuple /** * @since 1.0.0 */ -export const product = _product.tuple +export const product = product_.tuple diff --git a/src/typeclass/Bounded.ts b/src/typeclass/Bounded.ts index 6d59f747f..c188e2e61 100644 --- a/src/typeclass/Bounded.ts +++ b/src/typeclass/Bounded.ts @@ -2,8 +2,11 @@ * @since 1.0.0 */ import type { TypeLambda } from "@fp-ts/core/HKT" +import type { Monoid } from "@fp-ts/core/typeclass/Monoid" +import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as order from "@fp-ts/core/typeclass/Order" import type { Order } from "@fp-ts/core/typeclass/Order" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** * @category type class @@ -22,6 +25,24 @@ export interface BoundedTypeLambda extends TypeLambda { readonly type: Bounded } +/** + * `Monoid` that returns last minimum of elements. + * + * @category constructors + * @since 1.0.0 + */ +export const min = (B: Bounded): Monoid => + monoid.fromSemigroup(semigroup.min(B), B.maxBound) + +/** + * `Monoid` that returns last maximum of elements. + * + * @category constructors + * @since 1.0.0 + */ +export const max = (B: Bounded): Monoid => + monoid.fromSemigroup(semigroup.max(B), B.minBound) + /** * @category instances * @since 1.0.0 diff --git a/test/Number.ts b/test/Number.ts index a3f6c334e..86890685f 100644 --- a/test/Number.ts +++ b/test/Number.ts @@ -1,7 +1,15 @@ +import { pipe } from "@fp-ts/core/Function" import * as Number from "@fp-ts/core/Number" import { deepStrictEqual } from "@fp-ts/core/test/util" describe.concurrent("Number", () => { + it("exports", () => { + expect(Number.SemigroupMax).exists + expect(Number.SemigroupMin).exists + expect(Number.MonoidMax).exists + expect(Number.MonoidMin).exists + }) + it("isNumber", () => { expect(Number.isNumber(1)).toEqual(true) expect(Number.isNumber("a")).toEqual(false) @@ -9,15 +17,19 @@ describe.concurrent("Number", () => { }) it("sum", () => { - deepStrictEqual(Number.sum(1)(2), 3) + deepStrictEqual(pipe(1, Number.sum(2)), 3) + }) + + it("multiply", () => { + deepStrictEqual(pipe(2, Number.multiply(3)), 6) }) - it("sub", () => { - deepStrictEqual(Number.sub(1)(2), 1) + it("subtract", () => { + deepStrictEqual(pipe(3, Number.subtract(1)), 2) }) - it("multiply", () => { - deepStrictEqual(Number.multiply(3)(2), 6) + it("divide", () => { + deepStrictEqual(pipe(6, Number.divide(2)), 3) }) it("increment", () => { From 61e335867af8522ee13562290f6126e1c01891f0 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 21 Jan 2023 11:00:41 +0100 Subject: [PATCH 078/255] Boolean: add all, any --- src/Boolean.ts | 10 ++++++++++ src/Predicate.ts | 24 +++++------------------- test/Boolean.ts | 4 +++- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/Boolean.ts b/src/Boolean.ts index f3e6e4743..ec0241537 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -125,3 +125,13 @@ export const or = (that: boolean) => * @since 1.0.0 */ export const not = (self: boolean): boolean => !self + +/** + * @since 1.0.0 + */ +export const all = MonoidAll.combineAll + +/** + * @since 1.0.0 + */ +export const any = MonoidAny.combineAll diff --git a/src/Predicate.ts b/src/Predicate.ts index 2f55da2a7..42ae6c8ae 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -6,7 +6,7 @@ import type { TypeLambda } from "@fp-ts/core/HKT" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import * as invariant from "@fp-ts/core/typeclass/Invariant" -import type * as monoid from "@fp-ts/core/typeclass/Monoid" +import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as of_ from "@fp-ts/core/typeclass/Of" import * as product_ from "@fp-ts/core/typeclass/Product" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" @@ -268,15 +268,8 @@ export const getSemigroupAny = (): semigroup.Semigroup> => * @category instances * @since 1.0.0 */ -export const getMonoidAny = (): monoid.Monoid> => { - const S = getSemigroupAny() - return ({ - combine: S.combine, - combineMany: S.combineMany, - combineAll: (collection) => S.combineMany(constFalse, collection), - empty: constFalse - }) -} +export const getMonoidAny = (): monoid.Monoid> => + monoid.fromSemigroup(getSemigroupAny(), constFalse) /** * @category instances @@ -289,15 +282,8 @@ export const getSemigroupAll = (): semigroup.Semigroup> => * @category instances * @since 1.0.0 */ -export const getMonoidAll = (): monoid.Monoid> => { - const S = getSemigroupAll() - return ({ - combine: S.combine, - combineMany: S.combineMany, - combineAll: (collection) => S.combineMany(constTrue, collection), - empty: constTrue - }) -} +export const getMonoidAll = (): monoid.Monoid> => + monoid.fromSemigroup(getSemigroupAll(), constTrue) /** * @since 1.0.0 diff --git a/test/Boolean.ts b/test/Boolean.ts index 39bd328cb..cf6cc8705 100644 --- a/test/Boolean.ts +++ b/test/Boolean.ts @@ -3,11 +3,13 @@ import { pipe } from "@fp-ts/core/Function" import { deepStrictEqual } from "@fp-ts/core/test/util" describe.concurrent("Boolean", () => { - it("instances and derived exports", () => { + it("exports", () => { expect(Boolean.SemigroupAll).exist expect(Boolean.MonoidAll).exist expect(Boolean.SemigroupAny).exist expect(Boolean.MonoidAny).exist + expect(Boolean.all).exist + expect(Boolean.any).exist }) it("isBoolean", () => { From 3c256fa8b9bbb4379ad51c5e48781deaaac2990a Mon Sep 17 00:00:00 2001 From: Michael Arnaldi Date: Sat, 21 Jan 2023 10:41:18 +0000 Subject: [PATCH 079/255] Add tracing code for Option --- .changeset/red-moons-hope.md | 5 +++++ src/internal/Option.ts | 17 ++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 .changeset/red-moons-hope.md diff --git a/.changeset/red-moons-hope.md b/.changeset/red-moons-hope.md new file mode 100644 index 000000000..142e4bf1b --- /dev/null +++ b/.changeset/red-moons-hope.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Add tracking code for Option diff --git a/src/internal/Option.ts b/src/internal/Option.ts index c3a101ea6..d5d85202c 100644 --- a/src/internal/Option.ts +++ b/src/internal/Option.ts @@ -6,9 +6,11 @@ import type { None, Option, Some } from "@fp-ts/core/Option" /** @internal */ export const isOption = (u: unknown): u is Option => - typeof u === "object" && u != null && "_tag" in u && + typeof u === "object" && u != null && structural in u && "_tag" in u && (u["_tag"] === "None" || u["_tag"] === "Some") +const structural = Symbol.for("@effect/data/Equal/structural") + /** @internal */ export const isNone = (fa: Option): fa is None => fa._tag === "None" @@ -16,10 +18,19 @@ export const isNone = (fa: Option): fa is None => fa._tag === "None" export const isSome = (fa: Option): fa is Some => fa._tag === "Some" /** @internal */ -export const none: Option = { _tag: "None" } +export const none: Option = Object.defineProperty( + { _tag: "None" }, + structural, + { enumerable: false, value: true } +) /** @internal */ -export const some = (a: A): Option => ({ _tag: "Some", value: a }) +export const some = (a: A): Option => + Object.defineProperty( + { _tag: "Some", value: a }, + structural, + { enumerable: false, value: true } + ) /** @internal */ export const fromNullable = ( From 1ef02f813c07e7f56346fb00125afff0b01c8e20 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 21 Jan 2023 12:28:14 +0100 Subject: [PATCH 080/255] fix dtslint --- dtslint/ts4.7/SemiAlternative.ts | 2 +- dtslint/ts4.7/tsconfig.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dtslint/ts4.7/SemiAlternative.ts b/dtslint/ts4.7/SemiAlternative.ts index e59f824d0..6d6024319 100644 --- a/dtslint/ts4.7/SemiAlternative.ts +++ b/dtslint/ts4.7/SemiAlternative.ts @@ -16,4 +16,4 @@ declare const fb: RAW<{ b: number }, number, "fb"> declare const SemiAlternative: _.SemiAlternative // $ExpectType RAW<{ a: string; } & { b: number; }, string | number, "fa" | "fb"> -pipe(fa, SemiAlternative.coproduct(fb)) +SemiAlternative.coproduct(fa, fb) diff --git a/dtslint/ts4.7/tsconfig.json b/dtslint/ts4.7/tsconfig.json index 0696bacfb..cc38df3bd 100644 --- a/dtslint/ts4.7/tsconfig.json +++ b/dtslint/ts4.7/tsconfig.json @@ -11,8 +11,8 @@ "noUnusedParameters": false, "noFallthroughCasesInSwitch": true, "moduleResolution": "node", - "target": "es2015", - "lib": ["es2015"], + "target": "ES2021", + "lib": ["ES2021"], "paths": { "@fp-ts/core": ["../../src/index.ts"], "@fp-ts/core/test/*": ["../../test/*"], From 0faff78ae3d713de61b06c9ba9cd30531fcbbf89 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 21 Jan 2023 12:39:06 +0100 Subject: [PATCH 081/255] Spread structural-tracking across all data types --- src/These.ts | 21 ++++++++++----------- src/internal/Either.ts | 9 ++++++--- src/internal/Option.ts | 18 ++++++------------ src/internal/effect.ts | 6 ++++++ 4 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 src/internal/effect.ts diff --git a/src/These.ts b/src/These.ts index f7569d8b0..678d747da 100644 --- a/src/These.ts +++ b/src/These.ts @@ -19,6 +19,7 @@ import type { Either, Left, Right } from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" +import { structural } from "@fp-ts/core/internal/effect" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" import type { Option } from "@fp-ts/core/Option" @@ -87,13 +88,13 @@ export interface ValidatedTypeLambda extends TypeLambda { * @category constructors * @since 1.0.0 */ -export const left = (left: E): These => ({ _tag: "Left", left }) +export const left: (left: E) => These = either.left /** * @category constructors * @since 1.0.0 */ -export const right = (right: A): These => ({ _tag: "Right", right }) +export const right: (right: A) => These = either.right /** * Alias of `right`. @@ -107,11 +108,11 @@ export const of = right * @category constructors * @since 1.0.0 */ -export const both = (left: E, right: A): These => ({ - _tag: "Both", - left, - right -}) +export const both = (left: E, right: A): These => + Object.defineProperty({ _tag: "Both", left, right }, structural, { + enumerable: false, + value: true + }) /** * @category constructors @@ -222,10 +223,8 @@ export const isBoth = (self: These): self is Both => self._tag * @since 1.0.0 */ export const isThese = (u: unknown): u is These => - typeof u === "object" && - u != null && "_tag" in u && - (u["_tag"] === "Left" || u["_tag"] === "Right" || - u["_tag"] === "Both") + typeof u === "object" && u != null && structural in u && "_tag" in u && + (u["_tag"] === "Left" || u["_tag"] === "Right" || u["_tag"] === "Both") /** * Constructs a new `These` from a function that might throw. diff --git a/src/internal/Either.ts b/src/internal/Either.ts index fbc5bce28..61d472503 100644 --- a/src/internal/Either.ts +++ b/src/internal/Either.ts @@ -4,12 +4,13 @@ import type { Either, Left, Right } from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" +import { structural } from "@fp-ts/core/internal/effect" import * as option from "@fp-ts/core/internal/Option" import type { Option } from "@fp-ts/core/Option" /** @internal */ export const isEither = (u: unknown): u is Either => - typeof u === "object" && u != null && "_tag" in u && + typeof u === "object" && u != null && structural in u && "_tag" in u && (u["_tag"] === "Left" || u["_tag"] === "Right") /** @internal */ @@ -19,10 +20,12 @@ export const isLeft = (ma: Either): ma is Left => ma._tag === "Le export const isRight = (ma: Either): ma is Right => ma._tag === "Right" /** @internal */ -export const left = (e: E): Either => ({ _tag: "Left", left: e }) +export const left = (e: E): Either => + Object.defineProperty({ _tag: "Left", left: e }, structural, { enumerable: false, value: true }) /** @internal */ -export const right = (a: A): Either => ({ _tag: "Right", right: a }) +export const right = (a: A): Either => + Object.defineProperty({ _tag: "Right", right: a }, structural, { enumerable: false, value: true }) /** @internal */ export const getLeft = ( diff --git a/src/internal/Option.ts b/src/internal/Option.ts index d5d85202c..433decce3 100644 --- a/src/internal/Option.ts +++ b/src/internal/Option.ts @@ -2,6 +2,7 @@ * @since 1.0.0 */ +import { structural } from "@fp-ts/core/internal/effect" import type { None, Option, Some } from "@fp-ts/core/Option" /** @internal */ @@ -9,8 +10,6 @@ export const isOption = (u: unknown): u is Option => typeof u === "object" && u != null && structural in u && "_tag" in u && (u["_tag"] === "None" || u["_tag"] === "Some") -const structural = Symbol.for("@effect/data/Equal/structural") - /** @internal */ export const isNone = (fa: Option): fa is None => fa._tag === "None" @@ -18,19 +17,14 @@ export const isNone = (fa: Option): fa is None => fa._tag === "None" export const isSome = (fa: Option): fa is Some => fa._tag === "Some" /** @internal */ -export const none: Option = Object.defineProperty( - { _tag: "None" }, - structural, - { enumerable: false, value: true } -) +export const none: Option = Object.defineProperty({ _tag: "None" }, structural, { + enumerable: false, + value: true +}) /** @internal */ export const some = (a: A): Option => - Object.defineProperty( - { _tag: "Some", value: a }, - structural, - { enumerable: false, value: true } - ) + Object.defineProperty({ _tag: "Some", value: a }, structural, { enumerable: false, value: true }) /** @internal */ export const fromNullable = ( diff --git a/src/internal/effect.ts b/src/internal/effect.ts new file mode 100644 index 000000000..0e6da6670 --- /dev/null +++ b/src/internal/effect.ts @@ -0,0 +1,6 @@ +/** + * @since 1.0.0 + */ + +/** @internal */ +export const structural = Symbol.for("@effect/data/Equal/structural") From 3cb63b8082154a32d491d0625f2e34f773138177 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 21 Jan 2023 16:50:39 +0100 Subject: [PATCH 082/255] Bigint: add divide --- src/Bigint.ts | 7 ++++++- test/Bigint.ts | 15 ++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Bigint.ts b/src/Bigint.ts index 6248af689..c6b878dd8 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -33,7 +33,12 @@ export const multiply = (that: bigint) => /** * @since 1.0.0 */ -export const sub = (that: bigint) => (self: bigint): bigint => self - that +export const subtract = (that: bigint) => (self: bigint): bigint => self - that + +/** + * @since 1.0.0 + */ +export const divide = (that: bigint) => (self: bigint): bigint => self / that /** * @since 1.0.0 diff --git a/test/Bigint.ts b/test/Bigint.ts index 94468621e..4f0661ffd 100644 --- a/test/Bigint.ts +++ b/test/Bigint.ts @@ -1,4 +1,5 @@ import * as Bigint from "@fp-ts/core/Bigint" +import { pipe } from "@fp-ts/core/Function" import { deepStrictEqual } from "@fp-ts/core/test/util" describe.concurrent("Bigint", () => { @@ -10,15 +11,19 @@ describe.concurrent("Bigint", () => { }) it("sum", () => { - deepStrictEqual(Bigint.sum(1n)(2n), 3n) + deepStrictEqual(pipe(1n, Bigint.sum(2n)), 3n) }) - it("sub", () => { - deepStrictEqual(Bigint.sub(1n)(2n), 1n) + it("multiply", () => { + deepStrictEqual(pipe(2n, Bigint.multiply(3n)), 6n) }) - it("multiply", () => { - deepStrictEqual(Bigint.multiply(3n)(2n), 6n) + it("subtract", () => { + deepStrictEqual(pipe(3n, Bigint.subtract(1n)), 2n) + }) + + it("divide", () => { + deepStrictEqual(pipe(6n, Bigint.divide(2n)), 3n) }) it("increment", () => { From 0851fdc142fae6c3a77c37aa4eb822fb1b8c1eee Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 23 Jan 2023 06:16:28 +0100 Subject: [PATCH 083/255] chore --- Either.md | 10 +++++----- Option.md | 10 +++++----- README.md | 4 +++- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Either.md b/Either.md index 1b1bf3953..26c6ea543 100644 --- a/Either.md +++ b/Either.md @@ -7,7 +7,7 @@ The `Left` variant is used to represent a failure, and it can contain useful inf Unlike the `Option` type, `Either` allows you to attach additional information to the failure case, making it more informative. In this usage, `None` is replaced with a `Left` which can contain useful information. `Right` takes the place of `Some`. -## Definition +# Definition The `Either` data type is the union of two members: `Left` and `Right`. The way chosen by the `@fp-ts/core` library to model this union in TypeScript is to use a feature of the language called [Discriminating Unions](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions): @@ -29,7 +29,7 @@ export type Right = { export type Either = Left | Right; ``` -## Using `Either` +# Using `Either` To create an instance of `Either`, you can use the `right` and `left` constructors, which construct a new `Either` holding a `Right` or `Left` value respectively. @@ -59,7 +59,7 @@ const failure: Either = pipe( The `fromOption` function requires an argument because it needs to know what value to use for the `Left` variant of the `Either` type when given a `None`. In the example, the argument "error message" is used as the value for the `Left` variant when `None` is encountered. This allows `Either` to provide more information about why a failure occurred. -## Working with `Either` +# Working with `Either` Once you have an instance of `Either`, you can use the various functions provided in the `@fp-ts/core/Either` module to work with it. @@ -80,7 +80,7 @@ const failure: Either = pipe( ); // left("error message!") ``` -## Handling failing computations +# Handling failing computations Let's see how to use the `Either` data type to model a computation that can fail, such as a function that can throw an exception based on certain conditions. Let's take the case of the following function: @@ -113,7 +113,7 @@ console.log(parseNumber("2")); // right(2) console.log(parseNumber("Not a number")); // left("Cannot parse 'Not a number' as a number") ``` -## Pattern matching +# Pattern matching The `match` function allows us to match on the `Left` and `Right` cases of an `Either` value and provide different actions for each. diff --git a/Option.md b/Option.md index 02086f9cf..e03e6303c 100644 --- a/Option.md +++ b/Option.md @@ -11,7 +11,7 @@ In the first of these two interpretations, the `None` union member represents th In the second of these two interpretations, the `None` union member represents the absence of the value, while the `Some` union member represents the presence of the value of type `A` -## Definition +# Definition The `Option` data type is the union of two members: `None` and `Some`. The way chosen by the `@fp-ts/core` library to model this union in TypeScript is to use a feature of the language called [Discriminating Unions](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions): @@ -32,7 +32,7 @@ export type Some = { export type Option = None | Some; ``` -## Using `Option` +# Using `Option` To create an instance of `Option`, you can use the `some` and `none` constructors, which construct a new `Option` holding a `Some` or `None` value respectively. @@ -43,7 +43,7 @@ const success: Option = some(1); const failure: Option = none(); ``` -## Working with `Option` +# Working with `Option` Once you have an instance of `Option`, you can use the various functions provided in the `@fp-ts/core/Option` module to work with it. @@ -59,7 +59,7 @@ const success: Option = pipe( ); // some(2) ``` -## Handling failing computations +# Handling failing computations Let's see how to use the `Option` data type to model a computation that can fail, such as a function that can throw an exception based on certain conditions. Let's take the case of the following function: @@ -92,7 +92,7 @@ console.log(parseNumber("2")); // some(2) console.log(parseNumber("Not a number")); // none() ``` -## Pattern matching +# Pattern matching The `match` function allows us to match on the `None` and `Some` cases of an `Option` value and provide different actions for each. diff --git a/README.md b/README.md index 3de06454e..0a1ed1e53 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ For those using [`fp-ts`](https://github.com/gcanti/fp-ts) v2 and its ecosystem, - [`io-ts`](https://github.com/gcanti/io-ts) -> [`@fp-ts/schema`](https://github.com/fp-ts/schema) - [`monocle-ts`](https://github.com/gcanti/monocle-ts) -> [`@fp-ts/optic`](https://github.com/fp-ts/optic) -Note that `@fp-ts/core` will not contain any effect system (e.g. `Task`, `TaskEither`, `ReaderTaskEither`) since the handling of effects is entirely delegated to the packages contained in [`@effect/*`](https://github.com/Effect-TS)." +Note that `@fp-ts/core` will not contain any effect system (e.g. `Task`, `TaskEither`, `ReaderTaskEither`) since the handling of effects is entirely delegated to the packages contained in [`@effect/*`](https://github.com/Effect-TS). # Installation @@ -48,6 +48,8 @@ npm install @fp-ts/core - [Typeclass overview](./typeclass.md) - [Data overview](./data.md) +- [The `Option` data type](./Option.md) +- [The `Either` data type](./Either.md) - [API Reference](https://fp-ts.github.io/core/) # License From 08f56889c1ec58c4d8085835c5d98edcbb26e847 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 23 Jan 2023 14:21:04 +0100 Subject: [PATCH 084/255] Predicate: optimise getSemigroupAny, getSemigroupAll --- src/Predicate.ts | 36 +++++++++++++++++++++++++++++++----- test/Predicate.ts | 24 ++++++++++++++++-------- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/src/Predicate.ts b/src/Predicate.ts index 42ae6c8ae..ee5cb5287 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -9,7 +9,7 @@ import * as invariant from "@fp-ts/core/typeclass/Invariant" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as of_ from "@fp-ts/core/typeclass/Of" import * as product_ from "@fp-ts/core/typeclass/Product" -import * as semigroup from "@fp-ts/core/typeclass/Semigroup" +import type * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** @@ -261,8 +261,21 @@ export const and = (that: Predicate) => * @category instances * @since 1.0.0 */ -export const getSemigroupAny = (): semigroup.Semigroup> => - semigroup.fromCombine((self, that) => pipe(self, or(that))) +export const getSemigroupAny = (): semigroup.Semigroup> => ({ + combine: (self, that) => pipe(self, or(that)), + combineMany: (self, collection) => + a => { + if (self(a)) { + return true + } + for (const p of collection) { + if (p(a)) { + return true + } + } + return false + } +}) /** * @category instances @@ -275,8 +288,21 @@ export const getMonoidAny = (): monoid.Monoid> => * @category instances * @since 1.0.0 */ -export const getSemigroupAll = (): semigroup.Semigroup> => - semigroup.fromCombine((self, that) => pipe(self, and(that))) +export const getSemigroupAll = (): semigroup.Semigroup> => ({ + combine: (self, that) => pipe(self, and(that)), + combineMany: (self, collection) => + a => { + if (!self(a)) { + return false + } + for (const p of collection) { + if (!p(a)) { + return false + } + } + return true + } +}) /** * @category instances diff --git a/test/Predicate.ts b/test/Predicate.ts index 5825f3879..39c2325d7 100644 --- a/test/Predicate.ts +++ b/test/Predicate.ts @@ -115,10 +115,14 @@ describe.concurrent("Predicate", () => { it("getSemigroupAny", () => { const S = _.getSemigroupAny() - const predicate = S.combine(isPositive, isNegative) - deepStrictEqual(predicate(0), false) - deepStrictEqual(predicate(-1), true) - deepStrictEqual(predicate(1), true) + const p1 = S.combine(isPositive, isNegative) + deepStrictEqual(p1(0), false) + deepStrictEqual(p1(-1), true) + deepStrictEqual(p1(1), true) + const p2 = S.combineMany(isPositive, [isNegative]) + deepStrictEqual(p2(0), false) + deepStrictEqual(p2(-1), true) + deepStrictEqual(p2(1), true) }) it("getMonoidAny", () => { @@ -131,10 +135,14 @@ describe.concurrent("Predicate", () => { it("getSemigroupAll", () => { const S = _.getSemigroupAll() - const predicate = S.combine(isPositive, isLessThan2) - deepStrictEqual(predicate(0), false) - deepStrictEqual(predicate(-2), false) - deepStrictEqual(predicate(1), true) + const p1 = S.combine(isPositive, isLessThan2) + deepStrictEqual(p1(0), false) + deepStrictEqual(p1(-2), false) + deepStrictEqual(p1(1), true) + const p2 = S.combineMany(isPositive, [isLessThan2]) + deepStrictEqual(p2(0), false) + deepStrictEqual(p2(-2), false) + deepStrictEqual(p2(1), true) }) it("getMonoidAll", () => { From 3959adfa020153b0a3ef36d1ef0222c3561eb76a Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 23 Jan 2023 18:25:46 +0100 Subject: [PATCH 085/255] rename size to length --- src/Number.ts | 2 +- src/ReadonlyArray.ts | 2 +- src/String.ts | 14 ++++++++++---- test/Either.ts | 6 +++--- test/Function.ts | 18 +++++++++--------- test/ReadonlyArray.ts | 8 ++++---- test/String.ts | 14 +++++++++----- test/These.ts | 8 ++++---- 8 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/Number.ts b/src/Number.ts index c67370659..df58f654e 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -144,4 +144,4 @@ export const MonoidMin = bounded.min(Bounded) /** * @since 1.0.0 */ -export const sign = (n: number): Ordering => (n < 0 ? -1 : n > 0 ? 1 : 0) +export const sign = (n: number): Ordering => n < 0 ? -1 : n > 0 ? 1 : 0 diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 7a41e7939..3798937c7 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -270,7 +270,7 @@ export const isNonEmpty: (self: ReadonlyArray) => self is NonEmptyReadonly * @category getters * @since 1.0.0 */ -export const size = (self: ReadonlyArray): number => self.length +export const length = (self: ReadonlyArray): number => self.length const isOutOfBound = (i: number, as: ReadonlyArray): boolean => i < 0 || i >= as.length diff --git a/src/String.ts b/src/String.ts index 0a3a89b21..2c78d4c63 100644 --- a/src/String.ts +++ b/src/String.ts @@ -59,8 +59,7 @@ export const empty: "" = "" as const /** * @since 1.0.0 */ -export const concat = (that: string) => - (self: string): string => semigroup.string.combine(self, that) +export const concat = (that: string) => (self: string): string => Semigroup.combine(self, that) /** * @example @@ -154,6 +153,13 @@ export const slice = (start: number, end: number) => (s: string): string => s.sl */ export const isEmpty = (s: string): s is "" => s.length === 0 +/** + * Test whether a `string` is non empty. + * + * @since 1.0.0 + */ +export const isNonEmpty = (s: string): boolean => s.length > 0 + /** * Calculate the number of characters in a `string`. * @@ -161,11 +167,11 @@ export const isEmpty = (s: string): s is "" => s.length === 0 * import * as S from '@fp-ts/core/String' * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe('abc', S.size), 3) + * assert.deepStrictEqual(pipe('abc', S.length), 3) * * @since 1.0.0 */ -export const size = (s: string): number => s.length +export const length = (s: string): number => s.length /** * @example diff --git a/test/Either.ts b/test/Either.ts index 8dd940be3..42a2de8b5 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -193,19 +193,19 @@ describe.concurrent("Either", () => { }) it("map", () => { - const f = _.map(String.size) + const f = _.map(String.length) deepStrictEqual(pipe(_.right("abc"), f), _.right(3)) deepStrictEqual(pipe(_.left("s"), f), _.left("s")) }) it("flatMap", () => { - const f = _.flatMap(flow(String.size, _.right)) + const f = _.flatMap(flow(String.length, _.right)) deepStrictEqual(pipe(_.right("abc"), f), _.right(3)) deepStrictEqual(pipe(_.left("maError"), f), _.left("maError")) }) it("bimap", () => { - const f = _.bimap(String.size, (n: number) => n > 2) + const f = _.bimap(String.length, (n: number) => n > 2) deepStrictEqual(pipe(_.right(1), f), _.right(false)) }) diff --git a/test/Function.ts b/test/Function.ts index 969d19b27..24a9a251a 100644 --- a/test/Function.ts +++ b/test/Function.ts @@ -1,37 +1,37 @@ import * as Function from "@fp-ts/core/Function" import * as Number from "@fp-ts/core/Number" +import * as String from "@fp-ts/core/String" import { deepStrictEqual, double } from "@fp-ts/core/test/util" import * as assert from "assert" const f = (n: number): number => n + 1 const g = double -const size = (s: string): number => s.length describe.concurrent("Function", () => { it("getSemigroup", () => { const S = Function.getSemigroup(Number.SemigroupSum)() const f = (s: string) => s === "a" ? 0 : 1 - const g = S.combine(size, f) + const g = S.combine(String.length, f) deepStrictEqual(g(""), 1) deepStrictEqual(g("a"), 1) deepStrictEqual(g("b"), 2) - deepStrictEqual(S.combineMany(size, [size, size])("a"), 3) + deepStrictEqual(S.combineMany(String.length, [String.length, String.length])("a"), 3) }) it("getMonoid", () => { const M = Function.getMonoid(Number.MonoidSum)() const f = (s: string) => s === "a" ? 0 : 1 - const g = M.combine(size, f) + const g = M.combine(String.length, f) deepStrictEqual(g(""), 1) deepStrictEqual(g("a"), 1) deepStrictEqual(g("b"), 2) - deepStrictEqual(M.combine(size, M.empty)("a"), 1) - deepStrictEqual(M.combine(M.empty, size)("a"), 1) - deepStrictEqual(M.combineAll([size, size])("a"), 2) + deepStrictEqual(M.combine(String.length, M.empty)("a"), 1) + deepStrictEqual(M.combine(M.empty, String.length)("a"), 1) + deepStrictEqual(M.combineAll([String.length, String.length])("a"), 2) }) it("apply", () => { - deepStrictEqual(Function.apply("a")(size), 1) + deepStrictEqual(Function.apply("a")(String.length), 1) }) it("flip", () => { @@ -40,7 +40,7 @@ describe.concurrent("Function", () => { }) it("compose", () => { - deepStrictEqual(Function.pipe(size, Function.compose(double))("aaa"), 6) + deepStrictEqual(Function.pipe(String.length, Function.compose(double))("aaa"), 6) }) it("unsafeCoerce", () => { diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 366631809..bf717f723 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -1584,10 +1584,10 @@ describe.concurrent("ReadonlyArray", () => { deepStrictEqual(pipe([-1, -2, -3], RA.some(isPositive)), false) }) - it("size", () => { - deepStrictEqual(RA.size(RA.empty()), 0) - deepStrictEqual(RA.size([]), 0) - deepStrictEqual(RA.size(["a"]), 1) + it("length", () => { + deepStrictEqual(RA.length(RA.empty()), 0) + deepStrictEqual(RA.length([]), 0) + deepStrictEqual(RA.length(["a"]), 1) }) it("fromOption", () => { diff --git a/test/String.ts b/test/String.ts index db96267c7..0eb2bed73 100644 --- a/test/String.ts +++ b/test/String.ts @@ -44,15 +44,19 @@ describe.concurrent("String", () => { }) it("isEmpty", () => { - deepStrictEqual(String.isEmpty(String.empty), true) deepStrictEqual(String.isEmpty(""), true) deepStrictEqual(String.isEmpty("a"), false) }) - it("size", () => { - deepStrictEqual(String.size(String.empty), 0) - deepStrictEqual(String.size(""), 0) - deepStrictEqual(String.size("a"), 1) + it("isNonEmpty", () => { + deepStrictEqual(String.isNonEmpty(""), false) + deepStrictEqual(String.isNonEmpty("a"), true) + }) + + it("length", () => { + deepStrictEqual(String.length(""), 0) + deepStrictEqual(String.length("a"), 1) + deepStrictEqual(String.length("aaa"), 3) }) it("toUpperCase", () => { diff --git a/test/These.ts b/test/These.ts index 66bb5b609..1dc85baa4 100644 --- a/test/These.ts +++ b/test/These.ts @@ -91,14 +91,14 @@ describe("These", () => { }) it("bimap", () => { - const f = _.bimap(S.size, U.double) + const f = _.bimap(S.length, U.double) U.deepStrictEqual(pipe(_.left("e"), f), _.left(1)) U.deepStrictEqual(pipe(_.right(2), f), _.right(4)) U.deepStrictEqual(pipe(_.both("eee", 1), f), _.both(3, 2)) }) it("mapLeft", () => { - const f = _.mapLeft(S.size) + const f = _.mapLeft(S.length) U.deepStrictEqual(pipe(_.left("e"), f), _.left(1)) U.deepStrictEqual(pipe(_.right(2), f), _.right(2)) U.deepStrictEqual(pipe(_.both("eee", 1), f), _.both(3, 1)) @@ -411,8 +411,8 @@ describe("These", () => { }) it("match", () => { - const f = (s: string, n: number) => S.size(s) + U.double(n) - const match = _.match(S.size, U.double, f) + const f = (s: string, n: number) => S.length(s) + U.double(n) + const match = _.match(S.length, U.double, f) U.deepStrictEqual(match(_.left("foo")), 3) U.deepStrictEqual(match(_.right(1)), 2) U.deepStrictEqual(match(_.both("foo", 1)), 5) From f859ba5ff07559fe0d48d4aea89e89cd1c52477c Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 23 Jan 2023 18:33:26 +0100 Subject: [PATCH 086/255] String: rename trimLeft, trimRight --- src/Number.ts | 11 +++++++++++ src/String.ts | 32 ++++++++++++++++++++++++++++---- src/Tuple.ts | 2 +- test/String.ts | 8 ++++---- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/Number.ts b/src/Number.ts index df58f654e..b1568fea2 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -145,3 +145,14 @@ export const MonoidMin = bounded.min(Bounded) * @since 1.0.0 */ export const sign = (n: number): Ordering => n < 0 ? -1 : n > 0 ? 1 : 0 + +/* + + Missing: + + - toFixed + - toPrecision + - toExponential + - toLocaleString + +*/ diff --git a/src/String.ts b/src/String.ts index 2c78d4c63..ce49115e1 100644 --- a/src/String.ts +++ b/src/String.ts @@ -111,22 +111,22 @@ export const trim = (s: string): string => s.trim() * import * as S from '@fp-ts/core/String' * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(' a ', S.trimLeft), 'a ') + * assert.deepStrictEqual(pipe(' a ', S.trimStart), 'a ') * * @since 1.0.0 */ -export const trimLeft = (s: string): string => s.trimLeft() +export const trimStart = (s: string): string => s.trimStart() /** * @example * import * as S from '@fp-ts/core/String' * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(' a ', S.trimRight), ' a') + * assert.deepStrictEqual(pipe(' a ', S.trimEnd), ' a') * * @since 1.0.0 */ -export const trimRight = (s: string): string => s.trimRight() +export const trimEnd = (s: string): string => s.trimEnd() /** * @example @@ -257,6 +257,30 @@ export const takeLeft = (n: number) => (self: string): string => self.slice(0, M export const takeRight = (n: number) => (s: string): string => s.slice(Math.max(0, s.length - Math.floor(n)), Infinity) +/* + + Missing: + + - charCodeAt + - substring + - at + - charAt + - codePointAt + - indexOf + - lastIndexOf + - localeCompare + - match + - matchAll + - normalize + - padEnd + - padStart + - repeat + - replaceAll + - search + - toLocaleLowerCase + - toLocaleUpperCase +*/ + // TODO: 100% coverage tests (ask Max) // const CR = 0x0d // const LF = 0x0a diff --git a/src/Tuple.ts b/src/Tuple.ts index 6b072345c..d2d20992b 100644 --- a/src/Tuple.ts +++ b/src/Tuple.ts @@ -18,7 +18,7 @@ import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" export const tuple = >(...elements: A): A => elements /** - * Adds an element to the end of a tuple. + * Appends an element to the end of a tuple. * * @since 1.0.0 */ diff --git a/test/String.ts b/test/String.ts index 0eb2bed73..76c514f5a 100644 --- a/test/String.ts +++ b/test/String.ts @@ -80,12 +80,12 @@ describe.concurrent("String", () => { deepStrictEqual(pipe(" a ", String.trim), "a") }) - it("trimLeft", () => { - deepStrictEqual(pipe(" a ", String.trimLeft), "a ") + it("trimStart", () => { + deepStrictEqual(pipe(" a ", String.trimStart), "a ") }) - it("trimRight", () => { - deepStrictEqual(pipe(" a ", String.trimRight), " a") + it("trimEnd", () => { + deepStrictEqual(pipe(" a ", String.trimEnd), " a") }) it("includes", () => { From 515418940c919b3dce41d70c9e95d2d0626cd279 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 23 Jan 2023 19:05:41 +0100 Subject: [PATCH 087/255] downgrade docs-ts --- docs-ts.json | 12 +----------- package.json | 2 +- pnpm-lock.yaml | 9 +++++---- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/docs-ts.json b/docs-ts.json index 3530339f7..ba45ceaea 100644 --- a/docs-ts.json +++ b/docs-ts.json @@ -1,14 +1,4 @@ { "exclude": ["src/internal/**/*.ts"], - "theme": "mikearnaldi/just-the-docs", - "compilerOptions": { - "noEmit": true, - "strict": true, - "paths": { - "@fp-ts/core": ["./src/index.ts"], - "@fp-ts/core/test/*": ["./test/*"], - "@fp-ts/core/examples/*": ["./examples/*"], - "@fp-ts/core/*": ["./src/*"] - } - } + "theme": "mikearnaldi/just-the-docs" } diff --git a/package.json b/package.json index c8f97183b..f4bbebe05 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "c8": "^7.11.3", "concurrently": "^7.6.0", "cpx": "^1.5.0", - "docs-ts": "^0.7.0", + "docs-ts": "0.6.10", "dtslint": "github:gcanti/dtslint", "eslint": "^8.28.0", "eslint-import-resolver-typescript": "^3.5.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b1ddf22e..25ec441ac 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -33,7 +33,7 @@ importers: c8: ^7.11.3 concurrently: ^7.6.0 cpx: ^1.5.0 - docs-ts: ^0.7.0 + docs-ts: 0.6.10 dtslint: github:gcanti/dtslint eslint: ^8.28.0 eslint-import-resolver-typescript: ^3.5.2 @@ -76,7 +76,7 @@ importers: c8: 7.12.0 concurrently: 7.6.0 cpx: 1.5.0 - docs-ts: 0.7.0_brpckf4sz23pco3jyty2eys3iq + docs-ts: 0.6.10_pulkjstupuiumlrt7ngjhrpf2e_brpckf4sz23pco3jyty2eys3iq dtslint: github.com/gcanti/dtslint/4552d162099399c4e14f8486ced673411e5b3659 eslint: 8.28.0 eslint-import-resolver-typescript: 3.5.2_ktrec6dplf4now6nlbc6d67jee @@ -2381,8 +2381,8 @@ packages: dev: true patched: true - /docs-ts/0.7.0_brpckf4sz23pco3jyty2eys3iq: - resolution: {integrity: sha512-S9UM7Ddh0l3qwftSJiko+3+aGJrnGTnigKq4wpsOvQBmMJz7kMmdAeiTwNCRgzQI70oT3T2uyuzR9hy5JT2xPQ==} + /docs-ts/0.6.10_pulkjstupuiumlrt7ngjhrpf2e_brpckf4sz23pco3jyty2eys3iq: + resolution: {integrity: sha512-DTX9c5AJ92ojMOKqqvwF8t77C8Gdgs9FPB8seymHs+F+Wl6aapc3ZkHUM+p8o+jwcBmPoihxssdK903dfwQ1JQ==} hasBin: true peerDependencies: prettier: ^2.0.0 @@ -2402,6 +2402,7 @@ packages: ts-node: 8.10.2_typescript@4.9.3 typescript: 4.9.3 dev: true + patched: true /doctrine/2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} From 88f30ce2a34bc47533a267ab57031021cfeb6555 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 23 Jan 2023 19:19:22 +0100 Subject: [PATCH 088/255] update docs --- docs/modules/Bigint.ts.md | 184 ++ docs/modules/Boolean.ts.md | 236 ++ docs/modules/Either.ts.md | 1420 ++++++++++ docs/modules/Function.ts.md | 701 +++++ docs/modules/HKT.ts.md | 2 +- docs/modules/Identity.ts.md | 702 +++++ docs/modules/Number.ts.md | 268 ++ docs/modules/Option.ts.md | 1520 ++++++++++ docs/modules/Ordering.ts.md | 87 + docs/modules/Predicate.ts.md | 443 +++ docs/modules/ReadonlyArray.ts.md | 2438 +++++++++++++++++ docs/modules/ReadonlyRecord.ts.md | 78 + docs/modules/String.ts.md | 434 +++ docs/modules/Struct.ts.md | 117 + docs/modules/Symbol.ts.md | 30 + docs/modules/These.ts.md | 1517 ++++++++++ docs/modules/Tuple.ts.md | 116 + docs/modules/index.ts.md | 275 +- docs/modules/typeclass/Alternative.ts.md | 2 +- docs/modules/typeclass/Applicative.ts.md | 6 +- docs/modules/typeclass/Bicovariant.ts.md | 21 +- docs/modules/typeclass/Bounded.ts.md | 45 +- docs/modules/typeclass/Chainable.ts.md | 22 +- docs/modules/typeclass/Compactable.ts.md | 64 + docs/modules/typeclass/Contravariant.ts.md | 18 +- docs/modules/typeclass/Coproduct.ts.md | 4 +- docs/modules/typeclass/Covariant.ts.md | 37 +- docs/modules/typeclass/Equivalence.ts.md | 268 ++ docs/modules/typeclass/Filterable.ts.md | 98 + docs/modules/typeclass/FlatMap.ts.md | 20 +- docs/modules/typeclass/Foldable.ts.md | 49 +- docs/modules/typeclass/Invariant.ts.md | 21 +- docs/modules/typeclass/Monad.ts.md | 2 +- docs/modules/typeclass/Monoid.ts.md | 188 +- .../typeclass/NonEmptyTraversable.ts.md | 112 - docs/modules/typeclass/Of.ts.md | 11 +- docs/modules/typeclass/Order.ts.md | 128 +- docs/modules/typeclass/Pointed.ts.md | 2 +- docs/modules/typeclass/Product.ts.md | 28 +- docs/modules/typeclass/SemiAlternative.ts.md | 2 +- docs/modules/typeclass/SemiApplicative.ts.md | 43 +- docs/modules/typeclass/SemiCoproduct.ts.md | 14 +- docs/modules/typeclass/SemiProduct.ts.md | 102 +- docs/modules/typeclass/Semigroup.ts.md | 206 +- docs/modules/typeclass/Traversable.ts.md | 44 +- .../typeclass/TraversableFilterable.ts.md | 107 + src/Boolean.ts | 10 +- src/Either.ts | 4 +- src/Function.ts | 16 +- src/Number.ts | 4 +- src/Option.ts | 58 +- 51 files changed, 11732 insertions(+), 592 deletions(-) create mode 100644 docs/modules/Bigint.ts.md create mode 100644 docs/modules/Boolean.ts.md create mode 100644 docs/modules/Either.ts.md create mode 100644 docs/modules/Function.ts.md create mode 100644 docs/modules/Identity.ts.md create mode 100644 docs/modules/Number.ts.md create mode 100644 docs/modules/Option.ts.md create mode 100644 docs/modules/Ordering.ts.md create mode 100644 docs/modules/Predicate.ts.md create mode 100644 docs/modules/ReadonlyArray.ts.md create mode 100644 docs/modules/ReadonlyRecord.ts.md create mode 100644 docs/modules/String.ts.md create mode 100644 docs/modules/Struct.ts.md create mode 100644 docs/modules/Symbol.ts.md create mode 100644 docs/modules/These.ts.md create mode 100644 docs/modules/Tuple.ts.md create mode 100644 docs/modules/typeclass/Compactable.ts.md create mode 100644 docs/modules/typeclass/Equivalence.ts.md create mode 100644 docs/modules/typeclass/Filterable.ts.md delete mode 100644 docs/modules/typeclass/NonEmptyTraversable.ts.md create mode 100644 docs/modules/typeclass/TraversableFilterable.ts.md diff --git a/docs/modules/Bigint.ts.md b/docs/modules/Bigint.ts.md new file mode 100644 index 000000000..ccb2493f7 --- /dev/null +++ b/docs/modules/Bigint.ts.md @@ -0,0 +1,184 @@ +--- +title: Bigint.ts +nav_order: 1 +parent: Modules +--- + +## Bigint overview + +This module provides utility functions and type class instances for working with the `bigint` type in TypeScript. +It includes functions for basic arithmetic operations, as well as type class instances for +`Equivalence`, `Order`, `Semigroup`, and `Monoid`. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [guards](#guards) + - [isBigint](#isbigint) +- [instances](#instances) + - [Equivalence](#equivalence) + - [MonoidMultiply](#monoidmultiply) + - [MonoidSum](#monoidsum) + - [Order](#order) + - [SemigroupMultiply](#semigroupmultiply) + - [SemigroupSum](#semigroupsum) +- [utils](#utils) + - [decrement](#decrement) + - [divide](#divide) + - [increment](#increment) + - [multiply](#multiply) + - [subtract](#subtract) + - [sum](#sum) + +--- + +# guards + +## isBigint + +**Signature** + +```ts +export declare const isBigint: (u: unknown) => u is bigint +``` + +Added in v1.0.0 + +# instances + +## Equivalence + +**Signature** + +```ts +export declare const Equivalence: any +``` + +Added in v1.0.0 + +## MonoidMultiply + +`bigint` monoid under multiplication. + +The `empty` value is `1n`. + +**Signature** + +```ts +export declare const MonoidMultiply: any +``` + +Added in v1.0.0 + +## MonoidSum + +`bigint` monoid under addition. + +The `empty` value is `0n`. + +**Signature** + +```ts +export declare const MonoidSum: any +``` + +Added in v1.0.0 + +## Order + +**Signature** + +```ts +export declare const Order: any +``` + +Added in v1.0.0 + +## SemigroupMultiply + +`bigint` semigroup under multiplication. + +**Signature** + +```ts +export declare const SemigroupMultiply: any +``` + +Added in v1.0.0 + +## SemigroupSum + +`bigint` semigroup under addition. + +**Signature** + +```ts +export declare const SemigroupSum: any +``` + +Added in v1.0.0 + +# utils + +## decrement + +**Signature** + +```ts +export declare const decrement: (n: bigint) => bigint +``` + +Added in v1.0.0 + +## divide + +**Signature** + +```ts +export declare const divide: (that: bigint) => (self: bigint) => bigint +``` + +Added in v1.0.0 + +## increment + +**Signature** + +```ts +export declare const increment: (n: bigint) => bigint +``` + +Added in v1.0.0 + +## multiply + +**Signature** + +```ts +export declare const multiply: (that: bigint) => (self: bigint) => bigint +``` + +Added in v1.0.0 + +## subtract + +**Signature** + +```ts +export declare const subtract: (that: bigint) => (self: bigint) => bigint +``` + +Added in v1.0.0 + +## sum + +**Signature** + +```ts +export declare const sum: (that: bigint) => (self: bigint) => bigint +``` + +Added in v1.0.0 diff --git a/docs/modules/Boolean.ts.md b/docs/modules/Boolean.ts.md new file mode 100644 index 000000000..e96a52d2c --- /dev/null +++ b/docs/modules/Boolean.ts.md @@ -0,0 +1,236 @@ +--- +title: Boolean.ts +nav_order: 2 +parent: Modules +--- + +## Boolean overview + +This module provides utility functions and type class instances for working with the `boolean` type in TypeScript. +It includes functions for basic boolean operations, as well as type class instances for +`Equivalence`, `Order`, `Semigroup`, and `Monoid`. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [combinators](#combinators) + - [and](#and) + - [not](#not) + - [or](#or) +- [guards](#guards) + - [isBoolean](#isboolean) +- [instances](#instances) + - [Equivalence](#equivalence) + - [MonoidAll](#monoidall) + - [MonoidAny](#monoidany) + - [Order](#order) + - [SemigroupAll](#semigroupall) + - [SemigroupAny](#semigroupany) +- [pattern matching](#pattern-matching) + - [match](#match) +- [utils](#utils) + - [all](#all) + - [any](#any) + +--- + +# combinators + +## and + +**Signature** + +```ts +export declare const and: (that: boolean) => (self: boolean) => boolean +``` + +Added in v1.0.0 + +## not + +**Signature** + +```ts +export declare const not: (self: boolean) => boolean +``` + +Added in v1.0.0 + +## or + +**Signature** + +```ts +export declare const or: (that: boolean) => (self: boolean) => boolean +``` + +Added in v1.0.0 + +# guards + +## isBoolean + +**Signature** + +```ts +export declare const isBoolean: any +``` + +Added in v1.0.0 + +# instances + +## Equivalence + +**Signature** + +```ts +export declare const Equivalence: any +``` + +Added in v1.0.0 + +## MonoidAll + +`boolean` monoid under conjunction. + +The `empty` value is `true`. + +**Signature** + +```ts +export declare const MonoidAll: any +``` + +Added in v1.0.0 + +## MonoidAny + +`boolean` monoid under disjunction. + +The `empty` value is `false`. + +**Signature** + +```ts +export declare const MonoidAny: any +``` + +Added in v1.0.0 + +## Order + +**Signature** + +```ts +export declare const Order: any +``` + +Added in v1.0.0 + +## SemigroupAll + +`boolean` semigroup under conjunction. + +**Signature** + +```ts +export declare const SemigroupAll: any +``` + +**Example** + +```ts +import { SemigroupAll } from '@fp-ts/core/Boolean' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(SemigroupAll.combine(true, true), true) +assert.deepStrictEqual(SemigroupAll.combine(true, false), false) +``` + +Added in v1.0.0 + +## SemigroupAny + +`boolean` semigroup under disjunction. + +**Signature** + +```ts +export declare const SemigroupAny: any +``` + +**Example** + +```ts +import { SemigroupAny } from '@fp-ts/core/Boolean' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(SemigroupAny.combine(true, true), true) +assert.deepStrictEqual(SemigroupAny.combine(true, false), true) +assert.deepStrictEqual(SemigroupAny.combine(false, false), false) +``` + +Added in v1.0.0 + +# pattern matching + +## match + +Defines the match over a boolean value. +Takes two thunks `onTrue`, `onFalse` and a `boolean` value. +If `value` is `false`, `onFalse()` is returned, otherwise `onTrue()`. + +**Signature** + +```ts +export declare const match: (onFalse: any, onTrue: any) => (value: boolean) => A | B +``` + +**Example** + +```ts +import { some, map } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' +import { match } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual( + pipe( + some(true), + map( + match( + () => 'false', + () => 'true' + ) + ) + ), + some('true') +) +``` + +Added in v1.0.0 + +# utils + +## all + +**Signature** + +```ts +export declare const all: any +``` + +Added in v1.0.0 + +## any + +**Signature** + +```ts +export declare const any: any +``` + +Added in v1.0.0 diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md new file mode 100644 index 000000000..59a192b5a --- /dev/null +++ b/docs/modules/Either.ts.md @@ -0,0 +1,1420 @@ +--- +title: Either.ts +nav_order: 3 +parent: Modules +--- + +## Either overview + +The `Either` data type is a powerful and flexible tool for handling potentially failed computations. +It has two variants, `Left` and `Right`, which can be used to represent different outcomes. + +The `Left` variant is used to represent a failure, and it can contain useful information such as an error message +or a failure code. The `Right` variant is used to represent a successful outcome, and it can contain the result +of the computation. + +Unlike `Option`, `Either` allows you to attach additional information to the failure case, making it more +informative than a simple `null` or `undefined`. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [combining](#combining) + - [getFirstLeftMonoid](#getfirstleftmonoid) + - [getFirstLeftSemigroup](#getfirstleftsemigroup) + - [getFirstRightSemigroup](#getfirstrightsemigroup) +- [constructors](#constructors) + - [left](#left) + - [of](#of) + - [right](#right) +- [conversions](#conversions) + - [fromIterable](#fromiterable) + - [fromNullable](#fromnullable) + - [fromOption](#fromoption) + - [toRefinement](#torefinement) +- [debugging](#debugging) + - [inspectLeft](#inspectleft) + - [inspectRight](#inspectright) +- [do notation](#do-notation) + - [Do](#do) + - [andThenBind](#andthenbind) + - [bind](#bind) + - [bindTo](#bindto) + - [let](#let) +- [error handling](#error-handling) + - [catchAll](#catchall) + - [firstSuccessOf](#firstsuccessof) + - [mapLeft](#mapleft) + - [orElse](#orelse) + - [orElseEither](#orelseeither) + - [orElseFail](#orelsefail) + - [orElseSucceed](#orelsesucceed) + - [tapError](#taperror) +- [filtering](#filtering) + - [compact](#compact) + - [filter](#filter) + - [filterMap](#filtermap) +- [getters](#getters) + - [getLeft](#getleft) + - [getOrElse](#getorelse) + - [getOrNull](#getornull) + - [getOrUndefined](#getorundefined) + - [getRight](#getright) + - [merge](#merge) +- [guards](#guards) + - [isEither](#iseither) + - [isLeft](#isleft) + - [isRight](#isright) +- [instances](#instances) + - [Applicative](#applicative) + - [Bicovariant](#bicovariant) + - [Chainable](#chainable) + - [Covariant](#covariant) + - [FlatMap](#flatmap) + - [Foldable](#foldable) + - [Invariant](#invariant) + - [Monad](#monad) + - [Of](#of) + - [Pointed](#pointed) + - [Product](#product) + - [SemiAlternative](#semialternative) + - [SemiApplicative](#semiapplicative) + - [SemiCoproduct](#semicoproduct) + - [SemiProduct](#semiproduct) + - [Traversable](#traversable) +- [interop](#interop) + - [fromThrowable](#fromthrowable) + - [getOrThrow](#getorthrow) + - [liftThrowable](#liftthrowable) +- [lifting](#lifting) + - [lift2](#lift2) + - [lift3](#lift3) + - [liftNullable](#liftnullable) + - [liftOption](#liftoption) + - [liftPredicate](#liftpredicate) +- [mapping](#mapping) + - [as](#as) + - [asUnit](#asunit) + - [bimap](#bimap) + - [flap](#flap) + - [imap](#imap) + - [map](#map) + - [tupled](#tupled) +- [models](#models) + - [Either (type alias)](#either-type-alias) + - [Left (type alias)](#left-type-alias) + - [Right (type alias)](#right-type-alias) +- [pattern matching](#pattern-matching) + - [match](#match) +- [sequencing](#sequencing) + - [andThenDiscard](#andthendiscard) + - [flatMap](#flatmap) + - [flatMapNullable](#flatmapnullable) + - [flatMapOption](#flatmapoption) +- [traversing](#traversing) + - [sequence](#sequence) + - [traverse](#traverse) + - [traverseTap](#traversetap) +- [type lambdas](#type-lambdas) + - [EitherTypeLambda (interface)](#eithertypelambda-interface) +- [utils](#utils) + - [andThen](#andthen) + - [ap](#ap) + - [composeKleisliArrow](#composekleisliarrow) + - [contains](#contains) + - [element](#element) + - [exists](#exists) + - [flatten](#flatten) + - [reverse](#reverse) + - [struct](#struct) + - [tap](#tap) + - [tuple](#tuple) + - [unit](#unit) + +--- + +# combining + +## getFirstLeftMonoid + +Monoid returning the left-most `Left` value. If both operands are `Right`s then the inner values +are concatenated using the provided `Monoid`. + +The `empty` value is `right(M.empty)`. + +**Signature** + +```ts +export declare const getFirstLeftMonoid: (M: any) => any +``` + +Added in v1.0.0 + +## getFirstLeftSemigroup + +Semigroup returning the left-most `Left` value. If both operands are `Right`s then the inner values +are concatenated using the provided `Semigroup`. + +| x | y | x | > combine(y) | +| -------- | -------- | ------- | ------------- | +| left(a) | left(b) | left(a) | +| left(a) | right(2) | left(a) | +| right(1) | left(b) | left(b) | +| right(1) | right(2) | right(1 | > combine(2)) | + +**Signature** + +```ts +export declare const getFirstLeftSemigroup: (S: any) => any +``` + +Added in v1.0.0 + +## getFirstRightSemigroup + +Semigroup returning the left-most `Right` value. + +| x | y | x | > combine(y) | +| -------- | -------- | -------- | ------------ | +| left(a) | left(b) | left(b) | +| left(a) | right(2) | right(2) | +| right(1) | left(b) | right(1) | +| right(1) | right(2) | right(1) | + +**Signature** + +```ts +export declare const getFirstRightSemigroup: () => any +``` + +Added in v1.0.0 + +# constructors + +## left + +Constructs a new `Either` holding a `Left` value. This usually represents a failure, due to the right-bias of this +structure. + +**Signature** + +```ts +export declare const left: (e: E) => Either +``` + +Added in v1.0.0 + +## of + +Alias of `right`. + +**Signature** + +```ts +export declare const of:
(a: A) => Either +``` + +Added in v1.0.0 + +## right + +Constructs a new `Either` holding a `Right` value. This usually represents a successful value due to the right bias +of this structure. + +**Signature** + +```ts +export declare const right: (a: A) => Either +``` + +Added in v1.0.0 + +# conversions + +## fromIterable + +**Signature** + +```ts +export declare const fromIterable: (onEmpty: any) => (collection: Iterable) => Either +``` + +Added in v1.0.0 + +## fromNullable + +Takes a lazy default and a nullable value, if the value is not nully, turn it into a `Right`, if the value is nully use +the provided default as a `Left`. + +**Signature** + +```ts +export declare const fromNullable: (onNullable: any) => (a: A) => Either> +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' + +const parse = E.fromNullable(() => 'nullable') + +assert.deepStrictEqual(parse(1), E.right(1)) +assert.deepStrictEqual(parse(null), E.left('nullable')) +``` + +Added in v1.0.0 + +## fromOption + +**Signature** + +```ts +export declare const fromOption: (onNone: any) => (self: any) => Either +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' +import { pipe } from '@fp-ts/core/Function' +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual( + pipe( + O.some(1), + E.fromOption(() => 'error') + ), + E.right(1) +) +assert.deepStrictEqual( + pipe( + O.none(), + E.fromOption(() => 'error') + ), + E.left('error') +) +``` + +Added in v1.0.0 + +## toRefinement + +Returns a `Refinement` from a `Either` returning function. +This function ensures that a `Refinement` definition is type-safe. + +**Signature** + +```ts +export declare const toRefinement: (f: (a: A) => Either) => any +``` + +Added in v1.0.0 + +# debugging + +## inspectLeft + +**Signature** + +```ts +export declare const inspectLeft: (onLeft: (e: E) => void) => (self: Either) => Either +``` + +Added in v1.0.0 + +## inspectRight + +**Signature** + +```ts +export declare const inspectRight: (onRight: (a: A) => void) => (self: Either) => Either +``` + +Added in v1.0.0 + +# do notation + +## Do + +**Signature** + +```ts +export declare const Do: Either +``` + +Added in v1.0.0 + +## andThenBind + +A variant of `bind` that sequentially ignores the scope. + +**Signature** + +```ts +export declare const andThenBind: ( + name: Exclude, + that: Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + +## bind + +**Signature** + +```ts +export declare const bind: ( + name: Exclude, + f: (a: A) => Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + +## bindTo + +**Signature** + +```ts +export declare const bindTo: (name: N) => (self: Either) => Either +``` + +Added in v1.0.0 + +## let + +**Signature** + +```ts +export declare const let: ( + name: Exclude, + f: (a: A) => B +) => (self: Either) => Either +``` + +Added in v1.0.0 + +# error handling + +## catchAll + +Recovers from all errors. + +**Signature** + +```ts +export declare const catchAll: ( + onLeft: (e: E1) => Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + +## firstSuccessOf + +**Signature** + +```ts +export declare const firstSuccessOf: (collection: Iterable>) => (self: Either) => Either +``` + +Added in v1.0.0 + +## mapLeft + +Returns an effect with its error channel mapped using the specified +function. This can be used to lift a "smaller" error into a "larger" error. + +**Signature** + +```ts +export declare const mapLeft: (f: (e: E) => G) => (self: Either) => Either +``` + +Added in v1.0.0 + +## orElse + +Executes this effect and returns its value, if it succeeds, but otherwise +executes the specified effect. + +| x | y | x | > orElse(y) | +| -------- | -------- | -------- | ----------- | +| left(a) | left(b) | left(b) | +| left(a) | right(2) | right(2) | +| right(1) | left(b) | right(1) | +| right(1) | right(2) | right(1) | + +**Signature** + +```ts +export declare const orElse: (that: Either) => (self: Either) => Either +``` + +Added in v1.0.0 + +## orElseEither + +Returns an effect that will produce the value of this effect, unless it +fails, in which case, it will produce the value of the specified effect. + +**Signature** + +```ts +export declare const orElseEither: ( + that: Either +) => (self: Either) => Either> +``` + +Added in v1.0.0 + +## orElseFail + +Executes this effect and returns its value, if it succeeds, but otherwise +fails with the specified error. + +**Signature** + +```ts +export declare const orElseFail: (onLeft: any) => (self: Either) => Either +``` + +Added in v1.0.0 + +## orElseSucceed + +Executes this effect and returns its value, if it succeeds, but otherwise +succeeds with the specified value. + +**Signature** + +```ts +export declare const orElseSucceed: (onLeft: any) => (self: Either) => Either +``` + +Added in v1.0.0 + +## tapError + +Returns an effect that effectfully "peeks" at the failure of this effect. + +**Signature** + +```ts +export declare const tapError: ( + onLeft: (e: E1) => Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + +# filtering + +## compact + +**Signature** + +```ts +export declare const compact: (onNone: any) => (self: Either) => Either +``` + +Added in v1.0.0 + +## filter + +**Signature** + +```ts +export declare const filter: { + (refinement: any, onFalse: any): (self: Either) => Either + (predicate: any, onFalse: any): (self: Either) => Either +} +``` + +Added in v1.0.0 + +## filterMap + +**Signature** + +```ts +export declare const filterMap: ( + f: (a: A) => any, + onNone: any +) => (self: Either) => Either +``` + +Added in v1.0.0 + +# getters + +## getLeft + +Converts a `Either` to an `Option` discarding the Right. + +**Signature** + +```ts +export declare const getLeft: (self: Either) => any +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(E.getLeft(E.right('ok')), O.none()) +assert.deepStrictEqual(E.getLeft(E.left('err')), O.some('err')) +``` + +Added in v1.0.0 + +## getOrElse + +Returns the wrapped value if it's a `Right` or a default value if is a `Left`. + +**Signature** + +```ts +export declare const getOrElse: (onLeft: any) => (self: Either) => B | A +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual( + pipe( + E.right(1), + E.getOrElse(() => 0) + ), + 1 +) +assert.deepStrictEqual( + pipe( + E.left('error'), + E.getOrElse(() => 0) + ), + 0 +) +``` + +Added in v1.0.0 + +## getOrNull + +**Signature** + +```ts +export declare const getOrNull: (self: Either) => A | null +``` + +Added in v1.0.0 + +## getOrUndefined + +**Signature** + +```ts +export declare const getOrUndefined: (self: Either) => A | undefined +``` + +Added in v1.0.0 + +## getRight + +Converts a `Either` to an `Option` discarding the error. + +**Signature** + +```ts +export declare const getRight: (self: Either) => any +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(E.getRight(E.right('ok')), O.some('ok')) +assert.deepStrictEqual(E.getRight(E.left('err')), O.none()) +``` + +Added in v1.0.0 + +## merge + +**Signature** + +```ts +export declare const merge: (self: Either) => E | A +``` + +Added in v1.0.0 + +# guards + +## isEither + +Returns `true` if the specified value is an instance of `Either`, `false` +otherwise. + +**Signature** + +```ts +export declare const isEither: (u: unknown) => u is Either +``` + +Added in v1.0.0 + +## isLeft + +Returns `true` if the either is an instance of `Left`, `false` otherwise. + +**Signature** + +```ts +export declare const isLeft: (self: Either) => self is Left +``` + +Added in v1.0.0 + +## isRight + +Returns `true` if the either is an instance of `Right`, `false` otherwise. + +**Signature** + +```ts +export declare const isRight: (self: Either) => self is Right +``` + +Added in v1.0.0 + +# instances + +## Applicative + +**Signature** + +```ts +export declare const Applicative: any +``` + +Added in v1.0.0 + +## Bicovariant + +**Signature** + +```ts +export declare const Bicovariant: any +``` + +Added in v1.0.0 + +## Chainable + +**Signature** + +```ts +export declare const Chainable: any +``` + +Added in v1.0.0 + +## Covariant + +**Signature** + +```ts +export declare const Covariant: any +``` + +Added in v1.0.0 + +## FlatMap + +**Signature** + +```ts +export declare const FlatMap: any +``` + +Added in v1.0.0 + +## Foldable + +**Signature** + +```ts +export declare const Foldable: any +``` + +Added in v1.0.0 + +## Invariant + +**Signature** + +```ts +export declare const Invariant: any +``` + +Added in v1.0.0 + +## Monad + +**Signature** + +```ts +export declare const Monad: any +``` + +Added in v1.0.0 + +## Of + +**Signature** + +```ts +export declare const Of: any +``` + +Added in v1.0.0 + +## Pointed + +**Signature** + +```ts +export declare const Pointed: any +``` + +Added in v1.0.0 + +## Product + +**Signature** + +```ts +export declare const Product: any +``` + +Added in v1.0.0 + +## SemiAlternative + +**Signature** + +```ts +export declare const SemiAlternative: any +``` + +Added in v1.0.0 + +## SemiApplicative + +**Signature** + +```ts +export declare const SemiApplicative: any +``` + +Added in v1.0.0 + +## SemiCoproduct + +**Signature** + +```ts +export declare const SemiCoproduct: any +``` + +Added in v1.0.0 + +## SemiProduct + +**Signature** + +```ts +export declare const SemiProduct: any +``` + +Added in v1.0.0 + +## Traversable + +**Signature** + +```ts +export declare const Traversable: any +``` + +Added in v1.0.0 + +# interop + +## fromThrowable + +Constructs a new `Either` from a function that might throw. + +**Signature** + +```ts +export declare const fromThrowable: (f: () => A, onThrow: (error: unknown) => E) => Either +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' +import { identity } from '@fp-ts/core/Function' + +const unsafeHead = (as: ReadonlyArray): A => { + if (as.length > 0) { + return as[0] + } else { + throw new Error('empty array') + } +} + +const head = (as: ReadonlyArray): E.Either => E.fromThrowable(() => unsafeHead(as), identity) + +assert.deepStrictEqual(head([]), E.left(new Error('empty array'))) +assert.deepStrictEqual(head([1, 2, 3]), E.right(1)) +``` + +Added in v1.0.0 + +## getOrThrow + +**Signature** + +```ts +export declare const getOrThrow: (onLeft: (e: E) => unknown) => (self: Either) => A +``` + +Added in v1.0.0 + +## liftThrowable + +Lifts a function that may throw to one returning a `Either`. + +**Signature** + +```ts +export declare const liftThrowable: ( + f: (...a: A) => B, + onThrow: (error: unknown) => E +) => (...a: A) => Either +``` + +Added in v1.0.0 + +# lifting + +## lift2 + +**Signature** + +```ts +export declare const lift2: ( + f: (a: A, b: B) => C +) => (fa: Either, fb: Either) => Either +``` + +Added in v1.0.0 + +## lift3 + +**Signature** + +```ts +export declare const lift3: ( + f: (a: A, b: B, c: C) => D +) => (fa: Either, fb: Either, fc: Either) => Either +``` + +Added in v1.0.0 + +## liftNullable + +**Signature** + +```ts +export declare const liftNullable: ( + f: (...a: A) => B | null | undefined, + onNullable: (...a: A) => E +) => (...a: A) => Either> +``` + +Added in v1.0.0 + +## liftOption + +**Signature** + +```ts +export declare const liftOption: ( + f: (...a: A) => any, + onNone: (...a: A) => E +) => (...a: A) => Either +``` + +Added in v1.0.0 + +## liftPredicate + +**Signature** + +```ts +export declare const liftPredicate: { + (refinement: any, onFalse: any): (c: C) => Either + (predicate: any, onFalse: any): (b: B) => Either +} +``` + +**Example** + +```ts +import { liftPredicate, left, right } from '@fp-ts/core/Either' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual( + pipe( + 1, + liftPredicate( + (n) => n > 0, + () => 'error' + ) + ), + right(1) +) +assert.deepStrictEqual( + pipe( + -1, + liftPredicate( + (n) => n > 0, + () => 'error' + ) + ), + left('error') +) +``` + +Added in v1.0.0 + +# mapping + +## as + +Maps the Right value of this effect to the specified constant value. + +**Signature** + +```ts +export declare const as: (b: B) => (self: Either) => Either +``` + +Added in v1.0.0 + +## asUnit + +Returns the effect Eithering from mapping the Right of this effect to unit. + +**Signature** + +```ts +export declare const asUnit: (self: Either) => Either +``` + +Added in v1.0.0 + +## bimap + +Returns an effect whose Left and Right channels have been mapped by +the specified pair of functions, `f` and `g`. + +**Signature** + +```ts +export declare const bimap: (f: (e: E) => G, g: (a: A) => B) => (self: Either) => Either +``` + +Added in v1.0.0 + +## flap + +**Signature** + +```ts +export declare const flap: (a: A) => (self: Either B>) => Either +``` + +Added in v1.0.0 + +## imap + +**Signature** + +```ts +export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (self: Either) => Either +``` + +Added in v1.0.0 + +## map + +Returns an effect whose Right is mapped by the specified `f` function. + +**Signature** + +```ts +export declare const map: (f: (a: A) => B) => (self: Either) => Either +``` + +Added in v1.0.0 + +## tupled + +**Signature** + +```ts +export declare const tupled: (self: Either) => Either +``` + +Added in v1.0.0 + +# models + +## Either (type alias) + +**Signature** + +```ts +export type Either = Left | Right +``` + +Added in v1.0.0 + +## Left (type alias) + +**Signature** + +```ts +export type Left = { + readonly _tag: 'Left' + readonly left: E +} +``` + +Added in v1.0.0 + +## Right (type alias) + +**Signature** + +```ts +export type Right = { + readonly _tag: 'Right' + readonly right: A +} +``` + +Added in v1.0.0 + +# pattern matching + +## match + +Takes two functions and an `Either` value, if the value is a `Left` the inner value is applied to the first function, +if the value is a `Right` the inner value is applied to the second function. + +**Signature** + +```ts +export declare const match: (onLeft: (e: E) => B, onRight: (a: A) => C) => (self: Either) => B | C +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' +import { pipe } from '@fp-ts/core/Function' + +const onLeft = (errors: ReadonlyArray): string => `Errors: ${errors.join(', ')}` + +const onRight = (value: number): string => `Ok: ${value}` + +assert.strictEqual(pipe(E.right(1), E.match(onLeft, onRight)), 'Ok: 1') +assert.strictEqual(pipe(E.left(['error 1', 'error 2']), E.match(onLeft, onRight)), 'Errors: error 1, error 2') +``` + +Added in v1.0.0 + +# sequencing + +## andThenDiscard + +Sequences the specified effect after this effect, but ignores the value +produced by the effect. + +**Signature** + +```ts +export declare const andThenDiscard: (that: Either) => (self: Either) => Either +``` + +Added in v1.0.0 + +## flatMap + +**Signature** + +```ts +export declare const flatMap: (f: (a: A) => Either) => (self: Either) => Either +``` + +Added in v1.0.0 + +## flatMapNullable + +**Signature** + +```ts +export declare const flatMapNullable: ( + f: (a: A) => B | null | undefined, + onNullable: (a: A) => E2 +) => (self: Either) => Either> +``` + +Added in v1.0.0 + +## flatMapOption + +**Signature** + +```ts +export declare const flatMapOption: ( + f: (a: A) => any, + onNone: (a: A) => E2 +) => (self: Either) => Either +``` + +Added in v1.0.0 + +# traversing + +## sequence + +**Signature** + +```ts +export declare const sequence: (F: any) => (self: Either) => any +``` + +Added in v1.0.0 + +## traverse + +**Signature** + +```ts +export declare const traverse: ( + F: any +) => (f: (a: A) => any) => (self: Either) => any +``` + +Added in v1.0.0 + +## traverseTap + +**Signature** + +```ts +export declare const traverseTap: ( + F: any +) => (f: (a: A) => any) => (self: Either) => any +``` + +Added in v1.0.0 + +# type lambdas + +## EitherTypeLambda (interface) + +**Signature** + +```ts +export interface EitherTypeLambda extends TypeLambda { + readonly type: Either +} +``` + +Added in v1.0.0 + +# utils + +## andThen + +**Signature** + +```ts +export declare const andThen: (that: Either) => (self: Either) => Either +``` + +Added in v1.0.0 + +## ap + +**Signature** + +```ts +export declare const ap: (fa: Either) => (self: Either B>) => Either +``` + +Added in v1.0.0 + +## composeKleisliArrow + +**Signature** + +```ts +export declare const composeKleisliArrow: ( + bfc: (b: B) => Either +) => (afb: (a: A) => Either) => (a: A) => Either +``` + +Added in v1.0.0 + +## contains + +Returns a function that checks if an `Either` contains a given value using a provided `equivalence` function. + +**Signature** + +```ts +export declare const contains: (equivalence: any) => (a: A) => (self: Either) => boolean +``` + +Added in v1.0.0 + +## element + +Adds an element to the end of a tuple. + +**Signature** + +```ts +export declare const element: ( + that: Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + +## exists + +Returns `false` if `Left` or returns the Either of the application of the given predicate to the `Right` value. + +**Signature** + +```ts +export declare const exists: (predicate: any) => (self: Either) => boolean +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' + +const f = E.exists((n: number) => n > 2) + +assert.strictEqual(f(E.left('a')), false) +assert.strictEqual(f(E.right(1)), false) +assert.strictEqual(f(E.right(3)), true) +``` + +Added in v1.0.0 + +## flatten + +**Signature** + +```ts +export declare const flatten: (self: Either>) => Either +``` + +Added in v1.0.0 + +## reverse + +**Signature** + +```ts +export declare const reverse: (self: Either) => Either +``` + +Added in v1.0.0 + +## struct + +**Signature** + +```ts +export declare const struct: >>( + r: R +) => Either< + [R[keyof R]] extends [Either] ? E : never, + { [K in keyof R]: [R[K]] extends [Either] ? A : never } +> +``` + +Added in v1.0.0 + +## tap + +Returns an effect that effectfully "peeks" at the success of this effect. + +**Signature** + +```ts +export declare const tap: (f: (a: A) => Either) => (self: Either) => Either +``` + +Added in v1.0.0 + +## tuple + +**Signature** + +```ts +export declare const tuple: []>( + ...tuple: T +) => Either< + [T[number]] extends [Either] ? E : never, + { [I in keyof T]: [T[I]] extends [Either] ? A : never } +> +``` + +Added in v1.0.0 + +## unit + +**Signature** + +```ts +export declare const unit: Either +``` + +Added in v1.0.0 diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md new file mode 100644 index 000000000..862ec1b2e --- /dev/null +++ b/docs/modules/Function.ts.md @@ -0,0 +1,701 @@ +--- +title: Function.ts +nav_order: 4 +parent: Modules +--- + +## Function overview + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [instances](#instances) + - [getMonoid](#getmonoid) + - [getSemigroup](#getsemigroup) +- [type lambdas](#type-lambdas) + - [FunctionTypeLambda (interface)](#functiontypelambda-interface) +- [utils](#utils) + - [FunctionN (interface)](#functionn-interface) + - [LazyArg (interface)](#lazyarg-interface) + - [SK](#sk) + - [absurd](#absurd) + - [apply](#apply) + - [compose](#compose) + - [constFalse](#constfalse) + - [constNull](#constnull) + - [constTrue](#consttrue) + - [constUndefined](#constundefined) + - [constVoid](#constvoid) + - [constant](#constant) + - [flip](#flip) + - [flow](#flow) + - [hole](#hole) + - [identity](#identity) + - [pipe](#pipe) + - [tupled](#tupled) + - [unsafeCoerce](#unsafecoerce) + - [untupled](#untupled) + +--- + +# instances + +## getMonoid + +Unary functions form a monoid as long as you can provide a monoid for the codomain. + +**Signature** + +```ts +export declare const getMonoid: (Monoid: any) =>
() => any +``` + +**Example** + +```ts +import { Predicate } from '@fp-ts/core/Predicate' +import { getMonoid, pipe } from '@fp-ts/core/Function' +import * as B from '@fp-ts/core/Boolean' + +const f: Predicate = (n) => n <= 2 +const g: Predicate = (n) => n >= 0 + +const M1 = getMonoid(B.MonoidAll)() + +assert.deepStrictEqual(M1.combine(f, g)(1), true) +assert.deepStrictEqual(M1.combine(f, g)(3), false) + +const M2 = getMonoid(B.MonoidAny)() + +assert.deepStrictEqual(M2.combine(f, g)(1), true) +assert.deepStrictEqual(M2.combine(f, g)(3), true) +``` + +Added in v1.0.0 + +## getSemigroup + +Unary functions form a semigroup as long as you can provide a semigroup for the codomain. + +**Signature** + +```ts +export declare const getSemigroup: (Semigroup: any) => () => any +``` + +**Example** + +```ts +import { Predicate } from '@fp-ts/core/Predicate' +import { pipe, getSemigroup } from '@fp-ts/core/Function' +import * as B from '@fp-ts/core/Boolean' + +const f: Predicate = (n) => n <= 2 +const g: Predicate = (n) => n >= 0 + +const S1 = getSemigroup(B.SemigroupAll)() + +assert.deepStrictEqual(S1.combine(f, g)(1), true) +assert.deepStrictEqual(S1.combine(f, g)(3), false) + +const S2 = getSemigroup(B.SemigroupAny)() + +assert.deepStrictEqual(S2.combine(f, g)(1), true) +assert.deepStrictEqual(S2.combine(f, g)(3), true) +``` + +Added in v1.0.0 + +# type lambdas + +## FunctionTypeLambda (interface) + +**Signature** + +```ts +export interface FunctionTypeLambda extends TypeLambda { + readonly type: (a: this['In']) => this['Target'] +} +``` + +Added in v1.0.0 + +# utils + +## FunctionN (interface) + +**Signature** + +```ts +export interface FunctionN, B> { + (...args: A): B +} +``` + +**Example** + +```ts +import { FunctionN } from '@fp-ts/core/Function' + +export const sum: FunctionN<[number, number], number> = (a, b) => a + b +``` + +Added in v1.0.0 + +## LazyArg (interface) + +A lazy argument + +**Signature** + +```ts +export interface LazyArg { + (): A +} +``` + +Added in v1.0.0 + +## SK + +`SK` function (SKI combinator calculus). + +**Signature** + +```ts +export declare const SK: (_: A, b: B) => B +``` + +Added in v1.0.0 + +## absurd + +**Signature** + +```ts +export declare const absurd: (_: never) => A +``` + +Added in v1.0.0 + +## apply + +**Signature** + +```ts +export declare const apply: (a: A) => (self: (a: A) => B) => B +``` + +Added in v1.0.0 + +## compose + +**Signature** + +```ts +export declare const compose: (bc: (b: B) => C) => (ab: (a: A) => B) => (a: A) => C +``` + +Added in v1.0.0 + +## constFalse + +A thunk that returns always `false`. + +**Signature** + +```ts +export declare const constFalse: LazyArg +``` + +Added in v1.0.0 + +## constNull + +A thunk that returns always `null`. + +**Signature** + +```ts +export declare const constNull: LazyArg +``` + +Added in v1.0.0 + +## constTrue + +A thunk that returns always `true`. + +**Signature** + +```ts +export declare const constTrue: LazyArg +``` + +Added in v1.0.0 + +## constUndefined + +A thunk that returns always `undefined`. + +**Signature** + +```ts +export declare const constUndefined: LazyArg +``` + +Added in v1.0.0 + +## constVoid + +A thunk that returns always `void`. + +**Signature** + +```ts +export declare const constVoid: LazyArg +``` + +Added in v1.0.0 + +## constant + +**Signature** + +```ts +export declare const constant: (a: A) => LazyArg +``` + +Added in v1.0.0 + +## flip + +Flips the arguments of a curried function. + +**Signature** + +```ts +export declare const flip: (f: (a: A) => (b: B) => C) => (b: B) => (a: A) => C +``` + +**Example** + +```ts +import { flip } from '@fp-ts/core/Function' + +const f = (a: number) => (b: string) => a - b.length + +assert.strictEqual(flip(f)('aaa')(2), -1) +``` + +Added in v1.0.0 + +## flow + +Performs left-to-right function composition. The first argument may have any arity, the remaining arguments must be unary. + +**Signature** + +```ts +export declare function flow, B>(ab: (...a: A) => B): (...a: A) => B +export declare function flow, B, C>( + ab: (...a: A) => B, + bc: (b: B) => C +): (...a: A) => C +export declare function flow, B, C, D>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D +): (...a: A) => D +export declare function flow, B, C, D, E>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E +): (...a: A) => E +export declare function flow, B, C, D, E, F>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F +): (...a: A) => F +export declare function flow, B, C, D, E, F, G>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G +): (...a: A) => G +export declare function flow, B, C, D, E, F, G, H>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H +): (...a: A) => H +export declare function flow, B, C, D, E, F, G, H, I>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I +): (...a: A) => I +export declare function flow, B, C, D, E, F, G, H, I, J>( + ab: (...a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J +): (...a: A) => J +``` + +**Example** + +```ts +import { flow } from '@fp-ts/core/Function' + +const len = (s: string): number => s.length +const double = (n: number): number => n * 2 + +const f = flow(len, double) + +assert.strictEqual(f('aaa'), 6) +``` + +Added in v1.0.0 + +## hole + +Type hole simulation + +**Signature** + +```ts +export declare const hole: () => T +``` + +Added in v1.0.0 + +## identity + +**Signature** + +```ts +export declare const identity: (a: A) => A +``` + +Added in v1.0.0 + +## pipe + +Pipes the value of an expression into a pipeline of functions. + +**Signature** + +```ts +export declare function pipe(a: A): A +export declare function pipe(a: A, ab: (a: A) => B): B +export declare function pipe(a: A, ab: (a: A) => B, bc: (b: B) => C): C +export declare function pipe(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D +export declare function pipe(a: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E): E +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F +): F +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G +): G +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H +): H +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I +): I +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J +): J +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K +): K +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L +): L +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M +): M +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N +): N +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O +): O +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P +): P +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q +): Q +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R +): R +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => S +): S +export declare function pipe( + a: A, + ab: (a: A) => B, + bc: (b: B) => C, + cd: (c: C) => D, + de: (d: D) => E, + ef: (e: E) => F, + fg: (f: F) => G, + gh: (g: G) => H, + hi: (h: H) => I, + ij: (i: I) => J, + jk: (j: J) => K, + kl: (k: K) => L, + lm: (l: L) => M, + mn: (m: M) => N, + no: (n: N) => O, + op: (o: O) => P, + pq: (p: P) => Q, + qr: (q: Q) => R, + rs: (r: R) => S, + st: (s: S) => T +): T +``` + +**Example** + +```ts +import { pipe } from '@fp-ts/core/Function' + +const len = (s: string): number => s.length +const double = (n: number): number => n * 2 + +// without pipe +assert.strictEqual(double(len('aaa')), 6) + +// with pipe +assert.strictEqual(pipe('aaa', len, double), 6) +``` + +Added in v1.0.0 + +## tupled + +Creates a tupled version of this function: instead of `n` arguments, it accepts a single tuple argument. + +**Signature** + +```ts +export declare const tupled: (f: (...a: A) => B) => (a: A) => B +``` + +**Example** + +```ts +import { tupled } from '@fp-ts/core/Function' + +const add = tupled((x: number, y: number): number => x + y) + +assert.strictEqual(add([1, 2]), 3) +``` + +Added in v1.0.0 + +## unsafeCoerce + +**Signature** + +```ts +export declare const unsafeCoerce: (a: A) => B +``` + +Added in v1.0.0 + +## untupled + +Inverse function of `tupled` + +**Signature** + +```ts +export declare const untupled: (f: (a: A) => B) => (...a: A) => B +``` + +Added in v1.0.0 diff --git a/docs/modules/HKT.ts.md b/docs/modules/HKT.ts.md index dec5aeaae..fc7d5f430 100644 --- a/docs/modules/HKT.ts.md +++ b/docs/modules/HKT.ts.md @@ -1,6 +1,6 @@ --- title: HKT.ts -nav_order: 1 +nav_order: 5 parent: Modules --- diff --git a/docs/modules/Identity.ts.md b/docs/modules/Identity.ts.md new file mode 100644 index 000000000..bcc1e104f --- /dev/null +++ b/docs/modules/Identity.ts.md @@ -0,0 +1,702 @@ +--- +title: Identity.ts +nav_order: 6 +parent: Modules +--- + +## Identity overview + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [constructors](#constructors) + - [of](#of) +- [conversions](#conversions) + - [toArray](#toarray) + - [toArrayWith](#toarraywith) +- [do notation](#do-notation) + - [Do](#do) + - [andThenBind](#andthenbind) + - [bind](#bind) + - [bindTo](#bindto) + - [let](#let) +- [folding](#folding) + - [foldMap](#foldmap) + - [foldMapKind](#foldmapkind) + - [reduce](#reduce) + - [reduceKind](#reducekind) + - [reduceRight](#reduceright) + - [reduceRightKind](#reducerightkind) +- [instances](#instances) + - [Applicative](#applicative) + - [Chainable](#chainable) + - [Covariant](#covariant) + - [FlatMap](#flatmap) + - [Foldable](#foldable) + - [Invariant](#invariant) + - [Monad](#monad) + - [Of](#of) + - [Pointed](#pointed) + - [Product](#product) + - [SemiApplicative](#semiapplicative) + - [SemiProduct](#semiproduct) + - [Traversable](#traversable) + - [getSemiAlternative](#getsemialternative) + - [getSemiCoproduct](#getsemicoproduct) + - [liftSemigroup](#liftsemigroup) +- [lifting](#lifting) + - [lift2](#lift2) + - [lift3](#lift3) +- [mapping](#mapping) + - [as](#as) + - [asUnit](#asunit) + - [flap](#flap) +- [models](#models) + - [Identity (type alias)](#identity-type-alias) +- [sequencing](#sequencing) + - [andThenDiscard](#andthendiscard) + - [flatMap](#flatmap) +- [traversing](#traversing) + - [sequence](#sequence) + - [traverse](#traverse) + - [traverseTap](#traversetap) +- [type lambdas](#type-lambdas) + - [IdentityTypeLambda (interface)](#identitytypelambda-interface) + - [IdentityTypeLambdaFix (interface)](#identitytypelambdafix-interface) +- [utils](#utils) + - [andThen](#andthen) + - [ap](#ap) + - [composeKleisliArrow](#composekleisliarrow) + - [element](#element) + - [flatten](#flatten) + - [imap](#imap) + - [liftMonoid](#liftmonoid) + - [map](#map) + - [struct](#struct) + - [tap](#tap) + - [tuple](#tuple) + - [tupled](#tupled) + - [unit](#unit) + +--- + +# constructors + +## of + +**Signature** + +```ts +export declare const of:
(a: A) => A +``` + +Added in v1.0.0 + +# conversions + +## toArray + +**Signature** + +```ts +export declare const toArray: (self: A) => A[] +``` + +Added in v1.0.0 + +## toArrayWith + +**Signature** + +```ts +export declare const toArrayWith: (f: (a: A) => B) => (self: A) => B[] +``` + +Added in v1.0.0 + +# do notation + +## Do + +**Signature** + +```ts +export declare const Do: {} +``` + +Added in v1.0.0 + +## andThenBind + +A variant of `bind` that sequentially ignores the scope. + +**Signature** + +```ts +export declare const andThenBind: ( + name: Exclude, + that: B +) => (self: A) => { [K in N | keyof A]: K extends keyof A ? A[K] : B } +``` + +Added in v1.0.0 + +## bind + +**Signature** + +```ts +export declare const bind: ( + name: Exclude, + f: (a: A) => B +) => (self: A) => { [K in N | keyof A]: K extends keyof A ? A[K] : B } +``` + +Added in v1.0.0 + +## bindTo + +**Signature** + +```ts +export declare const bindTo: (name: N) => (self: A) => { [K in N]: A } +``` + +Added in v1.0.0 + +## let + +**Signature** + +```ts +export declare const let: ( + name: Exclude, + f: (a: A) => B +) => (self: A) => { [K in N | keyof A]: K extends keyof A ? A[K] : B } +``` + +Added in v1.0.0 + +# folding + +## foldMap + +**Signature** + +```ts +export declare const foldMap: (M: any) => (f: (a: A) => M) => (self: A) => M +``` + +Added in v1.0.0 + +## foldMapKind + +**Signature** + +```ts +export declare const foldMapKind: (G: any) => (f: (a: A) => any) => (self: A) => any +``` + +Added in v1.0.0 + +## reduce + +**Signature** + +```ts +export declare const reduce: (b: B, f: (b: B, a: A) => B) => (self: A) => B +``` + +Added in v1.0.0 + +## reduceKind + +**Signature** + +```ts +export declare const reduceKind: ( + G: any +) => (b: B, f: (b: B, a: A) => any) => (self: A) => any +``` + +Added in v1.0.0 + +## reduceRight + +**Signature** + +```ts +export declare const reduceRight: (b: B, f: (b: B, a: A) => B) => (self: A) => B +``` + +Added in v1.0.0 + +## reduceRightKind + +**Signature** + +```ts +export declare const reduceRightKind: ( + G: any +) => (b: B, f: (b: B, a: A) => any) => (self: A) => any +``` + +Added in v1.0.0 + +# instances + +## Applicative + +**Signature** + +```ts +export declare const Applicative: any +``` + +Added in v1.0.0 + +## Chainable + +**Signature** + +```ts +export declare const Chainable: any +``` + +Added in v1.0.0 + +## Covariant + +**Signature** + +```ts +export declare const Covariant: any +``` + +Added in v1.0.0 + +## FlatMap + +**Signature** + +```ts +export declare const FlatMap: any +``` + +Added in v1.0.0 + +## Foldable + +**Signature** + +```ts +export declare const Foldable: any +``` + +Added in v1.0.0 + +## Invariant + +**Signature** + +```ts +export declare const Invariant: any +``` + +Added in v1.0.0 + +## Monad + +**Signature** + +```ts +export declare const Monad: any +``` + +Added in v1.0.0 + +## Of + +**Signature** + +```ts +export declare const Of: any +``` + +Added in v1.0.0 + +## Pointed + +**Signature** + +```ts +export declare const Pointed: any +``` + +Added in v1.0.0 + +## Product + +**Signature** + +```ts +export declare const Product: any +``` + +Added in v1.0.0 + +## SemiApplicative + +**Signature** + +```ts +export declare const SemiApplicative: any +``` + +Added in v1.0.0 + +## SemiProduct + +**Signature** + +```ts +export declare const SemiProduct: any +``` + +Added in v1.0.0 + +## Traversable + +**Signature** + +```ts +export declare const Traversable: any +``` + +Added in v1.0.0 + +## getSemiAlternative + +**Signature** + +```ts +export declare const getSemiAlternative: (S: any) => any +``` + +Added in v1.0.0 + +## getSemiCoproduct + +**Signature** + +```ts +export declare const getSemiCoproduct: (S: any) => any +``` + +Added in v1.0.0 + +## liftSemigroup + +**Signature** + +```ts +export declare const liftSemigroup: (S: any) => any +``` + +Added in v1.0.0 + +# lifting + +## lift2 + +Lifts a binary function into `Identity`. + +**Signature** + +```ts +export declare const lift2: (f: (a: A, b: B) => C) => (fa: A, fb: B) => C +``` + +Added in v1.0.0 + +## lift3 + +Lifts a ternary function into `Identity`. + +**Signature** + +```ts +export declare const lift3: (f: (a: A, b: B, c: C) => D) => (fa: A, fb: B, fc: C) => D +``` + +Added in v1.0.0 + +# mapping + +## as + +Maps the success value of this effect to the specified constant value. + +**Signature** + +```ts +export declare const as: (b: B) => <_>(self: _) => B +``` + +Added in v1.0.0 + +## asUnit + +Returns the effect resulting from mapping the success of this effect to unit. + +**Signature** + +```ts +export declare const asUnit: <_>(self: _) => Identity +``` + +Added in v1.0.0 + +## flap + +**Signature** + +```ts +export declare const flap: (a: A) => (fab: (a: A) => B) => B +``` + +Added in v1.0.0 + +# models + +## Identity (type alias) + +**Signature** + +```ts +export type Identity = A +``` + +Added in v1.0.0 + +# sequencing + +## andThenDiscard + +Sequences the specified effect after this effect, but ignores the value +produced by the effect. + +**Signature** + +```ts +export declare const andThenDiscard: <_>(that: _) => (self: A) => A +``` + +Added in v1.0.0 + +## flatMap + +**Signature** + +```ts +export declare const flatMap: (f: (a: A) => B) => (self: A) => B +``` + +Added in v1.0.0 + +# traversing + +## sequence + +**Signature** + +```ts +export declare const sequence: (F: any) => (fas: any) => any +``` + +Added in v1.0.0 + +## traverse + +**Signature** + +```ts +export declare const traverse: (F: any) => (f: (a: A) => any) => (self: A) => any +``` + +Added in v1.0.0 + +## traverseTap + +**Signature** + +```ts +export declare const traverseTap: (F: any) => (f: (a: A) => any) => (self: A) => any +``` + +Added in v1.0.0 + +# type lambdas + +## IdentityTypeLambda (interface) + +**Signature** + +```ts +export interface IdentityTypeLambda extends TypeLambda { + readonly type: Identity +} +``` + +Added in v1.0.0 + +## IdentityTypeLambdaFix (interface) + +**Signature** + +```ts +export interface IdentityTypeLambdaFix extends TypeLambda { + readonly type: Identity +} +``` + +Added in v1.0.0 + +# utils + +## andThen + +**Signature** + +```ts +export declare const andThen: (that: B) => <_>(self: _) => B +``` + +Added in v1.0.0 + +## ap + +**Signature** + +```ts +export declare const ap: (fa: A) => (self: (a: A) => B) => B +``` + +Added in v1.0.0 + +## composeKleisliArrow + +**Signature** + +```ts +export declare const composeKleisliArrow: (bfc: (b: B) => C) => (afb: (a: A) => B) => (a: A) => C +``` + +Added in v1.0.0 + +## element + +Adds an element to the end of a tuple. + +**Signature** + +```ts +export declare const element: (fb: B) => (self: A) => [...A, B] +``` + +Added in v1.0.0 + +## flatten + +**Signature** + +```ts +export declare const flatten: (self: A) => A +``` + +Added in v1.0.0 + +## imap + +**Signature** + +```ts +export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (self: A) => B +``` + +Added in v1.0.0 + +## liftMonoid + +**Signature** + +```ts +export declare const liftMonoid: (M: any) => any +``` + +Added in v1.0.0 + +## map + +**Signature** + +```ts +export declare const map: (f: (a: A) => B) => (self: A) => B +``` + +Added in v1.0.0 + +## struct + +**Signature** + +```ts +export declare const struct: >(r: R) => { [K in keyof R]: R[K] } +``` + +Added in v1.0.0 + +## tap + +Returns an effect that effectfully "peeks" at the success of this effect. + +**Signature** + +```ts +export declare const tap: (f: (a: A) => _) => (self: A) => A +``` + +Added in v1.0.0 + +## tuple + +**Signature** + +```ts +export declare const tuple: (...tuple: T) => { [I in keyof T]: T[I] } +``` + +Added in v1.0.0 + +## tupled + +**Signature** + +```ts +export declare const tupled: (self: A) => [A] +``` + +Added in v1.0.0 + +## unit + +**Signature** + +```ts +export declare const unit: void +``` + +Added in v1.0.0 diff --git a/docs/modules/Number.ts.md b/docs/modules/Number.ts.md new file mode 100644 index 000000000..cc6393f80 --- /dev/null +++ b/docs/modules/Number.ts.md @@ -0,0 +1,268 @@ +--- +title: Number.ts +nav_order: 8 +parent: Modules +--- + +## Number overview + +This module provides utility functions and type class instances for working with the `number` type in TypeScript. +It includes functions for basic arithmetic operations, as well as type class instances for +`Equivalence`, `Order`, `Semigroup`, and `Monoid`. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [guards](#guards) + - [isNumber](#isnumber) +- [instances](#instances) + - [Bounded](#bounded) + - [Equivalence](#equivalence) + - [MonoidMax](#monoidmax) + - [MonoidMin](#monoidmin) + - [MonoidMultiply](#monoidmultiply) + - [MonoidSum](#monoidsum) + - [Order](#order) + - [SemigroupMax](#semigroupmax) + - [SemigroupMin](#semigroupmin) + - [SemigroupMultiply](#semigroupmultiply) + - [SemigroupSum](#semigroupsum) +- [utils](#utils) + - [decrement](#decrement) + - [divide](#divide) + - [increment](#increment) + - [multiply](#multiply) + - [sign](#sign) + - [subtract](#subtract) + - [sum](#sum) + +--- + +# guards + +## isNumber + +**Signature** + +```ts +export declare const isNumber: any +``` + +Added in v1.0.0 + +# instances + +## Bounded + +**Signature** + +```ts +export declare const Bounded: any +``` + +Added in v1.0.0 + +## Equivalence + +**Signature** + +```ts +export declare const Equivalence: any +``` + +Added in v1.0.0 + +## MonoidMax + +**Signature** + +```ts +export declare const MonoidMax: any +``` + +Added in v1.0.0 + +## MonoidMin + +**Signature** + +```ts +export declare const MonoidMin: any +``` + +Added in v1.0.0 + +## MonoidMultiply + +`number` monoid under multiplication. + +The `empty` value is `1`. + +**Signature** + +```ts +export declare const MonoidMultiply: any +``` + +Added in v1.0.0 + +## MonoidSum + +`number` monoid under addition. + +The `empty` value is `0`. + +**Signature** + +```ts +export declare const MonoidSum: any +``` + +Added in v1.0.0 + +## Order + +**Signature** + +```ts +export declare const Order: any +``` + +Added in v1.0.0 + +## SemigroupMax + +**Signature** + +```ts +export declare const SemigroupMax: any +``` + +Added in v1.0.0 + +## SemigroupMin + +**Signature** + +```ts +export declare const SemigroupMin: any +``` + +Added in v1.0.0 + +## SemigroupMultiply + +`number` semigroup under multiplication. + +**Signature** + +```ts +export declare const SemigroupMultiply: any +``` + +**Example** + +```ts +import { SemigroupMultiply } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(SemigroupMultiply.combine(2, 3), 6) +``` + +Added in v1.0.0 + +## SemigroupSum + +`number` semigroup under addition. + +**Signature** + +```ts +export declare const SemigroupSum: any +``` + +**Example** + +```ts +import { SemigroupSum } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(SemigroupSum.combine(2, 3), 5) +``` + +Added in v1.0.0 + +# utils + +## decrement + +**Signature** + +```ts +export declare const decrement: (n: number) => number +``` + +Added in v1.0.0 + +## divide + +**Signature** + +```ts +export declare const divide: (that: number) => (self: number) => number +``` + +Added in v1.0.0 + +## increment + +**Signature** + +```ts +export declare const increment: (n: number) => number +``` + +Added in v1.0.0 + +## multiply + +**Signature** + +```ts +export declare const multiply: (that: number) => (self: number) => number +``` + +Added in v1.0.0 + +## sign + +**Signature** + +```ts +export declare const sign: (n: number) => any +``` + +Added in v1.0.0 + +## subtract + +**Signature** + +```ts +export declare const subtract: (that: number) => (self: number) => number +``` + +Added in v1.0.0 + +## sum + +**Signature** + +```ts +export declare const sum: (that: number) => (self: number) => number +``` + +Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md new file mode 100644 index 000000000..0ddc1bdb9 --- /dev/null +++ b/docs/modules/Option.ts.md @@ -0,0 +1,1520 @@ +--- +title: Option.ts +nav_order: 9 +parent: Modules +--- + +## Option overview + +The `Option` type can be interpreted in a few ways: + +1. `Option
` is a container for an optional value of type `A`. If the value of type `A` is present, the `Option` is + an instance of `Some`, containing the present value of type `A`. If the value is absent, the `Option` is an + instance of `None`. +2. Another way to view `Option` is as a representation of a possibly failing computation. +3. An option can also be thought of as a collection or foldable structure with either one or zero elements. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [combining](#combining) + - [getFirstNoneMonoid](#getfirstnonemonoid) + - [getFirstNoneSemigroup](#getfirstnonesemigroup) + - [getFirstSomeSemigroup](#getfirstsomesemigroup) +- [constructors](#constructors) + - [none](#none) + - [of](#of) + - [some](#some) +- [conversions](#conversions) + - [fromEither](#fromeither) + - [fromIterable](#fromiterable) + - [fromNullable](#fromnullable) + - [getOrNull](#getornull) + - [getOrUndefined](#getorundefined) + - [toEither](#toeither) + - [toRefinement](#torefinement) +- [debugging](#debugging) + - [inspectNone](#inspectnone) + - [inspectSome](#inspectsome) +- [do notation](#do-notation) + - [Do](#do) + - [andThenBind](#andthenbind) + - [bind](#bind) + - [bindTo](#bindto) + - [let](#let) +- [error handling](#error-handling) + - [catchAll](#catchall) + - [firstSomeOf](#firstsomeof) + - [getOrElse](#getorelse) + - [orElse](#orelse) + - [orElseEither](#orelseeither) + - [orElseSucceed](#orelsesucceed) +- [filtering](#filtering) + - [compact](#compact) + - [filter](#filter) + - [filterMap](#filtermap) + - [separate](#separate) +- [guards](#guards) + - [isNone](#isnone) + - [isOption](#isoption) + - [isSome](#issome) +- [instances](#instances) + - [Alternative](#alternative) + - [Applicative](#applicative) + - [Chainable](#chainable) + - [Compactable](#compactable) + - [Coproduct](#coproduct) + - [Covariant](#covariant) + - [Filterable](#filterable) + - [FlatMap](#flatmap) + - [Foldable](#foldable) + - [Invariant](#invariant) + - [Monad](#monad) + - [Of](#of) + - [Pointed](#pointed) + - [Product](#product) + - [SemiAlternative](#semialternative) + - [SemiApplicative](#semiapplicative) + - [SemiCoproduct](#semicoproduct) + - [SemiProduct](#semiproduct) + - [Traversable](#traversable) +- [interop](#interop) + - [fromThrowable](#fromthrowable) + - [getOrThrow](#getorthrow) + - [liftThrowable](#liftthrowable) +- [lifting](#lifting) + - [getMonoid](#getmonoid) + - [lift2](#lift2) + - [lift3](#lift3) + - [liftEither](#lifteither) + - [liftNullable](#liftnullable) + - [liftPredicate](#liftpredicate) +- [mapping](#mapping) + - [as](#as) + - [asUnit](#asunit) + - [flap](#flap) + - [imap](#imap) + - [map](#map) +- [models](#models) + - [None (type alias)](#none-type-alias) + - [Option (type alias)](#option-type-alias) + - [Some (type alias)](#some-type-alias) +- [pattern matching](#pattern-matching) + - [match](#match) +- [sequencing](#sequencing) + - [andThenDiscard](#andthendiscard) + - [flatMap](#flatmap) + - [flatMapEither](#flatmapeither) + - [flatMapNullable](#flatmapnullable) +- [sorting](#sorting) + - [liftOrder](#liftorder) +- [traversing](#traversing) + - [sequence](#sequence) + - [traverse](#traverse) + - [traverseTap](#traversetap) +- [type lambdas](#type-lambdas) + - [OptionTypeLambda (interface)](#optiontypelambda-interface) +- [utils](#utils) + - [andThen](#andthen) + - [ap](#ap) + - [composeKleisliArrow](#composekleisliarrow) + - [contains](#contains) + - [coproductEither](#coproducteither) + - [element](#element) + - [exists](#exists) + - [flatten](#flatten) + - [struct](#struct) + - [tap](#tap) + - [toArray](#toarray) + - [tuple](#tuple) + - [tupled](#tupled) + - [unit](#unit) + +--- + +# combining + +## getFirstNoneMonoid + +Monoid returning the left-most `None` value. If both operands are `Right`s then the inner values +are concatenated using the provided `Monoid`. + +The `empty` value is `some(M.empty)`. + +**Signature** + +```ts +export declare const getFirstNoneMonoid:
(M: any) => any +``` + +Added in v1.0.0 + +## getFirstNoneSemigroup + +Semigroup returning the left-most `None` value. If both operands are `Right`s then the inner values +are concatenated using the provided `Semigroup`. + +**Signature** + +```ts +export declare const getFirstNoneSemigroup: (S: any) => any +``` + +Added in v1.0.0 + +## getFirstSomeSemigroup + +Semigroup returning the left-most `Some` value. + +**Signature** + +```ts +export declare const getFirstSomeSemigroup: () => any +``` + +Added in v1.0.0 + +# constructors + +## none + +**Signature** + +```ts +export declare const none: () => Option +``` + +Added in v1.0.0 + +## of + +**Signature** + +```ts +export declare const of: (a: A) => Option +``` + +Added in v1.0.0 + +## some + +**Signature** + +```ts +export declare const some: (a: A) => Option +``` + +Added in v1.0.0 + +# conversions + +## fromEither + +Converts a `Either` to an `Option` discarding the error. + +**Signature** + +```ts +export declare const fromEither: (self: any) => Option +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(O.fromEither(E.right(1)), O.some(1)) +assert.deepStrictEqual(O.fromEither(E.left('a')), O.none()) +``` + +Added in v1.0.0 + +## fromIterable + +**Signature** + +```ts +export declare const fromIterable: (collection: Iterable) => Option +``` + +Added in v1.0.0 + +## fromNullable + +Constructs a new `Option` from a nullable type. If the value is `null` or `undefined`, returns `None`, otherwise +returns the value wrapped in a `Some`. + +**Signature** + +```ts +export declare const fromNullable: (a: A) => Option> +``` + +**Example** + +```ts +import { none, some, fromNullable } from '@fp-ts/core/Option' + +assert.deepStrictEqual(fromNullable(undefined), none()) +assert.deepStrictEqual(fromNullable(null), none()) +assert.deepStrictEqual(fromNullable(1), some(1)) +``` + +Added in v1.0.0 + +## getOrNull + +Extracts the value out of the structure, if it exists. Otherwise returns `null`. + +**Signature** + +```ts +export declare const getOrNull: (self: Option) => A | null +``` + +**Example** + +```ts +import { some, none, getOrNull } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +assert.strictEqual(pipe(some(1), getOrNull), 1) +assert.strictEqual(pipe(none(), getOrNull), null) +``` + +Added in v1.0.0 + +## getOrUndefined + +Extracts the value out of the structure, if it exists. Otherwise returns `undefined`. + +**Signature** + +```ts +export declare const getOrUndefined: (self: Option) => A | undefined +``` + +**Example** + +```ts +import { some, none, getOrUndefined } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +assert.strictEqual(pipe(some(1), getOrUndefined), 1) +assert.strictEqual(pipe(none(), getOrUndefined), undefined) +``` + +Added in v1.0.0 + +## toEither + +**Signature** + +```ts +export declare const toEither: (onNone: any) => (self: Option) => any +``` + +Added in v1.0.0 + +## toRefinement + +Returns a `Refinement` from a `Option` returning function. +This function ensures that a `Refinement` definition is type-safe. + +**Signature** + +```ts +export declare const toRefinement: (f: (a: A) => Option) => any +``` + +Added in v1.0.0 + +# debugging + +## inspectNone + +**Signature** + +```ts +export declare const inspectNone: (onNone: () => void) => (self: Option) => Option +``` + +Added in v1.0.0 + +## inspectSome + +**Signature** + +```ts +export declare const inspectSome: (onSome: (a: A) => void) => (self: Option) => Option +``` + +Added in v1.0.0 + +# do notation + +## Do + +**Signature** + +```ts +export declare const Do: Option<{}> +``` + +Added in v1.0.0 + +## andThenBind + +A variant of `bind` that sequentially ignores the scope. + +**Signature** + +```ts +export declare const andThenBind: ( + name: Exclude, + that: Option +) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +``` + +Added in v1.0.0 + +## bind + +**Signature** + +```ts +export declare const bind: ( + name: Exclude, + f: (a: A) => Option +) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +``` + +Added in v1.0.0 + +## bindTo + +**Signature** + +```ts +export declare const bindTo: (name: N) => (self: Option) => Option<{ [K in N]: A }> +``` + +Added in v1.0.0 + +## let + +**Signature** + +```ts +export declare const let: ( + name: Exclude, + f: (a: A) => B +) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +``` + +Added in v1.0.0 + +# error handling + +## catchAll + +Lazy version of `orElse`. + +**Signature** + +```ts +export declare const catchAll: (that: any) => (self: Option) => Option +``` + +Added in v1.0.0 + +## firstSomeOf + +**Signature** + +```ts +export declare const firstSomeOf: (collection: Iterable>) => (self: Option) => Option +``` + +Added in v1.0.0 + +## getOrElse + +Extracts the value out of the structure, if it exists. Otherwise returns the given default value + +**Signature** + +```ts +export declare const getOrElse: (onNone: any) => (self: Option) => B | A +``` + +**Example** + +```ts +import { some, none, getOrElse } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +assert.strictEqual( + pipe( + some(1), + getOrElse(() => 0) + ), + 1 +) +assert.strictEqual( + pipe( + none(), + getOrElse(() => 0) + ), + 0 +) +``` + +Added in v1.0.0 + +## orElse + +Identifies an associative operation on a type constructor. It is similar to `Semigroup`, except that it applies to +types of kind `* -> *`. + +In case of `Option` returns the left-most non-`None` value. + +| x | y | pipe(x, orElse(y) | +| ------- | ------- | ----------------- | +| none | none | none | +| some(a) | none | some(a) | +| none | some(b) | some(b) | +| some(a) | some(b) | some(a) | + +**Signature** + +```ts +export declare const orElse: (that: Option) => (self: Option) => Option +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(O.none(), O.orElse(O.none())), O.none()) +assert.deepStrictEqual(pipe(O.some('a'), O.orElse(O.none())), O.some('a')) +assert.deepStrictEqual(pipe(O.none(), O.orElse(O.some('b'))), O.some('b')) +assert.deepStrictEqual(pipe(O.some('a'), O.orElse(O.some('b'))), O.some('a')) +``` + +Added in v1.0.0 + +## orElseEither + +Returns an effect that will produce the value of this effect, unless it +fails, in which case, it will produce the value of the specified effect. + +**Signature** + +```ts +export declare const orElseEither: (that: Option) => (self: Option) => Option +``` + +Added in v1.0.0 + +## orElseSucceed + +Executes this effect and returns its value, if it succeeds, but otherwise +succeeds with the specified value. + +**Signature** + +```ts +export declare const orElseSucceed: (onNone: () => B) => (self: Option) => Option +``` + +Added in v1.0.0 + +# filtering + +## compact + +Alias of `flatten`. + +**Signature** + +```ts +export declare const compact: (self: Option>) => Option +``` + +Added in v1.0.0 + +## filter + +**Signature** + +```ts +export declare const filter: { + (refinement: any): (fc: Option) => Option + (predicate: any): (fb: Option) => Option +} +``` + +Added in v1.0.0 + +## filterMap + +**Signature** + +```ts +export declare const filterMap: (f: (a: A) => Option) => (self: Option) => Option +``` + +Added in v1.0.0 + +## separate + +**Signature** + +```ts +export declare const separate: (self: Option) => [Option, Option] +``` + +Added in v1.0.0 + +# guards + +## isNone + +Returns `true` if the option is `None`, `false` otherwise. + +**Signature** + +```ts +export declare const isNone: (self: Option) => self is None +``` + +**Example** + +```ts +import { some, none, isNone } from '@fp-ts/core/Option' + +assert.strictEqual(isNone(some(1)), false) +assert.strictEqual(isNone(none()), true) +``` + +Added in v1.0.0 + +## isOption + +Returns `true` if the specified value is an instance of `Option`, `false` +otherwise. + +**Signature** + +```ts +export declare const isOption: (u: unknown) => u is Option +``` + +**Example** + +```ts +import { some, none, isOption } from '@fp-ts/core/Option' + +assert.strictEqual(isOption(some(1)), true) +assert.strictEqual(isOption(none()), true) +assert.strictEqual(isOption({}), false) +``` + +Added in v1.0.0 + +## isSome + +Returns `true` if the option is an instance of `Some`, `false` otherwise. + +**Signature** + +```ts +export declare const isSome: (self: Option) => self is Some +``` + +**Example** + +```ts +import { some, none, isSome } from '@fp-ts/core/Option' + +assert.strictEqual(isSome(some(1)), true) +assert.strictEqual(isSome(none()), false) +``` + +Added in v1.0.0 + +# instances + +## Alternative + +**Signature** + +```ts +export declare const Alternative: any +``` + +Added in v1.0.0 + +## Applicative + +**Signature** + +```ts +export declare const Applicative: any +``` + +Added in v1.0.0 + +## Chainable + +**Signature** + +```ts +export declare const Chainable: any +``` + +Added in v1.0.0 + +## Compactable + +**Signature** + +```ts +export declare const Compactable: any +``` + +Added in v1.0.0 + +## Coproduct + +**Signature** + +```ts +export declare const Coproduct: any +``` + +Added in v1.0.0 + +## Covariant + +**Signature** + +```ts +export declare const Covariant: any +``` + +Added in v1.0.0 + +## Filterable + +**Signature** + +```ts +export declare const Filterable: any +``` + +Added in v1.0.0 + +## FlatMap + +**Signature** + +```ts +export declare const FlatMap: any +``` + +Added in v1.0.0 + +## Foldable + +**Signature** + +```ts +export declare const Foldable: any +``` + +Added in v1.0.0 + +## Invariant + +**Signature** + +```ts +export declare const Invariant: any +``` + +Added in v1.0.0 + +## Monad + +**Signature** + +```ts +export declare const Monad: any +``` + +Added in v1.0.0 + +## Of + +**Signature** + +```ts +export declare const Of: any +``` + +Added in v1.0.0 + +## Pointed + +**Signature** + +```ts +export declare const Pointed: any +``` + +Added in v1.0.0 + +## Product + +**Signature** + +```ts +export declare const Product: any +``` + +Added in v1.0.0 + +## SemiAlternative + +**Signature** + +```ts +export declare const SemiAlternative: any +``` + +Added in v1.0.0 + +## SemiApplicative + +**Signature** + +```ts +export declare const SemiApplicative: any +``` + +Added in v1.0.0 + +## SemiCoproduct + +**Signature** + +```ts +export declare const SemiCoproduct: any +``` + +Added in v1.0.0 + +## SemiProduct + +**Signature** + +```ts +export declare const SemiProduct: any +``` + +Added in v1.0.0 + +## Traversable + +**Signature** + +```ts +export declare const Traversable: any +``` + +Added in v1.0.0 + +# interop + +## fromThrowable + +Converts an exception into an `Option`. If `f` throws, returns `None`, otherwise returns the output wrapped in a +`Some`. + +**Signature** + +```ts +export declare const fromThrowable: (f: () => A) => Option +``` + +**Example** + +```ts +import { none, some, fromThrowable } from '@fp-ts/core/Option' + +assert.deepStrictEqual( + fromThrowable(() => { + throw new Error() + }), + none() +) +assert.deepStrictEqual( + fromThrowable(() => 1), + some(1) +) +``` + +Added in v1.0.0 + +## getOrThrow + +**Signature** + +```ts +export declare const getOrThrow: (onError: any) => (self: Option) => A +``` + +Added in v1.0.0 + +## liftThrowable + +Lifts a function that may throw to one returning a `Option`. + +**Signature** + +```ts +export declare const liftThrowable: (f: (...a: A) => B) => (...a: A) => Option +``` + +Added in v1.0.0 + +# lifting + +## getMonoid + +Monoid returning the left-most non-`None` value. If both operands are `Some`s then the inner values are +combined using the provided `Semigroup` + +| x | y | combine(y)(x) | +| ------- | ------- | ------------------- | +| none | none | none | +| some(a) | none | some(a) | +| none | some(a) | some(a) | +| some(a) | some(b) | some(combine(b)(a)) | + +**Signature** + +```ts +export declare const getMonoid: (Semigroup: any) => any +``` + +**Example** + +```ts +import { getMonoid, some, none } from '@fp-ts/core/Option' +import * as N from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +const M = getMonoid(N.SemigroupSum) +assert.deepStrictEqual(M.combine(none(), none()), none()) +assert.deepStrictEqual(M.combine(some(1), none()), some(1)) +assert.deepStrictEqual(M.combine(none(), some(1)), some(1)) +assert.deepStrictEqual(M.combine(some(1), some(2)), some(3)) +``` + +Added in v1.0.0 + +## lift2 + +Lifts a binary function into `Option`. + +**Signature** + +```ts +export declare const lift2: (f: (a: A, b: B) => C) => (fa: Option, fb: Option) => Option +``` + +Added in v1.0.0 + +## lift3 + +Lifts a ternary function into `Option`. + +**Signature** + +```ts +export declare const lift3: ( + f: (a: A, b: B, c: C) => D +) => (fa: Option, fb: Option, fc: Option) => Option +``` + +Added in v1.0.0 + +## liftEither + +**Signature** + +```ts +export declare const liftEither: (f: (...a: A) => any) => (...a: A) => Option +``` + +Added in v1.0.0 + +## liftNullable + +Returns a _smart constructor_ from a function that returns a nullable value. + +**Signature** + +```ts +export declare const liftNullable: ( + f: (...a: A) => B | null | undefined +) => (...a: A) => Option> +``` + +**Example** + +```ts +import { liftNullable, none, some } from '@fp-ts/core/Option' + +const f = (s: string): number | undefined => { + const n = parseFloat(s) + return isNaN(n) ? undefined : n +} + +const g = liftNullable(f) + +assert.deepStrictEqual(g('1'), some(1)) +assert.deepStrictEqual(g('a'), none()) +``` + +Added in v1.0.0 + +## liftPredicate + +Returns a _smart constructor_ based on the given predicate. + +**Signature** + +```ts +export declare const liftPredicate: { + (refinement: any): (c: C) => Option + (predicate: any): (b: B) => Option +} +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +const getOption = O.liftPredicate((n: number) => n >= 0) + +assert.deepStrictEqual(getOption(-1), O.none()) +assert.deepStrictEqual(getOption(1), O.some(1)) +``` + +Added in v1.0.0 + +# mapping + +## as + +Maps the success value of this effect to the specified constant value. + +**Signature** + +```ts +export declare const as: (b: B) => <_>(self: Option<_>) => Option +``` + +Added in v1.0.0 + +## asUnit + +Returns the effect resulting from mapping the success of this effect to unit. + +**Signature** + +```ts +export declare const asUnit: <_>(self: Option<_>) => Option +``` + +Added in v1.0.0 + +## flap + +**Signature** + +```ts +export declare const flap: (a: A) => (fab: Option<(a: A) => B>) => Option +``` + +Added in v1.0.0 + +## imap + +**Signature** + +```ts +export declare const imap: any +``` + +Added in v1.0.0 + +## map + +Returns an effect whose success is mapped by the specified `f` function. + +**Signature** + +```ts +export declare const map: (f: (a: A) => B) => (self: Option) => Option +``` + +Added in v1.0.0 + +# models + +## None (type alias) + +**Signature** + +```ts +export type None = { + readonly _tag: 'None' +} +``` + +Added in v1.0.0 + +## Option (type alias) + +**Signature** + +```ts +export type Option = None | Some +``` + +Added in v1.0.0 + +## Some (type alias) + +**Signature** + +```ts +export type Some = { + readonly _tag: 'Some' + readonly value: A +} +``` + +Added in v1.0.0 + +# pattern matching + +## match + +Takes a (lazy) default value, a function, and an `Option` value, if the `Option` value is `None` the default value is +returned, otherwise the function is applied to the value inside the `Some` and the result is returned. + +**Signature** + +```ts +export declare const match: (onNone: any, onSome: (a: A) => C) => (self: Option) => B | C +``` + +**Example** + +```ts +import { some, none, match } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +assert.strictEqual( + pipe( + some(1), + match( + () => 'a none', + (a) => `a some containing ${a}` + ) + ), + 'a some containing 1' +) + +assert.strictEqual( + pipe( + none(), + match( + () => 'a none', + (a) => `a some containing ${a}` + ) + ), + 'a none' +) +``` + +Added in v1.0.0 + +# sequencing + +## andThenDiscard + +Sequences the specified effect after this effect, but ignores the value +produced by the effect. + +**Signature** + +```ts +export declare const andThenDiscard: <_>(that: Option<_>) => (self: Option) => Option +``` + +Added in v1.0.0 + +## flatMap + +**Signature** + +```ts +export declare const flatMap: (f: (a: A) => Option) => (self: Option) => Option +``` + +Added in v1.0.0 + +## flatMapEither + +**Signature** + +```ts +export declare const flatMapEither: (f: (a: A) => any) => (self: Option) => Option +``` + +Added in v1.0.0 + +## flatMapNullable + +This is `flatMap` + `fromNullable`, useful when working with optional values. + +**Signature** + +```ts +export declare const flatMapNullable: ( + f: (a: A) => B | null | undefined +) => (self: Option) => Option> +``` + +**Example** + +```ts +import { some, none, fromNullable, flatMapNullable } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +interface Employee { + company?: { + address?: { + street?: { + name?: string + } + } + } +} + +const employee1: Employee = { company: { address: { street: { name: 'high street' } } } } + +assert.deepStrictEqual( + pipe( + fromNullable(employee1.company), + flatMapNullable((company) => company.address), + flatMapNullable((address) => address.street), + flatMapNullable((street) => street.name) + ), + some('high street') +) + +const employee2: Employee = { company: { address: { street: {} } } } + +assert.deepStrictEqual( + pipe( + fromNullable(employee2.company), + flatMapNullable((company) => company.address), + flatMapNullable((address) => address.street), + flatMapNullable((street) => street.name) + ), + none() +) +``` + +Added in v1.0.0 + +# sorting + +## liftOrder + +The `Order` instance allows `Option` values to be compared with +`compare`, whenever there is an `Order` instance for +the type the `Option` contains. + +`None` is considered to be less than any `Some` value. + +**Signature** + +```ts +export declare const liftOrder: (O: any) => any +``` + +**Example** + +```ts +import { none, some, liftOrder } from '@fp-ts/core/Option' +import * as N from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +const O = liftOrder(N.Order) +assert.strictEqual(O.compare(none(), none()), 0) +assert.strictEqual(O.compare(none(), some(1)), -1) +assert.strictEqual(O.compare(some(1), none()), 1) +assert.strictEqual(O.compare(some(1), some(2)), -1) +assert.strictEqual(O.compare(some(1), some(1)), 0) +``` + +Added in v1.0.0 + +# traversing + +## sequence + +**Signature** + +```ts +export declare const sequence: (F: any) => (fas: Option) => any +``` + +Added in v1.0.0 + +## traverse + +**Signature** + +```ts +export declare const traverse: (F: any) => (f: (a: A) => any) => (self: Option) => any +``` + +Added in v1.0.0 + +## traverseTap + +**Signature** + +```ts +export declare const traverseTap: ( + F: any +) => (f: (a: A) => any) => (self: Option) => any +``` + +Added in v1.0.0 + +# type lambdas + +## OptionTypeLambda (interface) + +**Signature** + +```ts +export interface OptionTypeLambda extends TypeLambda { + readonly type: Option +} +``` + +Added in v1.0.0 + +# utils + +## andThen + +**Signature** + +```ts +export declare const andThen: (that: Option) => <_>(self: Option<_>) => Option +``` + +Added in v1.0.0 + +## ap + +**Signature** + +```ts +export declare const ap: (fa: Option) => (self: Option<(a: A) => B>) => Option +``` + +Added in v1.0.0 + +## composeKleisliArrow + +**Signature** + +```ts +export declare const composeKleisliArrow: ( + bfc: (b: B) => Option +) => (afb: (a: A) => Option) => (a: A) => Option +``` + +Added in v1.0.0 + +## contains + +Returns a function that checks if an `Option` contains a given value using a provided `equivalence` function. + +**Signature** + +```ts +export declare const contains: (equivalence: any) => (a: A) => (self: Option) => boolean +``` + +Added in v1.0.0 + +## coproductEither + +**Signature** + +```ts +export declare const coproductEither: (that: Option) => (self: Option) => Option +``` + +Added in v1.0.0 + +## element + +Adds an element to the end of a tuple. + +**Signature** + +```ts +export declare const element: (fb: Option) => (self: Option) => Option<[...A, B]> +``` + +Added in v1.0.0 + +## exists + +Returns `true` if the predicate is satisfied by the wrapped value + +**Signature** + +```ts +export declare const exists: (predicate: any) => (self: Option) => boolean +``` + +**Example** + +```ts +import { some, none, exists } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +assert.strictEqual( + pipe( + some(1), + exists((n) => n > 0) + ), + true +) +assert.strictEqual( + pipe( + some(1), + exists((n) => n > 1) + ), + false +) +assert.strictEqual( + pipe( + none(), + exists((n) => n > 0) + ), + false +) +``` + +Added in v1.0.0 + +## flatten + +**Signature** + +```ts +export declare const flatten: (self: Option>) => Option +``` + +Added in v1.0.0 + +## struct + +**Signature** + +```ts +export declare const struct: >>( + r: R +) => Option<{ [K in keyof R]: [R[K]] extends [Option] ? A : never }> +``` + +Added in v1.0.0 + +## tap + +Returns an effect that effectfully "peeks" at the success of this effect. + +**Signature** + +```ts +export declare const tap: (f: (a: A) => Option<_>) => (self: Option) => Option +``` + +Added in v1.0.0 + +## toArray + +**Signature** + +```ts +export declare const toArray: (self: Option) => A[] +``` + +Added in v1.0.0 + +## tuple + +**Signature** + +```ts +export declare const tuple: []>( + ...tuple: T +) => Option<{ [I in keyof T]: [T[I]] extends [Option] ? A : never }> +``` + +Added in v1.0.0 + +## tupled + +**Signature** + +```ts +export declare const tupled: (self: Option) => Option<[A]> +``` + +Added in v1.0.0 + +## unit + +**Signature** + +```ts +export declare const unit: Option +``` + +Added in v1.0.0 diff --git a/docs/modules/Ordering.ts.md b/docs/modules/Ordering.ts.md new file mode 100644 index 000000000..e2bb1b904 --- /dev/null +++ b/docs/modules/Ordering.ts.md @@ -0,0 +1,87 @@ +--- +title: Ordering.ts +nav_order: 10 +parent: Modules +--- + +## Ordering overview + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [instances](#instances) + - [Monoid](#monoid) + - [Semigroup](#semigroup) +- [model](#model) + - [Ordering (type alias)](#ordering-type-alias) +- [pattern matching](#pattern-matching) + - [match](#match) +- [utils](#utils) + - [reverse](#reverse) + +--- + +# instances + +## Monoid + +**Signature** + +```ts +export declare const Monoid: any +``` + +Added in v1.0.0 + +## Semigroup + +**Signature** + +```ts +export declare const Semigroup: any +``` + +Added in v1.0.0 + +# model + +## Ordering (type alias) + +**Signature** + +```ts +export type Ordering = -1 | 0 | 1 +``` + +Added in v1.0.0 + +# pattern matching + +## match + +**Signature** + +```ts +export declare const match: ( + onLessThan: any, + onEqual: any, + onGreaterThan: any +) => (o: Ordering) => A | B | C +``` + +Added in v1.0.0 + +# utils + +## reverse + +**Signature** + +```ts +export declare const reverse: (o: Ordering) => Ordering +``` + +Added in v1.0.0 diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md new file mode 100644 index 000000000..e661d80a1 --- /dev/null +++ b/docs/modules/Predicate.ts.md @@ -0,0 +1,443 @@ +--- +title: Predicate.ts +nav_order: 11 +parent: Modules +--- + +## Predicate overview + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [constructors](#constructors) + - [id](#id) +- [do notation](#do-notation) + - [bindTo](#bindto) +- [guards](#guards) + - [isBigInt](#isbigint) + - [isBoolean](#isboolean) + - [isNumber](#isnumber) + - [isString](#isstring) + - [isSymbol](#issymbol) +- [instances](#instances) + - [Contravariant](#contravariant) + - [Invariant](#invariant) + - [Of](#of) + - [Product](#product) + - [SemiProduct](#semiproduct) + - [getMonoidAll](#getmonoidall) + - [getMonoidAny](#getmonoidany) + - [getSemigroupAll](#getsemigroupall) + - [getSemigroupAny](#getsemigroupany) +- [models](#models) + - [Predicate (interface)](#predicate-interface) +- [type lambdas](#type-lambdas) + - [PredicateTypeLambda (interface)](#predicatetypelambda-interface) +- [utils](#utils) + - [Do](#do) + - [Refinement (interface)](#refinement-interface) + - [all](#all) + - [and](#and) + - [andThenBind](#andthenbind) + - [any](#any) + - [compose](#compose) + - [contramap](#contramap) + - [element](#element) + - [imap](#imap) + - [not](#not) + - [of](#of) + - [or](#or) + - [struct](#struct) + - [tuple](#tuple) + - [tupled](#tupled) + - [unit](#unit) + +--- + +# constructors + +## id + +**Signature** + +```ts +export declare const id:
() => Refinement +``` + +Added in v1.0.0 + +# do notation + +## bindTo + +**Signature** + +```ts +export declare const bindTo: ( + name: N +) => (self: Predicate) => Predicate<{ readonly [K in N]: A }> +``` + +Added in v1.0.0 + +# guards + +## isBigInt + +**Signature** + +```ts +export declare const isBigInt: (u: unknown) => u is bigint +``` + +Added in v1.0.0 + +## isBoolean + +**Signature** + +```ts +export declare const isBoolean: Refinement +``` + +Added in v1.0.0 + +## isNumber + +**Signature** + +```ts +export declare const isNumber: Refinement +``` + +Added in v1.0.0 + +## isString + +**Signature** + +```ts +export declare const isString: Refinement +``` + +Added in v1.0.0 + +## isSymbol + +**Signature** + +```ts +export declare const isSymbol: (u: unknown) => u is symbol +``` + +Added in v1.0.0 + +# instances + +## Contravariant + +**Signature** + +```ts +export declare const Contravariant: any +``` + +Added in v1.0.0 + +## Invariant + +**Signature** + +```ts +export declare const Invariant: any +``` + +Added in v1.0.0 + +## Of + +**Signature** + +```ts +export declare const Of: any +``` + +Added in v1.0.0 + +## Product + +**Signature** + +```ts +export declare const Product: any +``` + +Added in v1.0.0 + +## SemiProduct + +**Signature** + +```ts +export declare const SemiProduct: any +``` + +Added in v1.0.0 + +## getMonoidAll + +**Signature** + +```ts +export declare const getMonoidAll: () => any +``` + +Added in v1.0.0 + +## getMonoidAny + +**Signature** + +```ts +export declare const getMonoidAny: () => any +``` + +Added in v1.0.0 + +## getSemigroupAll + +**Signature** + +```ts +export declare const getSemigroupAll: () => any +``` + +Added in v1.0.0 + +## getSemigroupAny + +**Signature** + +```ts +export declare const getSemigroupAny: () => any +``` + +Added in v1.0.0 + +# models + +## Predicate (interface) + +**Signature** + +```ts +export interface Predicate { + (a: A): boolean +} +``` + +Added in v1.0.0 + +# type lambdas + +## PredicateTypeLambda (interface) + +**Signature** + +```ts +export interface PredicateTypeLambda extends TypeLambda { + readonly type: Predicate +} +``` + +Added in v1.0.0 + +# utils + +## Do + +**Signature** + +```ts +export declare const Do: Predicate<{}> +``` + +Added in v1.0.0 + +## Refinement (interface) + +**Signature** + +```ts +export interface Refinement { + (a: A): a is B +} +``` + +Added in v1.0.0 + +## all + +**Signature** + +```ts +export declare const all: (collection: Iterable>) => Predicate +``` + +Added in v1.0.0 + +## and + +**Signature** + +```ts +export declare const and: (that: Predicate) => (self: Predicate) => Predicate +``` + +Added in v1.0.0 + +## andThenBind + +**Signature** + +```ts +export declare const andThenBind: ( + name: Exclude, + that: Predicate +) => (self: Predicate) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> +``` + +Added in v1.0.0 + +## any + +**Signature** + +```ts +export declare const any: (collection: Iterable>) => Predicate +``` + +Added in v1.0.0 + +## compose + +**Signature** + +```ts +export declare const compose: ( + bc: Refinement +) => (ab: Refinement) => Refinement +``` + +Added in v1.0.0 + +## contramap + +**Signature** + +```ts +export declare const contramap: (f: (b: B) => A) => (self: Predicate) => Predicate +``` + +Added in v1.0.0 + +## element + +Adds an element to the end of a tuple. + +**Signature** + +```ts +export declare const element: ( + that: Predicate +) => (self: Predicate) => Predicate +``` + +Added in v1.0.0 + +## imap + +**Signature** + +```ts +export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (self: Predicate) => Predicate +``` + +Added in v1.0.0 + +## not + +**Signature** + +```ts +export declare const not: (self: Predicate) => Predicate +``` + +Added in v1.0.0 + +## of + +**Signature** + +```ts +export declare const of: (_: A) => Predicate +``` + +Added in v1.0.0 + +## or + +**Signature** + +```ts +export declare const or: (that: Predicate) => (self: Predicate) => Predicate +``` + +Added in v1.0.0 + +## struct + +**Signature** + +```ts +export declare const struct: >>( + predicates: R +) => Predicate<{ readonly [K in keyof R]: [R[K]] extends [Predicate] ? A : never }> +``` + +Added in v1.0.0 + +## tuple + +**Signature** + +```ts +export declare const tuple: []>( + ...predicates: T +) => Predicate] ? A : never }>> +``` + +Added in v1.0.0 + +## tupled + +**Signature** + +```ts +export declare const tupled: (self: Predicate) => Predicate +``` + +Added in v1.0.0 + +## unit + +**Signature** + +```ts +export declare const unit: Predicate +``` + +Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md new file mode 100644 index 000000000..5a5b47479 --- /dev/null +++ b/docs/modules/ReadonlyArray.ts.md @@ -0,0 +1,2438 @@ +--- +title: ReadonlyArray.ts +nav_order: 12 +parent: Modules +--- + +## ReadonlyArray overview + +This module provides utility functions for working with arrays in TypeScript. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [constructors](#constructors) + - [empty](#empty) + - [make](#make) + - [makeBy](#makeby) + - [of](#of) + - [range](#range) + - [replicate](#replicate) + - [unfold](#unfold) +- [conversions](#conversions) + - [fromEither](#fromeither) + - [fromIterable](#fromiterable) + - [fromNullable](#fromnullable) + - [fromOption](#fromoption) +- [do notation](#do-notation) + - [Do](#do) + - [andThenBind](#andthenbind) + - [bind](#bind) + - [bindTo](#bindto) + - [let](#let) +- [filtering](#filtering) + - [compact](#compact) + - [filter](#filter) + - [filterMap](#filtermap) + - [filterMapWithIndex](#filtermapwithindex) + - [filterWithIndex](#filterwithindex) + - [partition](#partition) + - [partitionMap](#partitionmap) + - [partitionMapWithIndex](#partitionmapwithindex) + - [partitionWithIndex](#partitionwithindex) + - [separate](#separate) + - [span](#span) + - [traverseFilterMap](#traversefiltermap) + - [traversePartitionMap](#traversepartitionmap) +- [folding](#folding) + - [foldMap](#foldmap) + - [foldMapKind](#foldmapkind) + - [foldMapNonEmpty](#foldmapnonempty) + - [foldMapNonEmptyWithIndex](#foldmapnonemptywithindex) + - [foldMapWithIndex](#foldmapwithindex) + - [reduce](#reduce) + - [reduceKind](#reducekind) + - [reduceRight](#reduceright) + - [reduceRightKind](#reducerightkind) + - [reduceRightWithIndex](#reducerightwithindex) + - [reduceWithIndex](#reducewithindex) + - [scan](#scan) + - [scanRight](#scanright) +- [getters](#getters) + - [chunksOf](#chunksof) + - [chunksOfNonEmpty](#chunksofnonempty) + - [drop](#drop) + - [dropRight](#dropright) + - [dropWhile](#dropwhile) + - [findFirst](#findfirst) + - [findFirstIndex](#findfirstindex) + - [findLast](#findlast) + - [findLastIndex](#findlastindex) + - [get](#get) + - [head](#head) + - [headNonEmpty](#headnonempty) + - [init](#init) + - [initNonEmpty](#initnonempty) + - [last](#last) + - [lastNonEmpty](#lastnonempty) + - [lefts](#lefts) + - [length](#length) + - [rights](#rights) + - [splitAt](#splitat) + - [splitNonEmptyAt](#splitnonemptyat) + - [tail](#tail) + - [tailNonEmpty](#tailnonempty) + - [take](#take) + - [takeRight](#takeright) + - [takeWhile](#takewhile) + - [unappend](#unappend) + - [unprepend](#unprepend) +- [grouping](#grouping) + - [group](#group) + - [groupBy](#groupby) +- [instances](#instances) + - [Applicative](#applicative) + - [Chainable](#chainable) + - [Compactable](#compactable) + - [Covariant](#covariant) + - [Filterable](#filterable) + - [FlatMap](#flatmap) + - [Foldable](#foldable) + - [Invariant](#invariant) + - [Monad](#monad) + - [Of](#of) + - [Pointed](#pointed) + - [Product](#product) + - [SemiApplicative](#semiapplicative) + - [SemiProduct](#semiproduct) + - [Traversable](#traversable) + - [TraversableFilterable](#traversablefilterable) + - [getIntersectionSemigroup](#getintersectionsemigroup) + - [getMonoid](#getmonoid) + - [getSemigroup](#getsemigroup) + - [getUnionMonoid](#getunionmonoid) + - [getUnionSemigroup](#getunionsemigroup) +- [lifting](#lifting) + - [every](#every) + - [lift2](#lift2) + - [lift3](#lift3) + - [liftEither](#lifteither) + - [liftMonoid](#liftmonoid) + - [liftNullable](#liftnullable) + - [liftOption](#liftoption) + - [liftOrder](#liftorder) + - [liftPredicate](#liftpredicate) + - [liftSemigroup](#liftsemigroup) +- [mapping](#mapping) + - [as](#as) + - [flap](#flap) + - [imap](#imap) + - [map](#map) + - [mapNonEmpty](#mapnonempty) + - [mapNonEmptyWithIndex](#mapnonemptywithindex) + - [mapWithIndex](#mapwithindex) + - [tupled](#tupled) +- [models](#models) + - [NonEmptyArray (type alias)](#nonemptyarray-type-alias) + - [NonEmptyReadonlyArray (type alias)](#nonemptyreadonlyarray-type-alias) +- [pattern matching](#pattern-matching) + - [match](#match) + - [matchRight](#matchright) +- [predicates](#predicates) + - [contains](#contains) + - [isEmpty](#isempty) + - [isNonEmpty](#isnonempty) + - [some](#some) +- [sequencing](#sequencing) + - [flatMap](#flatmap) + - [flatMapNonEmpty](#flatmapnonempty) + - [flatMapNonEmptyWithIndex](#flatmapnonemptywithindex) + - [flatMapNullable](#flatmapnullable) + - [flatMapWithIndex](#flatmapwithindex) + - [flatten](#flatten) + - [flattenNonEmpty](#flattennonempty) +- [sorting](#sorting) + - [sort](#sort) + - [sortBy](#sortby) + - [sortByNonEmpty](#sortbynonempty) + - [sortNonEmpty](#sortnonempty) +- [traversing](#traversing) + - [sequence](#sequence) + - [sequenceNonEmpty](#sequencenonempty) + - [traverse](#traverse) + - [traverseNonEmpty](#traversenonempty) + - [traverseNonEmptyWithIndex](#traversenonemptywithindex) + - [traverseTap](#traversetap) + - [traverseWithIndex](#traversewithindex) +- [type lambdas](#type-lambdas) + - [ReadonlyArrayTypeLambda (interface)](#readonlyarraytypelambda-interface) +- [unsafe](#unsafe) + - [unsafeGet](#unsafeget) +- [utils](#utils) + - [ap](#ap) + - [append](#append) + - [appendAll](#appendall) + - [appendAllNonEmpty](#appendallnonempty) + - [chop](#chop) + - [chopNonEmpty](#chopnonempty) + - [composeKleisliArrow](#composekleisliarrow) + - [copy](#copy) + - [difference](#difference) + - [extend](#extend) + - [insertAt](#insertat) + - [intercalate](#intercalate) + - [intercalateNonEmpty](#intercalatenonempty) + - [intersection](#intersection) + - [intersperse](#intersperse) + - [intersperseNonEmpty](#interspersenonempty) + - [join](#join) + - [max](#max) + - [min](#min) + - [modify](#modify) + - [modifyNonEmptyHead](#modifynonemptyhead) + - [modifyNonEmptyLast](#modifynonemptylast) + - [modifyOption](#modifyoption) + - [prepend](#prepend) + - [prependAll](#prependall) + - [prependAllNonEmpty](#prependallnonempty) + - [remove](#remove) + - [replace](#replace) + - [replaceOption](#replaceoption) + - [reverse](#reverse) + - [reverseNonEmpty](#reversenonempty) + - [rotate](#rotate) + - [rotateNonEmpty](#rotatenonempty) + - [setNonEmptyHead](#setnonemptyhead) + - [setNonEmptyLast](#setnonemptylast) + - [traverseFilter](#traversefilter) + - [traversePartition](#traversepartition) + - [union](#union) + - [unionNonEmpty](#unionnonempty) + - [uniq](#uniq) + - [uniqNonEmpty](#uniqnonempty) + - [unzip](#unzip) + - [unzipNonEmpty](#unzipnonempty) + - [zip](#zip) + - [zipNonEmpty](#zipnonempty) + - [zipNonEmptyWith](#zipnonemptywith) + - [zipWith](#zipwith) + +--- + +# constructors + +## empty + +**Signature** + +```ts +export declare const empty:
() => A[] +``` + +Added in v1.0.0 + +## make + +Builds a `NonEmptyArray` from an non-empty collection of elements. + +**Signature** + +```ts +export declare const make: ( + ...elements: Elements +) => [Elements[number], ...Elements[number][]] +``` + +Added in v1.0.0 + +## makeBy + +Return a `NonEmptyArray` of length `n` with element `i` initialized with `f(i)`. + +**Note**. `n` is normalized to an integer >= 1. + +**Signature** + +```ts +export declare const makeBy: (f: (i: number) => A) => (n: number) => [A, ...A[]] +``` + +Added in v1.0.0 + +## of + +**Signature** + +```ts +export declare const of: (a: A) => [A, ...A[]] +``` + +Added in v1.0.0 + +## range + +Return a `NonEmptyArray` containing a range of integers, including both endpoints. + +**Signature** + +```ts +export declare const range: (start: number, end: number) => [number, ...number[]] +``` + +Added in v1.0.0 + +## replicate + +Return a `NonEmptyArray` containing a value repeated the specified number of times. + +**Note**. `n` is normalized to an integer >= 1. + +**Signature** + +```ts +export declare const replicate: (a: A) => (n: number) => [A, ...A[]] +``` + +Added in v1.0.0 + +## unfold + +**Signature** + +```ts +export declare const unfold: (b: B, f: (b: B) => any) => A[] +``` + +Added in v1.0.0 + +# conversions + +## fromEither + +**Signature** + +```ts +export declare const fromEither: (self: any) => A[] +``` + +Added in v1.0.0 + +## fromIterable + +**Signature** + +```ts +export declare const fromIterable: (collection: Iterable) => A[] +``` + +Added in v1.0.0 + +## fromNullable + +**Signature** + +```ts +export declare const fromNullable: (a: A) => NonNullable[] +``` + +Added in v1.0.0 + +## fromOption + +**Signature** + +```ts +export declare const fromOption: (self: any) => A[] +``` + +Added in v1.0.0 + +# do notation + +## Do + +**Signature** + +```ts +export declare const Do: readonly {}[] +``` + +Added in v1.0.0 + +## andThenBind + +A variant of `bind` that sequentially ignores the scope. + +**Signature** + +```ts +export declare const andThenBind: ( + name: Exclude, + that: readonly B[] +) => (self: readonly A[]) => { [K in N | keyof A]: K extends keyof A ? A[K] : B }[] +``` + +Added in v1.0.0 + +## bind + +**Signature** + +```ts +export declare const bind: ( + name: Exclude, + f: (a: A) => readonly B[] +) => (self: readonly A[]) => { [K in N | keyof A]: K extends keyof A ? A[K] : B }[] +``` + +Added in v1.0.0 + +## bindTo + +**Signature** + +```ts +export declare const bindTo: (name: N) => (self: readonly A[]) => { [K in N]: A }[] +``` + +Added in v1.0.0 + +## let + +**Signature** + +```ts +export declare const let: ( + name: Exclude, + f: (a: A) => B +) => (self: readonly A[]) => { [K in N | keyof A]: K extends keyof A ? A[K] : B }[] +``` + +Added in v1.0.0 + +# filtering + +## compact + +**Signature** + +```ts +export declare const compact: (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## filter + +**Signature** + +```ts +export declare const filter: { + (refinement: any): (self: readonly C[]) => B[] + (predicate: any): (self: readonly B[]) => B[] +} +``` + +Added in v1.0.0 + +## filterMap + +**Signature** + +```ts +export declare const filterMap: (f: (a: A) => any) => (self: Iterable) => B[] +``` + +Added in v1.0.0 + +## filterMapWithIndex + +**Signature** + +```ts +export declare const filterMapWithIndex: (f: (a: A, i: number) => any) => (self: Iterable) => B[] +``` + +Added in v1.0.0 + +## filterWithIndex + +**Signature** + +```ts +export declare const filterWithIndex: { + (refinement: (a: A, i: number) => a is B): (self: readonly C[]) => B[] + (predicate: (a: A, i: number) => boolean): (self: readonly B[]) => B[] +} +``` + +Added in v1.0.0 + +## partition + +**Signature** + +```ts +export declare const partition: { + (refinement: any): (self: readonly C[]) => [C[], B[]] + (predicate: any): (self: readonly B[]) => [B[], B[]] +} +``` + +Added in v1.0.0 + +## partitionMap + +**Signature** + +```ts +export declare const partitionMap: (f: (a: A) => any) => (self: readonly A[]) => [B[], C[]] +``` + +Added in v1.0.0 + +## partitionMapWithIndex + +**Signature** + +```ts +export declare const partitionMapWithIndex: (f: (a: A, i: number) => any) => (self: readonly A[]) => [B[], C[]] +``` + +Added in v1.0.0 + +## partitionWithIndex + +**Signature** + +```ts +export declare const partitionWithIndex: { + (refinement: (a: A, i: number) => a is B): (self: readonly C[]) => [C[], B[]] + (predicate: (a: A, i: number) => boolean): (self: readonly B[]) => [B[], B[]] +} +``` + +Added in v1.0.0 + +## separate + +**Signature** + +```ts +export declare const separate: (self: readonly any[]) => [A[], B[]] +``` + +Added in v1.0.0 + +## span + +Split an `Iterable` into two parts: + +1. the longest initial subarray for which all elements satisfy the specified predicate +2. the remaining elements + +**Signature** + +```ts +export declare function span( + refinement: Refinement +): (self: Iterable) => [init: Array, rest: Array] +export declare function span( + predicate: Predicate +): (self: Iterable) => [init: Array, rest: Array] +export declare function span(predicate: Predicate): (self: Iterable) => [init: Array, rest: Array] +``` + +Added in v1.0.0 + +## traverseFilterMap + +**Signature** + +```ts +export declare const traverseFilterMap: ( + F: any +) => (f: (a: A) => any) => (ta: readonly A[]) => any +``` + +Added in v1.0.0 + +## traversePartitionMap + +**Signature** + +```ts +export declare const traversePartitionMap: ( + F: any +) => (f: (a: A) => any) => (self: readonly A[]) => any +``` + +Added in v1.0.0 + +# folding + +## foldMap + +**Signature** + +```ts +export declare const foldMap: (M: any) => (f: (a: A) => M) => (self: readonly A[]) => M +``` + +Added in v1.0.0 + +## foldMapKind + +**Signature** + +```ts +export declare const foldMapKind: ( + F: any +) => (f: (a: A) => any) => (self: readonly A[]) => any +``` + +Added in v1.0.0 + +## foldMapNonEmpty + +**Signature** + +```ts +export declare const foldMapNonEmpty: (S: any) => (f: (a: A) => S) => (self: readonly [A, ...A[]]) => S +``` + +Added in v1.0.0 + +## foldMapNonEmptyWithIndex + +**Signature** + +```ts +export declare const foldMapNonEmptyWithIndex: ( + S: any +) => (f: (a: A, i: number) => S) => (self: readonly [A, ...A[]]) => S +``` + +Added in v1.0.0 + +## foldMapWithIndex + +**Signature** + +```ts +export declare const foldMapWithIndex: (Monoid: any) => (f: (a: A, i: number) => M) => (self: readonly A[]) => M +``` + +Added in v1.0.0 + +## reduce + +**Signature** + +```ts +export declare const reduce: (b: B, f: (b: B, a: A) => B) => (self: readonly A[]) => B +``` + +Added in v1.0.0 + +## reduceKind + +**Signature** + +```ts +export declare const reduceKind: ( + F: any +) => (b: B, f: (b: B, a: A) => any) => (self: readonly A[]) => any +``` + +Added in v1.0.0 + +## reduceRight + +**Signature** + +```ts +export declare const reduceRight: (b: B, f: (b: B, a: A) => B) => (self: readonly A[]) => B +``` + +Added in v1.0.0 + +## reduceRightKind + +**Signature** + +```ts +export declare const reduceRightKind: ( + F: any +) => (b: B, f: (b: B, a: A) => any) => (self: readonly A[]) => any +``` + +Added in v1.0.0 + +## reduceRightWithIndex + +**Signature** + +```ts +export declare const reduceRightWithIndex: (b: B, f: (b: B, a: A, i: number) => B) => (self: readonly A[]) => B +``` + +Added in v1.0.0 + +## reduceWithIndex + +**Signature** + +```ts +export declare const reduceWithIndex: (b: B, f: (b: B, a: A, i: number) => B) => (self: readonly A[]) => B +``` + +Added in v1.0.0 + +## scan + +Fold an `Iterable` from the left, keeping all intermediate results instead of only the final result. + +**Signature** + +```ts +export declare const scan: (b: B, f: (b: B, a: A) => B) => (self: Iterable) => [B, ...B[]] +``` + +Added in v1.0.0 + +## scanRight + +Fold an `Iterable` from the right, keeping all intermediate results instead of only the final result. + +**Signature** + +```ts +export declare const scanRight: (b: B, f: (b: B, a: A) => B) => (self: Iterable) => [B, ...B[]] +``` + +Added in v1.0.0 + +# getters + +## chunksOf + +Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of +the `Iterable`. Note that `chunksOf(n)([])` is `[]`, not `[[]]`. This is intentional, and is consistent with a recursive +definition of `chunksOf`; it satisfies the property that + +```ts +chunksOf(n)(xs).concat(chunksOf(n)(ys)) == chunksOf(n)(xs.concat(ys))) +``` + +whenever `n` evenly divides the length of `self`. + +**Signature** + +```ts +export declare const chunksOf: (n: number) => (self: Iterable) => [A, ...A[]][] +``` + +Added in v1.0.0 + +## chunksOfNonEmpty + +Splits a `NonEmptyReadonlyArray` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of +the `NonEmptyReadonlyArray`. + +**Signature** + +```ts +export declare const chunksOfNonEmpty: (n: number) => (self: readonly [A, ...A[]]) => [[A, ...A[]], ...[A, ...A[]][]] +``` + +Added in v1.0.0 + +## drop + +Drop a max number of elements from the start of an `Iterable`, creating a new `Array`. + +**Note**. `n` is normalized to a non negative integer. + +**Signature** + +```ts +export declare const drop: (n: number) => (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## dropRight + +Drop a max number of elements from the end of an `Iterable`, creating a new `Array`. + +**Note**. `n` is normalized to a non negative integer. + +**Signature** + +```ts +export declare const dropRight: (n: number) => (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## dropWhile + +Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. + +**Signature** + +```ts +export declare function dropWhile(refinement: Refinement): (self: Iterable) => Array +export declare function dropWhile(predicate: Predicate): (self: Iterable) => Array +export declare function dropWhile(predicate: Predicate): (self: Iterable) => Array +``` + +Added in v1.0.0 + +## findFirst + +Find the first element for which a predicate holds. + +**Signature** + +```ts +export declare function findFirst(refinement: Refinement): (self: Iterable) => Option +export declare function findFirst(predicate: Predicate): (self: Iterable) => Option +export declare function findFirst(predicate: Predicate): (self: Iterable) => Option +``` + +Added in v1.0.0 + +## findFirstIndex + +Return the first index for which a predicate holds. + +**Signature** + +```ts +export declare const findFirstIndex: (predicate: any) => (self: Iterable) => any +``` + +Added in v1.0.0 + +## findLast + +Find the last element for which a predicate holds. + +**Signature** + +```ts +export declare function findLast(refinement: Refinement): (self: Iterable) => Option +export declare function findLast(predicate: Predicate): (self: Iterable) => Option +export declare function findLast(predicate: Predicate): (self: Iterable) => Option +``` + +Added in v1.0.0 + +## findLastIndex + +Return the last index for which a predicate holds. + +**Signature** + +```ts +export declare const findLastIndex: (predicate: any) => (self: Iterable) => any +``` + +Added in v1.0.0 + +## get + +This function provides a safe way to read a value at a particular index from a `ReadonlyArray`. + +**Signature** + +```ts +export declare const get: (index: number) => (self: readonly A[]) => any +``` + +Added in v1.0.0 + +## head + +Get the first element of a `ReadonlyArray`, or `None` if the `ReadonlyArray` is empty. + +**Signature** + +```ts +export declare const head: (self: readonly A[]) => any +``` + +Added in v1.0.0 + +## headNonEmpty + +**Signature** + +```ts +export declare const headNonEmpty: (self: readonly [A, ...A[]]) => A +``` + +Added in v1.0.0 + +## init + +Get all but the last element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty. + +**Signature** + +```ts +export declare const init: (self: Iterable) => any +``` + +Added in v1.0.0 + +## initNonEmpty + +Get all but the last element of a non empty array, creating a new array. + +**Signature** + +```ts +export declare const initNonEmpty: (self: readonly [A, ...A[]]) => A[] +``` + +Added in v1.0.0 + +## last + +Get the last element in a `ReadonlyArray`, or `None` if the `ReadonlyArray` is empty. + +**Signature** + +```ts +export declare const last: (self: readonly A[]) => any +``` + +Added in v1.0.0 + +## lastNonEmpty + +**Signature** + +```ts +export declare const lastNonEmpty: (as: readonly [A, ...A[]]) => A +``` + +Added in v1.0.0 + +## lefts + +Return all the `Left` elements from an `Interable` of `Either`s. + +**Signature** + +```ts +export declare const lefts: (self: Iterable) => E[] +``` + +Added in v1.0.0 + +## length + +Return the number of elements in a `ReadonlyArray`. + +**Signature** + +```ts +export declare const length: (self: readonly A[]) => number +``` + +Added in v1.0.0 + +## rights + +Return all the `Right` elements from an `Interable` of `Either`s. + +**Signature** + +```ts +export declare const rights: (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## splitAt + +Splits an `Iterable` into two pieces, the first piece has max `n` elements. + +**Signature** + +```ts +export declare const splitAt: (n: number) => (self: Iterable) => [A[], A[]] +``` + +Added in v1.0.0 + +## splitNonEmptyAt + +Splits a `NonEmptyReadonlyArray` into two pieces, the first piece has max `n` elements. + +**Signature** + +```ts +export declare const splitNonEmptyAt: (n: number) => (self: readonly [A, ...A[]]) => [[A, ...A[]], A[]] +``` + +Added in v1.0.0 + +## tail + +Get all but the first element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty. + +**Signature** + +```ts +export declare const tail: (self: Iterable) => any +``` + +Added in v1.0.0 + +## tailNonEmpty + +**Signature** + +```ts +export declare const tailNonEmpty: (self: readonly [A, ...A[]]) => A[] +``` + +Added in v1.0.0 + +## take + +Keep only a max number of elements from the start of an `Iterable`, creating a new `Array`. + +**Note**. `n` is normalized to a non negative integer. + +**Signature** + +```ts +export declare const take: (n: number) => (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## takeRight + +Keep only a max number of elements from the end of an `Iterable`, creating a new `Array`. + +**Note**. `n` is normalized to a non negative integer. + +**Signature** + +```ts +export declare const takeRight: (n: number) => (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## takeWhile + +Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. + +**Signature** + +```ts +export declare function takeWhile(refinement: Refinement): (self: Iterable) => Array +export declare function takeWhile(predicate: Predicate): (self: Iterable) => Array +``` + +Added in v1.0.0 + +## unappend + +Return a tuple containing a copy of the `NonEmptyReadonlyArray` without its last element, and that last element. + +**Signature** + +```ts +export declare const unappend: (self: readonly [A, ...A[]]) => [A[], A] +``` + +Added in v1.0.0 + +## unprepend + +Return a tuple containing the first element, and a new `Array` of the remaining elements, if any. + +**Signature** + +```ts +export declare const unprepend: (self: readonly [A, ...A[]]) => [A, A[]] +``` + +Added in v1.0.0 + +# grouping + +## group + +Group equal, consecutive elements of a `NonEmptyReadonlyArray` into `NonEmptyArray`s. + +**Signature** + +```ts +export declare const group: (equivalence: any) => (self: readonly [A, ...A[]]) => [[A, ...A[]], ...[A, ...A[]][]] +``` + +Added in v1.0.0 + +## groupBy + +Splits an `Iterable` into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning +function on each element, and grouping the results according to values returned + +**Signature** + +```ts +export declare const groupBy: (f: (a: A) => string) => (self: Iterable) => Record +``` + +Added in v1.0.0 + +# instances + +## Applicative + +**Signature** + +```ts +export declare const Applicative: any +``` + +Added in v1.0.0 + +## Chainable + +**Signature** + +```ts +export declare const Chainable: any +``` + +Added in v1.0.0 + +## Compactable + +**Signature** + +```ts +export declare const Compactable: any +``` + +Added in v1.0.0 + +## Covariant + +**Signature** + +```ts +export declare const Covariant: any +``` + +Added in v1.0.0 + +## Filterable + +**Signature** + +```ts +export declare const Filterable: any +``` + +Added in v1.0.0 + +## FlatMap + +**Signature** + +```ts +export declare const FlatMap: any +``` + +Added in v1.0.0 + +## Foldable + +**Signature** + +```ts +export declare const Foldable: any +``` + +Added in v1.0.0 + +## Invariant + +**Signature** + +```ts +export declare const Invariant: any +``` + +Added in v1.0.0 + +## Monad + +**Signature** + +```ts +export declare const Monad: any +``` + +Added in v1.0.0 + +## Of + +**Signature** + +```ts +export declare const Of: any +``` + +Added in v1.0.0 + +## Pointed + +**Signature** + +```ts +export declare const Pointed: any +``` + +Added in v1.0.0 + +## Product + +**Signature** + +```ts +export declare const Product: any +``` + +Added in v1.0.0 + +## SemiApplicative + +**Signature** + +```ts +export declare const SemiApplicative: any +``` + +Added in v1.0.0 + +## SemiProduct + +**Signature** + +```ts +export declare const SemiProduct: any +``` + +Added in v1.0.0 + +## Traversable + +**Signature** + +```ts +export declare const Traversable: any +``` + +Added in v1.0.0 + +## TraversableFilterable + +**Signature** + +```ts +export declare const TraversableFilterable: any +``` + +Added in v1.0.0 + +## getIntersectionSemigroup + +**Signature** + +```ts +export declare const getIntersectionSemigroup: (equivalence: any) => any +``` + +Added in v1.0.0 + +## getMonoid + +Returns a `Monoid` for `ReadonlyArray`. + +**Signature** + +```ts +export declare const getMonoid: () => any +``` + +Added in v1.0.0 + +## getSemigroup + +Returns a `Semigroup` for `ReadonlyArray`. + +**Signature** + +```ts +export declare const getSemigroup: () => any +``` + +Added in v1.0.0 + +## getUnionMonoid + +**Signature** + +```ts +export declare const getUnionMonoid: (equivalence: any) => any +``` + +Added in v1.0.0 + +## getUnionSemigroup + +**Signature** + +```ts +export declare const getUnionSemigroup: (equivalence: any) => any +``` + +Added in v1.0.0 + +# lifting + +## every + +Check if a predicate holds true for every `ReadonlyArray` member. + +**Signature** + +```ts +export declare function every( + refinement: Refinement +): Refinement, ReadonlyArray> +export declare function every(predicate: Predicate): Predicate> +``` + +Added in v1.0.0 + +## lift2 + +Lifts a binary function into `ReadonlyArray`. + +**Signature** + +```ts +export declare const lift2: (f: (a: A, b: B) => C) => (fa: readonly A[], fb: readonly B[]) => C[] +``` + +Added in v1.0.0 + +## lift3 + +Lifts a ternary function into `ReadonlyArray`. + +**Signature** + +```ts +export declare const lift3: ( + f: (a: A, b: B, c: C) => D +) => (fa: readonly A[], fb: readonly B[], fc: readonly C[]) => D[] +``` + +Added in v1.0.0 + +## liftEither + +**Signature** + +```ts +export declare const liftEither: (f: (...a: A) => any) => (...a: A) => B[] +``` + +Added in v1.0.0 + +## liftMonoid + +**Signature** + +```ts +export declare const liftMonoid: (M: any) => any +``` + +Added in v1.0.0 + +## liftNullable + +**Signature** + +```ts +export declare const liftNullable: ( + f: (...a: A) => B | null | undefined +) => (...a: A) => NonNullable[] +``` + +Added in v1.0.0 + +## liftOption + +**Signature** + +```ts +export declare const liftOption: (f: (...a: A) => any) => (...a: A) => B[] +``` + +Added in v1.0.0 + +## liftOrder + +This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. +The returned `Order` compares two arrays by applying the given `Order` to each element in the arrays. +If all elements are equal, the arrays are then compared based on their length. +It is useful when you need to compare two arrays of the same type and you have a specific way of comparing each element of the array. + +**Signature** + +```ts +export declare const liftOrder: (O: any) => any +``` + +Added in v1.0.0 + +## liftPredicate + +**Signature** + +```ts +export declare const liftPredicate: { + (refinement: any): (c: C) => B[] + (predicate: any): (b: B) => B[] +} +``` + +Added in v1.0.0 + +## liftSemigroup + +**Signature** + +```ts +export declare const liftSemigroup: (S: any) => any +``` + +Added in v1.0.0 + +# mapping + +## as + +Maps the success value of this effect to the specified constant value. + +**Signature** + +```ts +export declare const as: (b: B) => (self: ReadonlyArray) => B[] +``` + +Added in v1.0.0 + +## flap + +**Signature** + +```ts +export declare const flap: (a: A) => (self: readonly ((a: A) => B)[]) => B[] +``` + +Added in v1.0.0 + +## imap + +**Signature** + +```ts +export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (self: readonly A[]) => B[] +``` + +Added in v1.0.0 + +## map + +**Signature** + +```ts +export declare const map: (f: (a: A) => B) => (self: readonly A[]) => B[] +``` + +Added in v1.0.0 + +## mapNonEmpty + +**Signature** + +```ts +export declare const mapNonEmpty: (f: (a: A) => B) => (self: readonly [A, ...A[]]) => [B, ...B[]] +``` + +Added in v1.0.0 + +## mapNonEmptyWithIndex + +**Signature** + +```ts +export declare const mapNonEmptyWithIndex: ( + f: (a: A, i: number) => B +) => (self: readonly [A, ...A[]]) => [B, ...B[]] +``` + +Added in v1.0.0 + +## mapWithIndex + +**Signature** + +```ts +export declare const mapWithIndex: (f: (a: A, i: number) => B) => (self: readonly A[]) => B[] +``` + +Added in v1.0.0 + +## tupled + +**Signature** + +```ts +export declare const tupled: (self: readonly A[]) => [A][] +``` + +Added in v1.0.0 + +# models + +## NonEmptyArray (type alias) + +**Signature** + +```ts +export type NonEmptyArray = [A, ...Array] +``` + +Added in v1.0.0 + +## NonEmptyReadonlyArray (type alias) + +**Signature** + +```ts +export type NonEmptyReadonlyArray = readonly [A, ...Array] +``` + +Added in v1.0.0 + +# pattern matching + +## match + +**Signature** + +```ts +export declare const match: ( + onEmpty: any, + onNonEmpty: (head: A, tail: A[]) => C +) => (self: readonly A[]) => B | C +``` + +Added in v1.0.0 + +## matchRight + +**Signature** + +```ts +export declare const matchRight: ( + onEmpty: any, + onNonEmpty: (init: A[], last: A) => C +) => (self: readonly A[]) => B | C +``` + +Added in v1.0.0 + +# predicates + +## contains + +Returns a function that checks if a `ReadonlyArray` contains a given value using a provided `equivalence` function. + +**Signature** + +```ts +export declare const contains: (equivalence: any) => (a: A) => (self: Iterable) => boolean +``` + +Added in v1.0.0 + +## isEmpty + +Test whether a `ReadonlyArray` is empty narrowing down the type to `[]`. + +**Signature** + +```ts +export declare const isEmpty: (self: readonly A[]) => self is readonly [] +``` + +Added in v1.0.0 + +## isNonEmpty + +Test whether a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyReadonlyArray`. + +**Signature** + +```ts +export declare const isNonEmpty: (self: readonly A[]) => self is readonly [A, ...A[]] +``` + +Added in v1.0.0 + +## some + +Check if a predicate holds true for any `ReadonlyArray` member. + +**Signature** + +```ts +export declare const some: (predicate: any) => (self: readonly A[]) => self is readonly [A, ...A[]] +``` + +Added in v1.0.0 + +# sequencing + +## flatMap + +**Signature** + +```ts +export declare const flatMap: (f: (a: A) => readonly B[]) => (self: readonly A[]) => B[] +``` + +Added in v1.0.0 + +## flatMapNonEmpty + +**Signature** + +```ts +export declare const flatMapNonEmpty: ( + f: (a: A) => readonly [B, ...B[]] +) => (self: readonly [A, ...A[]]) => [B, ...B[]] +``` + +Added in v1.0.0 + +## flatMapNonEmptyWithIndex + +**Signature** + +```ts +export declare const flatMapNonEmptyWithIndex: ( + f: (a: A, i: number) => readonly [B, ...B[]] +) => (self: readonly [A, ...A[]]) => [B, ...B[]] +``` + +Added in v1.0.0 + +## flatMapNullable + +**Signature** + +```ts +export declare const flatMapNullable: ( + f: (a: A) => B | null | undefined +) => (self: readonly A[]) => NonNullable[] +``` + +Added in v1.0.0 + +## flatMapWithIndex + +**Signature** + +```ts +export declare const flatMapWithIndex: (f: (a: A, i: number) => readonly B[]) => (self: readonly A[]) => B[] +``` + +Added in v1.0.0 + +## flatten + +**Signature** + +```ts +export declare const flatten: (self: readonly (readonly A[])[]) => A[] +``` + +Added in v1.0.0 + +## flattenNonEmpty + +**Signature** + +```ts +export declare const flattenNonEmpty: ( + self: readonly [readonly [A, ...A[]], ...(readonly [A, ...A[]])[]] +) => [A, ...A[]] +``` + +Added in v1.0.0 + +# sorting + +## sort + +Sort the elements of an `Iterable` in increasing order, creating a new `Array`. + +**Signature** + +```ts +export declare const sort: (O: any) => (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## sortBy + +Sort the elements of an `Iterable` in increasing order, where elements are compared +using first `orders[0]`, then `orders[1]`, etc... + +**Signature** + +```ts +export declare const sortBy: (...orders: readonly any[]) => (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## sortByNonEmpty + +**Signature** + +```ts +export declare const sortByNonEmpty: ( + ...orders: readonly any[] +) => (as: readonly [A, ...A[]]) => [A, ...A[]] +``` + +Added in v1.0.0 + +## sortNonEmpty + +Sort the elements of a `NonEmptyReadonlyArray` in increasing order, creating a new `NonEmptyArray`. + +**Signature** + +```ts +export declare const sortNonEmpty: (O: any) => (self: readonly [A, ...A[]]) => [A, ...A[]] +``` + +Added in v1.0.0 + +# traversing + +## sequence + +**Signature** + +```ts +export declare const sequence: (F: any) => (self: readonly any[]) => any +``` + +Added in v1.0.0 + +## sequenceNonEmpty + +**Signature** + +```ts +export declare const sequenceNonEmpty: (F: any) => (self: readonly [any, ...any[]]) => any +``` + +Added in v1.0.0 + +## traverse + +**Signature** + +```ts +export declare const traverse: ( + F: any +) => (f: (a: A) => any) => (self: readonly A[]) => any +``` + +Added in v1.0.0 + +## traverseNonEmpty + +**Signature** + +```ts +export declare const traverseNonEmpty: ( + F: any +) => (f: (a: A) => any) => (self: readonly [A, ...A[]]) => any +``` + +Added in v1.0.0 + +## traverseNonEmptyWithIndex + +**Signature** + +```ts +export declare const traverseNonEmptyWithIndex: ( + F: any +) => (f: (a: A, i: number) => any) => (self: readonly [A, ...A[]]) => any +``` + +Added in v1.0.0 + +## traverseTap + +**Signature** + +```ts +export declare const traverseTap: ( + F: any +) => (f: (a: A) => any) => (self: readonly A[]) => any +``` + +Added in v1.0.0 + +## traverseWithIndex + +**Signature** + +```ts +export declare const traverseWithIndex: ( + F: any +) => (f: (a: A, i: number) => any) => (self: readonly A[]) => any +``` + +Added in v1.0.0 + +# type lambdas + +## ReadonlyArrayTypeLambda (interface) + +**Signature** + +```ts +export interface ReadonlyArrayTypeLambda extends TypeLambda { + readonly type: ReadonlyArray +} +``` + +Added in v1.0.0 + +# unsafe + +## unsafeGet + +Gets an element unsafely, will throw on out of bounds. + +**Signature** + +```ts +export declare const unsafeGet: (index: number) => (self: readonly A[]) => A +``` + +Added in v1.0.0 + +# utils + +## ap + +**Signature** + +```ts +export declare const ap: (fa: readonly A[]) => (self: readonly ((a: A) => B)[]) => B[] +``` + +Added in v1.0.0 + +## append + +Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`. + +**Signature** + +```ts +export declare const append: (last: B) => (self: Iterable) => [B | A, ...(B | A)[]] +``` + +Added in v1.0.0 + +## appendAll + +**Signature** + +```ts +export declare const appendAll: (that: Iterable) => (self: Iterable) => (B | A)[] +``` + +Added in v1.0.0 + +## appendAllNonEmpty + +**Signature** + +```ts +export declare function appendAllNonEmpty( + that: NonEmptyReadonlyArray +): (self: Iterable) => NonEmptyArray +export declare function appendAllNonEmpty( + that: Iterable +): (self: NonEmptyReadonlyArray) => NonEmptyArray +``` + +Added in v1.0.0 + +## chop + +A useful recursion pattern for processing an `Iterable` to produce a new `Array`, often used for "chopping" up the input +`Iterable`. Typically chop is called with some function that will consume an initial prefix of the `Iterable` and produce a +value and the rest of the `Array`. + +**Signature** + +```ts +export declare const chop: ( + f: (as: readonly [A, ...A[]]) => readonly [B, readonly A[]] +) => (self: Iterable) => B[] +``` + +Added in v1.0.0 + +## chopNonEmpty + +A useful recursion pattern for processing a `NonEmptyReadonlyArray` to produce a new `NonEmptyReadonlyArray`, often used for "chopping" up the input +`NonEmptyReadonlyArray`. Typically `chop` is called with some function that will consume an initial prefix of the `NonEmptyReadonlyArray` and produce a +value and the tail of the `NonEmptyReadonlyArray`. + +**Signature** + +```ts +export declare const chopNonEmpty: ( + f: (as: readonly [A, ...A[]]) => readonly [B, readonly A[]] +) => (self: readonly [A, ...A[]]) => [B, ...B[]] +``` + +Added in v1.0.0 + +## composeKleisliArrow + +**Signature** + +```ts +export declare const composeKleisliArrow: ( + bfc: (b: B) => readonly C[] +) => (afb: (a: A) => readonly B[]) => (a: A) => readonly C[] +``` + +Added in v1.0.0 + +## copy + +**Signature** + +```ts +export declare function copy(self: NonEmptyReadonlyArray): NonEmptyArray +export declare function copy(self: ReadonlyArray): Array +``` + +Added in v1.0.0 + +## difference + +Creates a `Array` of values not included in the other given `Iterable`. +The order and references of result values are determined by the first `Iterable`. + +**Signature** + +```ts +export declare const difference: (equivalence: any) => (that: Iterable) => (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## extend + +**Signature** + +```ts +export declare const extend: (f: (as: readonly A[]) => B) => (self: readonly A[]) => B[] +``` + +Added in v1.0.0 + +## insertAt + +Insert an element at the specified index, creating a new `NonEmptyArray`, +or return `None` if the index is out of bounds. + +**Signature** + +```ts +export declare const insertAt: (i: number, b: B) => (self: Iterable) => any +``` + +Added in v1.0.0 + +## intercalate + +Fold a data structure, accumulating values in some `Monoid`, combining adjacent elements +using the specified separator. + +**Signature** + +```ts +export declare const intercalate: (M: any) => (middle: A) => (self: readonly A[]) => A +``` + +Added in v1.0.0 + +## intercalateNonEmpty + +Places an element in between members of a `NonEmptyReadonlyArray`, then folds the results using the provided `Semigroup`. + +**Signature** + +```ts +export declare const intercalateNonEmpty: (S: any) => (middle: A) => (self: readonly [A, ...A[]]) => A +``` + +Added in v1.0.0 + +## intersection + +Creates an `Array` of unique values that are included in all given `Iterable`s. +The order and references of result values are determined by the first `Iterable`. + +**Signature** + +```ts +export declare const intersection: (equivalence: any) => (that: Iterable) => (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## intersperse + +Places an element in between members of an `Iterable` + +**Signature** + +```ts +export declare const intersperse: (middle: B) => (self: Iterable) => (B | A)[] +``` + +Added in v1.0.0 + +## intersperseNonEmpty + +Places an element in between members of a `NonEmptyReadonlyArray` + +**Signature** + +```ts +export declare const intersperseNonEmpty: (middle: B) => (self: readonly [A, ...A[]]) => [B | A, ...(B | A)[]] +``` + +Added in v1.0.0 + +## join + +**Signature** + +```ts +export declare const join: (sep: string) => (self: ReadonlyArray) => string +``` + +Added in v1.0.0 + +## max + +**Signature** + +```ts +export declare const max: (O: any) => (self: readonly [A, ...A[]]) => A +``` + +Added in v1.0.0 + +## min + +**Signature** + +```ts +export declare const min: (O: any) => (self: readonly [A, ...A[]]) => A +``` + +Added in v1.0.0 + +## modify + +Apply a function to the element at the specified index, creating a new `Array`, +or return a copy of the input if the index is out of bounds. + +**Signature** + +```ts +export declare const modify: (i: number, f: (a: A) => B) => (self: Iterable) => (A | B)[] +``` + +Added in v1.0.0 + +## modifyNonEmptyHead + +Apply a function to the head, creating a new `NonEmptyReadonlyArray`. + +**Signature** + +```ts +export declare const modifyNonEmptyHead: (f: (a: A) => B) => (self: readonly [A, ...A[]]) => [A | B, ...(A | B)[]] +``` + +Added in v1.0.0 + +## modifyNonEmptyLast + +Apply a function to the last element, creating a new `NonEmptyReadonlyArray`. + +**Signature** + +```ts +export declare const modifyNonEmptyLast: (f: (a: A) => B) => (self: readonly [A, ...A[]]) => [A | B, ...(A | B)[]] +``` + +Added in v1.0.0 + +## modifyOption + +Apply a function to the element at the specified index, creating a new `Array`, +or return `None` if the index is out of bounds. + +**Signature** + +```ts +export declare const modifyOption: (i: number, f: (a: A) => B) => (self: Iterable) => any +``` + +Added in v1.0.0 + +## prepend + +Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray`. + +**Signature** + +```ts +export declare const prepend: (head: B) => (self: Iterable) => [B | A, ...(B | A)[]] +``` + +Added in v1.0.0 + +## prependAll + +**Signature** + +```ts +export declare const prependAll: (that: Iterable) => (self: Iterable) => (B | A)[] +``` + +Added in v1.0.0 + +## prependAllNonEmpty + +**Signature** + +```ts +export declare function prependAllNonEmpty( + that: NonEmptyReadonlyArray +): (self: Iterable) => NonEmptyArray +export declare function prependAllNonEmpty( + that: Iterable +): (self: NonEmptyReadonlyArray) => NonEmptyArray +``` + +Added in v1.0.0 + +## remove + +Delete the element at the specified index, creating a new `Array`, +or return a copy of the input if the index is out of bounds. + +**Signature** + +```ts +export declare const remove: (i: number) => (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## replace + +Change the element at the specified index, creating a new `Array`, +or return a copy of the input if the index is out of bounds. + +**Signature** + +```ts +export declare const replace: (i: number, b: B) => (self: Iterable) => (B | A)[] +``` + +Added in v1.0.0 + +## replaceOption + +**Signature** + +```ts +export declare const replaceOption: (i: number, b: B) => (self: Iterable) => any +``` + +Added in v1.0.0 + +## reverse + +Reverse an `Iterable`, creating a new `Array`. + +**Signature** + +```ts +export declare const reverse: (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## reverseNonEmpty + +**Signature** + +```ts +export declare const reverseNonEmpty: (self: readonly [A, ...A[]]) => [A, ...A[]] +``` + +Added in v1.0.0 + +## rotate + +Rotate an `Iterable` by `n` steps. + +**Signature** + +```ts +export declare const rotate: (n: number) => (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## rotateNonEmpty + +Rotate a `NonEmptyReadonlyArray` by `n` steps. + +**Signature** + +```ts +export declare const rotateNonEmpty: (n: number) => (self: readonly [A, ...A[]]) => [A, ...A[]] +``` + +Added in v1.0.0 + +## setNonEmptyHead + +Change the head, creating a new `NonEmptyReadonlyArray`. + +**Signature** + +```ts +export declare const setNonEmptyHead: (b: B) => (self: readonly [A, ...A[]]) => [B | A, ...(B | A)[]] +``` + +Added in v1.0.0 + +## setNonEmptyLast + +Change the last element, creating a new `NonEmptyReadonlyArray`. + +**Signature** + +```ts +export declare const setNonEmptyLast: (b: B) => (self: readonly [A, ...A[]]) => [B | A, ...(B | A)[]] +``` + +Added in v1.0.0 + +## traverseFilter + +Filter values inside a context. + +**Signature** + +```ts +export declare const traverseFilter: ( + F: any +) => (predicate: (a: A) => any) => (self: readonly B[]) => any +``` + +Added in v1.0.0 + +## traversePartition + +**Signature** + +```ts +export declare const traversePartition: ( + F: any +) => (predicate: (a: A) => any) => (self: readonly B[]) => any +``` + +Added in v1.0.0 + +## union + +**Signature** + +```ts +export declare const union: (equivalence: any) => (that: readonly A[]) => (self: readonly A[]) => A[] +``` + +Added in v1.0.0 + +## unionNonEmpty + +**Signature** + +```ts +export declare const unionNonEmpty: (equivalence: any) => { + (that: readonly [A, ...A[]]): (self: readonly A[]) => [A, ...A[]] + (that: readonly A[]): (self: readonly [A, ...A[]]) => [A, ...A[]] +} +``` + +Added in v1.0.0 + +## uniq + +Remove duplicates from am `Iterable`, keeping the first occurrence of an element. + +**Signature** + +```ts +export declare const uniq: (equivalence: any) => (self: Iterable) => A[] +``` + +Added in v1.0.0 + +## uniqNonEmpty + +Remove duplicates from a `NonEmptyReadonlyArray`, keeping the first occurrence of an element. + +**Signature** + +```ts +export declare const uniqNonEmpty: (equivalence: any) => (self: readonly [A, ...A[]]) => [A, ...A[]] +``` + +Added in v1.0.0 + +## unzip + +This function is the inverse of `zip`. Takes an `Iterable` of pairs and return two corresponding `Array`s. + +**Signature** + +```ts +export declare const unzip: (self: Iterable<[A, B]>) => [A[], B[]] +``` + +Added in v1.0.0 + +## unzipNonEmpty + +**Signature** + +```ts +export declare const unzipNonEmpty: (self: readonly [[A, B], ...[A, B][]]) => [[A, ...A[]], [B, ...B[]]] +``` + +Added in v1.0.0 + +## zip + +Takes two `Iterable`s and returns an `Array` of corresponding pairs. +If one input `Iterable` is short, excess elements of the +longer `Iterable` are discarded. + +**Signature** + +```ts +export declare const zip: (that: Iterable) => (self: Iterable) => [A, B][] +``` + +Added in v1.0.0 + +## zipNonEmpty + +**Signature** + +```ts +export declare const zipNonEmpty: ( + that: readonly [B, ...B[]] +) => (self: readonly [A, ...A[]]) => [[A, B], ...[A, B][]] +``` + +Added in v1.0.0 + +## zipNonEmptyWith + +**Signature** + +```ts +export declare const zipNonEmptyWith: ( + that: readonly [B, ...B[]], + f: (a: A, b: B) => C +) => (self: readonly [A, ...A[]]) => [C, ...C[]] +``` + +Added in v1.0.0 + +## zipWith + +Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results in a new `Array`. If one +input `Iterable` is short, excess elements of the longer `Iterable` are discarded. + +**Signature** + +```ts +export declare const zipWith: (that: Iterable, f: (a: A, b: B) => C) => (self: Iterable) => C[] +``` + +Added in v1.0.0 diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md new file mode 100644 index 000000000..36723a0b7 --- /dev/null +++ b/docs/modules/ReadonlyRecord.ts.md @@ -0,0 +1,78 @@ +--- +title: ReadonlyRecord.ts +nav_order: 13 +parent: Modules +--- + +## ReadonlyRecord overview + +This module provides utility functions for working with records in TypeScript. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [getters](#getters) + - [get](#get) +- [models](#models) + - [ReadonlyRecord (interface)](#readonlyrecord-interface) +- [utils](#utils) + - [modifyOption](#modifyoption) + - [replaceOption](#replaceoption) + +--- + +# getters + +## get + +This function provides a safe way to read a value at a particular key from a record. + +**Signature** + +```ts +export declare const get: (key: string) =>
(self: ReadonlyRecord) => any +``` + +Added in v1.0.0 + +# models + +## ReadonlyRecord (interface) + +**Signature** + +```ts +export interface ReadonlyRecord { + readonly [x: string]: A +} +``` + +Added in v1.0.0 + +# utils + +## modifyOption + +Apply a function to the element at the specified key, creating a new record, +or return `None` if the key doesn't exist. + +**Signature** + +```ts +export declare const modifyOption: (key: string, f: (a: A) => B) => (self: ReadonlyRecord) => any +``` + +Added in v1.0.0 + +## replaceOption + +**Signature** + +```ts +export declare const replaceOption: (key: string, b: B) => (self: ReadonlyRecord) => any +``` + +Added in v1.0.0 diff --git a/docs/modules/String.ts.md b/docs/modules/String.ts.md new file mode 100644 index 000000000..b6fbb9c7b --- /dev/null +++ b/docs/modules/String.ts.md @@ -0,0 +1,434 @@ +--- +title: String.ts +nav_order: 14 +parent: Modules +--- + +## String overview + +This module provides utility functions and type class instances for working with the `string` type in TypeScript. +It includes functions for basic string manipulation, as well as type class instances for +`Equivalence`, `Order`, `Semigroup`, and `Monoid`. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [guards](#guards) + - [isString](#isstring) +- [instances](#instances) + - [Equivalence](#equivalence) + - [Monoid](#monoid) + - [Order](#order) + - [Semigroup](#semigroup) +- [utils](#utils) + - [concat](#concat) + - [empty](#empty) + - [endsWith](#endswith) + - [includes](#includes) + - [isEmpty](#isempty) + - [isNonEmpty](#isnonempty) + - [length](#length) + - [replace](#replace) + - [slice](#slice) + - [split](#split) + - [startsWith](#startswith) + - [takeLeft](#takeleft) + - [takeRight](#takeright) + - [toLowerCase](#tolowercase) + - [toUpperCase](#touppercase) + - [trim](#trim) + - [trimEnd](#trimend) + - [trimStart](#trimstart) + +--- + +# guards + +## isString + +**Signature** + +```ts +export declare const isString: any +``` + +Added in v1.0.0 + +# instances + +## Equivalence + +**Signature** + +```ts +export declare const Equivalence: any +``` + +Added in v1.0.0 + +## Monoid + +`string` monoid under concatenation. + +The `empty` value is `''`. + +**Signature** + +```ts +export declare const Monoid: any +``` + +Added in v1.0.0 + +## Order + +**Signature** + +```ts +export declare const Order: any +``` + +Added in v1.0.0 + +## Semigroup + +`string` semigroup under concatenation. + +**Signature** + +```ts +export declare const Semigroup: any +``` + +Added in v1.0.0 + +# utils + +## concat + +**Signature** + +```ts +export declare const concat: (that: string) => (self: string) => string +``` + +Added in v1.0.0 + +## empty + +**Signature** + +```ts +export declare const empty: '' +``` + +Added in v1.0.0 + +## endsWith + +**Signature** + +```ts +export declare const endsWith: (searchString: string, position?: number | undefined) => (s: string) => boolean +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe('abc', S.endsWith('c')), true) +assert.deepStrictEqual(pipe('ab', S.endsWith('c')), false) +``` + +Added in v1.0.0 + +## includes + +**Signature** + +```ts +export declare const includes: (searchString: string, position?: number | undefined) => (s: string) => boolean +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe('abc', S.includes('b')), true) +assert.deepStrictEqual(pipe('abc', S.includes('d')), false) +``` + +Added in v1.0.0 + +## isEmpty + +Test whether a `string` is empty. + +**Signature** + +```ts +export declare const isEmpty: (s: string) => s is '' +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe('', S.isEmpty), true) +assert.deepStrictEqual(pipe('a', S.isEmpty), false) +``` + +Added in v1.0.0 + +## isNonEmpty + +Test whether a `string` is non empty. + +**Signature** + +```ts +export declare const isNonEmpty: (s: string) => boolean +``` + +Added in v1.0.0 + +## length + +Calculate the number of characters in a `string`. + +**Signature** + +```ts +export declare const length: (s: string) => number +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe('abc', S.length), 3) +``` + +Added in v1.0.0 + +## replace + +**Signature** + +```ts +export declare const replace: (searchValue: string | RegExp, replaceValue: string) => (s: string) => string +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe('abc', S.replace('b', 'd')), 'adc') +``` + +Added in v1.0.0 + +## slice + +**Signature** + +```ts +export declare const slice: (start: number, end: number) => (s: string) => string +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe('abcd', S.slice(1, 3)), 'bc') +``` + +Added in v1.0.0 + +## split + +**Signature** + +```ts +export declare const split: (separator: string | RegExp) => (s: string) => any +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe('abc', S.split('')), ['a', 'b', 'c']) +assert.deepStrictEqual(pipe('', S.split('')), ['']) +``` + +Added in v1.0.0 + +## startsWith + +**Signature** + +```ts +export declare const startsWith: (searchString: string, position?: number | undefined) => (s: string) => boolean +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe('abc', S.startsWith('a')), true) +assert.deepStrictEqual(pipe('bc', S.startsWith('a')), false) +``` + +Added in v1.0.0 + +## takeLeft + +Keep the specified number of characters from the start of a string. + +If `n` is larger than the available number of characters, the string will +be returned whole. + +If `n` is not a positive number, an empty string will be returned. + +If `n` is a float, it will be rounded down to the nearest integer. + +**Signature** + +```ts +export declare const takeLeft: (n: number) => (self: string) => string +``` + +Added in v1.0.0 + +## takeRight + +Keep the specified number of characters from the end of a string. + +If `n` is larger than the available number of characters, the string will +be returned whole. + +If `n` is not a positive number, an empty string will be returned. + +If `n` is a float, it will be rounded down to the nearest integer. + +**Signature** + +```ts +export declare const takeRight: (n: number) => (s: string) => string +``` + +Added in v1.0.0 + +## toLowerCase + +**Signature** + +```ts +export declare const toLowerCase: (s: string) => string +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe('A', S.toLowerCase), 'a') +``` + +Added in v1.0.0 + +## toUpperCase + +**Signature** + +```ts +export declare const toUpperCase: (s: string) => string +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe('a', S.toUpperCase), 'A') +``` + +Added in v1.0.0 + +## trim + +**Signature** + +```ts +export declare const trim: (s: string) => string +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(' a ', S.trim), 'a') +``` + +Added in v1.0.0 + +## trimEnd + +**Signature** + +```ts +export declare const trimEnd: (s: string) => string +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(' a ', S.trimEnd), ' a') +``` + +Added in v1.0.0 + +## trimStart + +**Signature** + +```ts +export declare const trimStart: (s: string) => string +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(' a ', S.trimStart), 'a ') +``` + +Added in v1.0.0 diff --git a/docs/modules/Struct.ts.md b/docs/modules/Struct.ts.md new file mode 100644 index 000000000..64c4c7df8 --- /dev/null +++ b/docs/modules/Struct.ts.md @@ -0,0 +1,117 @@ +--- +title: Struct.ts +nav_order: 15 +parent: Modules +--- + +## Struct overview + +This module provides utility functions for working with structs in TypeScript. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [utils](#utils) + - [getEquivalence](#getequivalence) + - [getMonoid](#getmonoid) + - [getOrder](#getorder) + - [getSemigroup](#getsemigroup) + - [nonEmptyProduct](#nonemptyproduct) + - [omit](#omit) + - [pick](#pick) + - [product](#product) + +--- + +# utils + +## getEquivalence + +**Signature** + +```ts +export declare const getEquivalence: any +``` + +Added in v1.0.0 + +## getMonoid + +**Signature** + +```ts +export declare const getMonoid: any +``` + +Added in v1.0.0 + +## getOrder + +**Signature** + +```ts +export declare const getOrder: any +``` + +Added in v1.0.0 + +## getSemigroup + +**Signature** + +```ts +export declare const getSemigroup: any +``` + +Added in v1.0.0 + +## nonEmptyProduct + +**Signature** + +```ts +export declare const nonEmptyProduct: any +``` + +Added in v1.0.0 + +## omit + +Create a new object by omitting properties of an existing object. + +**Signature** + +```ts +export declare const omit: ( + ...keys: Keys +) => (s: S) => { [K in Exclude]: S[K] } +``` + +Added in v1.0.0 + +## pick + +Create a new object by picking properties of an existing object. + +**Signature** + +```ts +export declare const pick: ( + ...keys: Keys +) => (s: S) => { [K in Keys[number]]: S[K] } +``` + +Added in v1.0.0 + +## product + +**Signature** + +```ts +export declare const product: any +``` + +Added in v1.0.0 diff --git a/docs/modules/Symbol.ts.md b/docs/modules/Symbol.ts.md new file mode 100644 index 000000000..4f3bcc7b8 --- /dev/null +++ b/docs/modules/Symbol.ts.md @@ -0,0 +1,30 @@ +--- +title: Symbol.ts +nav_order: 16 +parent: Modules +--- + +## Symbol overview + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [guards](#guards) + - [isSymbol](#issymbol) + +--- + +# guards + +## isSymbol + +**Signature** + +```ts +export declare const isSymbol: (u: unknown) => u is symbol +``` + +Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md new file mode 100644 index 000000000..062181e63 --- /dev/null +++ b/docs/modules/These.ts.md @@ -0,0 +1,1517 @@ +--- +title: These.ts +nav_order: 17 +parent: Modules +--- + +## These overview + +A data structure providing "inclusive-or" as opposed to `Either`'s "exclusive-or". + +If you interpret `Either` as suggesting the computation may either fail or succeed (exclusively), then +`These` may fail, succeed, or do both at the same time. + +There are a few ways to interpret the `Both` case: + +1. You can think of a computation that has a non-fatal error. +2. You can think of a computation that went as far as it could before erroring. +3. You can think of a computation that keeps track of errors as it completes. + +Another way you can think of `These` is saying that we want to handle `E` kind of data, `A` kind of data, or +both `E` and `A` kind of data at the same time. This is particularly useful when it comes to displaying UI's. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [combining](#combining) + - [getFirstLeftMonoid](#getfirstleftmonoid) + - [getFirstLeftSemigroup](#getfirstleftsemigroup) + - [getFirstRightOrBothSemigroup](#getfirstrightorbothsemigroup) +- [constructors](#constructors) + - [both](#both) + - [fail](#fail) + - [left](#left) + - [leftOrBoth](#leftorboth) + - [of](#of) + - [right](#right) + - [rightOrBoth](#rightorboth) + - [succeed](#succeed) + - [warn](#warn) +- [conversions](#conversions) + - [absolve](#absolve) + - [condemn](#condemn) + - [fromEither](#fromeither) + - [fromIterable](#fromiterable) + - [fromNullable](#fromnullable) + - [fromOption](#fromoption) + - [fromThese](#fromthese) + - [fromTuple](#fromtuple) + - [toEither](#toeither) +- [debugging](#debugging) + - [inspectBoth](#inspectboth) + - [inspectLeft](#inspectleft) + - [inspectRight](#inspectright) + - [inspectRightOrBoth](#inspectrightorboth) +- [do notation](#do-notation) + - [Do](#do) + - [andThenBind](#andthenbind) + - [andThenBindEither](#andthenbindeither) + - [andThenBindThese](#andthenbindthese) + - [bind](#bind) + - [bindEither](#bindeither) + - [bindThese](#bindthese) + - [bindTo](#bindto) + - [let](#let) +- [error handling](#error-handling) + - [catchAll](#catchall) + - [firstRightOrBothOf](#firstrightorbothof) + - [mapLeft](#mapleft) + - [orElse](#orelse) + - [orElseEither](#orelseeither) + - [orElseFail](#orelsefail) + - [orElseSucceed](#orelsesucceed) +- [filtering](#filtering) + - [compact](#compact) + - [filter](#filter) + - [filterMap](#filtermap) +- [getters](#getters) + - [getBoth](#getboth) + - [getBothOrElse](#getbothorelse) + - [getLeft](#getleft) + - [getLeftOnly](#getleftonly) + - [getOrElse](#getorelse) + - [getOrNull](#getornull) + - [getOrUndefined](#getorundefined) + - [getRight](#getright) + - [getRightOnly](#getrightonly) +- [guards](#guards) + - [isBoth](#isboth) + - [isLeft](#isleft) + - [isLeftOrBoth](#isleftorboth) + - [isRight](#isright) + - [isRightOrBoth](#isrightorboth) + - [isThese](#isthese) +- [instances](#instances) + - [Applicative](#applicative) + - [Bicovariant](#bicovariant) + - [Chainable](#chainable) + - [Covariant](#covariant) + - [FlatMap](#flatmap) + - [Foldable](#foldable) + - [Invariant](#invariant) + - [Monad](#monad) + - [Of](#of) + - [Pointed](#pointed) + - [Product](#product) + - [SemiAlternative](#semialternative) + - [SemiApplicative](#semiapplicative) + - [SemiCoproduct](#semicoproduct) + - [SemiProduct](#semiproduct) + - [Traversable](#traversable) +- [interop](#interop) + - [fromThrowable](#fromthrowable) + - [getOrThrow](#getorthrow) + - [getRightOnlyOrThrow](#getrightonlyorthrow) + - [liftThrowable](#liftthrowable) +- [lifting](#lifting) + - [lift2](#lift2) + - [lift3](#lift3) + - [liftEither](#lifteither) + - [liftNullable](#liftnullable) + - [liftOption](#liftoption) + - [liftPredicate](#liftpredicate) + - [liftThese](#liftthese) +- [mapping](#mapping) + - [as](#as) + - [asUnit](#asunit) + - [bimap](#bimap) + - [flap](#flap) + - [imap](#imap) + - [map](#map) + - [tupled](#tupled) +- [model](#model) + - [Both (type alias)](#both-type-alias) + - [These (type alias)](#these-type-alias) + - [Validated (type alias)](#validated-type-alias) +- [pattern matching](#pattern-matching) + - [match](#match) +- [predicates](#predicates) + - [exists](#exists) +- [sequencing](#sequencing) + - [andThenDiscard](#andthendiscard) + - [flatMap](#flatmap) + - [flatMapEither](#flatmapeither) + - [flatMapNullable](#flatmapnullable) + - [flatMapOption](#flatmapoption) + - [flatMapThese](#flatmapthese) +- [traversing](#traversing) + - [sequence](#sequence) + - [traverse](#traverse) + - [traverseTap](#traversetap) +- [type lambdas](#type-lambdas) + - [TheseTypeLambda (interface)](#thesetypelambda-interface) + - [ValidatedTypeLambda (interface)](#validatedtypelambda-interface) +- [utils](#utils) + - [andThen](#andthen) + - [ap](#ap) + - [composeKleisliArrow](#composekleisliarrow) + - [contains](#contains) + - [element](#element) + - [flatten](#flatten) + - [reverse](#reverse) + - [struct](#struct) + - [tap](#tap) + - [tuple](#tuple) + - [unit](#unit) + +--- + +# combining + +## getFirstLeftMonoid + +**Signature** + +```ts +export declare const getFirstLeftMonoid: (M: any) => any +``` + +Added in v1.0.0 + +## getFirstLeftSemigroup + +**Signature** + +```ts +export declare const getFirstLeftSemigroup: (S: any) => any +``` + +Added in v1.0.0 + +## getFirstRightOrBothSemigroup + +**Signature** + +```ts +export declare const getFirstRightOrBothSemigroup: () => any +``` + +Added in v1.0.0 + +# constructors + +## both + +**Signature** + +```ts +export declare const both: (left: E, right: A) => any +``` + +Added in v1.0.0 + +## fail + +**Signature** + +```ts +export declare const fail: (e: E) => any +``` + +Added in v1.0.0 + +## left + +**Signature** + +```ts +export declare const left: (left: E) => any +``` + +Added in v1.0.0 + +## leftOrBoth + +**Signature** + +```ts +export declare const leftOrBoth: (e: any) =>
(self: any) => any +``` + +Added in v1.0.0 + +## of + +Alias of `right`. + +**Signature** + +```ts +export declare const of: (right: A) => any +``` + +Added in v1.0.0 + +## right + +**Signature** + +```ts +export declare const right: (right: A) => any +``` + +Added in v1.0.0 + +## rightOrBoth + +**Signature** + +```ts +export declare const rightOrBoth: (a: () => A) => (self: any) => any +``` + +Added in v1.0.0 + +## succeed + +Alias of `right`. + +**Signature** + +```ts +export declare const succeed: (a: A) => any +``` + +Added in v1.0.0 + +## warn + +**Signature** + +```ts +export declare const warn: (e: E, a: A) => any +``` + +Added in v1.0.0 + +# conversions + +## absolve + +**Signature** + +```ts +export declare const absolve: (self: any) => any +``` + +Added in v1.0.0 + +## condemn + +**Signature** + +```ts +export declare const condemn: (self: any) => any +``` + +Added in v1.0.0 + +## fromEither + +**Signature** + +```ts +export declare const fromEither: (self: any) => any +``` + +Added in v1.0.0 + +## fromIterable + +**Signature** + +```ts +export declare const fromIterable: (onEmpty: any) => (collection: Iterable) => any +``` + +Added in v1.0.0 + +## fromNullable + +**Signature** + +```ts +export declare const fromNullable: (onNullable: any) => (a: A) => any +``` + +Added in v1.0.0 + +## fromOption + +**Signature** + +```ts +export declare const fromOption: (onNone: any) => (self: any) => any +``` + +Added in v1.0.0 + +## fromThese + +**Signature** + +```ts +export declare const fromThese: (self: any) => any +``` + +Added in v1.0.0 + +## fromTuple + +**Signature** + +```ts +export declare const fromTuple: (self: readonly [E, A]) => any +``` + +Added in v1.0.0 + +## toEither + +**Signature** + +```ts +export declare const toEither: (onBoth: (e: E, a: A) => any) => (self: any) => any +``` + +Added in v1.0.0 + +# debugging + +## inspectBoth + +**Signature** + +```ts +export declare const inspectBoth: (onBoth: (e: E, a: A) => void) => (self: any) => any +``` + +Added in v1.0.0 + +## inspectLeft + +**Signature** + +```ts +export declare const inspectLeft: (onLeft: (e: E) => void) => (self: any) => any +``` + +Added in v1.0.0 + +## inspectRight + +**Signature** + +```ts +export declare const inspectRight: (onRight: (a: A) => void) => (self: any) => any +``` + +Added in v1.0.0 + +## inspectRightOrBoth + +**Signature** + +```ts +export declare const inspectRightOrBoth: (onRightOrBoth: (a: A) => void) => (self: any) => any +``` + +Added in v1.0.0 + +# do notation + +## Do + +**Signature** + +```ts +export declare const Do: any +``` + +Added in v1.0.0 + +## andThenBind + +**Signature** + +```ts +export declare const andThenBind: ( + name: Exclude, + that: any +) => (self: any) => any +``` + +Added in v1.0.0 + +## andThenBindEither + +**Signature** + +```ts +export declare const andThenBindEither: ( + name: Exclude, + that: any +) => (self: any) => any +``` + +Added in v1.0.0 + +## andThenBindThese + +**Signature** + +```ts +export declare const andThenBindThese: ( + name: Exclude, + that: any +) => (self: any) => any +``` + +Added in v1.0.0 + +## bind + +**Signature** + +```ts +export declare const bind: ( + name: Exclude, + f: (a: A) => any +) => (self: any) => any +``` + +Added in v1.0.0 + +## bindEither + +**Signature** + +```ts +export declare const bindEither: ( + name: Exclude, + f: (a: A) => any +) => (self: any) => any +``` + +Added in v1.0.0 + +## bindThese + +**Signature** + +```ts +export declare const bindThese: ( + name: Exclude, + f: (a: A) => any +) => (self: any) => any +``` + +Added in v1.0.0 + +## bindTo + +**Signature** + +```ts +export declare const bindTo: (name: N) => (self: any) => any +``` + +Added in v1.0.0 + +## let + +**Signature** + +```ts +export declare const let: ( + name: Exclude, + f: (a: A) => B +) => (self: any) => any +``` + +Added in v1.0.0 + +# error handling + +## catchAll + +Recovers from all errors. + +**Signature** + +```ts +export declare const catchAll: (onLeft: (e: E1) => any) => (self: any) => any +``` + +Added in v1.0.0 + +## firstRightOrBothOf + +**Signature** + +```ts +export declare const firstRightOrBothOf: (collection: Iterable) => (self: any) => any +``` + +Added in v1.0.0 + +## mapLeft + +Returns an effect with its error channel mapped using the specified +function. This can be used to lift a "smaller" error into a "larger" error. + +**Signature** + +```ts +export declare const mapLeft: (f: (e: E) => G) => (self: any) => any +``` + +Added in v1.0.0 + +## orElse + +Executes this effect and returns its value, if it succeeds, but otherwise +executes the specified effect. + +**Signature** + +```ts +export declare const orElse: (that: any) => (self: any) => any +``` + +Added in v1.0.0 + +## orElseEither + +Returns an effect that will produce the value of this effect, unless it +fails, in which case, it will produce the value of the specified effect. + +**Signature** + +```ts +export declare const orElseEither: (that: any) => (self: any) => any +``` + +Added in v1.0.0 + +## orElseFail + +Executes this effect and returns its value, if it succeeds, but otherwise +fails with the specified error. + +**Signature** + +```ts +export declare const orElseFail: (onLeft: any) => (self: any) => any +``` + +Added in v1.0.0 + +## orElseSucceed + +Executes this effect and returns its value, if it succeeds, but otherwise +succeeds with the specified value. + +**Signature** + +```ts +export declare const orElseSucceed: (onLeft: any) => (self: any) => any +``` + +Added in v1.0.0 + +# filtering + +## compact + +**Signature** + +```ts +export declare const compact: (onNone: any) => (self: any) => any +``` + +Added in v1.0.0 + +## filter + +**Signature** + +```ts +export declare const filter: { + (refinement: any, onFalse: any): (self: any) => any + (predicate: any, onFalse: any): (self: any) => any +} +``` + +Added in v1.0.0 + +## filterMap + +**Signature** + +```ts +export declare const filterMap: (f: (a: A) => any, onNone: any) => (self: any) => any +``` + +Added in v1.0.0 + +# getters + +## getBoth + +**Signature** + +```ts +export declare const getBoth: (self: any) => any +``` + +Added in v1.0.0 + +## getBothOrElse + +**Signature** + +```ts +export declare const getBothOrElse: (e: any, a: any) => (self: any) => readonly [E, A] +``` + +Added in v1.0.0 + +## getLeft + +**Signature** + +```ts +export declare const getLeft: (self: any) => any +``` + +Added in v1.0.0 + +## getLeftOnly + +Returns the `E` value if and only if the value is constructed with `Left` + +**Signature** + +```ts +export declare const getLeftOnly: (self: any) => any +``` + +Added in v1.0.0 + +## getOrElse + +**Signature** + +```ts +export declare const getOrElse: (onLeft: any) => (self: any) => B | A +``` + +Added in v1.0.0 + +## getOrNull + +**Signature** + +```ts +export declare const getOrNull: (self: any) => A | null +``` + +Added in v1.0.0 + +## getOrUndefined + +**Signature** + +```ts +export declare const getOrUndefined: (self: any) => A | undefined +``` + +Added in v1.0.0 + +## getRight + +**Signature** + +```ts +export declare const getRight: (self: any) => any +``` + +Added in v1.0.0 + +## getRightOnly + +Returns the `A` value if and only if the value is constructed with `Right` + +**Signature** + +```ts +export declare const getRightOnly: (self: any) => any +``` + +Added in v1.0.0 + +# guards + +## isBoth + +Returns `true` if the these is an instance of `Both`, `false` otherwise + +**Signature** + +```ts +export declare const isBoth: (self: any) => self is Both +``` + +Added in v1.0.0 + +## isLeft + +Returns `true` if the these is an instance of `Left`, `false` otherwise + +**Signature** + +```ts +export declare const isLeft: (self: any) => self is any +``` + +Added in v1.0.0 + +## isLeftOrBoth + +**Signature** + +```ts +export declare const isLeftOrBoth: (self: any) => self is any +``` + +Added in v1.0.0 + +## isRight + +Returns `true` if the these is an instance of `Right`, `false` otherwise + +**Signature** + +```ts +export declare const isRight: (self: any) => self is any +``` + +Added in v1.0.0 + +## isRightOrBoth + +**Signature** + +```ts +export declare const isRightOrBoth: (self: any) => self is any +``` + +Added in v1.0.0 + +## isThese + +Returns `true` if the specified value is an instance of `These`, `false` +otherwise. + +**Signature** + +```ts +export declare const isThese: (u: unknown) => u is any +``` + +Added in v1.0.0 + +# instances + +## Applicative + +**Signature** + +```ts +export declare const Applicative: any +``` + +Added in v1.0.0 + +## Bicovariant + +**Signature** + +```ts +export declare const Bicovariant: any +``` + +Added in v1.0.0 + +## Chainable + +**Signature** + +```ts +export declare const Chainable: any +``` + +Added in v1.0.0 + +## Covariant + +**Signature** + +```ts +export declare const Covariant: any +``` + +Added in v1.0.0 + +## FlatMap + +**Signature** + +```ts +export declare const FlatMap: any +``` + +Added in v1.0.0 + +## Foldable + +**Signature** + +```ts +export declare const Foldable: any +``` + +Added in v1.0.0 + +## Invariant + +**Signature** + +```ts +export declare const Invariant: any +``` + +Added in v1.0.0 + +## Monad + +**Signature** + +```ts +export declare const Monad: any +``` + +Added in v1.0.0 + +## Of + +**Signature** + +```ts +export declare const Of: any +``` + +Added in v1.0.0 + +## Pointed + +**Signature** + +```ts +export declare const Pointed: any +``` + +Added in v1.0.0 + +## Product + +**Signature** + +```ts +export declare const Product: any +``` + +Added in v1.0.0 + +## SemiAlternative + +**Signature** + +```ts +export declare const SemiAlternative: any +``` + +Added in v1.0.0 + +## SemiApplicative + +**Signature** + +```ts +export declare const SemiApplicative: any +``` + +Added in v1.0.0 + +## SemiCoproduct + +**Signature** + +```ts +export declare const SemiCoproduct: any +``` + +Added in v1.0.0 + +## SemiProduct + +**Signature** + +```ts +export declare const SemiProduct: any +``` + +Added in v1.0.0 + +## Traversable + +**Signature** + +```ts +export declare const Traversable: any +``` + +Added in v1.0.0 + +# interop + +## fromThrowable + +Constructs a new `These` from a function that might throw. + +**Signature** + +```ts +export declare const fromThrowable: (f: () => A, onThrow: (error: unknown) => E) => any +``` + +Added in v1.0.0 + +## getOrThrow + +**Signature** + +```ts +export declare const getOrThrow: (onLeft: (e: E) => unknown) => (self: any) => A +``` + +Added in v1.0.0 + +## getRightOnlyOrThrow + +**Signature** + +```ts +export declare const getRightOnlyOrThrow: (onLeft: (e: E) => unknown) => (self: any) => A +``` + +Added in v1.0.0 + +## liftThrowable + +Lifts a function that may throw to one returning a `These`. + +**Signature** + +```ts +export declare const liftThrowable: ( + f: (...a: A) => B, + onThrow: (error: unknown) => E +) => (...a: A) => any +``` + +Added in v1.0.0 + +# lifting + +## lift2 + +**Signature** + +```ts +export declare const lift2: (f: (a: A, b: B) => C) => (fa: any, fb: any) => any +``` + +Added in v1.0.0 + +## lift3 + +**Signature** + +```ts +export declare const lift3: (f: (a: A, b: B, c: C) => D) => (fa: any, fb: any, fc: any) => any +``` + +Added in v1.0.0 + +## liftEither + +**Signature** + +```ts +export declare const liftEither: (f: (...a: A) => any) => (...a: A) => any +``` + +Added in v1.0.0 + +## liftNullable + +**Signature** + +```ts +export declare const liftNullable: ( + f: (...a: A) => B | null | undefined, + onNullable: (...a: A) => E +) => (...a: A) => any +``` + +Added in v1.0.0 + +## liftOption + +**Signature** + +```ts +export declare const liftOption: ( + f: (...a: A) => any, + onNone: (...a: A) => E +) => (...a: A) => any +``` + +Added in v1.0.0 + +## liftPredicate + +**Signature** + +```ts +export declare const liftPredicate: { + (refinement: any, onFalse: any): (c: C) => any + (predicate: any, onFalse: any): (b: B) => any +} +``` + +Added in v1.0.0 + +## liftThese + +**Signature** + +```ts +export declare const liftThese: (f: (...a: A) => any) => (...a: A) => any +``` + +Added in v1.0.0 + +# mapping + +## as + +Maps the right value of this effect to the specified constant value. + +**Signature** + +```ts +export declare const as: (b: B) => (self: any) => any +``` + +Added in v1.0.0 + +## asUnit + +Returns the effect resulting from mapping the right of this effect to unit. + +**Signature** + +```ts +export declare const asUnit: (self: any) => any +``` + +Added in v1.0.0 + +## bimap + +Returns an effect whose left and right channels have been mapped by +the specified pair of functions, `f` and `g`. + +**Signature** + +```ts +export declare const bimap: (f: (e: E) => G, g: (a: A) => B) => (self: any) => any +``` + +Added in v1.0.0 + +## flap + +**Signature** + +```ts +export declare const flap: (a: A) => (self: any) => any +``` + +Added in v1.0.0 + +## imap + +**Signature** + +```ts +export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (self: any) => any +``` + +Added in v1.0.0 + +## map + +Returns an effect whose right is mapped by the specified `f` function. + +**Signature** + +```ts +export declare const map: (f: (a: A) => B) => (self: any) => any +``` + +Added in v1.0.0 + +## tupled + +**Signature** + +```ts +export declare const tupled: (self: any) => any +``` + +Added in v1.0.0 + +# model + +## Both (type alias) + +**Signature** + +```ts +export type Both = { + readonly _tag: 'Both' + readonly left: E + readonly right: A +} +``` + +Added in v1.0.0 + +## These (type alias) + +**Signature** + +```ts +export type These = Either | Both +``` + +Added in v1.0.0 + +## Validated (type alias) + +**Signature** + +```ts +export type Validated = These, A> +``` + +Added in v1.0.0 + +# pattern matching + +## match + +**Signature** + +```ts +export declare const match: ( + onLeft: (e: E) => B, + onRight: (a: A) => C, + onBoth: (e: E, a: A) => D +) => (self: any) => B | C | D +``` + +Added in v1.0.0 + +# predicates + +## exists + +**Signature** + +```ts +export declare const exists: (predicate: any) => (self: any) => boolean +``` + +Added in v1.0.0 + +# sequencing + +## andThenDiscard + +Sequences the specified effect after this effect, but ignores the value +produced by the effect. + +**Signature** + +```ts +export declare const andThenDiscard: (that: any) => (self: any) => any +``` + +Added in v1.0.0 + +## flatMap + +**Signature** + +```ts +export declare const flatMap: (f: (a: A) => any) => (self: any) => any +``` + +Added in v1.0.0 + +## flatMapEither + +**Signature** + +```ts +export declare const flatMapEither: (f: (a: A) => any) => (self: any) => any +``` + +Added in v1.0.0 + +## flatMapNullable + +**Signature** + +```ts +export declare const flatMapNullable: ( + f: (a: A) => B | null | undefined, + onNullable: (a: A) => E2 +) => (self: any) => any +``` + +Added in v1.0.0 + +## flatMapOption + +**Signature** + +```ts +export declare const flatMapOption: (f: (a: A) => any, onNone: (a: A) => E2) => (self: any) => any +``` + +Added in v1.0.0 + +## flatMapThese + +**Signature** + +```ts +export declare const flatMapThese: (f: (a: A) => any) => (self: any) => any +``` + +Added in v1.0.0 + +# traversing + +## sequence + +**Signature** + +```ts +export declare const sequence: (F: any) => (self: any) => any +``` + +Added in v1.0.0 + +## traverse + +**Signature** + +```ts +export declare const traverse: (F: any) => (f: (a: A) => any) => (self: any) => any +``` + +Added in v1.0.0 + +## traverseTap + +**Signature** + +```ts +export declare const traverseTap: (F: any) => (f: (a: A) => any) => (self: any) => any +``` + +Added in v1.0.0 + +# type lambdas + +## TheseTypeLambda (interface) + +**Signature** + +```ts +export interface TheseTypeLambda extends TypeLambda { + readonly type: These +} +``` + +Added in v1.0.0 + +## ValidatedTypeLambda (interface) + +**Signature** + +```ts +export interface ValidatedTypeLambda extends TypeLambda { + readonly type: Validated +} +``` + +Added in v3.0.0 + +# utils + +## andThen + +**Signature** + +```ts +export declare const andThen: (that: any) => (self: any) => any +``` + +Added in v1.0.0 + +## ap + +**Signature** + +```ts +export declare const ap: (fa: any) => (self: any) => any +``` + +Added in v1.0.0 + +## composeKleisliArrow + +**Signature** + +```ts +export declare const composeKleisliArrow: (bfc: (b: B) => any) => (afb: (a: A) => any) => (a: A) => any +``` + +Added in v1.0.0 + +## contains + +Returns a function that checks if a `These` contains a given value using a provided `equivalence` function. + +**Signature** + +```ts +export declare const contains: (equivalence: any) => (a: A) => (self: any) => boolean +``` + +Added in v1.0.0 + +## element + +Adds an element to the end of a tuple. + +**Signature** + +```ts +export declare const element: (that: any) => (self: any) => any +``` + +Added in v1.0.0 + +## flatten + +**Signature** + +```ts +export declare const flatten: (self: any) => any +``` + +Added in v1.0.0 + +## reverse + +**Signature** + +```ts +export declare const reverse: (self: any) => any +``` + +Added in v1.0.0 + +## struct + +**Signature** + +```ts +export declare const struct: >(r: R) => any +``` + +Added in v1.0.0 + +## tap + +Returns an effect that effectfully "peeks" at the success of this effect. + +**Signature** + +```ts +export declare const tap: (f: (a: A) => any) => (self: any) => any +``` + +Added in v1.0.0 + +## tuple + +**Signature** + +```ts +export declare const tuple: (...tuple: T) => any +``` + +Added in v1.0.0 + +## unit + +**Signature** + +```ts +export declare const unit: any +``` + +Added in v1.0.0 diff --git a/docs/modules/Tuple.ts.md b/docs/modules/Tuple.ts.md new file mode 100644 index 000000000..2bf29beac --- /dev/null +++ b/docs/modules/Tuple.ts.md @@ -0,0 +1,116 @@ +--- +title: Tuple.ts +nav_order: 18 +parent: Modules +--- + +## Tuple overview + +This module provides utility functions for working with tuples in TypeScript. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [constructors](#constructors) + - [tuple](#tuple) +- [utils](#utils) + - [element](#element) + - [getEquivalence](#getequivalence) + - [getMonoid](#getmonoid) + - [getOrder](#getorder) + - [getSemigroup](#getsemigroup) + - [nonEmptyProduct](#nonemptyproduct) + - [product](#product) + +--- + +# constructors + +## tuple + +**Signature** + +```ts +export declare const tuple:
(...elements: A) => A +``` + +Added in v1.0.0 + +# utils + +## element + +Appends an element to the end of a tuple. + +**Signature** + +```ts +export declare const element: ( + that: readonly B[] +) => (self: readonly A[]) => [...A, B][] +``` + +Added in v1.0.0 + +## getEquivalence + +**Signature** + +```ts +export declare const getEquivalence: any +``` + +Added in v1.0.0 + +## getMonoid + +**Signature** + +```ts +export declare const getMonoid: any +``` + +Added in v1.0.0 + +## getOrder + +**Signature** + +```ts +export declare const getOrder: any +``` + +Added in v1.0.0 + +## getSemigroup + +**Signature** + +```ts +export declare const getSemigroup: any +``` + +Added in v1.0.0 + +## nonEmptyProduct + +**Signature** + +```ts +export declare const nonEmptyProduct: any +``` + +Added in v1.0.0 + +## product + +**Signature** + +```ts +export declare const product: any +``` + +Added in v1.0.0 diff --git a/docs/modules/index.ts.md b/docs/modules/index.ts.md index d1168088a..63dbcd40a 100644 --- a/docs/modules/index.ts.md +++ b/docs/modules/index.ts.md @@ -1,6 +1,6 @@ --- title: index.ts -nav_order: 2 +nav_order: 7 parent: Modules --- @@ -18,15 +18,17 @@ Added in v1.0.0 - [bicovariant](#bicovariant) - [bounded](#bounded) - [chainable](#chainable) + - [compactable](#compactable) - [contravariant](#contravariant) - [coproduct](#coproduct) - [covariant](#covariant) + - [equivalence](#equivalence) + - [filterable](#filterable) - [flatMap](#flatmap) - [foldable](#foldable) - [invariant](#invariant) - [monad](#monad) - [monoid](#monoid) - - [nonEmptyTraversable](#nonemptytraversable) - [of](#of) - [order](#order) - [pointed](#pointed) @@ -37,8 +39,25 @@ Added in v1.0.0 - [semiProduct](#semiproduct) - [semigroup](#semigroup) - [traversable](#traversable) + - [traversableFilterable](#traversablefilterable) - [utils](#utils) + - [bigint](#bigint) + - [boolean](#boolean) + - [either](#either) + - [function](#function) - [hkt](#hkt) + - [identity](#identity) + - [number](#number) + - [option](#option) + - [ordering](#ordering) + - [predicate](#predicate) + - [readonlyArray](#readonlyarray) + - [readonlyRecord](#readonlyrecord) + - [string](#string) + - [struct](#struct) + - [symbol](#symbol) + - [these](#these) + - [tuple](#tuple) --- @@ -49,7 +68,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const alternative: typeof alternative +export declare const alternative: any ``` Added in v1.0.0 @@ -59,7 +78,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const applicative: typeof applicative +export declare const applicative: any ``` Added in v1.0.0 @@ -69,7 +88,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const bicovariant: typeof bicovariant +export declare const bicovariant: any ``` Added in v1.0.0 @@ -79,7 +98,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const bounded: typeof bounded +export declare const bounded: any ``` Added in v1.0.0 @@ -89,7 +108,17 @@ Added in v1.0.0 **Signature** ```ts -export declare const chainable: typeof chainable +export declare const chainable: any +``` + +Added in v1.0.0 + +## compactable + +**Signature** + +```ts +export declare const compactable: any ``` Added in v1.0.0 @@ -99,7 +128,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const contravariant: typeof contravariant +export declare const contravariant: any ``` Added in v1.0.0 @@ -109,7 +138,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const coproduct: typeof coproduct +export declare const coproduct: any ``` Added in v1.0.0 @@ -119,67 +148,77 @@ Added in v1.0.0 **Signature** ```ts -export declare const covariant: typeof covariant +export declare const covariant: any ``` Added in v1.0.0 -## flatMap +## equivalence **Signature** ```ts -export declare const flatMap: typeof flatMap +export declare const equivalence: any ``` Added in v1.0.0 -## foldable +## filterable **Signature** ```ts -export declare const foldable: typeof foldable +export declare const filterable: any ``` Added in v1.0.0 -## invariant +## flatMap **Signature** ```ts -export declare const invariant: typeof invariant +export declare const flatMap: any ``` Added in v1.0.0 -## monad +## foldable **Signature** ```ts -export declare const monad: typeof monad +export declare const foldable: any ``` Added in v1.0.0 -## monoid +## invariant **Signature** ```ts -export declare const monoid: typeof monoid +export declare const invariant: any ``` Added in v1.0.0 -## nonEmptyTraversable +## monad **Signature** ```ts -export declare const nonEmptyTraversable: typeof nonEmptyTraversable +export declare const monad: any +``` + +Added in v1.0.0 + +## monoid + +**Signature** + +```ts +export declare const monoid: any ``` Added in v1.0.0 @@ -189,7 +228,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const of: typeof of +export declare const of: any ``` Added in v1.0.0 @@ -199,7 +238,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const order: typeof order +export declare const order: any ``` Added in v1.0.0 @@ -209,7 +248,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const pointed: typeof pointed +export declare const pointed: any ``` Added in v1.0.0 @@ -219,7 +258,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const product: typeof product +export declare const product: any ``` Added in v1.0.0 @@ -229,7 +268,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const semiAlternative: typeof semiAlternative +export declare const semiAlternative: any ``` Added in v1.0.0 @@ -239,7 +278,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const semiApplicative: typeof semiApplicative +export declare const semiApplicative: any ``` Added in v1.0.0 @@ -249,7 +288,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const semiCoproduct: typeof semiCoproduct +export declare const semiCoproduct: any ``` Added in v1.0.0 @@ -259,7 +298,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const semiProduct: typeof semiProduct +export declare const semiProduct: any ``` Added in v1.0.0 @@ -269,7 +308,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const semigroup: typeof semigroup +export declare const semigroup: any ``` Added in v1.0.0 @@ -279,19 +318,189 @@ Added in v1.0.0 **Signature** ```ts -export declare const traversable: typeof traversable +export declare const traversable: any +``` + +Added in v1.0.0 + +## traversableFilterable + +**Signature** + +```ts +export declare const traversableFilterable: any ``` Added in v1.0.0 # utils +## bigint + +**Signature** + +```ts +export declare const bigint: any +``` + +Added in v1.0.0 + +## boolean + +**Signature** + +```ts +export declare const boolean: any +``` + +Added in v1.0.0 + +## either + +**Signature** + +```ts +export declare const either: any +``` + +Added in v1.0.0 + +## function + +**Signature** + +```ts +export declare const function: any +``` + +Added in v1.0.0 + ## hkt **Signature** ```ts -export declare const hkt: typeof hkt +export declare const hkt: any +``` + +Added in v1.0.0 + +## identity + +**Signature** + +```ts +export declare const identity: any +``` + +Added in v1.0.0 + +## number + +**Signature** + +```ts +export declare const number: any +``` + +Added in v1.0.0 + +## option + +**Signature** + +```ts +export declare const option: any +``` + +Added in v1.0.0 + +## ordering + +**Signature** + +```ts +export declare const ordering: any +``` + +Added in v1.0.0 + +## predicate + +**Signature** + +```ts +export declare const predicate: any +``` + +Added in v1.0.0 + +## readonlyArray + +**Signature** + +```ts +export declare const readonlyArray: any +``` + +Added in v1.0.0 + +## readonlyRecord + +**Signature** + +```ts +export declare const readonlyRecord: any +``` + +Added in v1.0.0 + +## string + +**Signature** + +```ts +export declare const string: any +``` + +Added in v1.0.0 + +## struct + +**Signature** + +```ts +export declare const struct: any +``` + +Added in v1.0.0 + +## symbol + +**Signature** + +```ts +export declare const symbol: any +``` + +Added in v1.0.0 + +## these + +**Signature** + +```ts +export declare const these: any +``` + +Added in v1.0.0 + +## tuple + +**Signature** + +```ts +export declare const tuple: any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Alternative.ts.md b/docs/modules/typeclass/Alternative.ts.md index 973ea69a3..acbfce511 100644 --- a/docs/modules/typeclass/Alternative.ts.md +++ b/docs/modules/typeclass/Alternative.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Alternative.ts -nav_order: 3 +nav_order: 19 parent: Modules --- diff --git a/docs/modules/typeclass/Applicative.ts.md b/docs/modules/typeclass/Applicative.ts.md index 98c748387..4dbabc5d0 100644 --- a/docs/modules/typeclass/Applicative.ts.md +++ b/docs/modules/typeclass/Applicative.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Applicative.ts -nav_order: 4 +nav_order: 20 parent: Modules --- @@ -40,9 +40,7 @@ Lift a monoid into 'F', the inner values are combined using the provided `Monoid **Signature** ```ts -export declare const liftMonoid: ( - F: Applicative -) => (M: Monoid) => Monoid> +export declare const liftMonoid: (F: Applicative) => (M: any) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Bicovariant.ts.md b/docs/modules/typeclass/Bicovariant.ts.md index e01228986..d28425526 100644 --- a/docs/modules/typeclass/Bicovariant.ts.md +++ b/docs/modules/typeclass/Bicovariant.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Bicovariant.ts -nav_order: 5 +nav_order: 21 parent: Modules --- @@ -47,15 +47,10 @@ Returns a default `bimap` composition. **Signature** ```ts -export declare const bimapComposition: ( - CovariantF: Covariant, +export declare const bimapComposition: ( + CovariantF: any, BicovariantG: Bicovariant -) => ( - f: (e: E1) => E2, - g: (a: A) => B -) => ( - self: Kind> -) => Kind> +) => (f: (e: E1) => E2, g: (a: A) => B) => (self: any) => any ``` Added in v1.0.0 @@ -67,9 +62,7 @@ Returns a default `map` implementation. **Signature** ```ts -export declare const map: ( - F: Bicovariant -) => (f: (a: A) => B) => (self: Kind) => Kind +export declare const map: (F: Bicovariant) => any ``` Added in v1.0.0 @@ -79,9 +72,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const mapLeft: ( +export declare const mapLeft: ( F: Bicovariant -) => (f: (e: E1) => E2) => (self: Kind) => Kind +) => (f: (e: E1) => E2) => (self: any) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Bounded.ts.md b/docs/modules/typeclass/Bounded.ts.md index 89605b9f0..5553ae96e 100644 --- a/docs/modules/typeclass/Bounded.ts.md +++ b/docs/modules/typeclass/Bounded.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Bounded.ts -nav_order: 6 +nav_order: 22 parent: Modules --- @@ -12,6 +12,11 @@ Added in v1.0.0

Table of contents

+- [constructors](#constructors) + - [max](#max) + - [min](#min) +- [instances](#instances) + - [number](#number) - [type class](#type-class) - [Bounded (interface)](#bounded-interface) - [type lambdas](#type-lambdas) @@ -22,6 +27,44 @@ Added in v1.0.0 --- +# constructors + +## max + +`Monoid` that returns last maximum of elements. + +**Signature** + +```ts +export declare const max:
(B: Bounded) => any +``` + +Added in v1.0.0 + +## min + +`Monoid` that returns last minimum of elements. + +**Signature** + +```ts +export declare const min: (B: Bounded) => any +``` + +Added in v1.0.0 + +# instances + +## number + +**Signature** + +```ts +export declare const number: Bounded +``` + +Added in v1.0.0 + # type class ## Bounded (interface) diff --git a/docs/modules/typeclass/Chainable.ts.md b/docs/modules/typeclass/Chainable.ts.md index d4f584e52..8372e97e1 100644 --- a/docs/modules/typeclass/Chainable.ts.md +++ b/docs/modules/typeclass/Chainable.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Chainable.ts -nav_order: 7 +nav_order: 23 parent: Modules --- @@ -32,11 +32,9 @@ produced by the effect. **Signature** ```ts -export declare const andThenDiscard: ( +export declare const andThenDiscard: ( F: Chainable -) => ( - that: Kind -) => (self: Kind) => Kind +) => (that: any) => (self: any) => any ``` Added in v1.0.0 @@ -60,14 +58,12 @@ Added in v1.0.0 **Signature** ```ts -export declare const bind: ( +export declare const bind: ( F: Chainable ) => ( name: Exclude, - f: (a: A) => Kind -) => ( - self: Kind -) => Kind + f: (a: A) => any +) => (self: any) => any ``` Added in v1.0.0 @@ -79,11 +75,9 @@ Returns an effect that effectfully "peeks" at the success of this effect. **Signature** ```ts -export declare const tap: ( +export declare const tap: ( F: Chainable -) => ( - f: (a: A) => Kind -) => (self: Kind) => Kind +) => (f: (a: A) => any) => (self: any) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Compactable.ts.md b/docs/modules/typeclass/Compactable.ts.md new file mode 100644 index 000000000..1f9edea9e --- /dev/null +++ b/docs/modules/typeclass/Compactable.ts.md @@ -0,0 +1,64 @@ +--- +title: typeclass/Compactable.ts +nav_order: 24 +parent: Modules +--- + +## Compactable overview + +`Compactable` represents data structures which can be _compacted_/_separated_. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [models](#models) + - [Compactable (interface)](#compactable-interface) +- [utils](#utils) + - [compactComposition](#compactcomposition) + - [separate](#separate) + +--- + +# models + +## Compactable (interface) + +**Signature** + +```ts +export interface Compactable extends TypeClass { + readonly compact: (self: Kind>) => Kind +} +``` + +Added in v1.0.0 + +# utils + +## compactComposition + +Returns a default `compact` composition. + +**Signature** + +```ts +export declare const compactComposition: ( + F: any, + G: Compactable +) => (self: any) => any +``` + +Added in v1.0.0 + +## separate + +**Signature** + +```ts +export declare const separate: (F: any) => (self: any) => [any, any] +``` + +Added in v1.0.0 diff --git a/docs/modules/typeclass/Contravariant.ts.md b/docs/modules/typeclass/Contravariant.ts.md index ff16c82fa..d0f5e18e9 100644 --- a/docs/modules/typeclass/Contravariant.ts.md +++ b/docs/modules/typeclass/Contravariant.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Contravariant.ts -nav_order: 8 +nav_order: 25 parent: Modules --- @@ -29,8 +29,8 @@ Added in v1.0.0 **Signature** ```ts -export declare const make: ( - contramap: (f: (b: B) => A) => (self: Kind) => Kind +export declare const make: ( + contramap: (f: (b: B) => A) => (self: any) => any ) => Contravariant ``` @@ -61,14 +61,10 @@ Returns a default `map` composition. **Signature** ```ts -export declare const contramapComposition: ( +export declare const contramapComposition: ( F: Contravariant, G: Contravariant -) => ( - f: (a: A) => B -) => ( - self: Kind> -) => Kind> +) => (f: (a: A) => B) => (self: any) => any ``` Added in v1.0.0 @@ -80,9 +76,7 @@ Returns a default `imap` implementation. **Signature** ```ts -export declare const imap: ( - contramap: (f: (b: B) => A) => (self: Kind) => Kind -) => (to: (a: A) => B, from: (b: B) => A) => (self: Kind) => Kind +export declare const imap: (contramap: (f: (b: B) => A) => (self: any) => any) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Coproduct.ts.md b/docs/modules/typeclass/Coproduct.ts.md index dc19adbff..4dae57e12 100644 --- a/docs/modules/typeclass/Coproduct.ts.md +++ b/docs/modules/typeclass/Coproduct.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Coproduct.ts -nav_order: 9 +nav_order: 26 parent: Modules --- @@ -42,7 +42,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getMonoid: (F: Coproduct) => () => Monoid> +export declare const getMonoid: (F: Coproduct) => () => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index 5d948f250..77af9c2d2 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Covariant.ts -nav_order: 10 +nav_order: 27 parent: Modules --- @@ -34,9 +34,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const make: ( - map: (f: (a: A) => B) => (self: Kind) => Kind -) => Covariant +export declare const make: (map: (f: (a: A) => B) => (self: any) => any) => Covariant ``` Added in v1.0.0 @@ -48,9 +46,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const as: ( - F: Covariant -) => (b: B) => (self: Kind) => Kind +export declare const as: (F: Covariant) => (b: B) => (self: any) => any ``` Added in v1.0.0 @@ -60,9 +56,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const asUnit: ( - F: Covariant -) => (self: Kind) => Kind +export declare const asUnit: (F: Covariant) => (self: any) => any ``` Added in v1.0.0 @@ -72,9 +66,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const flap: ( - F: Covariant -) =>
(a: A) => (self: Kind B>) => Kind +export declare const flap: (F: Covariant) => (a: A) => (self: any) => any ``` Added in v1.0.0 @@ -102,9 +94,7 @@ Returns a default `imap` implementation. **Signature** ```ts -export declare const imap: ( - map: (f: (a: A) => B) => (self: Kind) => Kind -) => (to: (a: A) => B, from: (b: B) => A) => (self: Kind) => Kind +export declare const imap: (map: (f: (a: A) => B) => (self: any) => any) => any ``` Added in v1.0.0 @@ -114,12 +104,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const let: ( +export declare const let: ( F: Covariant -) => ( - name: Exclude, - f: (a: A) => B -) => (self: Kind) => Kind +) => (name: Exclude, f: (a: A) => B) => (self: any) => any ``` Added in v1.0.0 @@ -131,14 +118,10 @@ Returns a default `map` composition. **Signature** ```ts -export declare const mapComposition: ( +export declare const mapComposition: ( F: Covariant, G: Covariant -) => ( - f: (a: A) => B -) => ( - self: Kind> -) => Kind> +) => (f: (a: A) => B) => (self: any) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Equivalence.ts.md b/docs/modules/typeclass/Equivalence.ts.md new file mode 100644 index 000000000..177f3c61e --- /dev/null +++ b/docs/modules/typeclass/Equivalence.ts.md @@ -0,0 +1,268 @@ +--- +title: typeclass/Equivalence.ts +nav_order: 28 +parent: Modules +--- + +## Equivalence overview + +This module provides an implementation of the `Equivalence` type class, which defines a binary relation +that is reflexive, symmetric, and transitive. In other words, it defines a notion of equivalence between values of a certain type. +These properties are also known in mathematics as an "equivalence relation". + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [combinators](#combinators) + - [contramap](#contramap) +- [constructors](#constructors) + - [array](#array) + - [record](#record) + - [strict](#strict) + - [struct](#struct) + - [tuple](#tuple) +- [instances](#instances) + - [Contravariant](#contravariant) + - [Invariant](#invariant) + - [Product](#product) + - [SemiProduct](#semiproduct) + - [bigint](#bigint) + - [boolean](#boolean) + - [getMonoid](#getmonoid) + - [getSemigroup](#getsemigroup) + - [number](#number) + - [string](#string) + - [symbol](#symbol) +- [type class](#type-class) + - [Equivalence (interface)](#equivalence-interface) +- [type lambdas](#type-lambdas) + - [EquivalenceTypeLambda (interface)](#equivalencetypelambda-interface) + +--- + +# combinators + +## contramap + +**Signature** + +```ts +export declare const contramap: (f: (b: B) => A) => (self: Equivalence
) => Equivalence +``` + +Added in v1.0.0 + +# constructors + +## array + +Given an `Equivalence` of type `A`, returns a new `Equivalence` of type `ReadonlyArray`. +The returned `Equivalence` compares arrays by first checking their length and then applying the provided `Equivalence` to each element. +If all comparisons return true, the arrays are considered equal. + +**Signature** + +```ts +export declare const array: (equivalence: Equivalence) => Equivalence +``` + +Added in v1.0.0 + +## record + +Given an `Equivalence` of type `A`, returns a new `Equivalence` of type `{ readonly [x: string]: A }`. +The returned `Equivalence` compares records by first checking their number of keys and then applying the provided `Equivalence` to each value. +If all comparisons return true, the records are considered equal. + +**Signature** + +```ts +export declare const record: (equivalence: Equivalence) => Equivalence +``` + +Added in v1.0.0 + +## strict + +Return an `Equivalence` that uses strict equality (===) to compare values + +**Signature** + +```ts +export declare const strict: () => Equivalence +``` + +Added in v1.0.0 + +## struct + +Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct +by applying each `Equivalence` to the corresponding property of the struct. + +**Signature** + +```ts +export declare const struct: (equivalences: { [K in keyof A]: Equivalence }) => Equivalence<{ + readonly [K in keyof A]: A[K] +}> +``` + +Added in v1.0.0 + +## tuple + +Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple +by applying each `Equivalence` to the corresponding element of the tuple. + +**Signature** + +```ts +export declare const tuple: ( + ...equivalences: { readonly [K in keyof A]: Equivalence } +) => Equivalence> +``` + +Added in v1.0.0 + +# instances + +## Contravariant + +**Signature** + +```ts +export declare const Contravariant: any +``` + +Added in v1.0.0 + +## Invariant + +**Signature** + +```ts +export declare const Invariant: any +``` + +Added in v1.0.0 + +## Product + +**Signature** + +```ts +export declare const Product: any +``` + +Added in v1.0.0 + +## SemiProduct + +**Signature** + +```ts +export declare const SemiProduct: any +``` + +Added in v1.0.0 + +## bigint + +**Signature** + +```ts +export declare const bigint: Equivalence +``` + +Added in v1.0.0 + +## boolean + +**Signature** + +```ts +export declare const boolean: Equivalence +``` + +Added in v1.0.0 + +## getMonoid + +**Signature** + +```ts +export declare const getMonoid: () => any +``` + +Added in v2.6.0 + +## getSemigroup + +**Signature** + +```ts +export declare const getSemigroup: () => any +``` + +Added in v2.10.0 + +## number + +**Signature** + +```ts +export declare const number: Equivalence +``` + +Added in v1.0.0 + +## string + +**Signature** + +```ts +export declare const string: Equivalence +``` + +Added in v1.0.0 + +## symbol + +**Signature** + +```ts +export declare const symbol: Equivalence +``` + +Added in v1.0.0 + +# type class + +## Equivalence (interface) + +**Signature** + +```ts +export interface Equivalence { + (x: A, y: A): boolean +} +``` + +Added in v1.0.0 + +# type lambdas + +## EquivalenceTypeLambda (interface) + +**Signature** + +```ts +export interface EquivalenceTypeLambda extends TypeLambda { + readonly type: Equivalence +} +``` + +Added in v1.0.0 diff --git a/docs/modules/typeclass/Filterable.ts.md b/docs/modules/typeclass/Filterable.ts.md new file mode 100644 index 000000000..334992306 --- /dev/null +++ b/docs/modules/typeclass/Filterable.ts.md @@ -0,0 +1,98 @@ +--- +title: typeclass/Filterable.ts +nav_order: 29 +parent: Modules +--- + +## Filterable overview + +`Filterable` represents data structures which can be _partitioned_/_filtered_. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [models](#models) + - [Filterable (interface)](#filterable-interface) +- [utils](#utils) + - [filter](#filter) + - [filterMapComposition](#filtermapcomposition) + - [partition](#partition) + - [partitionMap](#partitionmap) + +--- + +# models + +## Filterable (interface) + +**Signature** + +```ts +export interface Filterable extends TypeClass { + readonly filterMap: (f: (a: A) => Option) => (self: Kind) => Kind +} +``` + +Added in v1.0.0 + +# utils + +## filter + +**Signature** + +```ts +export declare const filter: ( + F: Filterable +) => { + (refinement: (a: A) => a is B): (self: any) => any + (predicate: (a: A) => boolean): (self: any) => any +} +``` + +Added in v1.0.0 + +## filterMapComposition + +Returns a default `filterMap` composition. + +**Signature** + +```ts +export declare const filterMapComposition: ( + F: any, + G: Filterable +) => (f: (a: A) => any) => (self: any) => any +``` + +Added in v1.0.0 + +## partition + +**Signature** + +```ts +export declare const partition: ( + F: Filterable +) => { + (refinement: (a: A) => a is B): (self: any) => [any, any] + (predicate: (a: A) => boolean): (self: any) => [any, any] +} +``` + +Added in v1.0.0 + +## partitionMap + +**Signature** + +```ts +export declare const partitionMap: ( + F: Filterable +) => (f: (a: A) => any) => (self: any) => [any, any] +``` + +Added in v1.0.0 diff --git a/docs/modules/typeclass/FlatMap.ts.md b/docs/modules/typeclass/FlatMap.ts.md index 2ddc9163e..0c9a88819 100644 --- a/docs/modules/typeclass/FlatMap.ts.md +++ b/docs/modules/typeclass/FlatMap.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/FlatMap.ts -nav_order: 11 +nav_order: 30 parent: Modules --- @@ -46,11 +46,9 @@ A variant of `flatMap` that ignores the value produced by this effect. **Signature** ```ts -export declare const andThen: ( +export declare const andThen: ( F: FlatMap -) => ( - that: Kind -) => (self: Kind) => Kind +) => (that: any) => (self: any) => any ``` Added in v1.0.0 @@ -60,11 +58,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const composeKleisliArrow: ( +export declare const composeKleisliArrow: ( F: FlatMap -) => ( - bfc: (b: B) => Kind -) => (afb: (a: A) => Kind) => (a: A) => Kind +) => (bfc: (b: B) => any) => (afb: (a: A) => any) => (a: A) => any ``` Added in v1.0.0 @@ -74,11 +70,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatten: ( - F: FlatMap -) => ( - self: Kind> -) => Kind +export declare const flatten: (F: FlatMap) => (self: any) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Foldable.ts.md b/docs/modules/typeclass/Foldable.ts.md index a0d735c52..3e9a15f47 100644 --- a/docs/modules/typeclass/Foldable.ts.md +++ b/docs/modules/typeclass/Foldable.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Foldable.ts -nav_order: 12 +nav_order: 31 parent: Modules --- @@ -47,9 +47,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const foldMap: ( +export declare const foldMap: ( F: Foldable -) => (M: Monoid) =>
(f: (a: A) => M) => (self: Kind) => M +) => (M: any) => (f: (a: A) => M) => (self: any) => M ``` Added in v1.0.0 @@ -59,13 +59,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const foldMapKind: ( +export declare const foldMapKind: ( F: Foldable -) => ( - G: Coproduct -) => ( - f: (a: A) => Kind -) => (self: Kind) => Kind +) => (G: any) => (f: (a: A) => any) => (self: any) => any ``` Added in v1.0.0 @@ -77,13 +73,10 @@ Returns a default `reduce` composition. **Signature** ```ts -export declare const reduceComposition: ( +export declare const reduceComposition: ( F: Foldable, G: Foldable -) => ( - b: B, - f: (b: B, a: A) => B -) => (self: Kind>) => B +) => (b: B, f: (b: B, a: A) => B) => (self: any) => B ``` Added in v1.0.0 @@ -93,14 +86,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduceKind: ( +export declare const reduceKind: ( F: Foldable -) => ( - G: Monad -) => ( - b: B, - f: (b: B, a: A) => Kind -) => (self: Kind) => Kind +) => (G: any) => (b: B, f: (b: B, a: A) => any) => (self: any) => any ``` Added in v1.0.0 @@ -110,9 +98,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduceRight: ( +export declare const reduceRight: ( F: Foldable -) => (b: B, f: (b: B, a: A) => B) => (self: Kind) => B +) => (b: B, f: (b: B, a: A) => B) => (self: any) => B ``` Added in v1.0.0 @@ -122,14 +110,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduceRightKind: ( +export declare const reduceRightKind: ( F: Foldable -) => ( - G: Monad -) => ( - b: B, - f: (b: B, a: A) => Kind -) => (self: Kind) => Kind +) => (G: any) => (b: B, f: (b: B, a: A) => any) => (self: any) => any ``` Added in v1.0.0 @@ -139,7 +122,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const toArray: (F: Foldable) => (self: Kind) => A[] +export declare const toArray: (F: Foldable) => (self: any) => A[] ``` Added in v1.0.0 @@ -149,9 +132,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const toArrayWith: ( +export declare const toArrayWith: ( F: Foldable -) => (f: (a: A) => B) => (self: Kind) => B[] +) => (f: (a: A) => B) => (self: any) => B[] ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Invariant.ts.md b/docs/modules/typeclass/Invariant.ts.md index e88c28784..461283073 100644 --- a/docs/modules/typeclass/Invariant.ts.md +++ b/docs/modules/typeclass/Invariant.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Invariant.ts -nav_order: 13 +nav_order: 32 parent: Modules --- @@ -45,11 +45,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const bindTo: ( +export declare const bindTo: ( F: Invariant -) => ( - name: N -) => (self: Kind) => Kind +) => (name: N) => (self: any) => any ``` Added in v1.0.0 @@ -61,15 +59,10 @@ Returns a default `imap` composition. **Signature** ```ts -export declare const imapComposition: ( +export declare const imapComposition: ( F: Invariant, G: Invariant -) => ( - to: (a: A) => B, - from: (b: B) => A -) => ( - self: Kind> -) => Kind> +) => (to: (a: A) => B, from: (b: B) => A) => (self: any) => any ``` Added in v1.0.0 @@ -79,9 +72,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const tupled: ( - F: Invariant -) => (self: Kind) => Kind +export declare const tupled: (F: Invariant) => (self: any) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Monad.ts.md b/docs/modules/typeclass/Monad.ts.md index e29774286..eeb144205 100644 --- a/docs/modules/typeclass/Monad.ts.md +++ b/docs/modules/typeclass/Monad.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Monad.ts -nav_order: 14 +nav_order: 33 parent: Modules --- diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index 2b6823e5d..77141067d 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Monoid.ts -nav_order: 15 +nav_order: 34 parent: Modules --- @@ -12,29 +12,103 @@ Added in v1.0.0

Table of contents

+- [combinators](#combinators) + - [array](#array) + - [readonlyArray](#readonlyarray) + - [reverse](#reverse) + - [struct](#struct) + - [tuple](#tuple) - [constructors](#constructors) - [fromSemigroup](#fromsemigroup) - [max](#max) - [min](#min) +- [instances](#instances) + - [bigintMultiply](#bigintmultiply) + - [bigintSum](#bigintsum) + - [booleanAll](#booleanall) + - [booleanAny](#booleanany) + - [numberMultiply](#numbermultiply) + - [numberSum](#numbersum) + - [string](#string) - [type class](#type-class) - [Monoid (interface)](#monoid-interface) -- [utils](#utils) - - [reverse](#reverse) - - [struct](#struct) - - [tuple](#tuple) --- +# combinators + +## array + +Given a type `A`, this function creates and returns a `Monoid` for `Array
`. +The returned `Monoid`'s empty value is the empty array. + +**Signature** + +```ts +export declare const array: () => Monoid +``` + +Added in v1.0.0 + +## readonlyArray + +Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. +The returned `Monoid`'s empty value is the empty array. + +**Signature** + +```ts +export declare const readonlyArray: () => Monoid +``` + +Added in v1.0.0 + +## reverse + +The dual of a `Monoid`, obtained by swapping the arguments of `combine`. + +**Signature** + +```ts +export declare const reverse: (M: Monoid) => Monoid +``` + +Added in v1.0.0 + +## struct + +Given a struct of `Monoid`s returns a `Monoid` for the struct. + +**Signature** + +```ts +export declare const struct: (monoids: { readonly [K in keyof A]: Monoid }) => Monoid<{ + readonly [K in keyof A]: A[K] +}> +``` + +Added in v1.0.0 + +## tuple + +Given a tuple of `Monoid`s returns a `Monoid` for the tuple. + +**Signature** + +```ts +export declare const tuple: (...monoids: { [K in keyof A]: Monoid }) => Monoid +``` + +Added in v1.0.0 + # constructors ## fromSemigroup -Optimised. - **Signature** ```ts -export declare const fromSemigroup: (S: Semigroup, empty: A) => Monoid +export declare const fromSemigroup: (S: any, empty: A) => Monoid ``` Added in v1.0.0 @@ -48,7 +122,7 @@ The `empty` value is the `minimum` value. **Signature** ```ts -export declare const max: (B: Bounded) => Monoid +export declare const max: (B: any) => Monoid ``` Added in v1.0.0 @@ -62,64 +136,118 @@ The `empty` value is the `maxBound` value. **Signature** ```ts -export declare const min: (B: Bounded) => Monoid +export declare const min: (B: any) => Monoid ``` Added in v1.0.0 -# type class +# instances -## Monoid (interface) +## bigintMultiply + +`bigint` monoid under multiplication. + +The `empty` value is `1n`. **Signature** ```ts -export interface Monoid extends Semigroup { - readonly empty: A - readonly combineAll: (collection: Iterable) => A -} +export declare const bigintMultiply: Monoid ``` Added in v1.0.0 -# utils +## bigintSum -## reverse +`number` monoid under addition. -The dual of a `Monoid`, obtained by swapping the arguments of `combine`. +The `bigint` value is `0n`. **Signature** ```ts -export declare const reverse: (M: Monoid) => Monoid +export declare const bigintSum: Monoid ``` Added in v1.0.0 -## struct +## booleanAll -Given a struct of monoids returns a monoid for the struct. +`boolean` monoid under conjunction. + +The `empty` value is `true`. **Signature** ```ts -export declare const struct: (monoids: { readonly [K in keyof A]: Monoid }) => Monoid<{ - readonly [K in keyof A]: A[K] -}> +export declare const booleanAll: Monoid ``` Added in v1.0.0 -## tuple +## booleanAny + +`boolean` monoid under disjunction. -Given a tuple of monoids returns a monoid for the tuple. +The `empty` value is `false`. **Signature** ```ts -export declare const tuple: ( - ...monoids: { [K in keyof A]: Monoid } -) => Monoid> +export declare const booleanAny: Monoid +``` + +Added in v1.0.0 + +## numberMultiply + +`number` monoid under multiplication. + +The `empty` value is `1`. + +**Signature** + +```ts +export declare const numberMultiply: Monoid +``` + +Added in v1.0.0 + +## numberSum + +`number` monoid under addition. + +The `empty` value is `0`. + +**Signature** + +```ts +export declare const numberSum: Monoid +``` + +Added in v1.0.0 + +## string + +**Signature** + +```ts +export declare const string: Monoid +``` + +Added in v1.0.0 + +# type class + +## Monoid (interface) + +**Signature** + +```ts +export interface Monoid extends Semigroup { + readonly empty: A + readonly combineAll: (collection: Iterable) => A +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/NonEmptyTraversable.ts.md b/docs/modules/typeclass/NonEmptyTraversable.ts.md deleted file mode 100644 index 3504f3ad5..000000000 --- a/docs/modules/typeclass/NonEmptyTraversable.ts.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: typeclass/NonEmptyTraversable.ts -nav_order: 16 -parent: Modules ---- - -## NonEmptyTraversable overview - -NonEmptyTraversable describes a parameterized type T that contains one or more values of type `A`. - -Added in v1.0.0 - ---- - -

Table of contents

- -- [type class](#type-class) - - [NonEmptyTraversable (interface)](#nonemptytraversable-interface) -- [utils](#utils) - - [sequenceNonEmpty](#sequencenonempty) - - [sequenceNonEmptyComposition](#sequencenonemptycomposition) - - [traverseNonEmptyComposition](#traversenonemptycomposition) - ---- - -# type class - -## NonEmptyTraversable (interface) - -**Signature** - -```ts -export interface NonEmptyTraversable extends TypeClass { - readonly traverseNonEmpty: ( - F: SemiApplicative - ) => ( - f: (a: A) => Kind - ) => (self: Kind) => Kind> - - readonly sequenceNonEmpty: ( - F: SemiApplicative - ) => ( - self: Kind> - ) => Kind> -} -``` - -Added in v1.0.0 - -# utils - -## sequenceNonEmpty - -Returns a default `sequenceNonEmpty` implementation. - -**Signature** - -```ts -export declare const sequenceNonEmpty: ( - traverseNonEmpty: ( - F: SemiApplicative - ) => ( - f: (a: A) => Kind - ) => (self: Kind) => Kind> -) => ( - F: SemiApplicative -) => ( - self: Kind> -) => Kind> -``` - -Added in v1.0.0 - -## sequenceNonEmptyComposition - -Returns a default `sequenceNonEmpty` composition. - -**Signature** - -```ts -export declare const sequenceNonEmptyComposition: ( - T: NonEmptyTraversable & Covariant, - G: NonEmptyTraversable -) => ( - F: SemiApplicative -) => ( - self: Kind>> -) => Kind>> -``` - -Added in v1.0.0 - -## traverseNonEmptyComposition - -Returns a default `traverseNonEmpty` composition. - -**Signature** - -```ts -export declare const traverseNonEmptyComposition: ( - T: NonEmptyTraversable, - G: NonEmptyTraversable -) => ( - F: SemiApplicative -) => ( - f: (a: A) => Kind -) => ( - self: Kind> -) => Kind>> -``` - -Added in v1.0.0 diff --git a/docs/modules/typeclass/Of.ts.md b/docs/modules/typeclass/Of.ts.md index a06bd5098..f00c7a399 100644 --- a/docs/modules/typeclass/Of.ts.md +++ b/docs/modules/typeclass/Of.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Of.ts -nav_order: 17 +nav_order: 35 parent: Modules --- @@ -42,7 +42,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Do: (F: Of) => Kind +export declare const Do: (F: Of) => any ``` Added in v1.0.0 @@ -54,10 +54,7 @@ Returns a default `of` composition. **Signature** ```ts -export declare const ofComposition: ( - F: Of, - G: Of -) =>
(a: A) => Kind> +export declare const ofComposition: (F: Of, G: Of) => (a: A) => any ``` Added in v1.0.0 @@ -67,7 +64,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const unit: (F: Of) => Kind +export declare const unit: (F: Of) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index c2f6a5c7f..3cee18971 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Order.ts -nav_order: 18 +nav_order: 36 parent: Modules --- @@ -12,6 +12,10 @@ Added in v1.0.0

Table of contents

+- [combinators](#combinators) + - [array](#array) + - [struct](#struct) + - [tuple](#tuple) - [constructors](#constructors) - [fromCompare](#fromcompare) - [instances](#instances) @@ -19,8 +23,12 @@ Added in v1.0.0 - [Invariant](#invariant) - [Product](#product) - [SemiProduct](#semiproduct) + - [bigint](#bigint) + - [boolean](#boolean) - [getMonoid](#getmonoid) - [getSemigroup](#getsemigroup) + - [number](#number) + - [string](#string) - [type class](#type-class) - [Order (interface)](#order-interface) - [type lambdas](#type-lambdas) @@ -36,10 +44,58 @@ Added in v1.0.0 - [max](#max) - [min](#min) - [reverse](#reverse) - - [tuple](#tuple) --- +# combinators + +## array + +This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. +The returned `Order` compares two arrays by applying the given `Order` to each element in the arrays. +If all elements are equal, the arrays are then compared based on their length. +It is useful when you need to compare two arrays of the same type and you have a specific way of comparing each element of the array. + +**Signature** + +```ts +export declare const array:
(O: Order) => Order +``` + +Added in v1.0.0 + +## struct + +This function creates and returns a new `Order` for a struct of values based on the given `Order`s +for each property in the struct. + +**Signature** + +```ts +export declare const struct: (orders: { readonly [K in keyof A]: Order }) => Order<{ + readonly [K in keyof A]: A[K] +}> +``` + +Added in v1.0.0 + +## tuple + +This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. +The returned `Order` compares two tuples of the same type by applying the corresponding `Order` to each element in the tuple. +It is useful when you need to compare two tuples of the same type and you have a specific way of comparing each element +of the tuple. + +**Signature** + +```ts +export declare const tuple: ( + ...orders: { readonly [K in keyof A]: Order } +) => Order> +``` + +Added in v1.0.0 + # constructors ## fromCompare @@ -49,7 +105,7 @@ Main constructor. **Signature** ```ts -export declare const fromCompare: (compare: (that: A) => (self: A) => 0 | 1 | -1) => Order +export declare const fromCompare: (compare: (self: A, that: A) => 0 | 1 | -1) => Order ``` Added in v1.0.0 @@ -61,7 +117,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Contravariant: contravariant.Contravariant +export declare const Contravariant: any ``` Added in v1.0.0 @@ -71,7 +127,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Invariant: invariant.Invariant +export declare const Invariant: any ``` Added in v1.0.0 @@ -81,7 +137,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: product.Product +export declare const Product: any ``` Added in v1.0.0 @@ -91,7 +147,27 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiProduct: semiProduct.SemiProduct +export declare const SemiProduct: any +``` + +Added in v1.0.0 + +## bigint + +**Signature** + +```ts +export declare const bigint: Order +``` + +Added in v1.0.0 + +## boolean + +**Signature** + +```ts +export declare const boolean: Order ``` Added in v1.0.0 @@ -101,7 +177,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getMonoid: () => Monoid> +export declare const getMonoid: () => any ``` Added in v1.0.0 @@ -111,7 +187,27 @@ Added in v1.0.0 **Signature** ```ts -export declare const getSemigroup: () => Semigroup> +export declare const getSemigroup: () => any +``` + +Added in v1.0.0 + +## number + +**Signature** + +```ts +export declare const number: Order +``` + +Added in v1.0.0 + +## string + +**Signature** + +```ts +export declare const string: Order ``` Added in v1.0.0 @@ -124,7 +220,7 @@ Added in v1.0.0 ```ts export interface Order { - readonly compare: (that: A) => (self: A) => -1 | 0 | 1 + readonly compare: (self: A, that: A) => -1 | 0 | 1 } ``` @@ -261,15 +357,3 @@ export declare const reverse: (O: Order) => Order ``` Added in v1.0.0 - -## tuple - -Given a tuple of `Compare`s returns a `Compare` for the tuple. - -**Signature** - -```ts -export declare const tuple: (...orders: { [K in keyof A]: Order }) => Order> -``` - -Added in v1.0.0 diff --git a/docs/modules/typeclass/Pointed.ts.md b/docs/modules/typeclass/Pointed.ts.md index 1f29db58e..c1d10a9df 100644 --- a/docs/modules/typeclass/Pointed.ts.md +++ b/docs/modules/typeclass/Pointed.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Pointed.ts -nav_order: 19 +nav_order: 37 parent: Modules --- diff --git a/docs/modules/typeclass/Product.ts.md b/docs/modules/typeclass/Product.ts.md index b804002af..7e2960ddf 100644 --- a/docs/modules/typeclass/Product.ts.md +++ b/docs/modules/typeclass/Product.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Product.ts -nav_order: 20 +nav_order: 38 parent: Modules --- @@ -28,7 +28,7 @@ Added in v1.0.0 ```ts export interface Product extends SemiProduct, Of { - readonly productAll: (collection: Iterable>) => Kind> + readonly productAll: (collection: Iterable>) => Kind> } ``` @@ -41,17 +41,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const struct: ( +export declare const struct: ( F: Product -) => >>( - fields: R -) => Kind< - F, - [R[keyof R]] extends [Kind] ? R : never, - [R[keyof R]] extends [Kind] ? O : never, - [R[keyof R]] extends [Kind] ? E : never, - { readonly [K in keyof R]: [R[K]] extends [Kind] ? A : never } -> +) => (fields: R) => any ``` Added in v1.0.0 @@ -61,17 +53,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const tuple: ( - F: Product -) => []>( - ...components: T -) => Kind< - F, - [T[number]] extends [Kind] ? R : never, - [T[number]] extends [Kind] ? O : never, - [T[number]] extends [Kind] ? E : never, - Readonly<{ [I in keyof T]: [T[I]] extends [Kind] ? A : never }> -> +export declare const tuple: (F: Product) => (...components: T) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiAlternative.ts.md b/docs/modules/typeclass/SemiAlternative.ts.md index 6d0e39a39..e855eedd0 100644 --- a/docs/modules/typeclass/SemiAlternative.ts.md +++ b/docs/modules/typeclass/SemiAlternative.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/SemiAlternative.ts -nav_order: 21 +nav_order: 39 parent: Modules --- diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index 99e700d4f..54cddac5d 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/SemiApplicative.ts -nav_order: 22 +nav_order: 40 parent: Modules --- @@ -43,11 +43,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const andThen: ( +export declare const andThen: ( F: SemiApplicative -) => ( - that: Kind -) => (self: Kind) => Kind +) => (that: any) => (self: any) => any ``` Added in v1.0.0 @@ -57,11 +55,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const andThenDiscard: ( +export declare const andThenDiscard: ( F: SemiApplicative -) => ( - that: Kind -) => (self: Kind) => Kind +) => (that: any) => (self: any) => any ``` Added in v1.0.0 @@ -71,11 +67,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const ap: ( +export declare const ap: ( F: SemiApplicative -) => ( - fa: Kind -) => (self: Kind B>) => Kind +) => (fa: any) => (self: any) => any ``` Added in v1.0.0 @@ -87,14 +81,9 @@ Lifts a binary function into `F`. **Signature** ```ts -export declare const lift2: ( +export declare const lift2: ( F: SemiApplicative -) => ( - f: (a: A, b: B) => C -) => ( - fa: Kind, - fb: Kind -) => Kind +) => (f: (a: A, b: B) => C) => (fa: any, fb: any) => any ``` Added in v1.0.0 @@ -106,15 +95,9 @@ Lifts a ternary function into 'F'. **Signature** ```ts -export declare const lift3: ( +export declare const lift3: ( F: SemiApplicative -) => ( - f: (a: A, b: B, c: C) => D -) => ( - fa: Kind, - fb: Kind, - fc: Kind -) => Kind +) => (f: (a: A, b: B, c: C) => D) => (fa: any, fb: any, fc: any) => any ``` Added in v1.0.0 @@ -126,9 +109,7 @@ Lift a `Semigroup` into 'F', the inner values are combined using the provided `S **Signature** ```ts -export declare const liftSemigroup: ( - F: SemiApplicative -) => (S: Semigroup) => Semigroup> +export declare const liftSemigroup: (F: SemiApplicative) => (S: any) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiCoproduct.ts.md b/docs/modules/typeclass/SemiCoproduct.ts.md index b1702361b..cc6d0f242 100644 --- a/docs/modules/typeclass/SemiCoproduct.ts.md +++ b/docs/modules/typeclass/SemiCoproduct.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/SemiCoproduct.ts -nav_order: 23 +nav_order: 41 parent: Modules --- @@ -27,13 +27,15 @@ Added in v1.0.0 ```ts export interface SemiCoproduct extends Invariant { - readonly coproduct: ( + readonly coproduct: ( + self: Kind, that: Kind - ) => (self: Kind) => Kind + ) => Kind readonly coproductMany: ( + self: Kind, collection: Iterable> - ) => (self: Kind) => Kind + ) => Kind } ``` @@ -46,9 +48,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getSemigroup: ( - F: SemiCoproduct -) => () => Semigroup> +export declare const getSemigroup: (F: SemiCoproduct) => () => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index da622d96d..197394475 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/SemiProduct.ts -nav_order: 25 +nav_order: 43 parent: Modules --- @@ -18,10 +18,10 @@ Added in v1.0.0 - [SemiProduct (interface)](#semiproduct-interface) - [utils](#utils) - [andThenBind](#andthenbind) + - [element](#element) - [nonEmptyStruct](#nonemptystruct) - [nonEmptyTuple](#nonemptytuple) - [productComposition](#productcomposition) - - [productFlatten](#productflatten) - [productManyComposition](#productmanycomposition) --- @@ -35,14 +35,10 @@ Returns a default `productMany` implementation (useful for tests). **Signature** ```ts -export declare const productMany: ( - Covariant: Covariant, - product: ( - that: Kind - ) => (self: Kind) => Kind -) => ( - collection: Iterable> -) => (self: Kind) => Kind +export declare const productMany: ( + Covariant: any, + product: (self: any, that: any) => any +) => (self: any, collection: Iterable) => any ``` Added in v1.0.0 @@ -55,13 +51,15 @@ Added in v1.0.0 ```ts export interface SemiProduct extends Invariant { - readonly product: ( + readonly product: ( + self: Kind, that: Kind - ) => (self: Kind) => Kind + ) => Kind readonly productMany: ( + self: Kind, collection: Iterable> - ) => (self: Kind) => Kind]> + ) => Kind]> } ``` @@ -74,89 +72,65 @@ Added in v1.0.0 **Signature** ```ts -export declare const andThenBind: ( +export declare const andThenBind: ( F: SemiProduct ) => ( name: Exclude, - that: Kind -) => ( - self: Kind -) => Kind + that: any +) => (self: any) => any ``` Added in v1.0.0 -## nonEmptyStruct +## element + +Adds an element to the end of a tuple. **Signature** ```ts -export declare const nonEmptyStruct: ( +export declare const element: ( F: SemiProduct -) => >>>( - fields: EnforceNonEmptyRecord & Record> -) => Kind< - F, - [R[keyof R]] extends [Kind] ? R : never, - [R[keyof R]] extends [Kind] ? O : never, - [R[keyof R]] extends [Kind] ? E : never, - { readonly [K in keyof R]: [R[K]] extends [Kind] ? A : never } -> +) => (that: any) => (self: any) => any ``` Added in v1.0.0 -## nonEmptyTuple +## nonEmptyStruct **Signature** ```ts -export declare const nonEmptyTuple: ( +export declare const nonEmptyStruct: ( F: SemiProduct -) => , ...Kind[]]>( - ...components: T -) => Kind< - F, - [T[number]] extends [Kind] ? R : never, - [T[number]] extends [Kind] ? O : never, - [T[number]] extends [Kind] ? E : never, - Readonly<{ [I in keyof T]: [T[I]] extends [Kind] ? A : never }> -> +) => (fields: EnforceNonEmptyRecord & { readonly [x: string]: any }) => any ``` Added in v1.0.0 -## productComposition - -Returns a default `product` composition. +## nonEmptyTuple **Signature** ```ts -export declare const productComposition: ( - F: SemiApplicative, - G: SemiProduct -) => ( - that: Kind> -) => ( - self: Kind> -) => Kind> +export declare const nonEmptyTuple: ( + F: SemiProduct +) => (...components: T) => any ``` Added in v1.0.0 -## productFlatten +## productComposition + +Returns a default `product` composition. **Signature** ```ts -export declare const productFlatten: ( - F: SemiProduct -) => ( - that: Kind -) => ( - self: Kind -) => Kind +export declare const productComposition: ( + F: any, + G: SemiProduct +) => (self: any, that: any) => any ``` Added in v1.0.0 @@ -168,14 +142,10 @@ Returns a default `productMany` composition. **Signature** ```ts -export declare const productManyComposition: ( - F: SemiApplicative, +export declare const productManyComposition: ( + F: any, G: SemiProduct -) => ( - collection: Iterable>> -) => ( - self: Kind> -) => Kind> +) => (self: any, collection: Iterable) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index 287320099..9da24d4d5 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Semigroup.ts -nav_order: 24 +nav_order: 42 parent: Modules --- @@ -10,8 +10,8 @@ parent: Modules ```ts export interface Semigroup { - combine: (that: A) => (self: A) => A - combineMany: (collection: Iterable) => (self: A) => A + combine: (self: A, that: A) => A + combineMany: (self: A, collection: Iterable) => A } ``` @@ -31,6 +31,11 @@ Added in v1.0.0

Table of contents

+- [combinators](#combinators) + - [array](#array) + - [readonlyArray](#readonlyarray) + - [struct](#struct) + - [tuple](#tuple) - [constructors](#constructors) - [constant](#constant) - [fromCombine](#fromcombine) @@ -40,8 +45,15 @@ Added in v1.0.0 - [Invariant](#invariant) - [Product](#product) - [SemiProduct](#semiproduct) + - [bigintMultiply](#bigintmultiply) + - [bigintSum](#bigintsum) + - [booleanAll](#booleanall) + - [booleanAny](#booleanany) - [first](#first) - [last](#last) + - [numberMultiply](#numbermultiply) + - [numberSum](#numbersum) + - [string](#string) - [type class](#type-class) - [Semigroup (interface)](#semigroup-interface) - [type lambdas](#type-lambdas) @@ -50,11 +62,69 @@ Added in v1.0.0 - [imap](#imap) - [intercalate](#intercalate) - [reverse](#reverse) - - [struct](#struct) - - [tuple](#tuple) --- +# combinators + +## array + +Given a type `A`, this function creates and returns a `Semigroup` for `Array
`. +The returned `Semigroup` combines two arrays by concatenating them. + +**Signature** + +```ts +export declare const array: () => Semigroup +``` + +Added in v1.0.0 + +## readonlyArray + +Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. +The returned `Semigroup` combines two arrays by concatenating them. + +**Signature** + +```ts +export declare const readonlyArray: () => Semigroup +``` + +Added in v1.0.0 + +## struct + +This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. +The returned `Semigroup` combines two structs of the same type by applying the corresponding `Semigroup` passed as arguments to each property in the struct. +It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. + +**Signature** + +```ts +export declare const struct: (semigroups: { readonly [K in keyof A]: Semigroup }) => Semigroup<{ + readonly [K in keyof A]: A[K] +}> +``` + +Added in v1.0.0 + +## tuple + +This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. +The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. +It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. + +**Signature** + +```ts +export declare const tuple: ( + ...semigroups: { readonly [K in keyof A]: Semigroup } +) => Semigroup +``` + +Added in v1.0.0 + # constructors ## constant @@ -74,7 +144,7 @@ Useful when `combineMany` can't be optimised. **Signature** ```ts -export declare const fromCombine: (combine: (that: A) => (self: A) => A) => Semigroup +export declare const fromCombine: (combine: (self: A, that: A) => A) => Semigroup ``` Added in v1.0.0 @@ -86,7 +156,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const max: (O: Order) => Semigroup +export declare const max: (O: any) => Semigroup ``` Added in v1.0.0 @@ -98,7 +168,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const min: (O: Order) => Semigroup +export declare const min: (O: any) => Semigroup ``` Added in v1.0.0 @@ -110,7 +180,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Invariant: invariant.Invariant +export declare const Invariant: any ``` Added in v1.0.0 @@ -120,7 +190,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: product.Product +export declare const Product: any ``` Added in v1.0.0 @@ -130,7 +200,55 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiProduct: semiProduct.SemiProduct +export declare const SemiProduct: any +``` + +Added in v1.0.0 + +## bigintMultiply + +`bigint` semigroup under multiplication. + +**Signature** + +```ts +export declare const bigintMultiply: Semigroup +``` + +Added in v1.0.0 + +## bigintSum + +`bigint` semigroup under addition. + +**Signature** + +```ts +export declare const bigintSum: Semigroup +``` + +Added in v1.0.0 + +## booleanAll + +`boolean` semigroup under conjunction. + +**Signature** + +```ts +export declare const booleanAll: Semigroup +``` + +Added in v1.0.0 + +## booleanAny + +`boolean` semigroup under disjunction. + +**Signature** + +```ts +export declare const booleanAny: Semigroup ``` Added in v1.0.0 @@ -159,93 +277,99 @@ export declare const last: () => Semigroup Added in v1.0.0 -# type class +## numberMultiply -## Semigroup (interface) +`number` semigroup under multiplication. **Signature** ```ts -export interface Semigroup { - readonly combine: (that: A) => (self: A) => A - readonly combineMany: (collection: Iterable) => (self: A) => A -} +export declare const numberMultiply: Semigroup ``` Added in v1.0.0 -# type lambdas +## numberSum -## SemigroupTypeLambda (interface) +`number` semigroup under addition. **Signature** ```ts -export interface SemigroupTypeLambda extends TypeLambda { - readonly type: Semigroup -} +export declare const numberSum: Semigroup ``` Added in v1.0.0 -# utils - -## imap +## string **Signature** ```ts -export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (S: Semigroup) => Semigroup +export declare const string: Semigroup ``` Added in v1.0.0 -## intercalate +# type class + +## Semigroup (interface) **Signature** ```ts -export declare const intercalate: (separator: A) => (S: Semigroup) => Semigroup +export interface Semigroup { + readonly combine: (self: A, that: A) => A + readonly combineMany: (self: A, collection: Iterable) => A +} ``` Added in v1.0.0 -## reverse +# type lambdas -The dual of a `Semigroup`, obtained by flipping the arguments of `combine`. +## SemigroupTypeLambda (interface) **Signature** ```ts -export declare const reverse: (S: Semigroup) => Semigroup +export interface SemigroupTypeLambda extends TypeLambda { + readonly type: Semigroup +} ``` Added in v1.0.0 -## struct +# utils -Given a struct of associatives returns an associative for the struct. +## imap **Signature** ```ts -export declare const struct: (semigroups: { [K in keyof A]: Semigroup }) => Semigroup<{ - readonly [K in keyof A]: A[K] -}> +export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (S: Semigroup) => Semigroup ``` Added in v1.0.0 -## tuple +## intercalate + +**Signature** + +```ts +export declare const intercalate: (separator: A) => (S: Semigroup) => Semigroup +``` + +Added in v1.0.0 + +## reverse -Given a tuple of associatives returns an associative for the tuple. +The dual of a `Semigroup`, obtained by flipping the arguments of `combine`. **Signature** ```ts -export declare const tuple: ( - ...semigroups: { [K in keyof A]: Semigroup } -) => Semigroup> +export declare const reverse: (S: Semigroup) => Semigroup ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Traversable.ts.md b/docs/modules/typeclass/Traversable.ts.md index fbd411377..4a1553bb6 100644 --- a/docs/modules/typeclass/Traversable.ts.md +++ b/docs/modules/typeclass/Traversable.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Traversable.ts -nav_order: 26 +nav_order: 44 parent: Modules --- @@ -55,17 +55,9 @@ Returns a default `sequence` implementation. **Signature** ```ts -export declare const sequence: ( - traverse: ( - F: Applicative - ) => ( - f: (a: A) => Kind - ) => (self: Kind) => Kind> -) => ( - F: Applicative -) => ( - self: Kind> -) => Kind> +export declare const sequence: ( + traverse: (F: any) => (f: (a: A) => any) => (self: any) => any +) => (F: any) => (self: any) => any ``` Added in v1.0.0 @@ -77,14 +69,10 @@ Returns a default `sequence` composition. **Signature** ```ts -export declare const sequenceComposition: ( - T: Traversable & Covariant, +export declare const sequenceComposition: ( + T: any, G: Traversable -) => ( - F: Applicative -) => ( - self: Kind>> -) => Kind>> +) => (F: any) => (self: any) => any ``` Added in v1.0.0 @@ -96,16 +84,10 @@ Returns a default `traverse` composition. **Signature** ```ts -export declare const traverseComposition: ( +export declare const traverseComposition: ( T: Traversable, G: Traversable -) => ( - F: Applicative -) => ( - f: (a: A) => Kind -) => ( - self: Kind> -) => Kind>> +) => (F: any) => (f: (a: A) => any) => (self: any) => any ``` Added in v1.0.0 @@ -120,13 +102,9 @@ returned by the provided function. **Signature** ```ts -export declare const traverseTap: ( +export declare const traverseTap: ( T: Traversable -) => ( - F: Applicative -) => ( - f: (a: A) => Kind -) => (self: Kind) => Kind> +) => (F: any) => (f: (a: A) => any) => (self: any) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/TraversableFilterable.ts.md b/docs/modules/typeclass/TraversableFilterable.ts.md new file mode 100644 index 000000000..5b5f24d21 --- /dev/null +++ b/docs/modules/typeclass/TraversableFilterable.ts.md @@ -0,0 +1,107 @@ +--- +title: typeclass/TraversableFilterable.ts +nav_order: 45 +parent: Modules +--- + +## TraversableFilterable overview + +`TraversableFilterable` represents data structures which can be _partitioned_ with effects in some `Applicative` functor. + +Added in v1.0.0 + +--- + +

Table of contents

+ +- [models](#models) + - [TraversableFilterable (interface)](#traversablefilterable-interface) +- [utils](#utils) + - [traverseFilter](#traversefilter) + - [traverseFilterMap](#traversefiltermap) + - [traversePartition](#traversepartition) + - [traversePartitionMap](#traversepartitionmap) + +--- + +# models + +## TraversableFilterable (interface) + +**Signature** + +```ts +export interface TraversableFilterable extends TypeClass { + readonly traversePartitionMap: ( + F: Applicative + ) => ( + f: (a: A) => Kind> + ) => (self: Kind) => Kind, Kind]> + + readonly traverseFilterMap: ( + F: Applicative + ) => ( + f: (a: A) => Kind> + ) => (self: Kind) => Kind> +} +``` + +Added in v1.0.0 + +# utils + +## traverseFilter + +**Signature** + +```ts +export declare const traverseFilter: ( + T: TraversableFilterable +) => ( + F: any +) => (predicate: (a: A) => any) => (self: any) => any +``` + +Added in v1.0.0 + +## traverseFilterMap + +Returns a default `traverseFilterMap` implementation. + +**Signature** + +```ts +export declare const traverseFilterMap: ( + T: any +) => (F: any) => (f: (a: A) => any) => (self: any) => any +``` + +Added in v1.0.0 + +## traversePartition + +**Signature** + +```ts +export declare const traversePartition: ( + T: TraversableFilterable +) => ( + F: any +) => (predicate: (a: A) => any) => (self: any) => any +``` + +Added in v1.0.0 + +## traversePartitionMap + +Returns a default `traversePartitionMap` implementation. + +**Signature** + +```ts +export declare const traversePartitionMap: ( + T: any +) => (F: any) => (f: (a: A) => any) => (self: any) => any +``` + +Added in v1.0.0 diff --git a/src/Boolean.ts b/src/Boolean.ts index ec0241537..af8651faa 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -62,8 +62,8 @@ export const Order: order.Order = order.boolean * import { SemigroupAll } from '@fp-ts/core/Boolean' * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(true, SemigroupAll.combine(true)), true) - * assert.deepStrictEqual(pipe(true, SemigroupAll.combine(false)), false) + * assert.deepStrictEqual(SemigroupAll.combine(true, true), true) + * assert.deepStrictEqual(SemigroupAll.combine(true, false), false) * * @category instances * @since 1.0.0 @@ -77,9 +77,9 @@ export const SemigroupAll: semigroup.Semigroup = semigroup.booleanAll * import { SemigroupAny } from '@fp-ts/core/Boolean' * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(true, SemigroupAny.combine(true)), true) - * assert.deepStrictEqual(pipe(true, SemigroupAny.combine(false)), true) - * assert.deepStrictEqual(pipe(false, SemigroupAny.combine(false)), false) + * assert.deepStrictEqual(SemigroupAny.combine(true, true), true) + * assert.deepStrictEqual(SemigroupAny.combine(true, false), true) + * assert.deepStrictEqual(SemigroupAny.combine(false, false), false) * * @category instances * @since 1.0.0 diff --git a/src/Either.ts b/src/Either.ts index 29b339d7d..e7ab02f47 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1017,7 +1017,7 @@ export const fromOption: (onNone: LazyArg) =>
(self: Option) => Eith * import * as O from '@fp-ts/core/Option' * import * as E from '@fp-ts/core/Either' * - * assert.deepStrictEqual(E.getLeft(E.right('ok')), O.none) + * assert.deepStrictEqual(E.getLeft(E.right('ok')), O.none()) * assert.deepStrictEqual(E.getLeft(E.left('err')), O.some('err')) * * @category getters @@ -1033,7 +1033,7 @@ export const getLeft: (self: Either) => Option = either.getLeft * import * as E from '@fp-ts/core/Either' * * assert.deepStrictEqual(E.getRight(E.right('ok')), O.some('ok')) - * assert.deepStrictEqual(E.getRight(E.left('err')), O.none) + * assert.deepStrictEqual(E.getRight(E.left('err')), O.none()) * * @category getters * @since 1.0.0 diff --git a/src/Function.ts b/src/Function.ts index ebe780f4e..9fb4d9dce 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -36,13 +36,13 @@ export const compose: (bc: (b: B) => C) => (ab: (a: A) => B) => (a: A) * * const S1 = getSemigroup(B.SemigroupAll)() * - * assert.deepStrictEqual(pipe(f, S1.combine(g))(1), true) - * assert.deepStrictEqual(pipe(f, S1.combine(g))(3), false) + * assert.deepStrictEqual(S1.combine(f, g)(1), true) + * assert.deepStrictEqual(S1.combine(f, g)(3), false) * * const S2 = getSemigroup(B.SemigroupAny)() * - * assert.deepStrictEqual(pipe(f, S2.combine(g))(1), true) - * assert.deepStrictEqual(pipe(f, S2.combine(g))(3), true) + * assert.deepStrictEqual(S2.combine(f, g)(1), true) + * assert.deepStrictEqual(S2.combine(f, g)(3), true) * * @category instances * @since 1.0.0 @@ -64,13 +64,13 @@ export const getSemigroup = (Semigroup: semigroup.Semigroup) => * * const M1 = getMonoid(B.MonoidAll)() * - * assert.deepStrictEqual(pipe(f, M1.combine(g))(1), true) - * assert.deepStrictEqual(pipe(f, M1.combine(g))(3), false) + * assert.deepStrictEqual(M1.combine(f, g)(1), true) + * assert.deepStrictEqual(M1.combine(f, g)(3), false) * * const M2 = getMonoid(B.MonoidAny)() * - * assert.deepStrictEqual(pipe(f, M2.combine(g))(1), true) - * assert.deepStrictEqual(pipe(f, M2.combine(g))(3), true) + * assert.deepStrictEqual(M2.combine(f, g)(1), true) + * assert.deepStrictEqual(M2.combine(f, g)(3), true) * * @category instances * @since 1.0.0 diff --git a/src/Number.ts b/src/Number.ts index b1568fea2..779a81ee5 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -76,7 +76,7 @@ export const Bounded = bounded.number * import { SemigroupSum } from '@fp-ts/core/Number' * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(2, SemigroupSum.combine(3)), 5) + * assert.deepStrictEqual(SemigroupSum.combine(2, 3), 5) * * @category instances * @since 1.0.0 @@ -102,7 +102,7 @@ export const SemigroupMin = semigroup.min(Order) * import { SemigroupMultiply } from '@fp-ts/core/Number' * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(2, SemigroupMultiply.combine(3)), 6) + * assert.deepStrictEqual(SemigroupMultiply.combine(2, 3), 6) * * @category instances * @since 1.0.0 diff --git a/src/Option.ts b/src/Option.ts index 479c75e30..95000e7be 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -93,7 +93,7 @@ export const some: (a: A) => Option = option.some * import { some, none, isOption } from '@fp-ts/core/Option' * * assert.strictEqual(isOption(some(1)), true) - * assert.strictEqual(isOption(none), true) + * assert.strictEqual(isOption(none()), true) * assert.strictEqual(isOption({}), false) * * @category guards @@ -108,8 +108,8 @@ export const isOption: (u: unknown) => u is Option = option.isOption * @example * import { none, some, fromNullable } from '@fp-ts/core/Option' * - * assert.deepStrictEqual(fromNullable(undefined), none) - * assert.deepStrictEqual(fromNullable(null), none) + * assert.deepStrictEqual(fromNullable(undefined), none()) + * assert.deepStrictEqual(fromNullable(null), none()) * assert.deepStrictEqual(fromNullable(1), some(1)) * * @category conversions @@ -138,7 +138,7 @@ export const toRefinement = (f: (a: A) => Option): Refinement * fromThrowable(() => { * throw new Error() * }), - * none + * none() * ) * assert.deepStrictEqual(fromThrowable(() => 1), some(1)) * @@ -516,10 +516,10 @@ export const SemiApplicative: semiApplicative.SemiApplicative * import { pipe } from '@fp-ts/core/Function' * * const M = getMonoid(N.SemigroupSum) - * assert.deepStrictEqual(pipe(none, M.combine(none)), none) - * assert.deepStrictEqual(pipe(some(1), M.combine(none)), some(1)) - * assert.deepStrictEqual(pipe(none, M.combine(some(1))), some(1)) - * assert.deepStrictEqual(pipe(some(1), M.combine(some(2))), some(3)) + * assert.deepStrictEqual(M.combine(none(), none()), none()) + * assert.deepStrictEqual(M.combine(some(1), none()), some(1)) + * assert.deepStrictEqual(M.combine(none(), some(1)), some(1)) + * assert.deepStrictEqual(M.combine(some(1), some(2)), some(3)) * * @category lifting * @since 1.0.0 @@ -799,7 +799,7 @@ export const traverseTap: ( * import { some, none, isNone } from '@fp-ts/core/Option' * * assert.strictEqual(isNone(some(1)), false) - * assert.strictEqual(isNone(none), true) + * assert.strictEqual(isNone(none()), true) * * @category guards * @since 1.0.0 @@ -813,7 +813,7 @@ export const isNone: (self: Option) => self is None = option.isNone * import { some, none, isSome } from '@fp-ts/core/Option' * * assert.strictEqual(isSome(some(1)), true) - * assert.strictEqual(isSome(none), false) + * assert.strictEqual(isSome(none()), false) * * @category guards * @since 1.0.0 @@ -839,7 +839,7 @@ export const fromIterable = (collection: Iterable): Option => { * import * as E from '@fp-ts/core/Either' * * assert.deepStrictEqual(O.fromEither(E.right(1)), O.some(1)) - * assert.deepStrictEqual(O.fromEither(E.left('a')), O.none) + * assert.deepStrictEqual(O.fromEither(E.left('a')), O.none()) * * @category conversions * @since 1.0.0 @@ -871,7 +871,7 @@ export const toEither: (onNone: LazyArg) => (self: Option) => Either * * assert.strictEqual( * pipe( - * none, + * none(), * match(() => 'a none', a => `a some containing ${a}`) * ), * 'a none' @@ -891,7 +891,7 @@ export const match = (onNone: LazyArg, onSome: (a: A) => C) => * import { pipe } from '@fp-ts/core/Function' * * assert.strictEqual(pipe(some(1), getOrElse(() => 0)), 1) - * assert.strictEqual(pipe(none, getOrElse(() => 0)), 0) + * assert.strictEqual(pipe(none(), getOrElse(() => 0)), 0) * * @category error handling * @since 1.0.0 @@ -913,7 +913,7 @@ export const getOrElse = (onNone: LazyArg) => * const g = liftNullable(f) * * assert.deepStrictEqual(g('1'), some(1)) - * assert.deepStrictEqual(g('a'), none) + * assert.deepStrictEqual(g('a'), none()) * * @category lifting * @since 1.0.0 @@ -960,7 +960,7 @@ export const liftNullable = , B>( * flatMapNullable(address => address.street), * flatMapNullable(street => street.name) * ), - * none + * none() * ) * * @category sequencing @@ -978,7 +978,7 @@ export const flatMapNullable = (f: (a: A) => B | null | undefined) => * import { pipe } from '@fp-ts/core/Function' * * assert.strictEqual(pipe(some(1), getOrNull), 1) - * assert.strictEqual(pipe(none, getOrNull), null) + * assert.strictEqual(pipe(none(), getOrNull), null) * * @category conversions * @since 1.0.0 @@ -993,7 +993,7 @@ export const getOrNull: (self: Option) => A | null = getOrElse(constNull) * import { pipe } from '@fp-ts/core/Function' * * assert.strictEqual(pipe(some(1), getOrUndefined), 1) - * assert.strictEqual(pipe(none, getOrUndefined), undefined) + * assert.strictEqual(pipe(none(), getOrUndefined), undefined) * * @category conversions * @since 1.0.0 @@ -1028,21 +1028,21 @@ export const catchAll = (that: LazyArg>) => * * assert.deepStrictEqual( * pipe( - * O.none, - * O.orElse(O.none) + * O.none(), + * O.orElse(O.none()) * ), - * O.none + * O.none() * ) * assert.deepStrictEqual( * pipe( * O.some('a'), - * O.orElse(O.none) + * O.orElse(O.none()) * ), * O.some('a') * ) * assert.deepStrictEqual( * pipe( - * O.none, + * O.none(), * O.orElse(O.some('b')) * ), * O.some('b') @@ -1100,11 +1100,11 @@ export const orElseSucceed = ( * import { pipe } from '@fp-ts/core/Function' * * const O = liftOrder(N.Order) - * assert.strictEqual(pipe(none, O.compare(none)), 0) - * assert.strictEqual(pipe(none, O.compare(some(1))), -1) - * assert.strictEqual(pipe(some(1), O.compare(none)), 1) - * assert.strictEqual(pipe(some(1), O.compare(some(2))), -1) - * assert.strictEqual(pipe(some(1), O.compare(some(1))), 0) + * assert.strictEqual(O.compare(none(), none()), 0) + * assert.strictEqual(O.compare(none(), some(1)), -1) + * assert.strictEqual(O.compare(some(1), none()), 1) + * assert.strictEqual(O.compare(some(1), some(2)), -1) + * assert.strictEqual(O.compare(some(1), some(1)), 0) * * @category sorting * @since 1.0.0 @@ -1122,7 +1122,7 @@ export const liftOrder = (O: Order): Order> => * * const getOption = O.liftPredicate((n: number) => n >= 0) * - * assert.deepStrictEqual(getOption(-1), O.none) + * assert.deepStrictEqual(getOption(-1), O.none()) * assert.deepStrictEqual(getOption(1), O.some(1)) * * @category lifting @@ -1179,7 +1179,7 @@ export const contains = (equivalence: Equivalence) => * ) * assert.strictEqual( * pipe( - * none, + * none(), * exists(n => n > 0) * ), * false From 776de1f4dc99facee72ab17d6df0672258d68acd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Jan 2023 18:26:35 +0000 Subject: [PATCH 089/255] Version Packages --- .changeset/modern-tomatoes-promise.md | 5 ----- .changeset/red-moons-hope.md | 5 ----- CHANGELOG.md | 10 ++++++++++ package.json | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) delete mode 100644 .changeset/modern-tomatoes-promise.md delete mode 100644 .changeset/red-moons-hope.md diff --git a/.changeset/modern-tomatoes-promise.md b/.changeset/modern-tomatoes-promise.md deleted file mode 100644 index d40355a05..000000000 --- a/.changeset/modern-tomatoes-promise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -add modules from @fp-ts/data diff --git a/.changeset/red-moons-hope.md b/.changeset/red-moons-hope.md deleted file mode 100644 index 142e4bf1b..000000000 --- a/.changeset/red-moons-hope.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -Add tracking code for Option diff --git a/CHANGELOG.md b/CHANGELOG.md index d91339d5f..3baefeaf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # @fp-ts/core +## 0.1.0 + +### Minor Changes + +- [#46](https://github.com/fp-ts/core/pull/46) [`0bd0d604`](https://github.com/fp-ts/core/commit/0bd0d60454642d7b1692d923c2d240b747ac797b) Thanks [@gcanti](https://github.com/gcanti)! - add modules from @fp-ts/data + +### Patch Changes + +- [#46](https://github.com/fp-ts/core/pull/46) [`3c256fa8`](https://github.com/fp-ts/core/commit/3c256fa8b9bbb4379ad51c5e48781deaaac2990a) Thanks [@gcanti](https://github.com/gcanti)! - Add tracking code for Option + ## next **Breaking changes** diff --git a/package.json b/package.json index f4bbebe05..191363182 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fp-ts/core", - "version": "0.0.11", + "version": "0.1.0", "publishConfig": { "access": "public", "directory": "dist" From da0bae8487d59d78c5ba6470d37727ccc66538bb Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 24 Jan 2023 08:00:45 +0100 Subject: [PATCH 090/255] change structural tracking --- .changeset/plenty-parents-collect.md | 5 + src/These.ts | 7 +- src/internal/Either.ts | 6 +- src/internal/Option.ts | 10 +- src/internal/effect.ts | 3 + test/Either.ts | 274 ++++++++------- test/Option.ts | 282 ++++++++------- test/These.ts | 507 ++++++++++++++------------- test/util.ts | 6 + 9 files changed, 573 insertions(+), 527 deletions(-) create mode 100644 .changeset/plenty-parents-collect.md diff --git a/.changeset/plenty-parents-collect.md b/.changeset/plenty-parents-collect.md new file mode 100644 index 000000000..815496e81 --- /dev/null +++ b/.changeset/plenty-parents-collect.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +change structural tracking diff --git a/src/These.ts b/src/These.ts index 678d747da..b6bf12097 100644 --- a/src/These.ts +++ b/src/These.ts @@ -19,7 +19,7 @@ import type { Either, Left, Right } from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import { structural } from "@fp-ts/core/internal/effect" +import { proto, structural } from "@fp-ts/core/internal/effect" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" import type { Option } from "@fp-ts/core/Option" @@ -109,10 +109,7 @@ export const of = right * @since 1.0.0 */ export const both = (left: E, right: A): These => - Object.defineProperty({ _tag: "Both", left, right }, structural, { - enumerable: false, - value: true - }) + Object.setPrototypeOf({ _tag: "Both", left, right }, proto) /** * @category constructors diff --git a/src/internal/Either.ts b/src/internal/Either.ts index 61d472503..e2a60961a 100644 --- a/src/internal/Either.ts +++ b/src/internal/Either.ts @@ -4,7 +4,7 @@ import type { Either, Left, Right } from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" -import { structural } from "@fp-ts/core/internal/effect" +import { proto, structural } from "@fp-ts/core/internal/effect" import * as option from "@fp-ts/core/internal/Option" import type { Option } from "@fp-ts/core/Option" @@ -21,11 +21,11 @@ export const isRight = (ma: Either): ma is Right => ma._tag === " /** @internal */ export const left = (e: E): Either => - Object.defineProperty({ _tag: "Left", left: e }, structural, { enumerable: false, value: true }) + Object.setPrototypeOf({ _tag: "Left", left: e }, proto) /** @internal */ export const right = (a: A): Either => - Object.defineProperty({ _tag: "Right", right: a }, structural, { enumerable: false, value: true }) + Object.setPrototypeOf({ _tag: "Right", right: a }, proto) /** @internal */ export const getLeft = ( diff --git a/src/internal/Option.ts b/src/internal/Option.ts index 433decce3..abed7ec08 100644 --- a/src/internal/Option.ts +++ b/src/internal/Option.ts @@ -2,7 +2,7 @@ * @since 1.0.0 */ -import { structural } from "@fp-ts/core/internal/effect" +import { proto, structural } from "@fp-ts/core/internal/effect" import type { None, Option, Some } from "@fp-ts/core/Option" /** @internal */ @@ -17,14 +17,10 @@ export const isNone = (fa: Option): fa is None => fa._tag === "None" export const isSome = (fa: Option): fa is Some => fa._tag === "Some" /** @internal */ -export const none: Option = Object.defineProperty({ _tag: "None" }, structural, { - enumerable: false, - value: true -}) +export const none: Option = Object.setPrototypeOf({ _tag: "None" }, proto) /** @internal */ -export const some = (a: A): Option => - Object.defineProperty({ _tag: "Some", value: a }, structural, { enumerable: false, value: true }) +export const some = (a: A): Option => Object.setPrototypeOf({ _tag: "Some", value: a }, proto) /** @internal */ export const fromNullable = ( diff --git a/src/internal/effect.ts b/src/internal/effect.ts index 0e6da6670..dab15a880 100644 --- a/src/internal/effect.ts +++ b/src/internal/effect.ts @@ -4,3 +4,6 @@ /** @internal */ export const structural = Symbol.for("@effect/data/Equal/structural") + +/** @internal */ +export const proto = Object.setPrototypeOf({ [structural]: true }, Object.prototype) diff --git a/test/Either.ts b/test/Either.ts index 42a2de8b5..b203afa74 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -1,8 +1,9 @@ import * as _ from "@fp-ts/core/Either" import { flow, identity, pipe } from "@fp-ts/core/Function" +import { structural } from "@fp-ts/core/internal/effect" import * as O from "@fp-ts/core/Option" import * as String from "@fp-ts/core/String" -import { deepStrictEqual, double } from "@fp-ts/core/test/util" +import * as Util from "@fp-ts/core/test/util" import { number } from "@fp-ts/core/typeclass/Equivalence" describe.concurrent("Either", () => { @@ -74,87 +75,98 @@ describe.concurrent("Either", () => { expect(_.traverseTap).exist }) + it("structural tracking", () => { + expect(Util.ownKeys(_.left("a"))).toEqual(["_tag", "left"]) + expect(Util.ownKeys(_.right(1))).toEqual(["_tag", "right"]) + + expect(Object.prototype.hasOwnProperty.call(_.left("a"), structural)).toEqual(false) + expect(Object.prototype.hasOwnProperty.call(_.right(1), structural)).toEqual(false) + + expect(Util.isStructural(_.left("a"))).toEqual(true) + expect(Util.isStructural(_.right(1))).toEqual(true) + }) + it("toRefinement", () => { const f = (s: string | number): _.Either => typeof s === "string" ? _.right(s) : _.left("not a string") const isString = _.toRefinement(f) - deepStrictEqual(isString("s"), true) - deepStrictEqual(isString(1), false) + Util.deepStrictEqual(isString("s"), true) + Util.deepStrictEqual(isString(1), false) type A = { readonly type: "A" } type B = { readonly type: "B" } type C = A | B const isA = _.toRefinement(( c: C ) => (c.type === "A" ? _.right(c) : _.left("not as A"))) - deepStrictEqual(isA({ type: "A" }), true) - deepStrictEqual(isA({ type: "B" }), false) + Util.deepStrictEqual(isA({ type: "A" }), true) + Util.deepStrictEqual(isA({ type: "B" }), false) }) it("isEither", () => { - deepStrictEqual(pipe(_.right(1), _.isEither), true) - deepStrictEqual(pipe(_.left("e"), _.isEither), true) - deepStrictEqual(pipe(O.some(1), _.isEither), false) + Util.deepStrictEqual(pipe(_.right(1), _.isEither), true) + Util.deepStrictEqual(pipe(_.left("e"), _.isEither), true) + Util.deepStrictEqual(pipe(O.some(1), _.isEither), false) }) it("orElseFail", () => { - deepStrictEqual(pipe(_.right(1), _.orElseFail(() => "e2")), _.right(1)) - deepStrictEqual(pipe(_.left("e1"), _.orElseFail(() => "e2")), _.left("e2")) + Util.deepStrictEqual(pipe(_.right(1), _.orElseFail(() => "e2")), _.right(1)) + Util.deepStrictEqual(pipe(_.left("e1"), _.orElseFail(() => "e2")), _.left("e2")) }) it("orElseSucceed", () => { - deepStrictEqual(pipe(_.right(1), _.orElseSucceed(() => 2)), _.right(1)) - deepStrictEqual(pipe(_.left("e"), _.orElseSucceed(() => 2)), _.right(2)) + Util.deepStrictEqual(pipe(_.right(1), _.orElseSucceed(() => 2)), _.right(1)) + Util.deepStrictEqual(pipe(_.left("e"), _.orElseSucceed(() => 2)), _.right(2)) }) it("reduce", () => { - deepStrictEqual(pipe(_.right("bar"), _.Foldable.reduce("foo", (b, a) => b + a)), "foobar") - deepStrictEqual(pipe(_.left("bar"), _.Foldable.reduce("foo", (b, a) => b + a)), "foo") + Util.deepStrictEqual(pipe(_.right("bar"), _.Foldable.reduce("foo", (b, a) => b + a)), "foobar") + Util.deepStrictEqual(pipe(_.left("bar"), _.Foldable.reduce("foo", (b, a) => b + a)), "foo") }) it("getRight", () => { - deepStrictEqual(pipe(_.right(1), _.getRight), O.some(1)) - deepStrictEqual(pipe(_.left("a"), _.getRight), O.none()) + Util.deepStrictEqual(pipe(_.right(1), _.getRight), O.some(1)) + Util.deepStrictEqual(pipe(_.left("a"), _.getRight), O.none()) }) it("getLeft", () => { - deepStrictEqual(pipe(_.right(1), _.getLeft), O.none()) - deepStrictEqual(pipe(_.left("e"), _.getLeft), O.some("e")) + Util.deepStrictEqual(pipe(_.right(1), _.getLeft), O.none()) + Util.deepStrictEqual(pipe(_.left("e"), _.getLeft), O.some("e")) }) it("getOrNull", () => { - deepStrictEqual(pipe(_.right(1), _.getOrNull), 1) - deepStrictEqual(pipe(_.left("a"), _.getOrNull), null) + Util.deepStrictEqual(pipe(_.right(1), _.getOrNull), 1) + Util.deepStrictEqual(pipe(_.left("a"), _.getOrNull), null) }) it("getOrUndefined", () => { - deepStrictEqual(pipe(_.right(1), _.getOrUndefined), 1) - deepStrictEqual(pipe(_.left("a"), _.getOrUndefined), undefined) + Util.deepStrictEqual(pipe(_.right(1), _.getOrUndefined), 1) + Util.deepStrictEqual(pipe(_.left("a"), _.getOrUndefined), undefined) }) it("compact", () => { - deepStrictEqual(pipe(_.right(O.some(1)), _.compact(() => "e2")), _.right(1)) - deepStrictEqual(pipe(_.right(O.none()), _.compact(() => "e2")), _.left("e2")) - deepStrictEqual(pipe(_.left("e1"), _.compact(() => "e2")), _.left("e1")) + Util.deepStrictEqual(pipe(_.right(O.some(1)), _.compact(() => "e2")), _.right(1)) + Util.deepStrictEqual(pipe(_.right(O.none()), _.compact(() => "e2")), _.left("e2")) + Util.deepStrictEqual(pipe(_.left("e1"), _.compact(() => "e2")), _.left("e1")) }) it("inspectRight", () => { const log: Array = [] pipe(_.right(1), _.inspectRight((e) => log.push(e))) pipe(_.left("e"), _.inspectRight((e) => log.push(e))) - deepStrictEqual(log, [1]) + Util.deepStrictEqual(log, [1]) }) it("tapError", () => { - deepStrictEqual(pipe(_.right(1), _.tapError(() => _.right(2))), _.right(1)) - deepStrictEqual(pipe(_.left("a"), _.tapError(() => _.right(2))), _.left("a")) - deepStrictEqual(pipe(_.left("a"), _.tapError(() => _.left("b"))), _.left("b")) + Util.deepStrictEqual(pipe(_.right(1), _.tapError(() => _.right(2))), _.right(1)) + Util.deepStrictEqual(pipe(_.left("a"), _.tapError(() => _.right(2))), _.left("a")) + Util.deepStrictEqual(pipe(_.left("a"), _.tapError(() => _.left("b"))), _.left("b")) }) it("inspectLeft", () => { const log: Array = [] pipe(_.right(1), _.inspectLeft((e) => log.push(e))) pipe(_.left("e"), _.inspectLeft((e) => log.push(e))) - deepStrictEqual(log, ["e"]) + Util.deepStrictEqual(log, ["e"]) }) it("getOrThrow", () => { @@ -165,24 +177,24 @@ describe.concurrent("Either", () => { }) it("andThenDiscard", () => { - deepStrictEqual(pipe(_.right(1), _.andThenDiscard(_.right("a"))), _.right(1)) - deepStrictEqual(pipe(_.right(1), _.andThenDiscard(_.left(true))), _.left(true)) - deepStrictEqual(pipe(_.left(1), _.andThenDiscard(_.right("a"))), _.left(1)) - deepStrictEqual(pipe(_.left(1), _.andThenDiscard(_.left(true))), _.left(1)) + Util.deepStrictEqual(pipe(_.right(1), _.andThenDiscard(_.right("a"))), _.right(1)) + Util.deepStrictEqual(pipe(_.right(1), _.andThenDiscard(_.left(true))), _.left(true)) + Util.deepStrictEqual(pipe(_.left(1), _.andThenDiscard(_.right("a"))), _.left(1)) + Util.deepStrictEqual(pipe(_.left(1), _.andThenDiscard(_.left(true))), _.left(1)) }) it("andThen", () => { - deepStrictEqual(pipe(_.right(1), _.andThen(_.right("a"))), _.right("a")) - deepStrictEqual(pipe(_.right(1), _.andThen(_.left(true))), _.left(true)) - deepStrictEqual(pipe(_.left(1), _.andThen(_.right("a"))), _.left(1)) - deepStrictEqual(pipe(_.left(1), _.andThen(_.left(true))), _.left(1)) + Util.deepStrictEqual(pipe(_.right(1), _.andThen(_.right("a"))), _.right("a")) + Util.deepStrictEqual(pipe(_.right(1), _.andThen(_.left(true))), _.left(true)) + Util.deepStrictEqual(pipe(_.left(1), _.andThen(_.right("a"))), _.left(1)) + Util.deepStrictEqual(pipe(_.left(1), _.andThen(_.left(true))), _.left(1)) }) it("orElse", () => { - deepStrictEqual(pipe(_.right(1), _.orElse(_.right(2))), _.right(1)) - deepStrictEqual(pipe(_.right(1), _.orElse(_.left("b"))), _.right(1)) - deepStrictEqual(pipe(_.left("a"), _.orElse(_.right(2))), _.right(2)) - deepStrictEqual(pipe(_.left("a"), _.orElse(_.left("b"))), _.left("b")) + Util.deepStrictEqual(pipe(_.right(1), _.orElse(_.right(2))), _.right(1)) + Util.deepStrictEqual(pipe(_.right(1), _.orElse(_.left("b"))), _.right(1)) + Util.deepStrictEqual(pipe(_.left("a"), _.orElse(_.right(2))), _.right(2)) + Util.deepStrictEqual(pipe(_.left("a"), _.orElse(_.left("b"))), _.left("b")) }) it("orElseEither", () => { @@ -194,113 +206,113 @@ describe.concurrent("Either", () => { it("map", () => { const f = _.map(String.length) - deepStrictEqual(pipe(_.right("abc"), f), _.right(3)) - deepStrictEqual(pipe(_.left("s"), f), _.left("s")) + Util.deepStrictEqual(pipe(_.right("abc"), f), _.right(3)) + Util.deepStrictEqual(pipe(_.left("s"), f), _.left("s")) }) it("flatMap", () => { const f = _.flatMap(flow(String.length, _.right)) - deepStrictEqual(pipe(_.right("abc"), f), _.right(3)) - deepStrictEqual(pipe(_.left("maError"), f), _.left("maError")) + Util.deepStrictEqual(pipe(_.right("abc"), f), _.right(3)) + Util.deepStrictEqual(pipe(_.left("maError"), f), _.left("maError")) }) it("bimap", () => { const f = _.bimap(String.length, (n: number) => n > 2) - deepStrictEqual(pipe(_.right(1), f), _.right(false)) + Util.deepStrictEqual(pipe(_.right(1), f), _.right(false)) }) it("mapLeft", () => { - const f = _.mapLeft(double) - deepStrictEqual(pipe(_.right("a"), f), _.right("a")) - deepStrictEqual(pipe(_.left(1), f), _.left(2)) + const f = _.mapLeft(Util.double) + Util.deepStrictEqual(pipe(_.right("a"), f), _.right("a")) + Util.deepStrictEqual(pipe(_.left(1), f), _.left(2)) }) it("traverse", () => { const traverse = _.traverse(O.Applicative)(( n: number ) => (n >= 2 ? O.some(n) : O.none())) - deepStrictEqual(pipe(_.left("a"), traverse), O.some(_.left("a"))) - deepStrictEqual(pipe(_.right(1), traverse), O.none()) - deepStrictEqual(pipe(_.right(3), traverse), O.some(_.right(3))) + Util.deepStrictEqual(pipe(_.left("a"), traverse), O.some(_.left("a"))) + Util.deepStrictEqual(pipe(_.right(1), traverse), O.none()) + Util.deepStrictEqual(pipe(_.right(3), traverse), O.some(_.right(3))) }) it("sequence", () => { const sequence = _.sequence(O.Applicative) - deepStrictEqual(sequence(_.right(O.some(1))), O.some(_.right(1))) - deepStrictEqual(sequence(_.left("a")), O.some(_.left("a"))) - deepStrictEqual(sequence(_.right(O.none())), O.none()) + Util.deepStrictEqual(sequence(_.right(O.some(1))), O.some(_.right(1))) + Util.deepStrictEqual(sequence(_.left("a")), O.some(_.left("a"))) + Util.deepStrictEqual(sequence(_.right(O.none())), O.none()) }) it("match", () => { const f = (s: string) => `left${s.length}` const g = (s: string) => `right${s.length}` const match = _.match(f, g) - deepStrictEqual(match(_.left("abc")), "left3") - deepStrictEqual(match(_.right("abc")), "right3") + Util.deepStrictEqual(match(_.left("abc")), "left3") + Util.deepStrictEqual(match(_.right("abc")), "right3") }) it("getOrElse", () => { - deepStrictEqual(pipe(_.right(12), _.getOrElse(() => 17)), 12) - deepStrictEqual(pipe(_.left("a"), _.getOrElse(() => 17)), 17) + Util.deepStrictEqual(pipe(_.right(12), _.getOrElse(() => 17)), 12) + Util.deepStrictEqual(pipe(_.left("a"), _.getOrElse(() => 17)), 17) }) it("contains", () => { const contains = _.contains(number) - deepStrictEqual(pipe(_.left("a"), contains(2)), false) - deepStrictEqual(pipe(_.right(2), contains(2)), true) - deepStrictEqual(pipe(_.right(2), contains(1)), false) + Util.deepStrictEqual(pipe(_.left("a"), contains(2)), false) + Util.deepStrictEqual(pipe(_.right(2), contains(2)), true) + Util.deepStrictEqual(pipe(_.right(2), contains(1)), false) }) it("filter", () => { const predicate = (n: number) => n > 10 - deepStrictEqual(pipe(_.right(12), _.filter(predicate, () => -1)), _.right(12)) - deepStrictEqual(pipe(_.right(7), _.filter(predicate, () => -1)), _.left(-1)) - deepStrictEqual(pipe(_.left(12), _.filter(predicate, () => -1)), _.left(12)) + Util.deepStrictEqual(pipe(_.right(12), _.filter(predicate, () => -1)), _.right(12)) + Util.deepStrictEqual(pipe(_.right(7), _.filter(predicate, () => -1)), _.left(-1)) + Util.deepStrictEqual(pipe(_.left(12), _.filter(predicate, () => -1)), _.left(12)) }) it("isLeft", () => { - deepStrictEqual(_.isLeft(_.right(1)), false) - deepStrictEqual(_.isLeft(_.left(1)), true) + Util.deepStrictEqual(_.isLeft(_.right(1)), false) + Util.deepStrictEqual(_.isLeft(_.left(1)), true) }) it("isRight", () => { - deepStrictEqual(_.isRight(_.right(1)), true) - deepStrictEqual(_.isRight(_.left(1)), false) + Util.deepStrictEqual(_.isRight(_.right(1)), true) + Util.deepStrictEqual(_.isRight(_.left(1)), false) }) it("catchAll", () => { - deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.right(2))), _.right(1)) - deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.left("foo"))), _.right(1)) - deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.right(1))), _.right(1)) - deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.left("b"))), _.left("b")) + Util.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.right(2))), _.right(1)) + Util.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.left("foo"))), _.right(1)) + Util.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.right(1))), _.right(1)) + Util.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.left("b"))), _.left("b")) }) it("swap", () => { - deepStrictEqual(_.reverse(_.right("a")), _.left("a")) - deepStrictEqual(_.reverse(_.left("b")), _.right("b")) + Util.deepStrictEqual(_.reverse(_.right("a")), _.left("a")) + Util.deepStrictEqual(_.reverse(_.left("b")), _.right("b")) }) it("liftPredicate", () => { const f = _.liftPredicate((n: number) => n >= 2, () => "e") - deepStrictEqual(f(3), _.right(3)) - deepStrictEqual(f(1), _.left("e")) + Util.deepStrictEqual(f(3), _.right(3)) + Util.deepStrictEqual(f(1), _.left("e")) }) it("fromNullable", () => { - deepStrictEqual(_.fromNullable(() => "default")(null), _.left("default")) - deepStrictEqual(_.fromNullable(() => "default")(undefined), _.left("default")) - deepStrictEqual(_.fromNullable(() => "default")(1), _.right(1)) + Util.deepStrictEqual(_.fromNullable(() => "default")(null), _.left("default")) + Util.deepStrictEqual(_.fromNullable(() => "default")(undefined), _.left("default")) + Util.deepStrictEqual(_.fromNullable(() => "default")(1), _.right(1)) }) it("fromThrowable", () => { - deepStrictEqual( + Util.deepStrictEqual( _.fromThrowable(() => { return 1 }, identity), _.right(1) ) - deepStrictEqual( + Util.deepStrictEqual( _.fromThrowable(() => { throw "string error" }, identity), @@ -311,56 +323,56 @@ describe.concurrent("Either", () => { it("filterMap", () => { const p = (n: number) => n > 2 const f = (n: number) => (p(n) ? O.some(n + 1) : O.none()) - deepStrictEqual(pipe(_.left("123"), _.filterMap(f, () => "")), _.left("123")) - deepStrictEqual(pipe(_.right(1), _.filterMap(f, () => "")), _.left(String.Monoid.empty)) - deepStrictEqual(pipe(_.right(3), _.filterMap(f, () => "")), _.right(4)) + Util.deepStrictEqual(pipe(_.left("123"), _.filterMap(f, () => "")), _.left("123")) + Util.deepStrictEqual(pipe(_.right(1), _.filterMap(f, () => "")), _.left(String.Monoid.empty)) + Util.deepStrictEqual(pipe(_.right(3), _.filterMap(f, () => "")), _.right(4)) }) it("fromIterable", () => { - deepStrictEqual(_.fromIterable(() => "e")([]), _.left("e")) - deepStrictEqual(_.fromIterable(() => "e")(["a"]), _.right("a")) + Util.deepStrictEqual(_.fromIterable(() => "e")([]), _.left("e")) + Util.deepStrictEqual(_.fromIterable(() => "e")(["a"]), _.right("a")) }) it("firstSuccessOf", () => { - deepStrictEqual(pipe(_.right(1), _.firstSuccessOf([])), _.right(1)) - deepStrictEqual(pipe(_.left("e"), _.firstSuccessOf([])), _.left("e")) - deepStrictEqual( + Util.deepStrictEqual(pipe(_.right(1), _.firstSuccessOf([])), _.right(1)) + Util.deepStrictEqual(pipe(_.left("e"), _.firstSuccessOf([])), _.left("e")) + Util.deepStrictEqual( pipe(_.left("e1"), _.firstSuccessOf([_.left("e2"), _.left("e3"), _.left("e4"), _.right(1)])), _.right(1) ) - deepStrictEqual( + Util.deepStrictEqual( pipe(_.left("e1"), _.firstSuccessOf([_.left("e2"), _.left("e3"), _.left("e4")])), _.left("e4") ) }) it("fromOption", () => { - deepStrictEqual(_.fromOption(() => "none")(O.none()), _.left("none")) - deepStrictEqual(_.fromOption(() => "none")(O.some(1)), _.right(1)) + Util.deepStrictEqual(_.fromOption(() => "none")(O.none()), _.left("none")) + Util.deepStrictEqual(_.fromOption(() => "none")(O.some(1)), _.right(1)) }) it("liftOption", () => { const f = _.liftOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "a") - deepStrictEqual(f(1), _.right(1)) - deepStrictEqual(f(-1), _.left("a")) + Util.deepStrictEqual(f(1), _.right(1)) + Util.deepStrictEqual(f(-1), _.left("a")) }) it("flatMapOption", () => { const f = _.flatMapOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "a") - deepStrictEqual(f(_.right(1)), _.right(1)) - deepStrictEqual(f(_.right(-1)), _.left("a")) - deepStrictEqual(f(_.left("b")), _.left("b")) + Util.deepStrictEqual(f(_.right(1)), _.right(1)) + Util.deepStrictEqual(f(_.right(-1)), _.left("a")) + Util.deepStrictEqual(f(_.left("b")), _.left("b")) }) it("exists", () => { const gt2 = _.exists((n: number) => n > 2) - deepStrictEqual(gt2(_.left("a")), false) - deepStrictEqual(gt2(_.right(1)), false) - deepStrictEqual(gt2(_.right(3)), true) + Util.deepStrictEqual(gt2(_.left("a")), false) + Util.deepStrictEqual(gt2(_.right(1)), false) + Util.deepStrictEqual(gt2(_.right(3)), true) }) it("do notation", () => { - deepStrictEqual( + Util.deepStrictEqual( pipe( _.right(1), _.bindTo("a"), @@ -372,7 +384,7 @@ describe.concurrent("Either", () => { }) it("andThenBind", () => { - deepStrictEqual( + Util.deepStrictEqual( pipe(_.right(1), _.bindTo("a"), _.andThenBind("b", _.right("b"))), _.right({ a: 1, b: "b" }) ) @@ -380,10 +392,10 @@ describe.concurrent("Either", () => { it("product", () => { const product = _.SemiProduct.product - deepStrictEqual(product(_.right(1), _.right("a")), _.right([1, "a"])) - deepStrictEqual(product(_.right(1), _.left("e2")), _.left("e2")) - deepStrictEqual(product(_.left("e1"), _.right("a")), _.left("e1")) - deepStrictEqual(product(_.left("e1"), _.left("2")), _.left("e1")) + Util.deepStrictEqual(product(_.right(1), _.right("a")), _.right([1, "a"])) + Util.deepStrictEqual(product(_.right(1), _.left("e2")), _.left("e2")) + Util.deepStrictEqual(product(_.left("e1"), _.right("a")), _.left("e1")) + Util.deepStrictEqual(product(_.left("e1"), _.left("2")), _.left("e1")) }) it("productMany", () => { @@ -392,12 +404,12 @@ describe.concurrent("Either", () => { collection: Iterable<_.Either> ) => _.Either]> = _.SemiProduct.productMany - deepStrictEqual(productMany(_.right(1), []), _.right([1])) - deepStrictEqual( + Util.deepStrictEqual(productMany(_.right(1), []), _.right([1])) + Util.deepStrictEqual( productMany(_.right(1), [_.right(2), _.right(3)]), _.right([1, 2, 3]) ) - deepStrictEqual( + Util.deepStrictEqual( productMany(_.right(1), [_.left("e"), _.right(3)]), _.left("e") ) @@ -408,12 +420,12 @@ describe.concurrent("Either", () => { it("productAll", () => { const productAll = _.Product.productAll - deepStrictEqual(productAll([]), _.right([])) - deepStrictEqual( + Util.deepStrictEqual(productAll([]), _.right([])) + Util.deepStrictEqual( productAll([_.right(1), _.right(2), _.right(3)]), _.right([1, 2, 3]) ) - deepStrictEqual( + Util.deepStrictEqual( productAll([_.left("e"), _.right(2), _.right(3)]), _.left("e") ) @@ -421,21 +433,21 @@ describe.concurrent("Either", () => { it("coproduct", () => { const coproduct = _.SemiCoproduct.coproduct - deepStrictEqual(coproduct(_.right(1), _.right(2)), _.right(1)) - deepStrictEqual(coproduct(_.right(1), _.left("e2")), _.right(1)) - deepStrictEqual(coproduct(_.left("e1"), _.right(2)), _.right(2)) - deepStrictEqual(coproduct(_.left("e1"), _.left("e2")), _.left("e2")) + Util.deepStrictEqual(coproduct(_.right(1), _.right(2)), _.right(1)) + Util.deepStrictEqual(coproduct(_.right(1), _.left("e2")), _.right(1)) + Util.deepStrictEqual(coproduct(_.left("e1"), _.right(2)), _.right(2)) + Util.deepStrictEqual(coproduct(_.left("e1"), _.left("e2")), _.left("e2")) }) it("coproductMany", () => { const coproductMany = _.SemiCoproduct.coproductMany - deepStrictEqual(coproductMany(_.right(1), [_.right(2)]), _.right(1)) - deepStrictEqual( + Util.deepStrictEqual(coproductMany(_.right(1), [_.right(2)]), _.right(1)) + Util.deepStrictEqual( coproductMany(_.right(1), [_.left("e2")]), _.right(1) ) - deepStrictEqual(coproductMany(_.left("e1"), [_.right(2)]), _.right(2)) - deepStrictEqual(coproductMany(_.left("e1"), [_.left("e2")]), _.left("e2")) + Util.deepStrictEqual(coproductMany(_.left("e1"), [_.right(2)]), _.right(2)) + Util.deepStrictEqual(coproductMany(_.left("e1"), [_.left("e2")]), _.left("e2")) }) it("element", () => { @@ -446,20 +458,20 @@ describe.concurrent("Either", () => { it("liftNullable", () => { const f = _.liftNullable((n: number) => (n > 0 ? n : null), () => "error") - deepStrictEqual(f(1), _.right(1)) - deepStrictEqual(f(-1), _.left("error")) + Util.deepStrictEqual(f(1), _.right(1)) + Util.deepStrictEqual(f(-1), _.left("error")) }) it("flatMapNullable", () => { const f = _.flatMapNullable((n: number) => (n > 0 ? n : null), () => "error") - deepStrictEqual(f(_.right(1)), _.right(1)) - deepStrictEqual(f(_.right(-1)), _.left("error")) - deepStrictEqual(f(_.left("a")), _.left("a")) + Util.deepStrictEqual(f(_.right(1)), _.right(1)) + Util.deepStrictEqual(f(_.right(-1)), _.left("error")) + Util.deepStrictEqual(f(_.left("a")), _.left("a")) }) it("merge", () => { - deepStrictEqual(_.merge(_.right(1)), 1) - deepStrictEqual(_.merge(_.left("a")), "a") + Util.deepStrictEqual(_.merge(_.right(1)), 1) + Util.deepStrictEqual(_.merge(_.left("a")), "a") }) it("liftThrowable", () => { @@ -470,7 +482,7 @@ describe.concurrent("Either", () => { } throw new Error("empty string") }, identity) - deepStrictEqual(f("a"), _.right(1)) - deepStrictEqual(f(""), _.left(new Error("empty string"))) + Util.deepStrictEqual(f("a"), _.right(1)) + Util.deepStrictEqual(f(""), _.left(new Error("empty string"))) }) }) diff --git a/test/Option.ts b/test/Option.ts index ef5480f09..dd9fb35cc 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -1,10 +1,11 @@ import { equivalence } from "@fp-ts/core" import * as E from "@fp-ts/core/Either" import { pipe } from "@fp-ts/core/Function" +import { structural } from "@fp-ts/core/internal/effect" import * as _ from "@fp-ts/core/Option" import * as ReadonlyArray from "@fp-ts/core/ReadonlyArray" import * as S from "@fp-ts/core/String" -import { deepStrictEqual, double } from "@fp-ts/core/test/util" +import * as Util from "@fp-ts/core/test/util" const p = (n: number): boolean => n > 2 @@ -84,52 +85,63 @@ describe.concurrent("Option", () => { expect(_.filter).exist }) + it("structural tracking", () => { + expect(Util.ownKeys(_.none())).toEqual(["_tag"]) + expect(Util.ownKeys(_.some(1))).toEqual(["_tag", "value"]) + + expect(Object.prototype.hasOwnProperty.call(_.none(), structural)).toEqual(false) + expect(Object.prototype.hasOwnProperty.call(_.some(1), structural)).toEqual(false) + + expect(Util.isStructural(_.none())).toEqual(true) + expect(Util.isStructural(_.some(1))).toEqual(true) + }) + it("toRefinement", () => { const f = ( s: string | number ): _.Option => (typeof s === "string" ? _.some(s) : _.none()) const isString = _.toRefinement(f) - deepStrictEqual(isString("s"), true) - deepStrictEqual(isString(1), false) + Util.deepStrictEqual(isString("s"), true) + Util.deepStrictEqual(isString(1), false) type A = { readonly type: "A" } type B = { readonly type: "B" } type C = A | B const isA = _.toRefinement((c) => (c.type === "A" ? _.some(c) : _.none())) - deepStrictEqual(isA({ type: "A" }), true) - deepStrictEqual(isA({ type: "B" }), false) + Util.deepStrictEqual(isA({ type: "A" }), true) + Util.deepStrictEqual(isA({ type: "B" }), false) }) it("isOption", () => { - deepStrictEqual(pipe(_.some(1), _.isOption), true) - deepStrictEqual(pipe(_.none(), _.isOption), true) - deepStrictEqual(pipe(E.right(1), _.isOption), false) + Util.deepStrictEqual(pipe(_.some(1), _.isOption), true) + Util.deepStrictEqual(pipe(_.none(), _.isOption), true) + Util.deepStrictEqual(pipe(E.right(1), _.isOption), false) }) it("coproductEither", () => { - deepStrictEqual(pipe(_.none(), _.coproductEither(_.none())), _.none()) - deepStrictEqual(pipe(_.none(), _.coproductEither(_.some("a"))), _.some(E.right("a"))) - deepStrictEqual(pipe(_.some(1), _.coproductEither(_.none())), _.some(E.left(1))) - deepStrictEqual(pipe(_.some(1), _.coproductEither(_.some("a"))), _.some(E.left(1))) + Util.deepStrictEqual(pipe(_.none(), _.coproductEither(_.none())), _.none()) + Util.deepStrictEqual(pipe(_.none(), _.coproductEither(_.some("a"))), _.some(E.right("a"))) + Util.deepStrictEqual(pipe(_.some(1), _.coproductEither(_.none())), _.some(E.left(1))) + Util.deepStrictEqual(pipe(_.some(1), _.coproductEither(_.some("a"))), _.some(E.left(1))) }) it("firstSomeOf", () => { - deepStrictEqual(pipe(_.some(1), _.firstSomeOf([])), _.some(1)) - deepStrictEqual(pipe(_.none(), _.firstSomeOf([])), _.none()) - deepStrictEqual( + Util.deepStrictEqual(pipe(_.some(1), _.firstSomeOf([])), _.some(1)) + Util.deepStrictEqual(pipe(_.none(), _.firstSomeOf([])), _.none()) + Util.deepStrictEqual( pipe(_.none(), _.firstSomeOf([_.none(), _.none(), _.none(), _.some(1)])), _.some(1) ) - deepStrictEqual( + Util.deepStrictEqual( pipe(_.none(), _.firstSomeOf([_.none(), _.none(), _.none()])), _.none() ) }) it("catchAll", () => { - deepStrictEqual(pipe(_.some(1), _.catchAll(() => _.some(2))), _.some(1)) - deepStrictEqual(pipe(_.some(1), _.catchAll(() => _.none())), _.some(1)) - deepStrictEqual(pipe(_.none(), _.catchAll(() => _.some(1))), _.some(1)) - deepStrictEqual(pipe(_.none(), _.catchAll(() => _.none())), _.none()) + Util.deepStrictEqual(pipe(_.some(1), _.catchAll(() => _.some(2))), _.some(1)) + Util.deepStrictEqual(pipe(_.some(1), _.catchAll(() => _.none())), _.some(1)) + Util.deepStrictEqual(pipe(_.none(), _.catchAll(() => _.some(1))), _.some(1)) + Util.deepStrictEqual(pipe(_.none(), _.catchAll(() => _.none())), _.none()) }) it("orElseEither", () => { @@ -140,8 +152,8 @@ describe.concurrent("Option", () => { }) it("orElseSucceed", () => { - deepStrictEqual(pipe(_.some(1), _.orElseSucceed(() => 2)), _.some(1)) - deepStrictEqual(pipe(_.none(), _.orElseSucceed(() => 2)), _.some(2)) + Util.deepStrictEqual(pipe(_.some(1), _.orElseSucceed(() => 2)), _.some(1)) + Util.deepStrictEqual(pipe(_.none(), _.orElseSucceed(() => 2)), _.some(2)) }) it("inspectSome", () => { @@ -154,7 +166,7 @@ describe.concurrent("Option", () => { _.none(), _.inspectSome(() => log.push(2)) ) - deepStrictEqual( + Util.deepStrictEqual( log, [1] ) @@ -170,7 +182,7 @@ describe.concurrent("Option", () => { _.none(), _.inspectNone(() => log.push(2)) ) - deepStrictEqual( + Util.deepStrictEqual( log, [2] ) @@ -184,7 +196,7 @@ describe.concurrent("Option", () => { }) it("of", () => { - deepStrictEqual(_.of(1), _.some(1)) + Util.deepStrictEqual(_.of(1), _.some(1)) }) it("Foldable", () => { @@ -196,22 +208,22 @@ describe.concurrent("Option", () => { it("coproductAll", () => { const coproductAll = _.Coproduct.coproductAll - deepStrictEqual(coproductAll([]), _.none()) - deepStrictEqual(coproductAll([_.some(1)]), _.some(1)) - deepStrictEqual(coproductAll([_.none(), _.some(1)]), _.some(1)) - deepStrictEqual(coproductAll([_.some(1), _.some(2)]), _.some(1)) + Util.deepStrictEqual(coproductAll([]), _.none()) + Util.deepStrictEqual(coproductAll([_.some(1)]), _.some(1)) + Util.deepStrictEqual(coproductAll([_.none(), _.some(1)]), _.some(1)) + Util.deepStrictEqual(coproductAll([_.some(1), _.some(2)]), _.some(1)) }) it("unit", () => { - deepStrictEqual(_.unit, _.some(undefined)) + Util.deepStrictEqual(_.unit, _.some(undefined)) }) it("product", () => { const product = _.SemiProduct.product - deepStrictEqual(product(_.none(), _.none()), _.none()) - deepStrictEqual(product(_.some(1), _.none()), _.none()) - deepStrictEqual(product(_.none(), _.some("a")), _.none()) - deepStrictEqual( + Util.deepStrictEqual(product(_.none(), _.none()), _.none()) + Util.deepStrictEqual(product(_.some(1), _.none()), _.none()) + Util.deepStrictEqual(product(_.none(), _.some("a")), _.none()) + Util.deepStrictEqual( product(_.some(1), _.some("a")), _.some([1, "a"]) ) @@ -219,53 +231,53 @@ describe.concurrent("Option", () => { it("productMany", () => { const productMany = _.SemiProduct.productMany - deepStrictEqual(productMany(_.none(), []), _.none()) - deepStrictEqual(productMany(_.some(1), []), _.some([1])) - deepStrictEqual(productMany(_.some(1), [_.none()]), _.none()) - deepStrictEqual(productMany(_.some(1), [_.some(2)]), _.some([1, 2])) + Util.deepStrictEqual(productMany(_.none(), []), _.none()) + Util.deepStrictEqual(productMany(_.some(1), []), _.some([1])) + Util.deepStrictEqual(productMany(_.some(1), [_.none()]), _.none()) + Util.deepStrictEqual(productMany(_.some(1), [_.some(2)]), _.some([1, 2])) }) it("productAll", () => { const productAll = _.Applicative.productAll - deepStrictEqual(productAll([]), _.some([])) - deepStrictEqual(productAll([_.none()]), _.none()) - deepStrictEqual(productAll([_.some(1), _.some(2)]), _.some([1, 2])) - deepStrictEqual(productAll([_.some(1), _.none()]), _.none()) + Util.deepStrictEqual(productAll([]), _.some([])) + Util.deepStrictEqual(productAll([_.none()]), _.none()) + Util.deepStrictEqual(productAll([_.some(1), _.some(2)]), _.some([1, 2])) + Util.deepStrictEqual(productAll([_.some(1), _.none()]), _.none()) }) it("SemiCoproduct", () => { const coproduct = _.SemiCoproduct.coproduct - deepStrictEqual(coproduct(_.none(), _.none()), _.none()) - deepStrictEqual(coproduct(_.none(), _.some(2)), _.some(2)) - deepStrictEqual(coproduct(_.some(1), _.none()), _.some(1)) - deepStrictEqual(coproduct(_.some(1), _.some(2)), _.some(1)) + Util.deepStrictEqual(coproduct(_.none(), _.none()), _.none()) + Util.deepStrictEqual(coproduct(_.none(), _.some(2)), _.some(2)) + Util.deepStrictEqual(coproduct(_.some(1), _.none()), _.some(1)) + Util.deepStrictEqual(coproduct(_.some(1), _.some(2)), _.some(1)) const coproductMany = _.SemiCoproduct.coproductMany - deepStrictEqual(coproductMany(_.none(), []), _.none()) - deepStrictEqual(coproductMany(_.none(), [_.none()]), _.none()) - deepStrictEqual(coproductMany(_.none(), [_.some(2)]), _.some(2)) - deepStrictEqual(coproductMany(_.some(1), []), _.some(1)) - deepStrictEqual(coproductMany(_.some(1), [_.none() as _.Option]), _.some(1)) - deepStrictEqual(coproductMany(_.some(1), [_.some(2)]), _.some(1)) + Util.deepStrictEqual(coproductMany(_.none(), []), _.none()) + Util.deepStrictEqual(coproductMany(_.none(), [_.none()]), _.none()) + Util.deepStrictEqual(coproductMany(_.none(), [_.some(2)]), _.some(2)) + Util.deepStrictEqual(coproductMany(_.some(1), []), _.some(1)) + Util.deepStrictEqual(coproductMany(_.some(1), [_.none() as _.Option]), _.some(1)) + Util.deepStrictEqual(coproductMany(_.some(1), [_.some(2)]), _.some(1)) }) it("fromIterable", () => { - deepStrictEqual(_.fromIterable([]), _.none()) - deepStrictEqual(_.fromIterable(["a"]), _.some("a")) + Util.deepStrictEqual(_.fromIterable([]), _.none()) + Util.deepStrictEqual(_.fromIterable(["a"]), _.some("a")) }) it("map", () => { - deepStrictEqual(pipe(_.some(2), _.map(double)), _.some(4)) - deepStrictEqual(pipe(_.none(), _.map(double)), _.none()) + Util.deepStrictEqual(pipe(_.some(2), _.map(Util.double)), _.some(4)) + Util.deepStrictEqual(pipe(_.none(), _.map(Util.double)), _.none()) }) it("flatMap", () => { const f = (n: number) => _.some(n * 2) const g = () => _.none() - deepStrictEqual(pipe(_.some(1), _.flatMap(f)), _.some(2)) - deepStrictEqual(pipe(_.none(), _.flatMap(f)), _.none()) - deepStrictEqual(pipe(_.some(1), _.flatMap(g)), _.none()) - deepStrictEqual(pipe(_.none(), _.flatMap(g)), _.none()) + Util.deepStrictEqual(pipe(_.some(1), _.flatMap(f)), _.some(2)) + Util.deepStrictEqual(pipe(_.none(), _.flatMap(f)), _.none()) + Util.deepStrictEqual(pipe(_.some(1), _.flatMap(g)), _.none()) + Util.deepStrictEqual(pipe(_.none(), _.flatMap(g)), _.none()) }) it("orElse", () => { @@ -274,7 +286,7 @@ describe.concurrent("Option", () => { b: _.Option, expected: _.Option ) => { - deepStrictEqual(pipe(a, _.orElse(b)), expected) + Util.deepStrictEqual(pipe(a, _.orElse(b)), expected) } assertAlt(_.some(1), _.some(2), _.some(1)) assertAlt(_.some(1), _.none(), _.some(1)) @@ -283,34 +295,34 @@ describe.concurrent("Option", () => { }) it("compact", () => { - deepStrictEqual(_.compact(_.none()), _.none()) - deepStrictEqual(_.compact(_.some(_.none())), _.none()) - deepStrictEqual(_.compact(_.some(_.some("123"))), _.some("123")) + Util.deepStrictEqual(_.compact(_.none()), _.none()) + Util.deepStrictEqual(_.compact(_.some(_.none())), _.none()) + Util.deepStrictEqual(_.compact(_.some(_.some("123"))), _.some("123")) }) it("filterMap", () => { const f = (n: number) => (p(n) ? _.some(n + 1) : _.none()) - deepStrictEqual(pipe(_.none(), _.filterMap(f)), _.none()) - deepStrictEqual(pipe(_.some(1), _.filterMap(f)), _.none()) - deepStrictEqual(pipe(_.some(3), _.filterMap(f)), _.some(4)) + Util.deepStrictEqual(pipe(_.none(), _.filterMap(f)), _.none()) + Util.deepStrictEqual(pipe(_.some(1), _.filterMap(f)), _.none()) + Util.deepStrictEqual(pipe(_.some(3), _.filterMap(f)), _.some(4)) }) it("traverse", () => { - deepStrictEqual( + Util.deepStrictEqual( pipe( _.some("hello"), _.traverse(ReadonlyArray.Applicative)(() => []) ), [] ) - deepStrictEqual( + Util.deepStrictEqual( pipe( _.some("hello"), _.traverse(ReadonlyArray.Applicative)((s) => [s.length]) ), [_.some(5)] ) - deepStrictEqual( + Util.deepStrictEqual( pipe( _.none(), _.traverse(ReadonlyArray.Applicative)((s) => [s]) @@ -320,41 +332,41 @@ describe.concurrent("Option", () => { }) it("toEither", () => { - deepStrictEqual(pipe(_.none(), _.toEither(() => "e")), E.left("e")) - deepStrictEqual(pipe(_.some(1), _.toEither(() => "e")), E.right(1)) + Util.deepStrictEqual(pipe(_.none(), _.toEither(() => "e")), E.left("e")) + Util.deepStrictEqual(pipe(_.some(1), _.toEither(() => "e")), E.right(1)) }) it("match", () => { const f = () => "none" const g = (s: string) => `some${s.length}` const match = _.match(f, g) - deepStrictEqual(match(_.none()), "none") - deepStrictEqual(match(_.some("abc")), "some3") + Util.deepStrictEqual(match(_.none()), "none") + Util.deepStrictEqual(match(_.some("abc")), "some3") }) it("getOrElse", () => { - deepStrictEqual(pipe(_.some(1), _.getOrElse(() => 0)), 1) - deepStrictEqual(pipe(_.none(), _.getOrElse(() => 0)), 0) + Util.deepStrictEqual(pipe(_.some(1), _.getOrElse(() => 0)), 1) + Util.deepStrictEqual(pipe(_.none(), _.getOrElse(() => 0)), 0) }) it("getOrNull", () => { - deepStrictEqual(_.getOrNull(_.none()), null) - deepStrictEqual(_.getOrNull(_.some(1)), 1) + Util.deepStrictEqual(_.getOrNull(_.none()), null) + Util.deepStrictEqual(_.getOrNull(_.some(1)), 1) }) it("getOrUndefined", () => { - deepStrictEqual(_.getOrUndefined(_.none()), undefined) - deepStrictEqual(_.getOrUndefined(_.some(1)), 1) + Util.deepStrictEqual(_.getOrUndefined(_.none()), undefined) + Util.deepStrictEqual(_.getOrUndefined(_.some(1)), 1) }) it("liftOrder", () => { const OS = _.liftOrder(S.Order) - deepStrictEqual(OS.compare(_.none(), _.none()), 0) - deepStrictEqual(OS.compare(_.some("a"), _.none()), 1) - deepStrictEqual(OS.compare(_.none(), _.some("a")), -1) - deepStrictEqual(OS.compare(_.some("a"), _.some("a")), 0) - deepStrictEqual(OS.compare(_.some("a"), _.some("b")), -1) - deepStrictEqual(OS.compare(_.some("b"), _.some("a")), 1) + Util.deepStrictEqual(OS.compare(_.none(), _.none()), 0) + Util.deepStrictEqual(OS.compare(_.some("a"), _.none()), 1) + Util.deepStrictEqual(OS.compare(_.none(), _.some("a")), -1) + Util.deepStrictEqual(OS.compare(_.some("a"), _.some("a")), 0) + Util.deepStrictEqual(OS.compare(_.some("a"), _.some("b")), -1) + Util.deepStrictEqual(OS.compare(_.some("b"), _.some("a")), 1) }) it("flatMapNullable", () => { @@ -370,7 +382,7 @@ describe.concurrent("Option", () => { const x1: X = { a: {} } const x2: X = { a: { b: {} } } const x3: X = { a: { b: { c: { d: 1 } } } } - deepStrictEqual( + Util.deepStrictEqual( pipe( _.fromNullable(x1.a), _.flatMapNullable((x) => x.b), @@ -379,7 +391,7 @@ describe.concurrent("Option", () => { ), _.none() ) - deepStrictEqual( + Util.deepStrictEqual( pipe( _.fromNullable(x2.a), _.flatMapNullable((x) => x.b), @@ -388,7 +400,7 @@ describe.concurrent("Option", () => { ), _.none() ) - deepStrictEqual( + Util.deepStrictEqual( pipe( _.fromNullable(x3.a), _.flatMapNullable((x) => x.b), @@ -401,83 +413,83 @@ describe.concurrent("Option", () => { it("getMonoid", () => { const M = _.getMonoid(S.Semigroup) - deepStrictEqual(M.combine(_.none(), _.none()), _.none()) - deepStrictEqual(M.combine(_.none(), _.some("a")), _.some("a")) - deepStrictEqual(M.combine(_.some("a"), _.none()), _.some("a")) - deepStrictEqual(M.combine(_.some("b"), _.some("a")), _.some("ba")) - deepStrictEqual(M.combine(_.some("a"), _.some("b")), _.some("ab")) + Util.deepStrictEqual(M.combine(_.none(), _.none()), _.none()) + Util.deepStrictEqual(M.combine(_.none(), _.some("a")), _.some("a")) + Util.deepStrictEqual(M.combine(_.some("a"), _.none()), _.some("a")) + Util.deepStrictEqual(M.combine(_.some("b"), _.some("a")), _.some("ba")) + Util.deepStrictEqual(M.combine(_.some("a"), _.some("b")), _.some("ab")) - deepStrictEqual(M.combineMany(_.some("a"), [_.some("b")]), _.some("ab")) - deepStrictEqual(M.combineMany(_.none(), [_.some("b")]), _.some("b")) - deepStrictEqual(M.combineMany(_.some("a"), [_.none()]), _.some("a")) + Util.deepStrictEqual(M.combineMany(_.some("a"), [_.some("b")]), _.some("ab")) + Util.deepStrictEqual(M.combineMany(_.none(), [_.some("b")]), _.some("b")) + Util.deepStrictEqual(M.combineMany(_.some("a"), [_.none()]), _.some("a")) - deepStrictEqual(pipe(M.combineAll([])), _.none()) - deepStrictEqual(pipe(M.combineAll([_.some("a")])), _.some("a")) - deepStrictEqual(pipe(M.combineAll([_.some("a"), _.some("b")])), _.some("ab")) - deepStrictEqual(pipe(M.combineAll([_.some("a"), _.none()])), _.some("a")) + Util.deepStrictEqual(pipe(M.combineAll([])), _.none()) + Util.deepStrictEqual(pipe(M.combineAll([_.some("a")])), _.some("a")) + Util.deepStrictEqual(pipe(M.combineAll([_.some("a"), _.some("b")])), _.some("ab")) + Util.deepStrictEqual(pipe(M.combineAll([_.some("a"), _.none()])), _.some("a")) }) it("fromNullable", () => { - deepStrictEqual(_.fromNullable(2), _.some(2)) - deepStrictEqual(_.fromNullable(null), _.none()) - deepStrictEqual(_.fromNullable(undefined), _.none()) + Util.deepStrictEqual(_.fromNullable(2), _.some(2)) + Util.deepStrictEqual(_.fromNullable(null), _.none()) + Util.deepStrictEqual(_.fromNullable(undefined), _.none()) }) it("liftPredicate", () => { const f = _.liftPredicate(p) - deepStrictEqual(f(1), _.none()) - deepStrictEqual(f(3), _.some(3)) + Util.deepStrictEqual(f(1), _.none()) + Util.deepStrictEqual(f(3), _.some(3)) type Direction = "asc" | "desc" const parseDirection = _.liftPredicate((s: string): s is Direction => s === "asc" || s === "desc" ) - deepStrictEqual(parseDirection("asc"), _.some("asc")) - deepStrictEqual(parseDirection("foo"), _.none()) + Util.deepStrictEqual(parseDirection("asc"), _.some("asc")) + Util.deepStrictEqual(parseDirection("foo"), _.none()) }) it("contains", () => { const contains = _.contains(equivalence.number) - deepStrictEqual(pipe(_.none(), contains(2)), false) - deepStrictEqual(pipe(_.some(2), contains(2)), true) - deepStrictEqual(pipe(_.some(2), contains(1)), false) + Util.deepStrictEqual(pipe(_.none(), contains(2)), false) + Util.deepStrictEqual(pipe(_.some(2), contains(2)), true) + Util.deepStrictEqual(pipe(_.some(2), contains(1)), false) }) it("isNone", () => { - deepStrictEqual(_.isNone(_.none()), true) - deepStrictEqual(_.isNone(_.some(1)), false) + Util.deepStrictEqual(_.isNone(_.none()), true) + Util.deepStrictEqual(_.isNone(_.some(1)), false) }) it("isSome", () => { - deepStrictEqual(_.isSome(_.none()), false) - deepStrictEqual(_.isSome(_.some(1)), true) + Util.deepStrictEqual(_.isSome(_.none()), false) + Util.deepStrictEqual(_.isSome(_.some(1)), true) }) it("exists", () => { const predicate = (a: number) => a === 2 - deepStrictEqual(pipe(_.none(), _.exists(predicate)), false) - deepStrictEqual(pipe(_.some(1), _.exists(predicate)), false) - deepStrictEqual(pipe(_.some(2), _.exists(predicate)), true) + Util.deepStrictEqual(pipe(_.none(), _.exists(predicate)), false) + Util.deepStrictEqual(pipe(_.some(1), _.exists(predicate)), false) + Util.deepStrictEqual(pipe(_.some(2), _.exists(predicate)), true) }) it("fromThrowable", () => { - deepStrictEqual( + Util.deepStrictEqual( _.fromThrowable(() => JSON.parse("2")), _.some(2) ) - deepStrictEqual( + Util.deepStrictEqual( _.fromThrowable(() => JSON.parse("(")), _.none() ) }) it("fromEither", () => { - deepStrictEqual(_.fromEither(E.right(1)), _.some(1)) - deepStrictEqual(_.fromEither(E.left("e")), _.none()) + Util.deepStrictEqual(_.fromEither(E.right(1)), _.some(1)) + Util.deepStrictEqual(_.fromEither(E.left("e")), _.none()) }) it("do notation", () => { - deepStrictEqual( + Util.deepStrictEqual( pipe( _.some(1), _.bindTo("a"), @@ -488,7 +500,7 @@ describe.concurrent("Option", () => { }) it("andThenBind", () => { - deepStrictEqual( + Util.deepStrictEqual( pipe(_.some(1), _.bindTo("a"), _.andThenBind("b", _.some("b"))), _.some({ a: 1, b: "b" }) ) @@ -502,8 +514,8 @@ describe.concurrent("Option", () => { it("liftNullable", () => { const f = _.liftNullable((n: number) => (n > 0 ? n : null)) - deepStrictEqual(f(1), _.some(1)) - deepStrictEqual(f(-1), _.none()) + Util.deepStrictEqual(f(1), _.some(1)) + Util.deepStrictEqual(f(-1), _.none()) }) it("liftThrowable", () => { @@ -514,25 +526,25 @@ describe.concurrent("Option", () => { } throw new Error("empty string") }) - deepStrictEqual(f("a"), _.some(1)) - deepStrictEqual(f(""), _.none()) + Util.deepStrictEqual(f("a"), _.some(1)) + Util.deepStrictEqual(f(""), _.none()) }) it("liftEither", () => { const f = _.liftEither((n: number) => (n > 0 ? E.right(n) : E.left("e"))) - deepStrictEqual(f(1), _.some(1)) - deepStrictEqual(f(-1), _.none()) + Util.deepStrictEqual(f(1), _.some(1)) + Util.deepStrictEqual(f(-1), _.none()) }) it("flatMapEither", () => { const f = _.flatMapEither((n: number) => (n > 0 ? E.right(n) : E.left("e"))) - deepStrictEqual(pipe(_.none(), f), _.none()) - deepStrictEqual(pipe(_.some(0), f), _.none()) - deepStrictEqual(pipe(_.some(1), f), _.some(1)) + Util.deepStrictEqual(pipe(_.none(), f), _.none()) + Util.deepStrictEqual(pipe(_.some(0), f), _.none()) + Util.deepStrictEqual(pipe(_.some(1), f), _.some(1)) }) it("guard", () => { - deepStrictEqual( + Util.deepStrictEqual( pipe( _.Do, _.bind("x", () => _.some("a")), @@ -541,7 +553,7 @@ describe.concurrent("Option", () => { ), _.some({ x: "a", y: "a" }) ) - deepStrictEqual( + Util.deepStrictEqual( pipe( _.Do, _.bind("x", () => _.some("a")), diff --git a/test/These.ts b/test/These.ts index 1dc85baa4..4a7a5a8d0 100644 --- a/test/These.ts +++ b/test/These.ts @@ -1,10 +1,11 @@ import * as E from "@fp-ts/core/Either" import { identity, pipe } from "@fp-ts/core/Function" +import { structural } from "@fp-ts/core/internal/effect" import * as O from "@fp-ts/core/Option" import * as S from "@fp-ts/core/String" import * as _ from "@fp-ts/core/These" import { number } from "@fp-ts/core/typeclass/Equivalence" -import * as U from "./util" +import * as Util from "./util" describe("These", () => { it("instances and derived exports", () => { @@ -78,39 +79,53 @@ describe("These", () => { expect(_.traverseTap).exist }) + it("structural tracking", () => { + expect(Util.ownKeys(_.left("a"))).toEqual(["_tag", "left"]) + expect(Util.ownKeys(_.right(1))).toEqual(["_tag", "right"]) + expect(Util.ownKeys(_.both("a", 1))).toEqual(["_tag", "left", "right"]) + + expect(Object.prototype.hasOwnProperty.call(_.left("a"), structural)).toEqual(false) + expect(Object.prototype.hasOwnProperty.call(_.right(1), structural)).toEqual(false) + expect(Object.prototype.hasOwnProperty.call(_.both("a", 1), structural)).toEqual(false) + + expect(Util.isStructural(_.left("a"))).toEqual(true) + expect(Util.isStructural(_.right(1))).toEqual(true) + expect(Util.isStructural(_.both("a", 1))).toEqual(true) + }) + it("reduce", () => { - U.deepStrictEqual(pipe(_.right("a"), _.Foldable.reduce("-", (b, a) => b + a)), "-a") - U.deepStrictEqual(pipe(_.left("e"), _.Foldable.reduce("-", (b, a) => b + a)), "-") - U.deepStrictEqual(pipe(_.both("e", "a"), _.Foldable.reduce("-", (b, a) => b + a)), "-a") + Util.deepStrictEqual(pipe(_.right("a"), _.Foldable.reduce("-", (b, a) => b + a)), "-a") + Util.deepStrictEqual(pipe(_.left("e"), _.Foldable.reduce("-", (b, a) => b + a)), "-") + Util.deepStrictEqual(pipe(_.both("e", "a"), _.Foldable.reduce("-", (b, a) => b + a)), "-a") }) it("map", () => { - U.deepStrictEqual(pipe(_.left("e"), _.map(U.double)), _.left("e")) - U.deepStrictEqual(pipe(_.right(2), _.map(U.double)), _.right(4)) - U.deepStrictEqual(pipe(_.both("e", 2), _.map(U.double)), _.both("e", 4)) + Util.deepStrictEqual(pipe(_.left("e"), _.map(Util.double)), _.left("e")) + Util.deepStrictEqual(pipe(_.right(2), _.map(Util.double)), _.right(4)) + Util.deepStrictEqual(pipe(_.both("e", 2), _.map(Util.double)), _.both("e", 4)) }) it("bimap", () => { - const f = _.bimap(S.length, U.double) - U.deepStrictEqual(pipe(_.left("e"), f), _.left(1)) - U.deepStrictEqual(pipe(_.right(2), f), _.right(4)) - U.deepStrictEqual(pipe(_.both("eee", 1), f), _.both(3, 2)) + const f = _.bimap(S.length, Util.double) + Util.deepStrictEqual(pipe(_.left("e"), f), _.left(1)) + Util.deepStrictEqual(pipe(_.right(2), f), _.right(4)) + Util.deepStrictEqual(pipe(_.both("eee", 1), f), _.both(3, 2)) }) it("mapLeft", () => { const f = _.mapLeft(S.length) - U.deepStrictEqual(pipe(_.left("e"), f), _.left(1)) - U.deepStrictEqual(pipe(_.right(2), f), _.right(2)) - U.deepStrictEqual(pipe(_.both("eee", 1), f), _.both(3, 1)) + Util.deepStrictEqual(pipe(_.left("e"), f), _.left(1)) + Util.deepStrictEqual(pipe(_.right(2), f), _.right(2)) + Util.deepStrictEqual(pipe(_.both("eee", 1), f), _.both(3, 1)) }) it("traverse", () => { const traverse = _.traverse(O.Applicative)((n: number) => (n > 1 ? O.some(n) : O.none())) - U.deepStrictEqual(pipe(_.left("a"), traverse), O.some(_.left("a"))) - U.deepStrictEqual(pipe(_.right(2), traverse), O.some(_.right(2))) - U.deepStrictEqual(pipe(_.right(1), traverse), O.none()) - U.deepStrictEqual(pipe(_.both("a", 2), traverse), O.some(_.both("a", 2))) - U.deepStrictEqual( + Util.deepStrictEqual(pipe(_.left("a"), traverse), O.some(_.left("a"))) + Util.deepStrictEqual(pipe(_.right(2), traverse), O.some(_.right(2))) + Util.deepStrictEqual(pipe(_.right(1), traverse), O.none()) + Util.deepStrictEqual(pipe(_.both("a", 2), traverse), O.some(_.both("a", 2))) + Util.deepStrictEqual( pipe( _.both("a", 1), _.traverse(O.Applicative)((n) => (n >= 2 ? O.some(n) : O.none())) @@ -120,23 +135,23 @@ describe("These", () => { }) it("andThenBindEither", () => { - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindEither("b", E.right(2))), _.succeed({ a: 1, b: 2 }) ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindEither("b", E.left("e2"))), _.fail("e2") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindEither("b", E.right(2))), _.fail("e1") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindEither("b", E.left("e2"))), _.fail("e1") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.andThenBindEither("b", E.right(2))), _.warn("e1", { a: 1, b: 2 }) ) @@ -148,31 +163,31 @@ describe("These", () => { }) it("andThenBindThese", () => { - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindThese("b", _.right(2))), _.succeed({ a: 1, b: 2 }) ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindThese("b", _.left("e2"))), _.fail("e2") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindThese("b", _.both("e2", 2))), _.warn("e2", { a: 1, b: 2 }) ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindThese("b", _.right(2))), _.fail("e1") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindThese("b", _.left("e2"))), _.fail("e1") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindThese("b", _.both("e2", 2))), _.fail("e1") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.andThenBindThese("b", _.right(2))), _.warn("e1", { a: 1, b: 2 }) ) @@ -189,23 +204,23 @@ describe("These", () => { }) it("andThenBind", () => { - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindEither("b", () => E.right(2))), _.succeed({ a: 1, b: 2 }) ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindEither("b", () => E.left("e2"))), _.fail("e2") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.fail("e1")), _.bindEither("b", () => E.right(2))), _.fail("e1") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.fail("e1")), _.bindEither("b", () => E.left("e2"))), _.fail("e1") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.bindEither("b", () => E.right(2))), _.warn("e1", { a: 1, b: 2 }) ) @@ -217,31 +232,31 @@ describe("These", () => { }) it("andThenBind", () => { - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindThese("b", () => _.right(2))), _.succeed({ a: 1, b: 2 }) ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindThese("b", () => _.left("e2"))), _.fail("e2") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindThese("b", () => _.both("e2", 2))), _.warn("e2", { a: 1, b: 2 }) ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.fail("e1")), _.bindThese("b", () => _.right(2))), _.fail("e1") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.fail("e1")), _.bindThese("b", () => _.left("e2"))), _.fail("e1") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.fail("e1")), _.bindThese("b", () => _.both("e2", 2))), _.fail("e1") ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.bindThese("b", () => _.right(2))), _.warn("e1", { a: 1, b: 2 }) ) @@ -259,11 +274,11 @@ describe("These", () => { it("sequence", () => { const sequence = _.sequence(O.Applicative) - U.deepStrictEqual(sequence(_.left("a")), O.some(_.left("a"))) - U.deepStrictEqual(sequence(_.right(O.some(1))), O.some(_.right(1))) - U.deepStrictEqual(sequence(_.right(O.none())), O.none()) - U.deepStrictEqual(sequence(_.both("a", O.some(1))), O.some(_.both("a", 1))) - U.deepStrictEqual(sequence(_.both("a", O.none())), O.none()) + Util.deepStrictEqual(sequence(_.left("a")), O.some(_.left("a"))) + Util.deepStrictEqual(sequence(_.right(O.some(1))), O.some(_.right(1))) + Util.deepStrictEqual(sequence(_.right(O.none())), O.none()) + Util.deepStrictEqual(sequence(_.both("a", O.some(1))), O.some(_.both("a", 1))) + Util.deepStrictEqual(sequence(_.both("a", O.none())), O.none()) }) it("product", () => { @@ -273,12 +288,12 @@ describe("These", () => { const product = _.SemiProduct.product expect(product(_.right(1), _.right(2))).toEqual(_.right([1, 2])) - U.deepStrictEqual(product(_.right(1), _.left(b)), _.left(b)) + Util.deepStrictEqual(product(_.right(1), _.left(b)), _.left(b)) expect(product(_.right(1), _.both(b, 2))).toEqual(_.both(b, [1, 2])) - U.deepStrictEqual(product(_.left(a), _.right(2)), _.left(a)) - U.deepStrictEqual(product(_.left(a), _.left(b)), _.left(a)) - U.deepStrictEqual(product(_.left(a), _.both(b, 2)), _.left(a)) + Util.deepStrictEqual(product(_.left(a), _.right(2)), _.left(a)) + Util.deepStrictEqual(product(_.left(a), _.left(b)), _.left(a)) + Util.deepStrictEqual(product(_.left(a), _.both(b, 2)), _.left(a)) expect(product(_.both(a, 1), _.right(2))).toEqual(_.both(a, [1, 2])) expect(product(_.both(a, 1), _.left(b))).toEqual(_.left(ab)) @@ -296,7 +311,7 @@ describe("These", () => { ) => _.Validated]> = _.SemiProduct.productMany expect(productMany(_.right(1), [_.right(2)])).toEqual(_.right([1, 2])) - U.deepStrictEqual( + Util.deepStrictEqual( productMany(_.right(1), [_.left(b)]), _.left(b) ) @@ -306,9 +321,9 @@ describe("These", () => { _.both(b, [1, 2]) ) - U.deepStrictEqual(productMany(_.left(a), [_.right(2)]), _.left(a)) - U.deepStrictEqual(productMany(_.left(a), [_.left(b)]), _.left(a)) - U.deepStrictEqual( + Util.deepStrictEqual(productMany(_.left(a), [_.right(2)]), _.left(a)) + Util.deepStrictEqual(productMany(_.left(a), [_.left(b)]), _.left(a)) + Util.deepStrictEqual( productMany(_.left(a), [_.both(b, 2)]), _.left(a) ) @@ -326,15 +341,15 @@ describe("These", () => { const ab = ["a", "b"] as const const productAll = _.Product.productAll - U.deepStrictEqual(productAll([_.right(1), _.right(2)]), _.right([1, 2])) - U.deepStrictEqual(productAll([_.right(1), _.left(b)]), _.left(b)) - U.deepStrictEqual(productAll([_.right(1), _.both(b, 2)]), _.both(b, [1, 2])) + Util.deepStrictEqual(productAll([_.right(1), _.right(2)]), _.right([1, 2])) + Util.deepStrictEqual(productAll([_.right(1), _.left(b)]), _.left(b)) + Util.deepStrictEqual(productAll([_.right(1), _.both(b, 2)]), _.both(b, [1, 2])) - U.deepStrictEqual(productAll([_.left(a), _.right(2)]), _.left(a)) - U.deepStrictEqual(productAll([_.left(a), _.left(b)]), _.left(a)) - U.deepStrictEqual(productAll([_.left(a), _.both(b, 2)]), _.left(a)) + Util.deepStrictEqual(productAll([_.left(a), _.right(2)]), _.left(a)) + Util.deepStrictEqual(productAll([_.left(a), _.left(b)]), _.left(a)) + Util.deepStrictEqual(productAll([_.left(a), _.both(b, 2)]), _.left(a)) - U.deepStrictEqual(productAll([_.both(a, 1), _.right(2)]), _.both(a, [1, 2])) + Util.deepStrictEqual(productAll([_.both(a, 1), _.right(2)]), _.both(a, [1, 2])) expect(productAll([_.both(a, 1), _.left(b)])).toEqual(_.left(ab)) expect(productAll([_.both(a, 1), _.both(b, 2)])).toEqual(_.both(ab, [1, 2])) }) @@ -345,14 +360,14 @@ describe("These", () => { ) => (n >= 2 ? (n <= 5 ? _.succeed(n * 2) : _.warn("e2", n)) : _.fail("e3")) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.fail("e1"), _.flatMap(f)), _.fail("e1") ) - U.deepStrictEqual(pipe(_.succeed(2), _.flatMap(f)), _.succeed(4)) - U.deepStrictEqual(pipe(_.succeed(1), _.flatMap(f)), _.fail("e3")) - U.deepStrictEqual(pipe(_.succeed(6), _.flatMap(f)), _.warn("e2", 6)) - U.deepStrictEqual( + Util.deepStrictEqual(pipe(_.succeed(2), _.flatMap(f)), _.succeed(4)) + Util.deepStrictEqual(pipe(_.succeed(1), _.flatMap(f)), _.fail("e3")) + Util.deepStrictEqual(pipe(_.succeed(6), _.flatMap(f)), _.warn("e2", 6)) + Util.deepStrictEqual( pipe(_.warn("e1", 2), _.flatMap(f)), _.warn("e1", 4) ) @@ -362,28 +377,28 @@ describe("These", () => { it("flatMapNullable", () => { const f = _.flatMapNullable((n: number) => (n > 0 ? n : null), () => "e2") - U.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) - U.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) - U.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) - U.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) + Util.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) + Util.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) + Util.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) + Util.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) expect(f(_.warn("e1", -1))).toEqual(_.left(["e1", "e2"])) }) it("flatMapOption", () => { const f = _.flatMapOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "e2") - U.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) - U.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) - U.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) - U.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) + Util.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) + Util.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) + Util.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) + Util.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) expect(f(_.warn("e1", -1))).toEqual(_.left(["e1", "e2"])) }) it("flatMapEither", () => { const f = _.flatMapEither((n: number) => (n > 0 ? E.right(n) : E.left("e2"))) - U.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) - U.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) - U.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) - U.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) + Util.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) + Util.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) + Util.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) + Util.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) expect(f(_.warn("e1", -1))).toEqual(_.left(["e1", "e2"])) }) @@ -391,118 +406,118 @@ describe("These", () => { const f = _.flatMapThese(( n: number ) => (n > 10 ? _.both("e3", n) : n > 0 ? _.right(n) : _.left("e2"))) - U.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) - U.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) - U.deepStrictEqual(f(_.succeed(11)), _.warn("e3", 11)) - U.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) - U.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) + Util.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) + Util.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) + Util.deepStrictEqual(f(_.succeed(11)), _.warn("e3", 11)) + Util.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) + Util.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) expect(f(_.warn("e1", -1))).toEqual(_.left(["e1", "e2"])) expect(f(_.warn("e1", 11))).toEqual(_.both(["e1", "e3"], 11)) }) it("leftOrBoth", () => { - U.deepStrictEqual(_.leftOrBoth(() => "a")(O.none()), _.left("a")) - U.deepStrictEqual(_.leftOrBoth(() => "a")(O.some(1)), _.both("a", 1)) + Util.deepStrictEqual(_.leftOrBoth(() => "a")(O.none()), _.left("a")) + Util.deepStrictEqual(_.leftOrBoth(() => "a")(O.some(1)), _.both("a", 1)) }) it("rightOrBoth", () => { - U.deepStrictEqual(_.rightOrBoth(() => 1)(O.none()), _.right(1)) - U.deepStrictEqual(_.rightOrBoth(() => 1)(O.some("a")), _.both("a", 1)) + Util.deepStrictEqual(_.rightOrBoth(() => 1)(O.none()), _.right(1)) + Util.deepStrictEqual(_.rightOrBoth(() => 1)(O.some("a")), _.both("a", 1)) }) it("match", () => { - const f = (s: string, n: number) => S.length(s) + U.double(n) - const match = _.match(S.length, U.double, f) - U.deepStrictEqual(match(_.left("foo")), 3) - U.deepStrictEqual(match(_.right(1)), 2) - U.deepStrictEqual(match(_.both("foo", 1)), 5) + const f = (s: string, n: number) => S.length(s) + Util.double(n) + const match = _.match(S.length, Util.double, f) + Util.deepStrictEqual(match(_.left("foo")), 3) + Util.deepStrictEqual(match(_.right(1)), 2) + Util.deepStrictEqual(match(_.both("foo", 1)), 5) }) it("getBothOrElse", () => { const f = _.getBothOrElse(() => "a", () => 1) - U.deepStrictEqual(pipe(_.left("b"), f), ["b", 1]) - U.deepStrictEqual(pipe(_.right(2), f), ["a", 2]) - U.deepStrictEqual(pipe(_.both("b", 2), f), ["b", 2]) + Util.deepStrictEqual(pipe(_.left("b"), f), ["b", 1]) + Util.deepStrictEqual(pipe(_.right(2), f), ["a", 2]) + Util.deepStrictEqual(pipe(_.both("b", 2), f), ["b", 2]) }) it("getBoth", () => { - U.deepStrictEqual(pipe(_.left("e"), _.getBoth), O.none()) - U.deepStrictEqual(pipe(_.right(1), _.getBoth), O.none()) + Util.deepStrictEqual(pipe(_.left("e"), _.getBoth), O.none()) + Util.deepStrictEqual(pipe(_.right(1), _.getBoth), O.none()) expect(pipe(_.both("e", 1), _.getBoth)).toEqual(O.some(["e", 1])) }) it("getLeft", () => { - U.deepStrictEqual(_.getLeft(_.left("e")), O.some("e")) - U.deepStrictEqual(_.getLeft(_.right(1)), O.none()) - U.deepStrictEqual(_.getLeft(_.both("e", 1)), O.some("e")) + Util.deepStrictEqual(_.getLeft(_.left("e")), O.some("e")) + Util.deepStrictEqual(_.getLeft(_.right(1)), O.none()) + Util.deepStrictEqual(_.getLeft(_.both("e", 1)), O.some("e")) }) it("getRight", () => { - U.deepStrictEqual(_.getRight(_.left("e")), O.none()) - U.deepStrictEqual(_.getRight(_.right(1)), O.some(1)) - U.deepStrictEqual(_.getRight(_.both("e", 1)), O.some(1)) + Util.deepStrictEqual(_.getRight(_.left("e")), O.none()) + Util.deepStrictEqual(_.getRight(_.right(1)), O.some(1)) + Util.deepStrictEqual(_.getRight(_.both("e", 1)), O.some(1)) }) it("getLeftOnly", () => { - U.deepStrictEqual(_.getLeftOnly(_.left("e")), O.some("e")) - U.deepStrictEqual(_.getLeftOnly(_.right(1)), O.none()) - U.deepStrictEqual(_.getLeftOnly(_.both("e", 1)), O.none()) + Util.deepStrictEqual(_.getLeftOnly(_.left("e")), O.some("e")) + Util.deepStrictEqual(_.getLeftOnly(_.right(1)), O.none()) + Util.deepStrictEqual(_.getLeftOnly(_.both("e", 1)), O.none()) }) it("getRightOnly", () => { - U.deepStrictEqual(_.getRightOnly(_.left("e")), O.none()) - U.deepStrictEqual(_.getRightOnly(_.right(1)), O.some(1)) - U.deepStrictEqual(_.getRightOnly(_.both("e", 1)), O.none()) + Util.deepStrictEqual(_.getRightOnly(_.left("e")), O.none()) + Util.deepStrictEqual(_.getRightOnly(_.right(1)), O.some(1)) + Util.deepStrictEqual(_.getRightOnly(_.both("e", 1)), O.none()) }) it("isLeft", () => { - U.deepStrictEqual(_.isLeft(_.left("e")), true) - U.deepStrictEqual(_.isLeft(_.right(1)), false) - U.deepStrictEqual(_.isLeft(_.both("e", 1)), false) + Util.deepStrictEqual(_.isLeft(_.left("e")), true) + Util.deepStrictEqual(_.isLeft(_.right(1)), false) + Util.deepStrictEqual(_.isLeft(_.both("e", 1)), false) }) it("isLeftOrBoth", () => { - U.deepStrictEqual(_.isLeftOrBoth(_.left("e")), true) - U.deepStrictEqual(_.isLeftOrBoth(_.right(1)), false) - U.deepStrictEqual(_.isLeftOrBoth(_.both("e", 1)), true) + Util.deepStrictEqual(_.isLeftOrBoth(_.left("e")), true) + Util.deepStrictEqual(_.isLeftOrBoth(_.right(1)), false) + Util.deepStrictEqual(_.isLeftOrBoth(_.both("e", 1)), true) }) it("isRight", () => { - U.deepStrictEqual(_.isRight(_.left("e")), false) - U.deepStrictEqual(_.isRight(_.right(1)), true) - U.deepStrictEqual(_.isRight(_.both("", 1)), false) + Util.deepStrictEqual(_.isRight(_.left("e")), false) + Util.deepStrictEqual(_.isRight(_.right(1)), true) + Util.deepStrictEqual(_.isRight(_.both("", 1)), false) }) it("isRightOrBoth", () => { - U.deepStrictEqual(_.isRightOrBoth(_.left("e")), false) - U.deepStrictEqual(_.isRightOrBoth(_.right(1)), true) - U.deepStrictEqual(_.isRightOrBoth(_.both("e", 1)), true) + Util.deepStrictEqual(_.isRightOrBoth(_.left("e")), false) + Util.deepStrictEqual(_.isRightOrBoth(_.right(1)), true) + Util.deepStrictEqual(_.isRightOrBoth(_.both("e", 1)), true) }) it("isThese", () => { - U.deepStrictEqual(_.isThese(_.left("e")), true) - U.deepStrictEqual(_.isThese(_.right(1)), true) - U.deepStrictEqual(_.isThese(_.both("e", 1)), true) - U.deepStrictEqual(_.isThese(E.left("e")), true) - U.deepStrictEqual(_.isThese(E.right(1)), true) - U.deepStrictEqual(_.isThese(O.some(1)), false) + Util.deepStrictEqual(_.isThese(_.left("e")), true) + Util.deepStrictEqual(_.isThese(_.right(1)), true) + Util.deepStrictEqual(_.isThese(_.both("e", 1)), true) + Util.deepStrictEqual(_.isThese(E.left("e")), true) + Util.deepStrictEqual(_.isThese(E.right(1)), true) + Util.deepStrictEqual(_.isThese(O.some(1)), false) }) it("isBoth", () => { - U.deepStrictEqual(_.isBoth(_.left("e")), false) - U.deepStrictEqual(_.isBoth(_.right(1)), false) - U.deepStrictEqual(_.isBoth(_.both("e", 1)), true) + Util.deepStrictEqual(_.isBoth(_.left("e")), false) + Util.deepStrictEqual(_.isBoth(_.right(1)), false) + Util.deepStrictEqual(_.isBoth(_.both("e", 1)), true) }) it("fromThrowable", () => { - U.deepStrictEqual( + Util.deepStrictEqual( _.fromThrowable(() => { return 1 }, identity), _.right(1) ) - U.deepStrictEqual( + Util.deepStrictEqual( _.fromThrowable(() => { throw "string error" }, identity), @@ -518,8 +533,8 @@ describe("These", () => { } throw new Error("empty string") }, identity) - U.deepStrictEqual(f("a"), _.right(1)) - U.deepStrictEqual(f(""), _.left(new Error("empty string"))) + Util.deepStrictEqual(f("a"), _.right(1)) + Util.deepStrictEqual(f(""), _.left(new Error("empty string"))) }) it("inspectRight", () => { @@ -527,7 +542,7 @@ describe("These", () => { pipe(_.right(1), _.inspectRight((a) => log.push(a))) pipe(_.left("e1"), _.inspectRight((a) => log.push(a))) pipe(_.both("e2", 1), _.inspectRight((a) => log.push(a))) - U.deepStrictEqual(log, [1]) + Util.deepStrictEqual(log, [1]) }) it("inspectRightOrBoth", () => { @@ -535,7 +550,7 @@ describe("These", () => { pipe(_.right(1), _.inspectRightOrBoth((a) => log.push(a))) pipe(_.left("e1"), _.inspectRightOrBoth((a) => log.push(a))) pipe(_.both("e2", 2), _.inspectRightOrBoth((a) => log.push(a))) - U.deepStrictEqual(log, [1, 2]) + Util.deepStrictEqual(log, [1, 2]) }) it("inspectBoth", () => { @@ -543,7 +558,7 @@ describe("These", () => { pipe(_.right(1), _.inspectBoth((e, a) => log.push(e, a))) pipe(_.left("e1"), _.inspectBoth((e, a) => log.push(e, a))) pipe(_.both("e2", 2), _.inspectBoth((e, a) => log.push(e, a))) - U.deepStrictEqual(log, ["e2", 2]) + Util.deepStrictEqual(log, ["e2", 2]) }) it("inspectLeft", () => { @@ -551,7 +566,7 @@ describe("These", () => { pipe(_.right(1), _.inspectLeft((e) => log.push(e))) pipe(_.left("e1"), _.inspectLeft((e) => log.push(e))) pipe(_.both("e2", 1), _.inspectLeft((e) => log.push(e))) - U.deepStrictEqual(log, ["e1"]) + Util.deepStrictEqual(log, ["e1"]) }) it("getOrThrow", () => { @@ -573,60 +588,60 @@ describe("These", () => { }) it("getOrElse", () => { - U.deepStrictEqual(pipe(_.right(1), _.getOrElse(() => 2)), 1) - U.deepStrictEqual(pipe(_.left("e"), _.getOrElse(() => 2)), 2) - U.deepStrictEqual(pipe(_.both("e", 1), _.getOrElse(() => 2)), 1) + Util.deepStrictEqual(pipe(_.right(1), _.getOrElse(() => 2)), 1) + Util.deepStrictEqual(pipe(_.left("e"), _.getOrElse(() => 2)), 2) + Util.deepStrictEqual(pipe(_.both("e", 1), _.getOrElse(() => 2)), 1) }) it("getOrNull", () => { - U.deepStrictEqual(pipe(_.right(1), _.getOrNull), 1) - U.deepStrictEqual(pipe(_.left("e"), _.getOrNull), null) - U.deepStrictEqual(pipe(_.both("e", 1), _.getOrNull), 1) + Util.deepStrictEqual(pipe(_.right(1), _.getOrNull), 1) + Util.deepStrictEqual(pipe(_.left("e"), _.getOrNull), null) + Util.deepStrictEqual(pipe(_.both("e", 1), _.getOrNull), 1) }) it("getOrUndefined", () => { - U.deepStrictEqual(pipe(_.right(1), _.getOrUndefined), 1) - U.deepStrictEqual(pipe(_.left("e"), _.getOrUndefined), undefined) - U.deepStrictEqual(pipe(_.both("e", 1), _.getOrUndefined), 1) + Util.deepStrictEqual(pipe(_.right(1), _.getOrUndefined), 1) + Util.deepStrictEqual(pipe(_.left("e"), _.getOrUndefined), undefined) + Util.deepStrictEqual(pipe(_.both("e", 1), _.getOrUndefined), 1) }) it("fromNullable", () => { - U.deepStrictEqual(_.fromNullable(() => "default")(null), _.left("default")) - U.deepStrictEqual(_.fromNullable(() => "default")(undefined), _.left("default")) - U.deepStrictEqual(_.fromNullable(() => "default")(1), _.right(1)) + Util.deepStrictEqual(_.fromNullable(() => "default")(null), _.left("default")) + Util.deepStrictEqual(_.fromNullable(() => "default")(undefined), _.left("default")) + Util.deepStrictEqual(_.fromNullable(() => "default")(1), _.right(1)) }) it("liftNullable", () => { const f = _.liftNullable((n: number) => (n > 0 ? n : null), () => "error") - U.deepStrictEqual(f(1), _.right(1)) - U.deepStrictEqual(f(-1), _.left("error")) + Util.deepStrictEqual(f(1), _.right(1)) + Util.deepStrictEqual(f(-1), _.left("error")) }) it("liftPredicate", () => { const f = _.liftPredicate((n: number) => n >= 2, () => "e") - U.deepStrictEqual(f(3), _.right(3)) - U.deepStrictEqual(f(1), _.left("e")) + Util.deepStrictEqual(f(3), _.right(3)) + Util.deepStrictEqual(f(1), _.left("e")) }) it("fromIterable", () => { - U.deepStrictEqual(_.fromIterable(() => "e")([]), _.left("e")) - U.deepStrictEqual(_.fromIterable(() => "e")(["a"]), _.right("a")) + Util.deepStrictEqual(_.fromIterable(() => "e")([]), _.left("e")) + Util.deepStrictEqual(_.fromIterable(() => "e")(["a"]), _.right("a")) }) it("fromOption", () => { - U.deepStrictEqual(_.fromOption(() => "e")(O.none()), _.left("e")) - U.deepStrictEqual(_.fromOption(() => "e")(O.some(1)), _.right(1)) + Util.deepStrictEqual(_.fromOption(() => "e")(O.none()), _.left("e")) + Util.deepStrictEqual(_.fromOption(() => "e")(O.some(1)), _.right(1)) }) it("fromEither", () => { - U.deepStrictEqual(_.fromEither(E.right(1)), _.right(1)) + Util.deepStrictEqual(_.fromEither(E.right(1)), _.right(1)) expect(_.fromEither(E.left("e"))).toEqual(_.left(["e"])) }) it("fromThese", () => { - U.deepStrictEqual(_.fromThese(_.right(1)), _.succeed(1)) - U.deepStrictEqual(_.fromThese(_.left("e")), _.fail("e")) - U.deepStrictEqual(_.fromThese(_.both("e", 1)), _.warn("e", 1)) + Util.deepStrictEqual(_.fromThese(_.right(1)), _.succeed(1)) + Util.deepStrictEqual(_.fromThese(_.left("e")), _.fail("e")) + Util.deepStrictEqual(_.fromThese(_.both("e", 1)), _.warn("e", 1)) }) it("toEither", () => { @@ -634,33 +649,33 @@ describe("These", () => { }) it("absolve", () => { - U.deepStrictEqual(_.absolve(_.right(1)), E.right(1)) - U.deepStrictEqual(_.absolve(_.left("e")), E.left("e")) - U.deepStrictEqual(_.absolve(_.both("e", 1)), E.right(1)) + Util.deepStrictEqual(_.absolve(_.right(1)), E.right(1)) + Util.deepStrictEqual(_.absolve(_.left("e")), E.left("e")) + Util.deepStrictEqual(_.absolve(_.both("e", 1)), E.right(1)) }) it("condemn", () => { - U.deepStrictEqual(_.condemn(_.right(1)), E.right(1)) - U.deepStrictEqual(_.condemn(_.left("e")), E.left("e")) - U.deepStrictEqual(_.condemn(_.both("e", 1)), E.left("e")) + Util.deepStrictEqual(_.condemn(_.right(1)), E.right(1)) + Util.deepStrictEqual(_.condemn(_.left("e")), E.left("e")) + Util.deepStrictEqual(_.condemn(_.both("e", 1)), E.left("e")) }) it("liftOption", () => { const f = _.liftOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "e") - U.deepStrictEqual(f(1), _.right(1)) - U.deepStrictEqual(f(-1), _.left("e")) + Util.deepStrictEqual(f(1), _.right(1)) + Util.deepStrictEqual(f(-1), _.left("e")) }) it("liftEither", () => { const f = _.liftEither((n: number) => (n > 0 ? E.right(n) : E.left("e"))) - U.deepStrictEqual(f(1), _.succeed(1)) - U.deepStrictEqual(f(-1), _.fail("e")) + Util.deepStrictEqual(f(1), _.succeed(1)) + Util.deepStrictEqual(f(-1), _.fail("e")) }) it("liftThese", () => { const f = _.liftThese((n: number) => (n > 0 ? _.right(n) : _.left("e"))) - U.deepStrictEqual(f(1), _.succeed(1)) - U.deepStrictEqual(f(-1), _.fail("e")) + Util.deepStrictEqual(f(1), _.succeed(1)) + Util.deepStrictEqual(f(-1), _.fail("e")) }) it("fromTuple", () => { @@ -668,55 +683,55 @@ describe("These", () => { }) it("reverse", () => { - U.deepStrictEqual(_.reverse(_.left("e")), _.right("e")) - U.deepStrictEqual(_.reverse(_.right(1)), _.left(1)) - U.deepStrictEqual(_.reverse(_.both("e", 1)), _.both(1, "e")) + Util.deepStrictEqual(_.reverse(_.left("e")), _.right("e")) + Util.deepStrictEqual(_.reverse(_.right(1)), _.left(1)) + Util.deepStrictEqual(_.reverse(_.both("e", 1)), _.both(1, "e")) }) it("exists", () => { const gt2 = _.exists((n: number) => n > 2) - U.deepStrictEqual(gt2(_.left("a")), false) - U.deepStrictEqual(gt2(_.right(1)), false) - U.deepStrictEqual(gt2(_.right(3)), true) - U.deepStrictEqual(gt2(_.both("a", 1)), false) - U.deepStrictEqual(gt2(_.both("a", 3)), true) + Util.deepStrictEqual(gt2(_.left("a")), false) + Util.deepStrictEqual(gt2(_.right(1)), false) + Util.deepStrictEqual(gt2(_.right(3)), true) + Util.deepStrictEqual(gt2(_.both("a", 1)), false) + Util.deepStrictEqual(gt2(_.both("a", 3)), true) }) it("contains", () => { const contains = _.contains(number) - U.deepStrictEqual(contains(2)(_.left("a")), false) - U.deepStrictEqual(contains(2)(_.right(2)), true) - U.deepStrictEqual(contains(1)(_.right(2)), false) - U.deepStrictEqual(contains(2)(_.both("a", 2)), true) - U.deepStrictEqual(contains(1)(_.both("a", 2)), false) + Util.deepStrictEqual(contains(2)(_.left("a")), false) + Util.deepStrictEqual(contains(2)(_.right(2)), true) + Util.deepStrictEqual(contains(1)(_.right(2)), false) + Util.deepStrictEqual(contains(2)(_.both("a", 2)), true) + Util.deepStrictEqual(contains(1)(_.both("a", 2)), false) }) it("of", () => { - U.deepStrictEqual(_.of(1), _.right(1)) + Util.deepStrictEqual(_.of(1), _.right(1)) }) it("catchAll", () => { - U.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.right(2))), _.right(1)) - U.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.left("b"))), _.right(1)) - U.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.both("b", 2))), _.right(1)) - U.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.right(2))), _.right(2)) - U.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.left("b"))), _.left("b")) - U.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.both("b", 2))), _.both("b", 2)) - U.deepStrictEqual(pipe(_.both("a", 1), _.catchAll(() => _.right(2))), _.both("a", 1)) - U.deepStrictEqual(pipe(_.both("a", 1), _.catchAll(() => _.left("b"))), _.both("a", 1)) - U.deepStrictEqual(pipe(_.both("a", 1), _.catchAll(() => _.both("b", 2))), _.both("a", 1)) + Util.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.right(2))), _.right(1)) + Util.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.left("b"))), _.right(1)) + Util.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.both("b", 2))), _.right(1)) + Util.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.right(2))), _.right(2)) + Util.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.left("b"))), _.left("b")) + Util.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.both("b", 2))), _.both("b", 2)) + Util.deepStrictEqual(pipe(_.both("a", 1), _.catchAll(() => _.right(2))), _.both("a", 1)) + Util.deepStrictEqual(pipe(_.both("a", 1), _.catchAll(() => _.left("b"))), _.both("a", 1)) + Util.deepStrictEqual(pipe(_.both("a", 1), _.catchAll(() => _.both("b", 2))), _.both("a", 1)) }) it("orElse", () => { - U.deepStrictEqual(pipe(_.right(1), _.orElse(_.right(2))), _.right(1)) - U.deepStrictEqual(pipe(_.right(1), _.orElse(_.left("b"))), _.right(1)) - U.deepStrictEqual(pipe(_.right(1), _.orElse(_.both("b", 2))), _.right(1)) - U.deepStrictEqual(pipe(_.left("a"), _.orElse(_.right(2))), _.right(2)) - U.deepStrictEqual(pipe(_.left("a"), _.orElse(_.left("b"))), _.left("b")) - U.deepStrictEqual(pipe(_.left("a"), _.orElse(_.both("b", 2))), _.both("b", 2)) - U.deepStrictEqual(pipe(_.both("a", 1), _.orElse(_.right(2))), _.both("a", 1)) - U.deepStrictEqual(pipe(_.both("a", 1), _.orElse(_.left("b"))), _.both("a", 1)) - U.deepStrictEqual(pipe(_.both("a", 1), _.orElse(_.both("b", 2))), _.both("a", 1)) + Util.deepStrictEqual(pipe(_.right(1), _.orElse(_.right(2))), _.right(1)) + Util.deepStrictEqual(pipe(_.right(1), _.orElse(_.left("b"))), _.right(1)) + Util.deepStrictEqual(pipe(_.right(1), _.orElse(_.both("b", 2))), _.right(1)) + Util.deepStrictEqual(pipe(_.left("a"), _.orElse(_.right(2))), _.right(2)) + Util.deepStrictEqual(pipe(_.left("a"), _.orElse(_.left("b"))), _.left("b")) + Util.deepStrictEqual(pipe(_.left("a"), _.orElse(_.both("b", 2))), _.both("b", 2)) + Util.deepStrictEqual(pipe(_.both("a", 1), _.orElse(_.right(2))), _.both("a", 1)) + Util.deepStrictEqual(pipe(_.both("a", 1), _.orElse(_.left("b"))), _.both("a", 1)) + Util.deepStrictEqual(pipe(_.both("a", 1), _.orElse(_.both("b", 2))), _.both("a", 1)) }) it("orElseEither", () => { @@ -732,35 +747,35 @@ describe("These", () => { }) it("orElseFail", () => { - U.deepStrictEqual(pipe(_.right(1), _.orElseFail(() => "e2")), _.right(1)) - U.deepStrictEqual(pipe(_.left("e1"), _.orElseFail(() => "e2")), _.left("e2")) - U.deepStrictEqual(pipe(_.both("e1", 1), _.orElseFail(() => "e2")), _.both("e1", 1)) + Util.deepStrictEqual(pipe(_.right(1), _.orElseFail(() => "e2")), _.right(1)) + Util.deepStrictEqual(pipe(_.left("e1"), _.orElseFail(() => "e2")), _.left("e2")) + Util.deepStrictEqual(pipe(_.both("e1", 1), _.orElseFail(() => "e2")), _.both("e1", 1)) }) it("orElseSucceed", () => { - U.deepStrictEqual(pipe(_.right(1), _.orElseSucceed(() => 2)), _.right(1)) - U.deepStrictEqual(pipe(_.left("e"), _.orElseSucceed(() => 2)), _.right(2)) - U.deepStrictEqual(pipe(_.both("e", 1), _.orElseSucceed(() => 2)), _.both("e", 1)) + Util.deepStrictEqual(pipe(_.right(1), _.orElseSucceed(() => 2)), _.right(1)) + Util.deepStrictEqual(pipe(_.left("e"), _.orElseSucceed(() => 2)), _.right(2)) + Util.deepStrictEqual(pipe(_.both("e", 1), _.orElseSucceed(() => 2)), _.both("e", 1)) }) it("firstSuccessOf", () => { - U.deepStrictEqual(pipe(_.right(1), _.firstRightOrBothOf([])), _.right(1)) - U.deepStrictEqual(pipe(_.left("e"), _.firstRightOrBothOf([])), _.left("e")) - U.deepStrictEqual( + Util.deepStrictEqual(pipe(_.right(1), _.firstRightOrBothOf([])), _.right(1)) + Util.deepStrictEqual(pipe(_.left("e"), _.firstRightOrBothOf([])), _.left("e")) + Util.deepStrictEqual( pipe( _.left("e1"), _.firstRightOrBothOf([_.left("e2"), _.left("e3"), _.left("e4"), _.right(1)]) ), _.right(1) ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe( _.left("e1"), _.firstRightOrBothOf([_.left("e2"), _.left("e3"), _.left("e4"), _.both("e5", 1)]) ), _.both("e5", 1) ) - U.deepStrictEqual( + Util.deepStrictEqual( pipe(_.left("e1"), _.firstRightOrBothOf([_.left("e2"), _.left("e3"), _.left("e4")])), _.left("e4") ) @@ -768,47 +783,47 @@ describe("These", () => { it("coproduct", () => { const coproduct = _.SemiCoproduct.coproduct - U.deepStrictEqual(coproduct(_.right(1), _.right(2)), _.right(1)) - U.deepStrictEqual(coproduct(_.right(1), _.left("e2")), _.right(1)) - U.deepStrictEqual(coproduct(_.left("e1"), _.right(2)), _.right(2)) - U.deepStrictEqual(coproduct(_.left("e1"), _.left("e2")), _.left("e2")) - U.deepStrictEqual(coproduct(_.both("e1", 1), _.right(2)), _.both("e1", 1)) - U.deepStrictEqual(coproduct(_.both("e1", 1), _.left("e2")), _.both("e1", 1)) + Util.deepStrictEqual(coproduct(_.right(1), _.right(2)), _.right(1)) + Util.deepStrictEqual(coproduct(_.right(1), _.left("e2")), _.right(1)) + Util.deepStrictEqual(coproduct(_.left("e1"), _.right(2)), _.right(2)) + Util.deepStrictEqual(coproduct(_.left("e1"), _.left("e2")), _.left("e2")) + Util.deepStrictEqual(coproduct(_.both("e1", 1), _.right(2)), _.both("e1", 1)) + Util.deepStrictEqual(coproduct(_.both("e1", 1), _.left("e2")), _.both("e1", 1)) }) it("coproduct", () => { const coproductMany = _.SemiCoproduct.coproductMany - U.deepStrictEqual(coproductMany(_.right(1), [_.right(2)]), _.right(1)) - U.deepStrictEqual(coproductMany(_.right(1), [_.left("e2")]), _.right(1)) - U.deepStrictEqual(coproductMany(_.left("e1"), [_.right(2)]), _.right(2)) - U.deepStrictEqual(coproductMany(_.left("e1"), [_.left("e2")]), _.left("e2")) - U.deepStrictEqual(coproductMany(_.both("e1", 1), [_.right(2)]), _.both("e1", 1)) - U.deepStrictEqual(coproductMany(_.both("e1", 1), [_.left("e2")]), _.both("e1", 1)) + Util.deepStrictEqual(coproductMany(_.right(1), [_.right(2)]), _.right(1)) + Util.deepStrictEqual(coproductMany(_.right(1), [_.left("e2")]), _.right(1)) + Util.deepStrictEqual(coproductMany(_.left("e1"), [_.right(2)]), _.right(2)) + Util.deepStrictEqual(coproductMany(_.left("e1"), [_.left("e2")]), _.left("e2")) + Util.deepStrictEqual(coproductMany(_.both("e1", 1), [_.right(2)]), _.both("e1", 1)) + Util.deepStrictEqual(coproductMany(_.both("e1", 1), [_.left("e2")]), _.both("e1", 1)) }) it("compact", () => { - U.deepStrictEqual(pipe(_.right(O.some(1)), _.compact(() => "e2")), _.right(1)) - U.deepStrictEqual(pipe(_.right(O.none()), _.compact(() => "e2")), _.left("e2")) - U.deepStrictEqual(pipe(_.left("e1"), _.compact(() => "e2")), _.left("e1")) - U.deepStrictEqual(pipe(_.both("e1", O.some(1)), _.compact(() => "e2")), _.both("e1", 1)) - U.deepStrictEqual(pipe(_.both("e1", O.none()), _.compact(() => "e2")), _.left("e2")) + Util.deepStrictEqual(pipe(_.right(O.some(1)), _.compact(() => "e2")), _.right(1)) + Util.deepStrictEqual(pipe(_.right(O.none()), _.compact(() => "e2")), _.left("e2")) + Util.deepStrictEqual(pipe(_.left("e1"), _.compact(() => "e2")), _.left("e1")) + Util.deepStrictEqual(pipe(_.both("e1", O.some(1)), _.compact(() => "e2")), _.both("e1", 1)) + Util.deepStrictEqual(pipe(_.both("e1", O.none()), _.compact(() => "e2")), _.left("e2")) }) it("filter", () => { const predicate = (n: number) => n > 10 - U.deepStrictEqual(pipe(_.right(12), _.filter(predicate, () => "e2")), _.right(12)) - U.deepStrictEqual(pipe(_.right(7), _.filter(predicate, () => "e2")), _.left("e2")) - U.deepStrictEqual(pipe(_.left("e1"), _.filter(predicate, () => "e2")), _.left("e1")) - U.deepStrictEqual(pipe(_.both("e1", 12), _.filter(predicate, () => "e2")), _.both("e1", 12)) - U.deepStrictEqual(pipe(_.both("e1", 7), _.filter(predicate, () => "e2")), _.left("e2")) + Util.deepStrictEqual(pipe(_.right(12), _.filter(predicate, () => "e2")), _.right(12)) + Util.deepStrictEqual(pipe(_.right(7), _.filter(predicate, () => "e2")), _.left("e2")) + Util.deepStrictEqual(pipe(_.left("e1"), _.filter(predicate, () => "e2")), _.left("e1")) + Util.deepStrictEqual(pipe(_.both("e1", 12), _.filter(predicate, () => "e2")), _.both("e1", 12)) + Util.deepStrictEqual(pipe(_.both("e1", 7), _.filter(predicate, () => "e2")), _.left("e2")) }) it("filterMap", () => { const f = (n: number) => (n > 2 ? O.some(n + 1) : O.none()) - U.deepStrictEqual(pipe(_.left("e1"), _.filterMap(f, () => "e2")), _.left("e1")) - U.deepStrictEqual(pipe(_.right(1), _.filterMap(f, () => "e2")), _.left("e2")) - U.deepStrictEqual(pipe(_.right(3), _.filterMap(f, () => "e2")), _.right(4)) - U.deepStrictEqual(pipe(_.both("e1", 1), _.filterMap(f, () => "e2")), _.left("e2")) - U.deepStrictEqual(pipe(_.both("e1", 3), _.filterMap(f, () => "e2")), _.both("e1", 4)) + Util.deepStrictEqual(pipe(_.left("e1"), _.filterMap(f, () => "e2")), _.left("e1")) + Util.deepStrictEqual(pipe(_.right(1), _.filterMap(f, () => "e2")), _.left("e2")) + Util.deepStrictEqual(pipe(_.right(3), _.filterMap(f, () => "e2")), _.right(4)) + Util.deepStrictEqual(pipe(_.both("e1", 1), _.filterMap(f, () => "e2")), _.left("e2")) + Util.deepStrictEqual(pipe(_.both("e1", 3), _.filterMap(f, () => "e2")), _.both("e1", 4)) }) }) diff --git a/test/util.ts b/test/util.ts index 007cbfc6c..c042e20e2 100644 --- a/test/util.ts +++ b/test/util.ts @@ -1,3 +1,4 @@ +import { structural } from "@fp-ts/core/internal/effect" import * as assert from "assert" export const deepStrictEqual = (actual: A, expected: A) => { @@ -9,3 +10,8 @@ export const strictEqual = (actual: A, expected: A) => { } export const double = (n: number): number => n * 2 + +export const ownKeys = (o: object): ReadonlyArray => + (Object.keys(o) as ReadonlyArray).concat(Object.getOwnPropertySymbols(o)) + +export const isStructural = (u: unknown) => typeof u === "object" && u != null && structural in u From 763c563fab2899aa66d0e162b26a21ac0321fb54 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 24 Jan 2023 08:41:04 +0000 Subject: [PATCH 091/255] Version Packages --- .changeset/plenty-parents-collect.md | 5 ----- CHANGELOG.md | 6 ++++++ package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) delete mode 100644 .changeset/plenty-parents-collect.md diff --git a/.changeset/plenty-parents-collect.md b/.changeset/plenty-parents-collect.md deleted file mode 100644 index 815496e81..000000000 --- a/.changeset/plenty-parents-collect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -change structural tracking diff --git a/CHANGELOG.md b/CHANGELOG.md index 3baefeaf9..d8a133203 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # @fp-ts/core +## 0.1.1 + +### Patch Changes + +- [#48](https://github.com/fp-ts/core/pull/48) [`da0bae84`](https://github.com/fp-ts/core/commit/da0bae8487d59d78c5ba6470d37727ccc66538bb) Thanks [@gcanti](https://github.com/gcanti)! - change structural tracking + ## 0.1.0 ### Minor Changes diff --git a/package.json b/package.json index 191363182..44de22737 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fp-ts/core", - "version": "0.1.0", + "version": "0.1.1", "publishConfig": { "access": "public", "directory": "dist" From 3efb6d8a9a343ca177ec7bcc3e360974aec307cf Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 30 Jan 2023 09:35:28 +0100 Subject: [PATCH 092/255] Function: add dual utility --- .changeset/witty-toes-breathe.md | 5 +++++ docs/modules/Function.ts.md | 14 ++++++++++++++ src/Function.ts | 20 ++++++++++++++++++++ test/Function.ts | 9 +++++++++ 4 files changed, 48 insertions(+) create mode 100644 .changeset/witty-toes-breathe.md diff --git a/.changeset/witty-toes-breathe.md b/.changeset/witty-toes-breathe.md new file mode 100644 index 000000000..e14fd4788 --- /dev/null +++ b/.changeset/witty-toes-breathe.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Function: add dual utility diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 862ec1b2e..f7e99655a 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -30,6 +30,7 @@ Added in v1.0.0 - [constUndefined](#constundefined) - [constVoid](#constvoid) - [constant](#constant) + - [dual](#dual) - [flip](#flip) - [flow](#flow) - [hole](#hole) @@ -271,6 +272,19 @@ export declare const constant: (a: A) => LazyArg Added in v1.0.0 +## dual + +**Signature** + +```ts +export declare const dual: ) => any, P extends (...args: Array) => any>( + dfLen: Parameters['length'], + body: DF +) => DF & P +``` + +Added in v1.0.0 + ## flip Flips the arguments of a curried function. diff --git a/src/Function.ts b/src/Function.ts index 9fb4d9dce..cf032c250 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -642,3 +642,23 @@ export const hole: () => T = absurd as any * @since 1.0.0 */ export const SK = (_: A, b: B): B => b + +/** + * @since 1.0.0 + */ +export const dual = < + DF extends (...args: Array) => any, + P extends (...args: Array) => any +>( + dfLen: Parameters["length"], + body: DF +): DF & P => { + // @ts-expect-error + return function() { + if (arguments.length === dfLen) { + // @ts-expect-error + return body.apply(this, arguments) + } + return ((self: any) => body(self, ...arguments)) as any + } +} diff --git a/test/Function.ts b/test/Function.ts index 24a9a251a..4d2bd6a27 100644 --- a/test/Function.ts +++ b/test/Function.ts @@ -141,4 +141,13 @@ describe.concurrent("Function", () => { 4094 ) }) + + it("dual", () => { + const f = Function.dual< + (self: number, that: number) => number, + (that: number) => (self: number) => number + >(2, (a: number, b: number): number => a - b) + deepStrictEqual(f(3, 2), 1) + deepStrictEqual(Function.pipe(3, f(2)), 1) + }) }) From 175d6b9e93dbf6bfbea80b34a06f26ceb3d725aa Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 30 Jan 2023 09:38:52 +0100 Subject: [PATCH 093/255] Option, Either, These: switch to interfaces --- .changeset/swift-tomatoes-smile.md | 5 +++++ docs/modules/Either.ts.md | 12 ++++++------ docs/modules/Option.ts.md | 12 ++++++------ docs/modules/These.ts.md | 6 +++--- src/Either.ts | 4 ++-- src/Option.ts | 4 ++-- src/These.ts | 2 +- 7 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 .changeset/swift-tomatoes-smile.md diff --git a/.changeset/swift-tomatoes-smile.md b/.changeset/swift-tomatoes-smile.md new file mode 100644 index 000000000..a80b3e6c1 --- /dev/null +++ b/.changeset/swift-tomatoes-smile.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Option, Either, These: switch to interfaces diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 59a192b5a..7eb5d8994 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -105,8 +105,8 @@ Added in v1.0.0 - [tupled](#tupled) - [models](#models) - [Either (type alias)](#either-type-alias) - - [Left (type alias)](#left-type-alias) - - [Right (type alias)](#right-type-alias) + - [Left (interface)](#left-interface) + - [Right (interface)](#right-interface) - [pattern matching](#pattern-matching) - [match](#match) - [sequencing](#sequencing) @@ -1107,12 +1107,12 @@ export type Either = Left | Right Added in v1.0.0 -## Left (type alias) +## Left (interface) **Signature** ```ts -export type Left = { +export interface Left { readonly _tag: 'Left' readonly left: E } @@ -1120,12 +1120,12 @@ export type Left = { Added in v1.0.0 -## Right (type alias) +## Right (interface) **Signature** ```ts -export type Right = { +export interface Right { readonly _tag: 'Right' readonly right: A } diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 0ddc1bdb9..e2e56f330 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -99,9 +99,9 @@ Added in v1.0.0 - [imap](#imap) - [map](#map) - [models](#models) - - [None (type alias)](#none-type-alias) + - [None (interface)](#none-interface) - [Option (type alias)](#option-type-alias) - - [Some (type alias)](#some-type-alias) + - [Some (interface)](#some-interface) - [pattern matching](#pattern-matching) - [match](#match) - [sequencing](#sequencing) @@ -1084,12 +1084,12 @@ Added in v1.0.0 # models -## None (type alias) +## None (interface) **Signature** ```ts -export type None = { +export interface None { readonly _tag: 'None' } ``` @@ -1106,12 +1106,12 @@ export type Option = None | Some Added in v1.0.0 -## Some (type alias) +## Some (interface) **Signature** ```ts -export type Some = { +export interface Some { readonly _tag: 'Some' readonly value: A } diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 062181e63..ef4a5b57b 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -133,7 +133,7 @@ Added in v1.0.0 - [map](#map) - [tupled](#tupled) - [model](#model) - - [Both (type alias)](#both-type-alias) + - [Both (interface)](#both-interface) - [These (type alias)](#these-type-alias) - [Validated (type alias)](#validated-type-alias) - [pattern matching](#pattern-matching) @@ -1210,12 +1210,12 @@ Added in v1.0.0 # model -## Both (type alias) +## Both (interface) **Signature** ```ts -export type Both = { +export interface Both { readonly _tag: 'Both' readonly left: E readonly right: A diff --git a/src/Either.ts b/src/Either.ts index e7ab02f47..7a94c810f 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -42,7 +42,7 @@ import * as traversable from "@fp-ts/core/typeclass/Traversable" * @category models * @since 1.0.0 */ -export type Left = { +export interface Left { readonly _tag: "Left" readonly left: E } @@ -51,7 +51,7 @@ export type Left = { * @category models * @since 1.0.0 */ -export type Right = { +export interface Right { readonly _tag: "Right" readonly right: A } diff --git a/src/Option.ts b/src/Option.ts index 95000e7be..bddf2557a 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -46,7 +46,7 @@ import * as traversable from "@fp-ts/core/typeclass/Traversable" * @category models * @since 1.0.0 */ -export type None = { +export interface None { readonly _tag: "None" } @@ -54,7 +54,7 @@ export type None = { * @category models * @since 1.0.0 */ -export type Some = { +export interface Some { readonly _tag: "Some" readonly value: A } diff --git a/src/These.ts b/src/These.ts index b6bf12097..1479cc6ac 100644 --- a/src/These.ts +++ b/src/These.ts @@ -50,7 +50,7 @@ import * as traversable from "@fp-ts/core/typeclass/Traversable" * @category model * @since 1.0.0 */ -export type Both = { +export interface Both { readonly _tag: "Both" readonly left: E readonly right: A From 93bd9ad638a06f6041b8dba4685ed080d3737734 Mon Sep 17 00:00:00 2001 From: Jesse Kelly Date: Sat, 28 Jan 2023 16:03:04 +0000 Subject: [PATCH 094/255] feat: extended flip to support muliple props --- src/Function.ts | 5 +++-- test/Function.ts | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Function.ts b/src/Function.ts index cf032c250..3b2ca4835 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -170,8 +170,9 @@ export const constVoid: LazyArg = constUndefined * * @since 1.0.0 */ -export const flip = (f: (a: A) => (b: B) => C): ((b: B) => (a: A) => C) => - (b) => (a) => f(a)(b) +export const flip = , B extends Array, C>( + f: (...a: A) => (...b: B) => C +): ((...b: B) => (...a: A) => C) => (...b) => (...a) => f(...a)(...b) /** * Performs left-to-right function composition. The first argument may have any arity, the remaining arguments must be unary. diff --git a/test/Function.ts b/test/Function.ts index 4d2bd6a27..a5bcd369a 100644 --- a/test/Function.ts +++ b/test/Function.ts @@ -36,7 +36,10 @@ describe.concurrent("Function", () => { it("flip", () => { const f = (a: number) => (b: string) => a - b.length + const g = (a: number, i = 0) => (b: number) => a ** b + i + deepStrictEqual(Function.flip(f)("aaa")(2), -1) + deepStrictEqual(Function.flip(g)(2)(2, 1), 5) }) it("compose", () => { From 45e689d09041f20656ff173bce545b9153ead091 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 25 Jan 2023 08:48:22 +0100 Subject: [PATCH 095/255] docs: Option.md --- Option.md | 246 +++++++++++++++++++++++++++++++++++--- README.md | 19 ++- docs/modules/Number.ts.md | 54 +++++++++ docs/modules/Option.ts.md | 83 +++++++------ src/Number.ts | 36 ++++++ src/Option.ts | 112 ++++++++++++----- data.md => ts-types.md | 169 +++++++++++++------------- 7 files changed, 544 insertions(+), 175 deletions(-) rename data.md => ts-types.md (97%) diff --git a/Option.md b/Option.md index e03e6303c..5cccd956d 100644 --- a/Option.md +++ b/Option.md @@ -1,15 +1,19 @@ # The `Option` data type -The `Option` data type is a powerful and flexible tool for handling potentially failed computations in functional programming. It can be found in the `@fp-ts/core/Option` module, and it has two variants, `None` and `Some`, which can be used to represent different outcomes. +The `Option` data type is a powerful and flexible tool in functional programming, it can be found in the `@fp-ts/core/Option module`. It is used to model optional values in TypeScript, by providing a container that can hold either a value of a specific type (`Some`) or no value at all (`None`). This helps in handling the presence or absence of a value in a safe and predictable way, making it easy to chain computations and handle errors in a functional way. There are two possible interpretations of the `Option` data type: -1. as a representation of the result of a computation that can fail or return a value of type `A` -2. as a representation of an optional value of type `A` +1. as a representation of an **optional value** of type `A` +2. as a representation of the result of a **computation that can fail** or return a value of type `A` -In the first of these two interpretations, the `None` union member represents the result of a computation that has failed and therefore was not able to return any value, while the `Some` union member represents the result of a computation that has succeeded and was able to return a value of type `A`. +**Optional value** -In the second of these two interpretations, the `None` union member represents the absence of the value, while the `Some` union member represents the presence of the value of type `A` +In the first of these two interpretations, the `None` union member represents the absence of the value, while the `Some` union member represents the presence of the value of type `A` + +**Computation that can fail** + +In the second of these two interpretations, the `None` union member represents the result of a computation that has failed and therefore was not able to return any value, while the `Some` union member represents the result of a computation that has succeeded and was able to return a value of type `A`. # Definition @@ -17,48 +21,133 @@ The `Option` data type is the union of two members: `None` and `Some`. The way c > A common technique for working with unions is to have a single field which uses literal types which you can use to let TypeScript narrow down the possible current type +By convention in `@fp-ts/core`, this single field which uses literal types is named "\_tag" (but you can use any name when defining your unions). + +Furthermore, the data type `Option` is a "polymorphic" data type, that is, it makes use of a feature of TypeScript named ["Generics"](https://www.typescriptlang.org/docs/handbook/2/generics.html), meaning that the `Option` data type is a container that can hold any type. + Here's the complete definition of the `Option` type: ```ts export type None = { - readonly _tag: "None"; + readonly _tag: "None"; // represents the absence of a value }; export type Some = { - readonly _tag: "Some"; - readonly value: A; + readonly _tag: "Some"; // represents the presence of a value + readonly value: A; // the actual value }; -export type Option = None | Some; +export type Option = None | Some; // union type representing the option of having a value or not ``` +The `Option` type is defined as a union of two other types, `None` and `Some`, that represent the two possible states of the option: having a value or not. + +The type parameter `A` is used to specify the type of the value that the option holds. + +The `_tag` field is used to distinguish between the two options, "None" and "Some". + # Using `Option` -To create an instance of `Option`, you can use the `some` and `none` constructors, which construct a new `Option` holding a `Some` or `None` value respectively. +To create an instance of `Option`, you can use the `some` and `none` constructors, which construct a new `Option` holding a `Some` or `None` value respectively: ```ts -import { none, some } from "@fp-ts/core/Either"; +import { none, some } from "@fp-ts/core/Option"; const success: Option = some(1); -const failure: Option = none(); +const failure: Option = none(); ``` +Let's summarize the two cases in a table: + +**Cheat sheet** (constructors) + +| Name | Given | To | +| ------ | ----- | --------------- | +| `some` | `A` | `Option` | +| `none` | | `Option` | + +It is important to note that the `none` constructor by default returns a value of type `Option`, this makes it possible to assign this value to any `Option`, whatever the type `A` is. + +```ts +const optionNumber: Option = none(); +const optionString: Option = none(); +const optionBoolean: Option = none(); +``` + +Alternatively, if it is useful to you, you can specify the desired type at the call site, explicitly indicating which type `A` you are interested in. This way, you don't need the type annotations: + +```ts +const optionNumber = none(); +const optionString = none(); +const optionBoolean = none(); +``` + +In this way you don't need to specify the type of the variables `optionNumber`, `optionString`, `optionBoolean` because TypeScript infers the type from the call site. + +# Modeling optional properties with `Option` + +Here is an example of a `User` model where the `email` field is of type `Option`. This means that the value of the `email` field may or may not be present and will be of type `string` when it is present. + +```ts +interface User { + id: number; + username: string; + email: Option; +} +``` + +```ts +import { some, none } from "@fp-ts/core/Option"; + +// case with email +const user1: User = { + id: 1, + username: "john_doe", + email: some("john.doe@example.com"), +}; + +// case without email +const user2: User = { + id: 2, + username: "jane_doe", + email: none(), +}; +``` + +It's important to note that the optionality only concerns the **value** of the `email` field, while the key `"email"` will always be present in the object. + # Working with `Option` Once you have an instance of `Option`, you can use the various functions provided in the `@fp-ts/core/Option` module to work with it. -The `map` function can be used to transform the `Some` values. +The `map` function can be used to transform the `Some` values: ```ts import { pipe } from "@fp-ts/core/Function"; import { some, map } from "@fp-ts/core/Option"; +// create a value of type Option with the value of 1 const success: Option = pipe( some(1), + // maps the value inside the Option, adding 1, resulting in some(2) + map((x) => x + 1) +); +``` + +As you can see you can transform the result of your computation without unwrapping and wrapping the underlying value of `Option`. + +What is very convenient about `Option` is how the absence of value is handled (i.e. a `None`). See the example below: + +```ts +const failure: Option = pipe( + none(), + // tries to map the value inside the none, but it does not exist, resulting in none() map((x) => x + 1) -); // some(2) +); ``` +As you can see, even though we started with a `None` value, we can still operate on our `Option`. No errors are thrown or shown to the user, unless we do it intentionally. What happens is that when the `Option` is `None`, the mapping doesn't even happen and the `None` value representing the absence of value is returned unchanged. + # Handling failing computations Let's see how to use the `Option` data type to model a computation that can fail, such as a function that can throw an exception based on certain conditions. Let's take the case of the following function: @@ -92,7 +181,121 @@ console.log(parseNumber("2")); // some(2) console.log(parseNumber("Not a number")); // none() ``` -# Pattern matching +What happens if we add a call to the `parseNumber` function to a pipeline that already involves an `Option`? + +```ts +const result = pipe( + some("2"), + map((s) => parseNumber(s)), + map((n) => n * 2) // type-checker error! +); +``` + +There's something wrong, we received an error from the type checker, what happened? + +The problem is that in the second `map` the parameter `n` is of type `Option` and not `number`. + +```ts +const result = pipe( + some("2"), + map((s) => parseNumber(s)), + map((x: Option) => ...) +); +``` + +Fortunately, the fix is simple, when adding a computation that returns an `Option` to our pipeline we should use the `flatMap` function instead of the `map` function: + +```ts +import { flatMap } from "@fp-ts/core/Option"; + +const result = pipe( + some("2"), + flatMap((s) => parseNumber(s)), + map((n) => n * 2) // ok! now `n` has type `number` +); +``` + +Let's summarize the two cases in a table: + +**Cheat sheet** (sequencing) + +| Name | Given | To | +| --------- | ----------------------------- | ----------- | +| `map` | `Option`, `A => B` | `Option` | +| `flatMap` | `Option`, `A => Option` | `Option` | + +The `flatMap` function offers the same convenience as the `map` function, which only continues with the computations contained in the pipeline if a `None` value is **not** encountered: + +**Happy path, starting with a valid input** + +```ts +const success: Option = pipe( + some("2"), + flatMap((s) => parseNumber(s)), // parse the input to number + map((x) => x * 2), // double the parsed number + map((x) => x - 3) // subtract 3 +); // some(1) +``` + +**Error path, starting with an invalid input** + +```ts +const failure: Option = pipe( + some("a"), + flatMap((s) => parseNumber(s)), // parse the input to number + map((x) => x * 2), // This will not be executed because parseNumber will return None + map((x) => x - 3) // This will not be executed +); // none() +``` + +**Error path, starting with None** + +```ts +const noneStart: Option = pipe( + none, + flatMap((s) => parseNumber(s)), // This will not be executed because it starts with None + map((x) => x * 2), // This will not be executed + map((x) => x - 3) // This will not be executed +); // none() +``` + +When using this approach, the **desired outcome** is always in clear view while defining your pipeline. This allows you to focus on the expected result, while leaving it to `Option` to handle any potential errors that may arise seamlessly and transparently. + +You can focus on the successful scenario and let `Option` handle the tedious task of managing potential errors at every step of the pipeline, without the need for explicit handling. + +# Debugging + +At any time, it is possible to inspect what is happening in your pipeline using two utility functions: + +**Cheat sheet** (debugging) + +| Name | Given | To | Description | +| ------------- | ------------------------- | ----------- | ------------------------------------ | +| `inspectSome` | `Option`, `A => void` | `Option` | callback called if it is a `Some` | +| `inspectNone` | `Option`, `() => void` | `Option` | callback called if it is a `None` | + +Let's see an example where both are in action: + +```ts +import { inspectSome, inspectNone } from "@fp-ts/core/Option"; + +const failure: Option = pipe( + some("a"), + inspectSome(console.log), + flatMap((s) => parseNumber(s)), + inspectNone(() => console.error("none")), + map((x) => x * 2), + map((x) => x - 3) +); +// "a" +// "none" +``` + +Please note that these two functions should only be used for debugging purposes and it is not recommended to use them for performing side effects or encoding business logic. + +# Pattern matching and error handling + +We have seen how easy and convenient it is to build pipelines involving the `Option` data type, leaving it to handle any errors that may occur at any step. However, at some point, you will be interested in manually handling the error to understand the overall result obtained from the pipeline and decide what to do accordingly. The `match` function allows us to match on the `None` and `Some` cases of an `Option` value and provide different actions for each. @@ -118,3 +321,16 @@ const output = pipe( console.log(output); // Output: Error: Cannot parse 'Not a number' as a number ``` + +**Cheat sheet** (error handling) + +| Name | Given | To | +| ---------------- | --------------------------------------------------- | ---------------------- | +| `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | +| `getOrThrow` | `Option` | `A` | +| `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | +| `getOrNull` | `Option` | `A \| null` | +| `getOrUndefined` | `Option` | `A \| undefined` | +| `orElse` | `Option`, `Option` | `Option` | +| `orElseEither` | `Option`, `Option` | `Option>` | +| `firstSomeOf` | `Option`, `Iterable>` | `Option` | diff --git a/README.md b/README.md index 0a1ed1e53..ac709e059 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,16 @@ Functional programming in TypeScript

+# Credits and sponsorship + +This library was inspired by the following projects: + +- [fp-ts](https://github.com/gcanti/fp-ts) + +A huge thanks to my sponsors who made the development of `@fp-ts/core` possible. + +If you also want to **become a sponsor** to ensure this library continues to improve and receive maintenance, check out my [GitHub Sponsors profile](https://github.com/sponsors/gcanti?o=sd&sc=t) + # Typed functional programming in TypeScript This project represents the next major iteration of [`fp-ts`](https://github.com/gcanti/fp-ts) and it's objective is a reconciliation with [`@effect`](https://github.com/Effect-TS) in order to unify the ecosystems. @@ -44,12 +54,15 @@ To install the **alpha** version: npm install @fp-ts/core ``` +**Warning**. This package is primarily published to receive early feedback and for contributors, during this development phase we cannot guarantee the stability of the APIs, consider each release to contain breaking changes. + # Documentation - [Typeclass overview](./typeclass.md) -- [Data overview](./data.md) -- [The `Option` data type](./Option.md) -- [The `Either` data type](./Either.md) +- [Standard TypeScript types](./ts-types.md) (WIP) +- Functional Error handling + - [The `Option` data type](./Option.md) (WIP) + - [The `Either` data type](./Either.md) (WIP) - [API Reference](https://fp-ts.github.io/core/) # License diff --git a/docs/modules/Number.ts.md b/docs/modules/Number.ts.md index cc6393f80..1ca81f7c3 100644 --- a/docs/modules/Number.ts.md +++ b/docs/modules/Number.ts.md @@ -205,6 +205,15 @@ Added in v1.0.0 export declare const decrement: (n: number) => number ``` +**Example** + +```ts +import { decrement } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(3, decrement), 2) +``` + Added in v1.0.0 ## divide @@ -215,6 +224,15 @@ Added in v1.0.0 export declare const divide: (that: number) => (self: number) => number ``` +**Example** + +```ts +import { divide } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(6, divide(3)), 2) +``` + Added in v1.0.0 ## increment @@ -225,6 +243,15 @@ Added in v1.0.0 export declare const increment: (n: number) => number ``` +**Example** + +```ts +import { increment } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(2, increment), 3) +``` + Added in v1.0.0 ## multiply @@ -235,6 +262,15 @@ Added in v1.0.0 export declare const multiply: (that: number) => (self: number) => number ``` +**Example** + +```ts +import { multiply } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(2, multiply(3)), 6) +``` + Added in v1.0.0 ## sign @@ -255,6 +291,15 @@ Added in v1.0.0 export declare const subtract: (that: number) => (self: number) => number ``` +**Example** + +```ts +import { subtract } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(2, subtract(3)), -1) +``` + Added in v1.0.0 ## sum @@ -265,4 +310,13 @@ Added in v1.0.0 export declare const sum: (that: number) => (self: number) => number ``` +**Example** + +```ts +import { sum } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(2, sum(3)), 5) +``` + Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index e2e56f330..9896382ab 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -20,6 +20,8 @@ Added in v1.0.0

Table of contents

+- [combinators](#combinators) + - [tap](#tap) - [combining](#combining) - [getFirstNoneMonoid](#getfirstnonemonoid) - [getFirstNoneSemigroup](#getfirstnonesemigroup) @@ -127,7 +129,6 @@ Added in v1.0.0 - [exists](#exists) - [flatten](#flatten) - [struct](#struct) - - [tap](#tap) - [toArray](#toarray) - [tuple](#tuple) - [tupled](#tupled) @@ -135,6 +136,23 @@ Added in v1.0.0 --- +# combinators + +## tap + +Applies the provided function `f` to the value of the `Option` if it is `Some` and returns the original `Option` +unless `f` returns `None`, in which case it returns `None`. + +This function is useful for performing additional computations on the value of the input `Option` without affecting its value. + +**Signature** + +```ts +export declare const tap: (f: (a: A) => Option<_>) => (self: Option) => Option +``` + +Added in v1.0.0 + # combining ## getFirstNoneMonoid @@ -181,6 +199,8 @@ Added in v1.0.0 ## none +Creates a new `Option` that represents a absence of value. + **Signature** ```ts @@ -201,6 +221,8 @@ Added in v1.0.0 ## some +Creates a new `Option` that wraps the given value. + **Signature** ```ts @@ -268,7 +290,7 @@ Added in v1.0.0 ## getOrNull -Extracts the value out of the structure, if it exists. Otherwise returns `null`. +Returns the value of the option if it is a `Some`, otherwise returns `null`. **Signature** @@ -290,7 +312,7 @@ Added in v1.0.0 ## getOrUndefined -Extracts the value out of the structure, if it exists. Otherwise returns `undefined`. +Returns the value of the option if it is a `Some`, otherwise returns `undefined`. **Signature** @@ -337,6 +359,8 @@ Added in v1.0.0 ## inspectNone +Useful for debugging purposes, the `onNone` callback is is called if `self` is a `None`. + **Signature** ```ts @@ -347,6 +371,8 @@ Added in v1.0.0 ## inspectSome +Useful for debugging purposes, the `onSome` callback is called with the value of `self` if it is a `Some`. + **Signature** ```ts @@ -434,6 +460,8 @@ Added in v1.0.0 ## firstSomeOf +Given an Iterable collection of `Option`s, the function returns the first `Some` option found in the collection. + **Signature** ```ts @@ -444,7 +472,7 @@ Added in v1.0.0 ## getOrElse -Extracts the value out of the structure, if it exists. Otherwise returns the given default value +Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` **Signature** @@ -478,17 +506,7 @@ Added in v1.0.0 ## orElse -Identifies an associative operation on a type constructor. It is similar to `Semigroup`, except that it applies to -types of kind `* -> *`. - -In case of `Option` returns the left-most non-`None` value. - -| x | y | pipe(x, orElse(y) | -| ------- | ------- | ----------------- | -| none | none | none | -| some(a) | none | some(a) | -| none | some(b) | some(b) | -| some(a) | some(b) | some(a) | +Returns the provided option `that` if `self` is `None`, otherwise returns `self`. **Signature** @@ -512,8 +530,9 @@ Added in v1.0.0 ## orElseEither -Returns an effect that will produce the value of this effect, unless it -fails, in which case, it will produce the value of the specified effect. +Similar to `orElse`, but instead of returning a simple union, it returns an `Either` object, +which contains information about which of the two options has been chosen. +This is useful when it's important to know whether the value was retrieved from the first option or the second option. **Signature** @@ -608,8 +627,7 @@ Added in v1.0.0 ## isOption -Returns `true` if the specified value is an instance of `Option`, `false` -otherwise. +Checks if the specified value is an instance of `Option`, returns `true` if it is, `false` otherwise. **Signature** @@ -876,6 +894,8 @@ Added in v1.0.0 ## getOrThrow +Returns the contained value if the option is `Some`, otherwise throws an error. + **Signature** ```ts @@ -1065,14 +1085,14 @@ Added in v1.0.0 **Signature** ```ts -export declare const imap: any +export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (self: Option) => Option ``` Added in v1.0.0 ## map -Returns an effect whose success is mapped by the specified `f` function. +Maps the given function to the value of the `Option` if it is a `Some`, otherwise it returns `None`. **Signature** @@ -1123,8 +1143,8 @@ Added in v1.0.0 ## match -Takes a (lazy) default value, a function, and an `Option` value, if the `Option` value is `None` the default value is -returned, otherwise the function is applied to the value inside the `Some` and the result is returned. +Matches the given `Option` and returns either the provided `onNone` value or the result of the provided `onSome` +function when passed the `Option`'s value. **Signature** @@ -1167,8 +1187,9 @@ Added in v1.0.0 ## andThenDiscard -Sequences the specified effect after this effect, but ignores the value -produced by the effect. +Sequences the specified `that` option but ignores its value. + +It is useful when we want to chain multiple operations, but only care about the result of `self`. **Signature** @@ -1465,18 +1486,6 @@ export declare const struct: >>( Added in v1.0.0 -## tap - -Returns an effect that effectfully "peeks" at the success of this effect. - -**Signature** - -```ts -export declare const tap: (f: (a: A) => Option<_>) => (self: Option) => Option -``` - -Added in v1.0.0 - ## toArray **Signature** diff --git a/src/Number.ts b/src/Number.ts index 779a81ee5..dba436fbc 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -20,33 +20,69 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" export const isNumber = predicate.isNumber /** + * @example + * import { sum } from '@fp-ts/core/Number' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.deepStrictEqual(pipe(2, sum(3)), 5) + * * @since 1.0.0 */ export const sum = (that: number) => (self: number): number => semigroup.numberSum.combine(self, that) /** + * @example + * import { multiply } from '@fp-ts/core/Number' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.deepStrictEqual(pipe(2, multiply(3)), 6) + * * @since 1.0.0 */ export const multiply = (that: number) => (self: number): number => semigroup.numberMultiply.combine(self, that) /** + * @example + * import { subtract } from '@fp-ts/core/Number' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.deepStrictEqual(pipe(2, subtract(3)), -1) + * * @since 1.0.0 */ export const subtract = (that: number) => (self: number): number => self - that /** + * @example + * import { divide } from '@fp-ts/core/Number' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.deepStrictEqual(pipe(6, divide(3)), 2) + * * @since 1.0.0 */ export const divide = (that: number) => (self: number): number => self / that /** + * @example + * import { increment } from '@fp-ts/core/Number' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.deepStrictEqual(pipe(2, increment), 3) + * * @since 1.0.0 */ export const increment = (n: number): number => n + 1 /** + * @example + * import { decrement } from '@fp-ts/core/Number' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.deepStrictEqual(pipe(3, decrement), 2) + * * @since 1.0.0 */ export const decrement = (n: number): number => n - 1 diff --git a/src/Option.ts b/src/Option.ts index bddf2557a..1efed6f5e 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -74,20 +74,23 @@ export interface OptionTypeLambda extends TypeLambda { } /** + * Creates a new `Option` that represents a absence of value. + * * @category constructors * @since 1.0.0 */ export const none = (): Option => option.none /** + * Creates a new `Option` that wraps the given value. + * * @category constructors * @since 1.0.0 */ export const some: (a: A) => Option = option.some /** - * Returns `true` if the specified value is an instance of `Option`, `false` - * otherwise. + * Checks if the specified value is an instance of `Option`, returns `true` if it is, `false` otherwise. * * @example * import { some, none, isOption } from '@fp-ts/core/Option' @@ -164,6 +167,12 @@ export const liftThrowable = , B>( ): ((...a: A) => Option) => (...a) => fromThrowable(() => f(...a)) /** + * Returns the contained value if the option is `Some`, otherwise throws an error. + * + * @param onError - A function that returns the error to be thrown when the option is `None` + * @param self - The option to extract the value from + * @throws The error returned by `onError` if the option is `None` + * * @category interop * @since 1.0.0 */ @@ -176,7 +185,10 @@ export const getOrThrow = (onError: LazyArg) => } /** - * Returns an effect whose success is mapped by the specified `f` function. + * Maps the given function to the value of the `Option` if it is a `Some`, otherwise it returns `None`. + * + * @param f - The function to map over the value of the `Option` + * @param self - An option to map * * @category mapping * @since 1.0.0 @@ -188,7 +200,10 @@ export const map = (f: (a: A) => B) => * @category mapping * @since 1.0.0 */ -export const imap = covariant.imap(map) +export const imap: ( + to: (a: A) => B, + from: (b: B) => A +) => (self: Option) => Option = covariant.imap(map) /** * @category instances @@ -347,8 +362,29 @@ export const bind: ( .bind(Chainable) /** - * Returns an effect that effectfully "peeks" at the success of this effect. + * Sequences the specified `that` option but ignores its value. + * + * It is useful when we want to chain multiple operations, but only care about the result of `self`. + * + * @param that - The option that will be ignored in the chain and discarded + * @param self - The option we care about + * + * @category sequencing + * @since 1.0.0 + */ +export const andThenDiscard: <_>(that: Option<_>) => (self: Option) => Option = chainable + .andThenDiscard(Chainable) + +/** + * Applies the provided function `f` to the value of the `Option` if it is `Some` and returns the original `Option` + * unless `f` returns `None`, in which case it returns `None`. + * + * This function is useful for performing additional computations on the value of the input `Option` without affecting its value. * + * @param f - Function to apply to the value of the `Option` if it is `Some` + * @param self - The `Option` to apply the function to + * + * @category combinators * @since 1.0.0 */ export const tap: (f: (a: A) => Option<_>) => (self: Option) => Option = chainable.tap( @@ -356,6 +392,11 @@ export const tap: (f: (a: A) => Option<_>) => (self: Option) => Option< ) /** + * Useful for debugging purposes, the `onSome` callback is called with the value of `self` if it is a `Some`. + * + * @param onSome - callback function that is called with the value of `self` if it is a `Some` + * @param self - the `Option` to inspect + * * @category debugging * @since 1.0.0 */ @@ -370,6 +411,11 @@ export const inspectSome = ( } /** + * Useful for debugging purposes, the `onNone` callback is is called if `self` is a `None`. + * + * @param onNone - callback function that is is called if `self` is a `None` + * @param self - the `Option` to inspect + * * @category debugging * @since 1.0.0 */ @@ -383,16 +429,6 @@ export const inspectNone = ( return self } -/** - * Sequences the specified effect after this effect, but ignores the value - * produced by the effect. - * - * @category sequencing - * @since 1.0.0 - */ -export const andThenDiscard: <_>(that: Option<_>) => (self: Option) => Option = chainable - .andThenDiscard(Chainable) - /** * @category instances * @since 1.0.0 @@ -612,6 +648,10 @@ export const getFirstNoneMonoid: (M: Monoid) => Monoid> = applic ) /** + * Given an Iterable collection of `Option`s, the function returns the first `Some` option found in the collection. + * + * @param collection - An iterable collection of `Option` to be searched + * * @category error handling * @since 1.0.0 */ @@ -854,8 +894,12 @@ export const toEither: (onNone: LazyArg) => (self: Option) => Either either.fromOption /** - * Takes a (lazy) default value, a function, and an `Option` value, if the `Option` value is `None` the default value is - * returned, otherwise the function is applied to the value inside the `Some` and the result is returned. + * Matches the given `Option` and returns either the provided `onNone` value or the result of the provided `onSome` + * function when passed the `Option`'s value. + * + * @param onNone - The value to be returned if the `Option` is `None` + * @param onSome - The function to be called if the `Option` is `Some`, it will be passed the `Option`'s value and its result will be returned + * @param self - The `Option` to match * * @example * import { some, none, match } from '@fp-ts/core/Option' @@ -884,8 +928,11 @@ export const match = (onNone: LazyArg, onSome: (a: A) => C) => (self: Option): B | C => isNone(self) ? onNone() : onSome(self.value) /** - * Extracts the value out of the structure, if it exists. Otherwise returns the given default value + * Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` * + * @param onNone - Function that returns the default value to return if the `Option` is `None` + * @param self - The `Option` to get the value of + * * * @example * import { some, none, getOrElse } from '@fp-ts/core/Option' * import { pipe } from '@fp-ts/core/Function' @@ -971,7 +1018,9 @@ export const flatMapNullable = (f: (a: A) => B | null | undefined) => isNone(self) ? option.none : fromNullable(f(self.value)) /** - * Extracts the value out of the structure, if it exists. Otherwise returns `null`. + * Returns the value of the option if it is a `Some`, otherwise returns `null`. + * + * @param self - The option to extract the value from * * @example * import { some, none, getOrNull } from '@fp-ts/core/Option' @@ -986,7 +1035,9 @@ export const flatMapNullable = (f: (a: A) => B | null | undefined) => export const getOrNull: (self: Option) => A | null = getOrElse(constNull) /** - * Extracts the value out of the structure, if it exists. Otherwise returns `undefined`. + * Returns the value of the option if it is a `Some`, otherwise returns `undefined`. + * + * @param self - The option to extract the value from * * @example * import { some, none, getOrUndefined } from '@fp-ts/core/Option' @@ -1010,17 +1061,10 @@ export const catchAll = (that: LazyArg>) => (self: Option): Option => isNone(self) ? that() : self /** - * Identifies an associative operation on a type constructor. It is similar to `Semigroup`, except that it applies to - * types of kind `* -> *`. + * Returns the provided option `that` if `self` is `None`, otherwise returns `self`. * - * In case of `Option` returns the left-most non-`None` value. - * - * | x | y | pipe(x, orElse(y) | - * | ------- | ------- | ------------------| - * | none | none | none | - * | some(a) | none | some(a) | - * | none | some(b) | some(b) | - * | some(a) | some(b) | some(a) | + * @param that - The option to return if `self` option is `None` + * @param self - The first option to be checked * * @example * import * as O from '@fp-ts/core/Option' @@ -1062,8 +1106,12 @@ export const orElse = (that: Option): ((self: Option) => Option that) /** - * Returns an effect that will produce the value of this effect, unless it - * fails, in which case, it will produce the value of the specified effect. + * Similar to `orElse`, but instead of returning a simple union, it returns an `Either` object, + * which contains information about which of the two options has been chosen. + * This is useful when it's important to know whether the value was retrieved from the first option or the second option. + * + * @param that - The second option to be considered if the first option is `None` + * @param self - The first option to be checked * * @category error handling * @since 1.0.0 diff --git a/data.md b/ts-types.md similarity index 97% rename from data.md rename to ts-types.md index ca819e536..54ac931f6 100644 --- a/data.md +++ b/ts-types.md @@ -1,76 +1,4 @@ -# Data overview - -## tuples - -This section covers the various modules and combinators that work with tuples. - -| Module | Name | Given | To | -| ----------- | --------------- | --------------------------------------- | -------------------------------------- | -| Equivalence | tuple | `[Equivalence, Equivalence, ...]` | `Equivalence` | -| Order | tuple | `[Order, Order, ...]` | `Order` | -| Semigroup | tuple | `[Semigroup, Semigroup, ...]` | `Semigroup<[A, B, ...]>` | -| Monoid | tuple | `[Monoid, Monoid, ...]` | `Monoid<[A, B, ...]>` | -| SemiProduct | nonEmptyTuple | `[F, F, ...]` (cannot be empty) | `F<[A, B, ...]>` | -| Product | tuple | `[F, F, ...]` | `F<[A, B, ...]>` | -| Either | tuple | `[Either, Either, ...]` | `Either` | -| Option | tuple | `[Option, Option, ...]` | `Option<[A, B, ...]>` | -| Predicate | tuple | `[Predicate, Predicate, ...]` | `Predicate` | -| These | tuple | `[These, These, ...]` | `These` | -| Tuple | getEquivalence | `[Equivalence, Equivalence, ...]` | `Equivalence` | -| Tuple | getOrder | `[Order, Order, ...]` | `Order` | -| Tuple | getSemigroup | `[Semigroup, Semigroup, ...]` | `Semigroup<[A, B, ...]>` | -| Tuple | getMonoid | `[Monoid, Monoid, ...]` | `Monoid<[A, B, ...]>` | -| Tuple | nonEmptyProduct | `[F, F, ...]` (cannot be empty) | `F<[A, B, ...]>` | -| Tuple | product | `[F, F, ...]` | `F<[A, B, ...]>` | - -## arrays - -This section covers the various modules and combinators that work with arrays. - -| Module | Name | Given | To | -| ------------- | ------------- | ---------------- | ------------------------------- | -| Equivalence | array | `Equivalence` | `Equivalence>` | -| Order | array | `Order` | `Order>` | -| Semigroup | array | `A` | `Semigroup>` | -| Semigroup | readonlyArray | `A` | `Semigroup>` | -| Monoid | array | `A` | `Monoid>` | -| Monoid | readonlyArray | `A` | `Monoid>` | -| ReadonlyArray | getSemigroup | `A` | `Semigroup>` | -| ReadonlyArray | getMonoid | `A` | `Monoid>` | - -## structs - -This section covers the various modules and combinators that work with structs. - -| Module | Name | Given | To | -| ----------- | --------------- | ----------------------------------------------- | ----------------------------------------- | -| Equivalence | struct | `{ a: Equivalence, b: Equivalence, ... }` | `Equivalence<{ a: A, b: B, ... }>` | -| Order | struct | `{ a: Order, b: Order, ... }` | `Order<{ a: A, b: B, ... }>` | -| Semigroup | struct | `{ a: Semigroup, b: Semigroup, ... }` | `Semigroup<{ a: A, b: B, ... }>` | -| Monoid | struct | `{ a: Monoid, b: Monoid, ... }` | `Monoid<{ a: A, b: B, ... }>` | -| SemiProduct | nonEmptyStruct | `{ a: F, b: F, ... }` (cannot be empty) | `F<{ a: A, b: B, ... }>` | -| Product | struct | `{ a: F, b: F, ... }` | `F<{ a: A, b: B, ... }>` | -| Either | struct | `{ a: Either, b: Either, ... }` | `Either` | -| Option | struct | `{ a: Option, b: Option, ... }` | `Option<{ a: A, b: B }>` | -| Predicate | struct | `{ a: Predicate, b: Predicate, ... }` | `Predicate>` | -| These | struct | `{ a: These, b: These, ... }` | `These` | -| Struct | getEquivalence | `{ a: Equivalence, b: Equivalence, ... }` | `Equivalence<{ a: A, b: B, ... }>` | -| Struct | getOrder | `{ a: Order, b: Order, ... }` | `Order<{ a: A, b: B, ... }>` | -| Struct | getSemigroup | `{ a: Semigroup, b: Semigroup, ... }` | `Semigroup<{ a: A, b: B, ... }>` | -| Struct | getMonoid | `{ a: Monoid, b: Monoid, ... }` | `Monoid<{ a: A, b: B, ... }>` | -| Struct | nonEmptyProduct | `{ a: F, b: F, ... }` (cannot be empty) | `F<{ a: A, b: B, ... }>` | -| Struct | product | `{ a: F, b: F, ... }` | `F<{ a: A, b: B, ... }>` | - -## records - -This section covers the various modules and combinators that work with records. - -| Module | Name | Given | To | -| -------------- | ------------- | -------------------------------------------- | -------------------------------- | -| Equivalence | record | `Equivalence` | `Equivalence>` | -| ReadonlyRecord | get | `key: string`, `ReadonlyRecord` | `Option` | -| ReadonlyRecord | replaceOption | `key: string`, `B`, `ReadonlyRecord` | `Option>` | -| ReadonlyRecord | modifyOption | `key: string`, `A => B`, `ReadonlyRecord` | `Option>` | +# Standard TypeScript types ## strings @@ -132,21 +60,6 @@ This section covers the various modules and combinators that work with records. ## bigints -| Module | Name | Given | To | -| ----------- | ------ | ----- | --------------------- | -| Equivalence | bigint | | `Equivalence` | -| Order | bigint | | `Order` | - -## symbols - -| Module | Name | Given | To | -| ----------- | -------- | ----- | ----------------------------- | -| Equivalence | symbol | | `Equivalence` | -| Predicate | isSymbol | | `Refinement` | -| Symbol | isSymbol | | `Refinement` | - -## bigints - | Module | Name | Given | To | | ----------- | ----------------- | ----- | ----------------------------- | | Equivalence | bigint | | `Equivalence` | @@ -163,3 +76,83 @@ This section covers the various modules and combinators that work with records. | Bigint | MonoidSum | | `Monoid` | | Bigint | MonoidMultiply | | `Monoid` | | Bigint | isBigint | | `Refinement` | + +## symbols + +| Module | Name | Given | To | +| ----------- | -------- | ----- | ----------------------------- | +| Equivalence | symbol | | `Equivalence` | +| Predicate | isSymbol | | `Refinement` | +| Symbol | isSymbol | | `Refinement` | + +## tuples + +This section covers the various modules and combinators that work with tuples. + +| Module | Name | Given | To | +| ----------- | --------------- | --------------------------------------- | -------------------------------------- | +| Equivalence | tuple | `[Equivalence, Equivalence, ...]` | `Equivalence` | +| Order | tuple | `[Order, Order, ...]` | `Order` | +| Semigroup | tuple | `[Semigroup, Semigroup, ...]` | `Semigroup<[A, B, ...]>` | +| Monoid | tuple | `[Monoid, Monoid, ...]` | `Monoid<[A, B, ...]>` | +| SemiProduct | nonEmptyTuple | `[F, F, ...]` (cannot be empty) | `F<[A, B, ...]>` | +| Product | tuple | `[F, F, ...]` | `F<[A, B, ...]>` | +| Either | tuple | `[Either, Either, ...]` | `Either` | +| Option | tuple | `[Option, Option, ...]` | `Option<[A, B, ...]>` | +| Predicate | tuple | `[Predicate, Predicate, ...]` | `Predicate` | +| These | tuple | `[These, These, ...]` | `These` | +| Tuple | getEquivalence | `[Equivalence, Equivalence, ...]` | `Equivalence` | +| Tuple | getOrder | `[Order, Order, ...]` | `Order` | +| Tuple | getSemigroup | `[Semigroup, Semigroup, ...]` | `Semigroup<[A, B, ...]>` | +| Tuple | getMonoid | `[Monoid, Monoid, ...]` | `Monoid<[A, B, ...]>` | +| Tuple | nonEmptyProduct | `[F, F, ...]` (cannot be empty) | `F<[A, B, ...]>` | +| Tuple | product | `[F, F, ...]` | `F<[A, B, ...]>` | + +## arrays + +This section covers the various modules and combinators that work with arrays. + +| Module | Name | Given | To | +| ------------- | ------------- | ---------------- | ------------------------------- | +| Equivalence | array | `Equivalence` | `Equivalence>` | +| Order | array | `Order` | `Order>` | +| Semigroup | array | `A` | `Semigroup>` | +| Semigroup | readonlyArray | `A` | `Semigroup>` | +| Monoid | array | `A` | `Monoid>` | +| Monoid | readonlyArray | `A` | `Monoid>` | +| ReadonlyArray | getSemigroup | `A` | `Semigroup>` | +| ReadonlyArray | getMonoid | `A` | `Monoid>` | + +## structs + +This section covers the various modules and combinators that work with structs. + +| Module | Name | Given | To | +| ----------- | --------------- | ----------------------------------------------- | ----------------------------------------- | +| Equivalence | struct | `{ a: Equivalence, b: Equivalence, ... }` | `Equivalence<{ a: A, b: B, ... }>` | +| Order | struct | `{ a: Order, b: Order, ... }` | `Order<{ a: A, b: B, ... }>` | +| Semigroup | struct | `{ a: Semigroup, b: Semigroup, ... }` | `Semigroup<{ a: A, b: B, ... }>` | +| Monoid | struct | `{ a: Monoid, b: Monoid, ... }` | `Monoid<{ a: A, b: B, ... }>` | +| SemiProduct | nonEmptyStruct | `{ a: F, b: F, ... }` (cannot be empty) | `F<{ a: A, b: B, ... }>` | +| Product | struct | `{ a: F, b: F, ... }` | `F<{ a: A, b: B, ... }>` | +| Either | struct | `{ a: Either, b: Either, ... }` | `Either` | +| Option | struct | `{ a: Option, b: Option, ... }` | `Option<{ a: A, b: B }>` | +| Predicate | struct | `{ a: Predicate, b: Predicate, ... }` | `Predicate>` | +| These | struct | `{ a: These, b: These, ... }` | `These` | +| Struct | getEquivalence | `{ a: Equivalence, b: Equivalence, ... }` | `Equivalence<{ a: A, b: B, ... }>` | +| Struct | getOrder | `{ a: Order, b: Order, ... }` | `Order<{ a: A, b: B, ... }>` | +| Struct | getSemigroup | `{ a: Semigroup, b: Semigroup, ... }` | `Semigroup<{ a: A, b: B, ... }>` | +| Struct | getMonoid | `{ a: Monoid, b: Monoid, ... }` | `Monoid<{ a: A, b: B, ... }>` | +| Struct | nonEmptyProduct | `{ a: F, b: F, ... }` (cannot be empty) | `F<{ a: A, b: B, ... }>` | +| Struct | product | `{ a: F, b: F, ... }` | `F<{ a: A, b: B, ... }>` | + +## records + +This section covers the various modules and combinators that work with records. + +| Module | Name | Given | To | +| -------------- | ------------- | -------------------------------------------- | -------------------------------- | +| Equivalence | record | `Equivalence` | `Equivalence>` | +| ReadonlyRecord | get | `key: string`, `ReadonlyRecord` | `Option` | +| ReadonlyRecord | replaceOption | `key: string`, `B`, `ReadonlyRecord` | `Option>` | +| ReadonlyRecord | modifyOption | `key: string`, `A => B`, `ReadonlyRecord` | `Option>` | From ca58e0b296440ca4ce1fb153b832de742fd5ff6d Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 26 Jan 2023 16:36:42 +0100 Subject: [PATCH 096/255] SemiApplicative: add lift2Curried, map2 --- src/Either.ts | 69 ++++++++++++++++++++++--- src/Identity.ts | 12 ----- src/Number.ts | 10 ++++ src/Option.ts | 84 ++++++++++++++++++++----------- src/ReadonlyArray.ts | 11 ---- src/These.ts | 14 ------ src/typeclass/SemiApplicative.ts | 58 ++++++++++----------- test/Either.ts | 48 +++++++++++++++++- test/Identity.ts | 1 - test/Number.ts | 2 + test/Option.ts | 42 +++++++++++++++- test/ReadonlyArray.ts | 1 - test/These.ts | 1 - test/typeclass/SemiApplicative.ts | 9 ---- 14 files changed, 245 insertions(+), 117 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 7a94c810f..fe60472ed 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -16,6 +16,7 @@ import { constNull, constUndefined, identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" +import * as N from "@fp-ts/core/Number" import type { Option } from "@fp-ts/core/Option" import type { Predicate, Refinement } from "@fp-ts/core/Predicate" import * as applicative from "@fp-ts/core/typeclass/Applicative" @@ -35,6 +36,7 @@ import type * as semiAlternative from "@fp-ts/core/typeclass/SemiAlternative" import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" @@ -484,6 +486,8 @@ export const getFirstLeftSemigroup: (S: Semigroup) => Semigroup( ) => (fa: Either, fb: Either) => Either = semiApplicative .lift2(SemiApplicative) +/** + * Lifts a binary function into `Either` as curried binary function. + * + * @category lifting + * @since 1.0.0 + */ +export const lift2Curried: ( + f: (a: A, b: B) => C +) => (that: Either) => (self: Either) => Either = semiApplicative + .lift2Curried(SemiApplicative) + /** * @category lifting * @since 1.0.0 */ -export const lift3: ( - f: (a: A, b: B, c: C) => D -) => ( - fa: Either, +export const map2: ( fb: Either, - fc: Either -) => Either = semiApplicative.lift3( - SemiApplicative -) + f: (a: A, b: B) => C +) => (fa: Either) => Either = semiApplicative.map2(SemiApplicative) /** * @since 1.0.0 @@ -1126,3 +1136,46 @@ export const contains = (equivalence: Equivalence) => */ export const exists = (predicate: Predicate) => (self: Either): boolean => isLeft(self) ? false : predicate(self.right) + +/** + * @since 1.0.0 + */ +export const sum = lift2Curried(N.SemigroupSum.combine) + +/** + * @since 1.0.0 + */ +export const multiply = lift2Curried(N.SemigroupMultiply.combine) + +/** + * @since 1.0.0 + */ +export const subtract = lift2Curried((a: number, b: number) => a - b) + +/** + * @since 1.0.0 + */ +export const divide = lift2Curried((a: number, b: number) => a / b) + +/** + * Semigroup returning the left-most non-`Left` value. If both operands are `Right`s then the inner values are + * concatenated using the provided `Semigroup` + * + * @category instances + * @since 2.0.0 + */ +export const getSemigroup = (S: Semigroup): Semigroup> => + semigroup.fromCombine(( + x, + y + ) => (isLeft(y) ? x : isLeft(x) ? y : right(S.combine(x.right, y.right)))) + +/** + * @since 1.0.0 + */ +export const sumMany = getSemigroup(N.SemigroupSum).combineMany + +/** + * @since 1.0.0 + */ +export const multiplyMany = getSemigroup(N.SemigroupMultiply).combineMany diff --git a/src/Identity.ts b/src/Identity.ts index e694c6248..f27316e75 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -348,18 +348,6 @@ export const lift2: ( SemiApplicative ) -/** - * Lifts a ternary function into `Identity`. - * - * @category lifting - * @since 1.0.0 - */ -export const lift3: ( - f: (a: A, b: B, c: C) => D -) => (fa: Identity, fb: Identity, fc: Identity) => Identity = semiApplicative.lift3( - SemiApplicative -) - /** * @since 1.0.0 */ diff --git a/src/Number.ts b/src/Number.ts index dba436fbc..12c58ceac 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -182,6 +182,16 @@ export const MonoidMin = bounded.min(Bounded) */ export const sign = (n: number): Ordering => n < 0 ? -1 : n > 0 ? 1 : 0 +/** + * @since 1.0.0 + */ +export const sumAll: (collection: Iterable) => number = MonoidSum.combineAll + +/** + * @since 1.0.0 + */ +export const multiplyAll: (collection: Iterable) => number = MonoidMultiply.combineAll + /* Missing: diff --git a/src/Option.ts b/src/Option.ts index 1efed6f5e..d48591c18 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -16,6 +16,7 @@ import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" +import * as N from "@fp-ts/core/Number" import type { Predicate, Refinement } from "@fp-ts/core/Predicate" import type * as alternative from "@fp-ts/core/typeclass/Alternative" import * as applicative from "@fp-ts/core/typeclass/Applicative" @@ -30,6 +31,7 @@ import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" +import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as of_ from "@fp-ts/core/typeclass/Of" import type { Order } from "@fp-ts/core/typeclass/Order" import * as order from "@fp-ts/core/typeclass/Order" @@ -39,6 +41,7 @@ import type * as semiAlternative from "@fp-ts/core/typeclass/SemiAlternative" import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" @@ -562,31 +565,16 @@ export const SemiApplicative: semiApplicative.SemiApplicative */ export const getMonoid = ( Semigroup: Semigroup -): Monoid> => { - const combine = (self: Option, that: Option): Option => - isNone(self) ? that : isNone(that) ? self : some(Semigroup.combine(self.value, that.value)) - return ({ - combine, - combineMany: (self, collection) => { - let c = self - for (const o of collection) { - c = combine(c, o) - } - return c - }, - combineAll: (collection: Iterable>): Option => { - let c: Option = option.none - for (const o of collection) { - c = combine(c, o) - } - return c - }, - empty: option.none - }) -} +): Monoid> => + monoid.fromSemigroup( + semigroup.fromCombine((self, that) => + isNone(self) ? that : isNone(that) ? self : some(Semigroup.combine(self.value, that.value)) + ), + option.none + ) /** - * Lifts a binary function into `Option`. + * Lifts a binary function into `Option` as uncurried binary function. * * @category lifting * @since 1.0.0 @@ -595,16 +583,22 @@ export const lift2: (f: (a: A, b: B) => C) => (fa: Option, fb: Optio semiApplicative.lift2(SemiApplicative) /** - * Lifts a ternary function into `Option`. + * Lifts a binary function into `Option` as curried binary function. * * @category lifting * @since 1.0.0 */ -export const lift3: ( - f: (a: A, b: B, c: C) => D -) => (fa: Option, fb: Option, fc: Option) => Option = semiApplicative.lift3( - SemiApplicative -) +export const lift2Curried: ( + f: (a: A, b: B) => C +) => (that: Option) => (self: Option) => Option = semiApplicative + .lift2Curried(SemiApplicative) + +/** + * @category lifting + * @since 1.0.0 + */ +export const map2: (fb: Option, f: (a: A, b: B) => C) => (fa: Option) => Option = + semiApplicative.map2(SemiApplicative) /** * @since 1.0.0 @@ -616,7 +610,7 @@ export const ap: ( ) /** - * Semigroup returning the left-most `None` value. If both operands are `Right`s then the inner values + * Semigroup returning the left-most `None` value. If both operands are `Some`s then the inner values * are concatenated using the provided `Semigroup`. * * @category combining @@ -1237,3 +1231,33 @@ export const contains = (equivalence: Equivalence) => */ export const exists = (predicate: Predicate) => (self: Option): boolean => isNone(self) ? false : predicate(self.value) + +/** + * @since 1.0.0 + */ +export const sum = lift2Curried(N.SemigroupSum.combine) + +/** + * @since 1.0.0 + */ +export const multiply = lift2Curried(N.SemigroupMultiply.combine) + +/** + * @since 1.0.0 + */ +export const subtract = lift2Curried((a: number, b: number) => a - b) + +/** + * @since 1.0.0 + */ +export const divide = lift2Curried((a: number, b: number) => a / b) + +/** + * @since 1.0.0 + */ +export const sumAll = getMonoid(N.SemigroupSum).combineAll + +/** + * @since 1.0.0 + */ +export const multiplyAll = getMonoid(N.SemigroupMultiply).combineAll diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 3798937c7..791654ce2 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1762,17 +1762,6 @@ export const lift2: ( SemiApplicative ) as any -/** - * Lifts a ternary function into `ReadonlyArray`. - * - * @category lifting - * @since 1.0.0 - */ -export const lift3: ( - f: (a: A, b: B, c: C) => D -) => (fa: ReadonlyArray, fb: ReadonlyArray, fc: ReadonlyArray) => Array = - semiApplicative.lift3(SemiApplicative) as any - /** * @category lifting * @since 1.0.0 diff --git a/src/These.ts b/src/These.ts index 1479cc6ac..dda9b1dce 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1010,20 +1010,6 @@ export const lift2: ( ) => Validated = semiApplicative .lift2(SemiApplicative) -/** - * @category lifting - * @since 1.0.0 - */ -export const lift3: ( - f: (a: A, b: B, c: C) => D -) => ( - fa: Validated, - fb: Validated, - fc: Validated -) => Validated = semiApplicative.lift3( - SemiApplicative -) - /** * @since 1.0.0 */ diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 48098ba35..641ab436f 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { pipe } from "@fp-ts/core/Function" +import { identity, pipe, SK } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" @@ -28,16 +28,25 @@ export const liftSemigroup = (F: SemiApplicative) => ) }) +/** + * Binary mapping into `F` context. + * + * @since 1.0.0 + */ +export const map2 = (F: SemiApplicative) => + (fb: Kind, f: (a: A, b: B) => C) => + (fa: Kind): Kind => + pipe(F.product(fa, fb), F.map(([a, b]) => f(a, b))) + /** * @since 1.0.0 */ export const ap = (F: SemiApplicative) => ( - fa: Kind - ) => - ( - self: Kind B> - ): Kind => pipe(F.product(self, fa), F.map(([f, a]) => f(a))) + that: Kind + ): ( + self: Kind B> + ) => Kind => map2(F)(that, (f, a) => f(a)) /** * @since 1.0.0 @@ -45,10 +54,9 @@ export const ap = (F: SemiApplicative) => export const andThenDiscard = (F: SemiApplicative) => ( that: Kind - ) => - ( - self: Kind - ): Kind => pipe(F.product(self, that), F.map(([a]) => a)) + ): ( + self: Kind + ) => Kind => map2(F)(that, identity) /** * @since 1.0.0 @@ -56,13 +64,12 @@ export const andThenDiscard = (F: SemiApplicative) => export const andThen = (F: SemiApplicative) => ( that: Kind - ) => - ( - self: Kind - ): Kind => pipe(F.product(self, that), F.map(([_, a]) => a)) + ): ( + self: Kind + ) => Kind => map2(F)(that, SK) /** - * Lifts a binary function into `F`. + * Lifts a binary function into `F` as uncurried binary function. * * @since 1.0.0 */ @@ -71,21 +78,16 @@ export const lift2 = (F: SemiApplicative) => ( fa: Kind, fb: Kind - ): Kind => pipe(F.product(fa, fb), F.map(([a, b]) => f(a, b))) + ): Kind => pipe(fa, map2(F)(fb, (a, b) => f(a, b))) /** - * Lifts a ternary function into 'F'. + * Lifts a binary function into `F` as curried binary function. * * @since 1.0.0 */ -export const lift3 = (F: SemiApplicative) => - (f: (a: A, b: B, c: C) => D) => - ( - fa: Kind, - fb: Kind, - fc: Kind - ): Kind => - pipe( - F.product(F.product(fa, fb), fc), - F.map(([[a, b], c]) => f(a, b, c)) - ) +export const lift2Curried = (F: SemiApplicative) => + (f: (a: A, b: B) => C) => + ( + that: Kind + ): (self: Kind) => Kind => + map2(F)(that, (a, b) => f(a, b)) diff --git a/test/Either.ts b/test/Either.ts index b203afa74..06313efad 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -53,7 +53,7 @@ describe.concurrent("Either", () => { expect(_.SemiApplicative).exist expect(_.getFirstLeftSemigroup).exist // liftSemigroup expect(_.lift2).exist - expect(_.lift3).exist + expect(_.lift2Curried).exist expect(_.ap).exist expect(_.andThenDiscard).exist expect(_.andThen).exist @@ -73,6 +73,8 @@ describe.concurrent("Either", () => { expect(_.traverse).exist expect(_.sequence).exist expect(_.traverseTap).exist + + expect(_.getSemigroup).exist }) it("structural tracking", () => { @@ -485,4 +487,48 @@ describe.concurrent("Either", () => { Util.deepStrictEqual(f("a"), _.right(1)) Util.deepStrictEqual(f(""), _.left(new Error("empty string"))) }) + + it("map2", () => { + expect(pipe(_.left("a"), _.map2(_.right(2), (a, b) => a + b))).toEqual(_.left("a")) + expect(pipe(_.right(1), _.map2(_.left("a"), (a, b) => a + b))).toEqual(_.left("a")) + expect(pipe(_.right(1), _.map2(_.right(2), (a, b) => a + b))).toEqual(_.right(3)) + }) + + it("sum", () => { + expect(pipe(_.left("a"), _.sum(_.right(2)))).toEqual(_.left("a")) + expect(pipe(_.right(1), _.sum(_.left("a")))).toEqual(_.left("a")) + expect(pipe(_.right(2), _.sum(_.right(3)))).toEqual(_.right(5)) + }) + + it("multiply", () => { + expect(pipe(_.left("a"), _.multiply(_.right(2)))).toEqual(_.left("a")) + expect(pipe(_.right(1), _.multiply(_.left("a")))).toEqual(_.left("a")) + expect(pipe(_.right(2), _.multiply(_.right(3)))).toEqual(_.right(6)) + }) + + it("subtract", () => { + expect(pipe(_.left("a"), _.subtract(_.right(2)))).toEqual(_.left("a")) + expect(pipe(_.right(1), _.subtract(_.left("a")))).toEqual(_.left("a")) + expect(pipe(_.right(2), _.subtract(_.right(3)))).toEqual(_.right(-1)) + }) + + it("subtract", () => { + expect(pipe(_.left("a"), _.divide(_.right(2)))).toEqual(_.left("a")) + expect(pipe(_.right(1), _.divide(_.left("a")))).toEqual(_.left("a")) + expect(pipe(_.right(6), _.divide(_.right(3)))).toEqual(_.right(2)) + }) + + it("sumMany", () => { + expect(_.sumMany(_.left("a"), [])).toEqual(_.left("a")) + expect(_.sumMany(_.left("a"), [_.right(2), _.right(3)])).toEqual(_.right(5)) + expect(_.sumMany(_.right(0), [_.right(2), _.right(3)])).toEqual(_.right(5)) + expect(_.sumMany(_.right(0), [_.right(2), _.left("a"), _.right(3)])).toEqual(_.right(5)) + }) + + it("multiplyMany", () => { + expect(_.multiplyMany(_.left("a"), [])).toEqual(_.left("a")) + expect(_.multiplyMany(_.left("a"), [_.right(2), _.right(3)])).toEqual(_.right(6)) + expect(_.multiplyMany(_.right(1), [_.right(2), _.right(3)])).toEqual(_.right(6)) + expect(_.multiplyMany(_.right(1), [_.right(2), _.left("a"), _.right(3)])).toEqual(_.right(6)) + }) }) diff --git a/test/Identity.ts b/test/Identity.ts index 4bde2fe48..14d6ee427 100644 --- a/test/Identity.ts +++ b/test/Identity.ts @@ -48,7 +48,6 @@ describe.concurrent("Identity", () => { expect(_.SemiApplicative).exist expect(_.liftSemigroup).exist expect(_.lift2).exist - expect(_.lift3).exist expect(_.ap).exist expect(_.andThenDiscard).exist expect(_.andThen).exist diff --git a/test/Number.ts b/test/Number.ts index 86890685f..5a3f89c0e 100644 --- a/test/Number.ts +++ b/test/Number.ts @@ -8,6 +8,8 @@ describe.concurrent("Number", () => { expect(Number.SemigroupMin).exists expect(Number.MonoidMax).exists expect(Number.MonoidMin).exists + expect(Number.sumAll).exists + expect(Number.multiplyAll).exists }) it("isNumber", () => { diff --git a/test/Option.ts b/test/Option.ts index dd9fb35cc..8aab0085c 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -51,7 +51,7 @@ describe.concurrent("Option", () => { expect(_.SemiApplicative).exist expect(_.getFirstNoneSemigroup).exist // liftSemigroup expect(_.lift2).exist - expect(_.lift3).exist + expect(_.lift2Curried).exist expect(_.ap).exist expect(_.andThenDiscard).exist expect(_.andThen).exist @@ -563,4 +563,44 @@ describe.concurrent("Option", () => { _.none() ) }) + + it("map2", () => { + expect(pipe(_.none(), _.map2(_.some(2), (a, b) => a + b))).toEqual(_.none()) + expect(pipe(_.some(1), _.map2(_.none(), (a, b) => a + b))).toEqual(_.none()) + expect(pipe(_.some(1), _.map2(_.some(2), (a, b) => a + b))).toEqual(_.some(3)) + }) + + it("sum", () => { + expect(pipe(_.none(), _.sum(_.some(2)))).toEqual(_.none()) + expect(pipe(_.some(1), _.sum(_.none()))).toEqual(_.none()) + expect(pipe(_.some(2), _.sum(_.some(3)))).toEqual(_.some(5)) + }) + + it("multiply", () => { + expect(pipe(_.none(), _.multiply(_.some(2)))).toEqual(_.none()) + expect(pipe(_.some(1), _.multiply(_.none()))).toEqual(_.none()) + expect(pipe(_.some(2), _.multiply(_.some(3)))).toEqual(_.some(6)) + }) + + it("subtract", () => { + expect(pipe(_.none(), _.subtract(_.some(2)))).toEqual(_.none()) + expect(pipe(_.some(1), _.subtract(_.none()))).toEqual(_.none()) + expect(pipe(_.some(2), _.subtract(_.some(3)))).toEqual(_.some(-1)) + }) + + it("subtract", () => { + expect(pipe(_.none(), _.divide(_.some(2)))).toEqual(_.none()) + expect(pipe(_.some(1), _.divide(_.none()))).toEqual(_.none()) + expect(pipe(_.some(6), _.divide(_.some(3)))).toEqual(_.some(2)) + }) + + it("sumAll", () => { + expect(_.sumAll([_.some(2), _.some(3)])).toEqual(_.some(5)) + expect(_.sumAll([_.some(2), _.none(), _.some(3)])).toEqual(_.some(5)) + }) + + it("multiplyAll", () => { + expect(_.multiplyAll([_.some(2), _.some(3)])).toEqual(_.some(6)) + expect(_.multiplyAll([_.some(2), _.none(), _.some(3)])).toEqual(_.some(6)) + }) }) diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index bf717f723..8923daa4b 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -47,7 +47,6 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.SemiApplicative).exist expect(RA.liftSemigroup).exist expect(RA.lift2).exist - expect(RA.lift3).exist expect(RA.ap).exist expect(RA.Applicative).exist diff --git a/test/These.ts b/test/These.ts index 4a7a5a8d0..4fbd87ac7 100644 --- a/test/These.ts +++ b/test/These.ts @@ -55,7 +55,6 @@ describe("These", () => { expect(_.SemiApplicative).exist expect(_.getFirstLeftSemigroup).exist // liftSemigroup expect(_.lift2).exist - expect(_.lift3).exist expect(_.ap).exist expect(_.andThenDiscard).exist expect(_.andThen).exist diff --git a/test/typeclass/SemiApplicative.ts b/test/typeclass/SemiApplicative.ts index a7ca047c9..315eac738 100644 --- a/test/typeclass/SemiApplicative.ts +++ b/test/typeclass/SemiApplicative.ts @@ -48,13 +48,4 @@ describe("SemiApplicative", () => { U.deepStrictEqual(sum(O.none(), O.some(2)), O.none()) U.deepStrictEqual(sum(O.some(1), O.some(2)), O.some(3)) }) - - it("lift3", () => { - const sum = _.lift3(O.SemiApplicative)((a: number, b: number, c: number) => a + b + c) - U.deepStrictEqual(sum(O.none(), O.none(), O.none()), O.none()) - U.deepStrictEqual(sum(O.some(1), O.none(), O.none()), O.none()) - U.deepStrictEqual(sum(O.none(), O.some(2), O.none()), O.none()) - U.deepStrictEqual(sum(O.none(), O.none(), O.some(3)), O.none()) - U.deepStrictEqual(sum(O.some(1), O.some(2), O.some(3)), O.some(6)) - }) }) From 99088b21a5945cb744a380947ee79378f19766f3 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 27 Jan 2023 09:20:36 +0100 Subject: [PATCH 097/255] remove `imap` from exports --- .changeset/smooth-terms-pay.md | 5 +++++ src/Either.ts | 20 +++++--------------- src/Identity.ts | 20 +++++--------------- src/Option.ts | 20 +++++--------------- src/Predicate.ts | 12 ++---------- src/ReadonlyArray.ts | 17 +++++------------ src/These.ts | 17 ++++------------- test/Either.ts | 1 - test/Identity.ts | 1 - test/Option.ts | 1 - test/Predicate.ts | 1 - test/ReadonlyArray.ts | 1 - test/These.ts | 1 - 13 files changed, 31 insertions(+), 86 deletions(-) create mode 100644 .changeset/smooth-terms-pay.md diff --git a/.changeset/smooth-terms-pay.md b/.changeset/smooth-terms-pay.md new file mode 100644 index 000000000..744353228 --- /dev/null +++ b/.changeset/smooth-terms-pay.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +remove `imap` from exports diff --git a/src/Either.ts b/src/Either.ts index fe60472ed..eedd9f5f2 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -133,20 +133,19 @@ export const map = (f: (a: A) => B) => (self: Either): Either => isRight(self) ? right(f(self.right)) : self /** - * @category mapping + * @category instances * @since 1.0.0 */ -export const imap: ( - to: (a: A) => B, - from: (b: B) => A -) => (self: Either) => Either = covariant.imap(map) +export const Covariant: covariant.Covariant = covariant.make( + map +) /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap + imap: Covariant.imap } /** @@ -165,15 +164,6 @@ export const bindTo: ( name: N ) => (self: Either) => Either = invariant.bindTo(Invariant) -/** - * @category instances - * @since 1.0.0 - */ -export const Covariant: covariant.Covariant = { - ...Invariant, - map -} - /** * @category mapping * @since 1.0.0 diff --git a/src/Identity.ts b/src/Identity.ts index f27316e75..44b941d2f 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -51,20 +51,19 @@ export interface IdentityTypeLambdaFix extends TypeLambda { export const map = (f: (a: A) => B) => (self: Identity): Identity => f(self) /** + * @category instances * @since 1.0.0 */ -export const imap: ( - to: (a: A) => B, - from: (b: B) => A -) => (self: Identity) => Identity = covariant - .imap(map) +export const Covariant: covariant.Covariant = covariant.make( + map +) /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap + imap: Covariant.imap } /** @@ -80,15 +79,6 @@ export const bindTo: ( name: N ) => (self: Identity) => Identity<{ [K in N]: A }> = invariant.bindTo(Invariant) -/** - * @category instances - * @since 1.0.0 - */ -export const Covariant: covariant.Covariant = { - ...Invariant, - map -} - const let_: ( name: Exclude, f: (a: A) => B diff --git a/src/Option.ts b/src/Option.ts index d48591c18..a167fa077 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -200,20 +200,19 @@ export const map = (f: (a: A) => B) => (self: Option): Option => isNone(self) ? option.none : some(f(self.value)) /** - * @category mapping + * @category instances * @since 1.0.0 */ -export const imap: ( - to: (a: A) => B, - from: (b: B) => A -) => (self: Option) => Option = covariant.imap(map) +export const Covariant: covariant.Covariant = covariant.make( + map +) /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap + imap: Covariant.imap } /** @@ -229,15 +228,6 @@ export const bindTo: ( name: N ) => (self: Option) => Option<{ [K in N]: A }> = invariant.bindTo(Invariant) -/** - * @category instances - * @since 1.0.0 - */ -export const Covariant: covariant.Covariant = { - ...Invariant, - map -} - const let_: ( name: Exclude, f: (a: A) => B diff --git a/src/Predicate.ts b/src/Predicate.ts index ee5cb5287..a2b8c8f5f 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -94,20 +94,12 @@ export const Contravariant: contravariant.Contravariant = c contramap ) -/** - * @since 1.0.0 - */ -export const imap: ( - to: (a: A) => B, - from: (b: B) => A -) => (self: Predicate) => Predicate = Contravariant.imap - /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap + imap: Contravariant.imap } /** @@ -174,7 +166,7 @@ const productMany = ( * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - imap, + imap: Invariant.imap, product: (self, that) => ([a, b]) => self(a) && that(b), productMany } diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 791654ce2..3c85f113b 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1267,20 +1267,19 @@ export const Of: of_.Of = { export const Do: ReadonlyArray<{}> = of_.Do(Of) /** - * @category mapping + * @category instances * @since 1.0.0 */ -export const imap: ( - to: (a: A) => B, - from: (b: B) => A -) => (self: ReadonlyArray) => Array = covariant.imap(map) as any +export const Covariant: covariant.Covariant = covariant.make( + map +) /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap + imap: Covariant.imap } /** @@ -1299,12 +1298,6 @@ export const bindTo: ( ) => (self: ReadonlyArray) => Array<{ [K in N]: A }> = invariant .bindTo(Invariant) as any -/** - * @category instances - * @since 1.0.0 - */ -export const Covariant: covariant.Covariant = covariant.make(map) - const let_: ( name: Exclude, f: (a: A) => B diff --git a/src/These.ts b/src/These.ts index dda9b1dce..60ab00b30 100644 --- a/src/These.ts +++ b/src/These.ts @@ -615,21 +615,12 @@ export const map: (f: (a: A) => B) => (self: These) => These = covariant.make(map) -/** - * @category mapping - * @since 1.0.0 - */ -export const imap: ( - to: (a: A) => B, - from: (b: B) => A -) => (self: These) => These = Covariant.imap - /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap + imap: Covariant.imap } /** @@ -984,7 +975,7 @@ const productMany = ( * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - imap, + imap: Invariant.imap, product, productMany } @@ -1212,7 +1203,7 @@ export const composeKleisliArrow: ( * @since 1.0.0 */ export const Chainable: chainable.Chainable = { - imap, + imap: Invariant.imap, map, flatMap } @@ -1281,7 +1272,7 @@ export const tap: ( * @since 1.0.0 */ export const Monad: monad.Monad = { - imap, + imap: Invariant.imap, map, of, flatMap diff --git a/test/Either.ts b/test/Either.ts index 06313efad..5f0d125c9 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -9,7 +9,6 @@ import { number } from "@fp-ts/core/typeclass/Equivalence" describe.concurrent("Either", () => { it("instances and derived exports", () => { expect(_.Invariant).exist - expect(_.imap).exist expect(_.tupled).exist expect(_.bindTo).exist diff --git a/test/Identity.ts b/test/Identity.ts index 14d6ee427..0e8b0be3a 100644 --- a/test/Identity.ts +++ b/test/Identity.ts @@ -7,7 +7,6 @@ import * as U from "./util" describe.concurrent("Identity", () => { it("instances and derived exports", () => { expect(_.Invariant).exist - expect(_.imap).exist expect(_.tupled).exist expect(_.bindTo).exist diff --git a/test/Option.ts b/test/Option.ts index 8aab0085c..486df230c 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -12,7 +12,6 @@ const p = (n: number): boolean => n > 2 describe.concurrent("Option", () => { it("instances and derived exports", () => { expect(_.Invariant).exist - expect(_.imap).exist expect(_.tupled).exist expect(_.bindTo).exist diff --git a/test/Predicate.ts b/test/Predicate.ts index 39c2325d7..eff0e7e70 100644 --- a/test/Predicate.ts +++ b/test/Predicate.ts @@ -19,7 +19,6 @@ const NonEmptyString: _.Refinement = (s): s is NonEmptyS describe.concurrent("Predicate", () => { it("instances and derived exports", () => { expect(_.Invariant).exist - expect(_.imap).exist expect(_.tupled).exist expect(_.bindTo).exist diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 8923daa4b..8f2e3672a 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -13,7 +13,6 @@ import * as fc from "fast-check" describe.concurrent("ReadonlyArray", () => { it("instances and derived exports", () => { expect(RA.Invariant).exist - expect(RA.imap).exist expect(RA.tupled).exist expect(RA.bindTo).exist diff --git a/test/These.ts b/test/These.ts index 4fbd87ac7..8c7178735 100644 --- a/test/These.ts +++ b/test/These.ts @@ -10,7 +10,6 @@ import * as Util from "./util" describe("These", () => { it("instances and derived exports", () => { expect(_.Invariant).exist - expect(_.imap).exist expect(_.tupled).exist expect(_.bindTo).exist From a4a6ebbcf73b453e526fbc42a76424732b8fdb23 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 27 Jan 2023 09:28:32 +0100 Subject: [PATCH 098/255] remove `orElseSucceed` --- .changeset/quiet-zoos-dream.md | 5 +++++ src/Either.ts | 11 ----------- src/Option.ts | 11 ----------- src/These.ts | 11 ----------- test/Either.ts | 5 ----- test/Option.ts | 5 ----- test/These.ts | 6 ------ 7 files changed, 5 insertions(+), 49 deletions(-) create mode 100644 .changeset/quiet-zoos-dream.md diff --git a/.changeset/quiet-zoos-dream.md b/.changeset/quiet-zoos-dream.md new file mode 100644 index 000000000..592b6e381 --- /dev/null +++ b/.changeset/quiet-zoos-dream.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +remove `orElseSucceed` diff --git a/src/Either.ts b/src/Either.ts index eedd9f5f2..837742040 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -664,17 +664,6 @@ export const orElseFail = ( onLeft: LazyArg ): (self: Either) => Either => catchAll(() => left(onLeft())) -/** - * Executes this effect and returns its value, if it succeeds, but otherwise - * succeeds with the specified value. - * - * @category error handling - * @since 1.0.0 - */ -export const orElseSucceed = ( - onLeft: LazyArg -): (self: Either) => Either => catchAll(() => right(onLeft())) - /** * @category instances * @since 1.0.0 diff --git a/src/Option.ts b/src/Option.ts index a167fa077..51986ba8d 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1108,17 +1108,6 @@ export const orElseEither = ( pipe(that, map(either.right)) : pipe, Option>>(self, map(either.left)) -/** - * Executes this effect and returns its value, if it succeeds, but otherwise - * succeeds with the specified value. - * - * @category error handling - * @since 1.0.0 - */ -export const orElseSucceed = ( - onNone: () => B -): (self: Option) => Option => catchAll(() => some(onNone())) - /** * The `Order` instance allows `Option` values to be compared with * `compare`, whenever there is an `Order` instance for diff --git a/src/These.ts b/src/These.ts index 60ab00b30..1141212c0 100644 --- a/src/These.ts +++ b/src/These.ts @@ -831,17 +831,6 @@ export const orElseFail = ( onLeft: LazyArg ): (self: These) => These => catchAll(() => left(onLeft())) -/** - * Executes this effect and returns its value, if it succeeds, but otherwise - * succeeds with the specified value. - * - * @category error handling - * @since 1.0.0 - */ -export const orElseSucceed = ( - onLeft: LazyArg -): (self: These) => These => catchAll(() => right(onLeft())) - /** * @category error handling * @since 1.0.0 diff --git a/test/Either.ts b/test/Either.ts index 5f0d125c9..b2356e308 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -114,11 +114,6 @@ describe.concurrent("Either", () => { Util.deepStrictEqual(pipe(_.left("e1"), _.orElseFail(() => "e2")), _.left("e2")) }) - it("orElseSucceed", () => { - Util.deepStrictEqual(pipe(_.right(1), _.orElseSucceed(() => 2)), _.right(1)) - Util.deepStrictEqual(pipe(_.left("e"), _.orElseSucceed(() => 2)), _.right(2)) - }) - it("reduce", () => { Util.deepStrictEqual(pipe(_.right("bar"), _.Foldable.reduce("foo", (b, a) => b + a)), "foobar") Util.deepStrictEqual(pipe(_.left("bar"), _.Foldable.reduce("foo", (b, a) => b + a)), "foo") diff --git a/test/Option.ts b/test/Option.ts index 486df230c..15ad49ef5 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -150,11 +150,6 @@ describe.concurrent("Option", () => { expect(pipe(_.none(), _.orElseEither(_.none()))).toEqual(_.none()) }) - it("orElseSucceed", () => { - Util.deepStrictEqual(pipe(_.some(1), _.orElseSucceed(() => 2)), _.some(1)) - Util.deepStrictEqual(pipe(_.none(), _.orElseSucceed(() => 2)), _.some(2)) - }) - it("inspectSome", () => { const log: Array = [] pipe( diff --git a/test/These.ts b/test/These.ts index 8c7178735..2ee0c2a62 100644 --- a/test/These.ts +++ b/test/These.ts @@ -750,12 +750,6 @@ describe("These", () => { Util.deepStrictEqual(pipe(_.both("e1", 1), _.orElseFail(() => "e2")), _.both("e1", 1)) }) - it("orElseSucceed", () => { - Util.deepStrictEqual(pipe(_.right(1), _.orElseSucceed(() => 2)), _.right(1)) - Util.deepStrictEqual(pipe(_.left("e"), _.orElseSucceed(() => 2)), _.right(2)) - Util.deepStrictEqual(pipe(_.both("e", 1), _.orElseSucceed(() => 2)), _.both("e", 1)) - }) - it("firstSuccessOf", () => { Util.deepStrictEqual(pipe(_.right(1), _.firstRightOrBothOf([])), _.right(1)) Util.deepStrictEqual(pipe(_.left("e"), _.firstRightOrBothOf([])), _.left("e")) From bfb22498cb9287d40e231b4992937e3313fae1fe Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 27 Jan 2023 09:32:20 +0100 Subject: [PATCH 099/255] Option: remove `compact` --- .changeset/tender-bugs-shave.md | 5 +++++ src/Option.ts | 10 +--------- test/Option.ts | 7 ------- 3 files changed, 6 insertions(+), 16 deletions(-) create mode 100644 .changeset/tender-bugs-shave.md diff --git a/.changeset/tender-bugs-shave.md b/.changeset/tender-bugs-shave.md new file mode 100644 index 000000000..07c647af9 --- /dev/null +++ b/.changeset/tender-bugs-shave.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Option: remove `compact` diff --git a/src/Option.ts b/src/Option.ts index 51986ba8d..8a6c6856a 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -727,20 +727,12 @@ export const Foldable: foldable.Foldable = { */ export const toArray: (self: Option) => Array = foldable.toArray(Foldable) -/** - * Alias of `flatten`. - * - * @category filtering - * @since 1.0.0 - */ -export const compact: (self: Option>) => Option = flatten - /** * @category instances * @since 1.0.0 */ export const Compactable: compactable.Compactable = { - compact + compact: flatten } /** diff --git a/test/Option.ts b/test/Option.ts index 15ad49ef5..33a255ab4 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -76,7 +76,6 @@ describe.concurrent("Option", () => { expect(_.traverseTap).exist expect(_.Compactable).exist - expect(_.compact).exist expect(_.separate).exist expect(_.Filterable).exist @@ -288,12 +287,6 @@ describe.concurrent("Option", () => { assertAlt(_.none(), _.none(), _.none()) }) - it("compact", () => { - Util.deepStrictEqual(_.compact(_.none()), _.none()) - Util.deepStrictEqual(_.compact(_.some(_.none())), _.none()) - Util.deepStrictEqual(_.compact(_.some(_.some("123"))), _.some("123")) - }) - it("filterMap", () => { const f = (n: number) => (p(n) ? _.some(n + 1) : _.none()) Util.deepStrictEqual(pipe(_.none(), _.filterMap(f)), _.none()) From 03e0f6d38608b2e663e3dfd54197af35cbdd7a9a Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 27 Jan 2023 12:41:40 +0100 Subject: [PATCH 100/255] Option: renaming - rename `getFirstNoneSemigroup` to `getFailureSemigroup` - rename `getFirstNoneMonoid` to `getFailureMonoid` - rename `getMonoid` to `getOptionalMonoid` --- .changeset/great-carrots-build.md | 5 ++++ Option.md | 22 +++++++------- src/Option.ts | 49 +++++++++++++++---------------- src/typeclass/SemiApplicative.ts | 4 +-- test/Option.ts | 8 ++--- test/typeclass/Invariant.ts | 2 +- 6 files changed, 47 insertions(+), 43 deletions(-) create mode 100644 .changeset/great-carrots-build.md diff --git a/.changeset/great-carrots-build.md b/.changeset/great-carrots-build.md new file mode 100644 index 000000000..ae4c8b26d --- /dev/null +++ b/.changeset/great-carrots-build.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Option: renaming diff --git a/Option.md b/Option.md index 5cccd956d..f14db0ff5 100644 --- a/Option.md +++ b/Option.md @@ -324,13 +324,15 @@ console.log(output); // Output: Error: Cannot parse 'Not a number' as a number **Cheat sheet** (error handling) -| Name | Given | To | -| ---------------- | --------------------------------------------------- | ---------------------- | -| `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | -| `getOrThrow` | `Option` | `A` | -| `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | -| `getOrNull` | `Option` | `A \| null` | -| `getOrUndefined` | `Option` | `A \| undefined` | -| `orElse` | `Option`, `Option` | `Option` | -| `orElseEither` | `Option`, `Option` | `Option>` | -| `firstSomeOf` | `Option`, `Iterable>` | `Option` | +| Name | Given | To | +| --------------------- | --------------------------------------------------- | ---------------------- | +| `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | +| `getOrThrow` | `Option` | `A` | +| `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | +| `getOrNull` | `Option` | `A \| null` | +| `getOrUndefined` | `Option` | `A \| undefined` | +| `orElse` | `Option`, `Option` | `Option` | +| `orElseEither` | `Option`, `Option` | `Option>` | +| `firstSomeOf` | `Option`, `Iterable>` | `Option` | +| `getFailureSemigroup` | `Semigroup` | `Semigroup>` | +| `getFailureMonoid` | `Monoid` | `Monoid>` | diff --git a/src/Option.ts b/src/Option.ts index 8a6c6856a..0758bdd68 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -529,22 +529,15 @@ export const SemiApplicative: semiApplicative.SemiApplicative } /** - * Monoid returning the left-most non-`None` value. If both operands are `Some`s then the inner values are - * combined using the provided `Semigroup` - * - * | x | y | combine(y)(x) | - * | ------- | ------- | ------------------- | - * | none | none | none | - * | some(a) | none | some(a) | - * | none | some(a) | some(a) | - * | some(a) | some(b) | some(combine(b)(a)) | + * Monoid that models the combination of values that may be absent, elements that are `None` are ignored + * while elements that are `Some` are combined using the provided `Semigroup`. * * @example - * import { getMonoid, some, none } from '@fp-ts/core/Option' + * import { getOptionalMonoid, some, none } from '@fp-ts/core/Option' * import * as N from '@fp-ts/core/Number' * import { pipe } from '@fp-ts/core/Function' * - * const M = getMonoid(N.SemigroupSum) + * const M = getOptionalMonoid(N.SemigroupSum) * assert.deepStrictEqual(M.combine(none(), none()), none()) * assert.deepStrictEqual(M.combine(some(1), none()), some(1)) * assert.deepStrictEqual(M.combine(none(), some(1)), some(1)) @@ -553,7 +546,7 @@ export const SemiApplicative: semiApplicative.SemiApplicative * @category lifting * @since 1.0.0 */ -export const getMonoid = ( +export const getOptionalMonoid = ( Semigroup: Semigroup ): Monoid> => monoid.fromSemigroup( @@ -600,13 +593,16 @@ export const ap: ( ) /** - * Semigroup returning the left-most `None` value. If both operands are `Some`s then the inner values - * are concatenated using the provided `Semigroup`. + * Semigroup that models the combination of computations that can fail, if at least one element is `None` + * then the resulting combination is `None`, otherwise if all elements are `Some` then the resulting combination + * is the combination of the wrapped elements using the provided `Semigroup`. * - * @category combining + * See also `getFailureMonoid` if you need a `Monoid` instead of a `Semigroup`. + * + * @category error handling * @since 1.0.0 */ -export const getFirstNoneSemigroup: (S: Semigroup) => Semigroup> = semiApplicative +export const getFailureSemigroup: (S: Semigroup) => Semigroup> = semiApplicative .liftSemigroup(SemiApplicative) /** @@ -619,15 +615,18 @@ export const Applicative: applicative.Applicative = { } /** - * Monoid returning the left-most `None` value. If both operands are `Right`s then the inner values - * are concatenated using the provided `Monoid`. + * Monoid that models the combination of computations that can fail, if at least one element is `None` + * then the resulting combination is `None`, otherwise if all elements are `Some` then the resulting combination + * is the combination of the wrapped elements using the provided `Monoid`. * * The `empty` value is `some(M.empty)`. * - * @category combining + * See also `getFailureSemigroup` if you need a `Semigroup` instead of a `Monoid`. + * + * @category error handling * @since 1.0.0 */ -export const getFirstNoneMonoid: (M: Monoid) => Monoid> = applicative.liftMonoid( +export const getFailureMonoid: (M: Monoid) => Monoid> = applicative.liftMonoid( Applicative ) @@ -664,15 +663,13 @@ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { } /** - * Semigroup returning the left-most `Some` value. + * Semigroup returning the first `Some` value encountered. * * @category combining * @since 1.0.0 */ export const getFirstSomeSemigroup: () => Semigroup> = semiCoproduct - .getSemigroup( - SemiCoproduct - ) + .getSemigroup(SemiCoproduct) /** * @since 1.0.0 @@ -1226,9 +1223,9 @@ export const divide = lift2Curried((a: number, b: number) => a / b) /** * @since 1.0.0 */ -export const sumAll = getMonoid(N.SemigroupSum).combineAll +export const sumAll = getOptionalMonoid(N.SemigroupSum).combineAll /** * @since 1.0.0 */ -export const multiplyAll = getMonoid(N.SemigroupMultiply).combineAll +export const multiplyAll = getOptionalMonoid(N.SemigroupMultiply).combineAll diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 641ab436f..c97f6479f 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -78,7 +78,7 @@ export const lift2 = (F: SemiApplicative) => ( fa: Kind, fb: Kind - ): Kind => pipe(fa, map2(F)(fb, (a, b) => f(a, b))) + ): Kind => pipe(fa, map2(F)(fb, f)) /** * Lifts a binary function into `F` as curried binary function. @@ -90,4 +90,4 @@ export const lift2Curried = (F: SemiApplicative) => ( that: Kind ): (self: Kind) => Kind => - map2(F)(that, (a, b) => f(a, b)) + map2(F)(that, f) diff --git a/test/Option.ts b/test/Option.ts index 33a255ab4..4bafd76d6 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -48,7 +48,7 @@ describe.concurrent("Option", () => { expect(_.struct).exist expect(_.SemiApplicative).exist - expect(_.getFirstNoneSemigroup).exist // liftSemigroup + expect(_.getFailureSemigroup).exist // liftSemigroup expect(_.lift2).exist expect(_.lift2Curried).exist expect(_.ap).exist @@ -56,7 +56,7 @@ describe.concurrent("Option", () => { expect(_.andThen).exist expect(_.Applicative).exist - expect(_.getFirstNoneMonoid).exist // liftMonoid + expect(_.getFailureMonoid).exist // liftMonoid expect(_.SemiCoproduct).exist expect(_.getFirstSomeSemigroup).exist // getSemigroup @@ -398,8 +398,8 @@ describe.concurrent("Option", () => { ) }) - it("getMonoid", () => { - const M = _.getMonoid(S.Semigroup) + it("getOptionalMonoid", () => { + const M = _.getOptionalMonoid(S.Semigroup) Util.deepStrictEqual(M.combine(_.none(), _.none()), _.none()) Util.deepStrictEqual(M.combine(_.none(), _.some("a")), _.some("a")) Util.deepStrictEqual(M.combine(_.some("a"), _.none()), _.some("a")) diff --git a/test/typeclass/Invariant.ts b/test/typeclass/Invariant.ts index f1572662d..2076dbed4 100644 --- a/test/typeclass/Invariant.ts +++ b/test/typeclass/Invariant.ts @@ -9,7 +9,7 @@ import * as U from "../util" describe("Invariant", () => { it("imapComposition", () => { const imap = _.imapComposition(semigroup.Invariant, O.Invariant) - const S = pipe(O.getMonoid(String.Semigroup), imap(s => [s], ([s]) => s)) + const S = pipe(O.getOptionalMonoid(String.Semigroup), imap(s => [s], ([s]) => s)) U.deepStrictEqual(S.combine(O.none(), O.none()), O.none()) U.deepStrictEqual(S.combine(O.none(), O.some(["b"])), O.some(["b"])) U.deepStrictEqual(S.combine(O.some(["a"]), O.none()), O.some(["a"])) From 4463f4f1649ca2f984d715d0aa22055a3a8d6519 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 27 Jan 2023 12:50:41 +0100 Subject: [PATCH 101/255] Option: change `firstSomeOf` signature --- .changeset/unlucky-berries-boil.md | 5 +++ Option.md | 2 +- src/Option.ts | 53 ++++++++++++++++-------------- test/Option.ts | 23 ++++++++++--- 4 files changed, 53 insertions(+), 30 deletions(-) create mode 100644 .changeset/unlucky-berries-boil.md diff --git a/.changeset/unlucky-berries-boil.md b/.changeset/unlucky-berries-boil.md new file mode 100644 index 000000000..f5fc2674f --- /dev/null +++ b/.changeset/unlucky-berries-boil.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Option: change `firstSomeOf` signature diff --git a/Option.md b/Option.md index f14db0ff5..339a09093 100644 --- a/Option.md +++ b/Option.md @@ -333,6 +333,6 @@ console.log(output); // Output: Error: Cannot parse 'Not a number' as a number | `getOrUndefined` | `Option` | `A \| undefined` | | `orElse` | `Option`, `Option` | `Option` | | `orElseEither` | `Option`, `Option` | `Option>` | -| `firstSomeOf` | `Option`, `Iterable>` | `Option` | +| `firstSomeOf` | `Iterable>` | `Option` | | `getFailureSemigroup` | `Semigroup` | `Semigroup>` | | `getFailureMonoid` | `Monoid` | `Monoid>` | diff --git a/src/Option.ts b/src/Option.ts index 0758bdd68..2b2022462 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -15,7 +15,6 @@ import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" -import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import * as N from "@fp-ts/core/Number" import type { Predicate, Refinement } from "@fp-ts/core/Predicate" import type * as alternative from "@fp-ts/core/typeclass/Alternative" @@ -630,27 +629,18 @@ export const getFailureMonoid: (M: Monoid) => Monoid> = applicat Applicative ) -/** - * Given an Iterable collection of `Option`s, the function returns the first `Some` option found in the collection. - * - * @param collection - An iterable collection of `Option` to be searched - * - * @category error handling - * @since 1.0.0 - */ -export const firstSomeOf = (collection: Iterable>) => - (self: Option): Option => { - let out = self +const coproductMany = (self: Option, collection: Iterable>): Option => { + let out = self + if (isSome(out)) { + return out + } + for (out of collection) { if (isSome(out)) { return out } - for (out of collection) { - if (isSome(out)) { - return out - } - } - return out } + return out +} /** * @category instances @@ -659,7 +649,7 @@ export const firstSomeOf = (collection: Iterable>) => export const SemiCoproduct: semiCoproduct.SemiCoproduct = { ...Invariant, coproduct: (self, that) => isSome(self) ? self : that, - coproductMany: (self, collection) => pipe(self, firstSomeOf(collection)) + coproductMany } /** @@ -678,6 +668,24 @@ export const coproductEither = (that: Option) => (self: Option): Option> => isNone(self) ? pipe(that, map(either.right)) : pipe(self, map(either.left)) +/** + * Given an Iterable collection of `Option`s, the function returns the first `Some` option found in the collection. + * + * @param collection - An iterable collection of `Option` to be searched + * + * @category error handling + * @since 1.0.0 + */ +export const firstSomeOf = (collection: Iterable>): Option => { + let out: Option = none() + for (out of collection) { + if (isSome(out)) { + return out + } + } + return out +} + /** * @category instances * @since 1.0.0 @@ -685,12 +693,7 @@ export const coproductEither = (that: Option) => export const Coproduct: coproduct_.Coproduct = { ...SemiCoproduct, zero: none, - coproductAll: collection => { - const options = readonlyArray.fromIterable(collection) - return options.length > 0 ? - SemiCoproduct.coproductMany(options[0], options.slice(1)) : - option.none - } + coproductAll: firstSomeOf } /** diff --git a/test/Option.ts b/test/Option.ts index 4bafd76d6..0eacc6127 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -122,15 +122,30 @@ describe.concurrent("Option", () => { Util.deepStrictEqual(pipe(_.some(1), _.coproductEither(_.some("a"))), _.some(E.left(1))) }) + it("coproductMany", () => { + const coproductMany = _.SemiCoproduct.coproductMany + Util.deepStrictEqual(coproductMany(_.some(1), []), _.some(1)) + Util.deepStrictEqual(coproductMany(_.none(), []), _.none()) + Util.deepStrictEqual( + coproductMany(_.none(), [_.none(), _.none(), _.none(), _.some(1)]), + _.some(1) + ) + Util.deepStrictEqual( + coproductMany(_.none(), [_.none(), _.none(), _.none()]), + _.none() + ) + }) + it("firstSomeOf", () => { - Util.deepStrictEqual(pipe(_.some(1), _.firstSomeOf([])), _.some(1)) - Util.deepStrictEqual(pipe(_.none(), _.firstSomeOf([])), _.none()) + Util.deepStrictEqual(_.firstSomeOf([]), _.none()) + Util.deepStrictEqual(_.firstSomeOf([_.some(1)]), _.some(1)) + Util.deepStrictEqual(_.firstSomeOf([_.none()]), _.none()) Util.deepStrictEqual( - pipe(_.none(), _.firstSomeOf([_.none(), _.none(), _.none(), _.some(1)])), + _.firstSomeOf([_.none(), _.none(), _.none(), _.none(), _.some(1)]), _.some(1) ) Util.deepStrictEqual( - pipe(_.none(), _.firstSomeOf([_.none(), _.none(), _.none()])), + _.firstSomeOf([_.none(), _.none(), _.none(), _.none()]), _.none() ) }) From 3b96d8df0f5fb933e96401f80f5453b5ad22cc72 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 27 Jan 2023 12:54:49 +0100 Subject: [PATCH 102/255] changeset: use minor instead of patch --- .changeset/great-carrots-build.md | 2 +- .changeset/quiet-zoos-dream.md | 2 +- .changeset/smooth-terms-pay.md | 2 +- .changeset/tender-bugs-shave.md | 2 +- .changeset/unlucky-berries-boil.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.changeset/great-carrots-build.md b/.changeset/great-carrots-build.md index ae4c8b26d..4bdfd9e9f 100644 --- a/.changeset/great-carrots-build.md +++ b/.changeset/great-carrots-build.md @@ -1,5 +1,5 @@ --- -"@fp-ts/core": patch +"@fp-ts/core": minor --- Option: renaming diff --git a/.changeset/quiet-zoos-dream.md b/.changeset/quiet-zoos-dream.md index 592b6e381..f137d0e4f 100644 --- a/.changeset/quiet-zoos-dream.md +++ b/.changeset/quiet-zoos-dream.md @@ -1,5 +1,5 @@ --- -"@fp-ts/core": patch +"@fp-ts/core": minor --- remove `orElseSucceed` diff --git a/.changeset/smooth-terms-pay.md b/.changeset/smooth-terms-pay.md index 744353228..09b523ed8 100644 --- a/.changeset/smooth-terms-pay.md +++ b/.changeset/smooth-terms-pay.md @@ -1,5 +1,5 @@ --- -"@fp-ts/core": patch +"@fp-ts/core": minor --- remove `imap` from exports diff --git a/.changeset/tender-bugs-shave.md b/.changeset/tender-bugs-shave.md index 07c647af9..dca859734 100644 --- a/.changeset/tender-bugs-shave.md +++ b/.changeset/tender-bugs-shave.md @@ -1,5 +1,5 @@ --- -"@fp-ts/core": patch +"@fp-ts/core": minor --- Option: remove `compact` diff --git a/.changeset/unlucky-berries-boil.md b/.changeset/unlucky-berries-boil.md index f5fc2674f..9513485f0 100644 --- a/.changeset/unlucky-berries-boil.md +++ b/.changeset/unlucky-berries-boil.md @@ -1,5 +1,5 @@ --- -"@fp-ts/core": patch +"@fp-ts/core": minor --- Option: change `firstSomeOf` signature From ba42e0a887f56d7a986763b9653e0a517f9a4d85 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 27 Jan 2023 14:15:15 +0100 Subject: [PATCH 103/255] move docs to guides folder --- README.md | 11 +- docs/modules/Either.ts.md | 137 ++++++++--- docs/modules/Identity.ts.md | 24 -- docs/modules/Number.ts.md | 22 ++ docs/modules/Option.ts.md | 228 +++++++++++-------- docs/modules/Predicate.ts.md | 11 - docs/modules/ReadonlyArray.ts.md | 26 --- docs/modules/These.ts.md | 36 --- docs/modules/typeclass/SemiApplicative.ts.md | 29 ++- Either.md => guides/Either.md | 0 FAQ.md => guides/FAQ.md | 0 Option.md => guides/Option.md | 0 ts-types.md => guides/ts-types.md | 0 typeclass.md => guides/typeclass.md | 0 src/Option.ts | 8 - 15 files changed, 286 insertions(+), 246 deletions(-) rename Either.md => guides/Either.md (100%) rename FAQ.md => guides/FAQ.md (100%) rename Option.md => guides/Option.md (100%) rename ts-types.md => guides/ts-types.md (100%) rename typeclass.md => guides/typeclass.md (100%) diff --git a/README.md b/README.md index ac709e059..ddef982b5 100644 --- a/README.md +++ b/README.md @@ -58,11 +58,12 @@ npm install @fp-ts/core # Documentation -- [Typeclass overview](./typeclass.md) -- [Standard TypeScript types](./ts-types.md) (WIP) -- Functional Error handling - - [The `Option` data type](./Option.md) (WIP) - - [The `Either` data type](./Either.md) (WIP) +- Guides (WIP) + - [Typeclass overview](./guides/typeclass.md) + - [Standard TypeScript types](./guides/ts-types.md) + - Functional Error handling + - [The `Option` data type](./guides/Option.md) + - [The `Either` data type](./guides/Either.md) - [API Reference](https://fp-ts.github.io/core/) # License diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 7eb5d8994..0a5fdee91 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -51,7 +51,6 @@ Added in v1.0.0 - [orElse](#orelse) - [orElseEither](#orelseeither) - [orElseFail](#orelsefail) - - [orElseSucceed](#orelsesucceed) - [tapError](#taperror) - [filtering](#filtering) - [compact](#compact) @@ -85,22 +84,23 @@ Added in v1.0.0 - [SemiCoproduct](#semicoproduct) - [SemiProduct](#semiproduct) - [Traversable](#traversable) + - [getSemigroup](#getsemigroup) - [interop](#interop) - [fromThrowable](#fromthrowable) - [getOrThrow](#getorthrow) - [liftThrowable](#liftthrowable) - [lifting](#lifting) - [lift2](#lift2) - - [lift3](#lift3) + - [lift2Curried](#lift2curried) - [liftNullable](#liftnullable) - [liftOption](#liftoption) - [liftPredicate](#liftpredicate) + - [map2](#map2) - [mapping](#mapping) - [as](#as) - [asUnit](#asunit) - [bimap](#bimap) - [flap](#flap) - - [imap](#imap) - [map](#map) - [tupled](#tupled) - [models](#models) @@ -125,11 +125,17 @@ Added in v1.0.0 - [ap](#ap) - [composeKleisliArrow](#composekleisliarrow) - [contains](#contains) + - [divide](#divide) - [element](#element) - [exists](#exists) - [flatten](#flatten) + - [multiply](#multiply) + - [multiplyMany](#multiplymany) - [reverse](#reverse) - [struct](#struct) + - [subtract](#subtract) + - [sum](#sum) + - [sumMany](#summany) - [tap](#tap) - [tuple](#tuple) - [unit](#unit) @@ -486,19 +492,6 @@ export declare const orElseFail: (onLeft: any) => (self: Either(onLeft: any) => (self: Either) => Either -``` - -Added in v1.0.0 - ## tapError Returns an effect that effectfully "peeks" at the failure of this effect. @@ -862,6 +855,19 @@ export declare const Traversable: any Added in v1.0.0 +## getSemigroup + +Semigroup returning the left-most non-`Left` value. If both operands are `Right`s then the inner values are +concatenated using the provided `Semigroup` + +**Signature** + +```ts +export declare const getSemigroup: (S: any) => any +``` + +Added in v2.0.0 + # interop ## fromThrowable @@ -925,6 +931,8 @@ Added in v1.0.0 ## lift2 +Lifts a binary function into `Either` as uncurried binary function. + **Signature** ```ts @@ -935,14 +943,16 @@ export declare const lift2: ( Added in v1.0.0 -## lift3 +## lift2Curried + +Lifts a binary function into `Either` as curried binary function. **Signature** ```ts -export declare const lift3: ( - f: (a: A, b: B, c: C) => D -) => (fa: Either, fb: Either, fc: Either) => Either +export declare const lift2Curried: ( + f: (a: A, b: B) => C +) => (that: Either) => (self: Either) => Either ``` Added in v1.0.0 @@ -1014,6 +1024,19 @@ assert.deepStrictEqual( Added in v1.0.0 +## map2 + +**Signature** + +```ts +export declare const map2: ( + fb: Either, + f: (a: A, b: B) => C +) => (fa: Either) => Either +``` + +Added in v1.0.0 + # mapping ## as @@ -1063,16 +1086,6 @@ export declare const flap: (a: A) => (self: Either B>) => Added in v1.0.0 -## imap - -**Signature** - -```ts -export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (self: Either) => Either -``` - -Added in v1.0.0 - ## map Returns an effect whose Right is mapped by the specified `f` function. @@ -1309,6 +1322,16 @@ export declare const contains: (equivalence: any) => (a: A) => (self: Eith Added in v1.0.0 +## divide + +**Signature** + +```ts +export declare const divide: (that: Either) => (self: Either) => Either +``` + +Added in v1.0.0 + ## element Adds an element to the end of a tuple. @@ -1357,6 +1380,28 @@ export declare const flatten: (self: Either>) => Ei Added in v1.0.0 +## multiply + +**Signature** + +```ts +export declare const multiply: ( + that: Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + +## multiplyMany + +**Signature** + +```ts +export declare const multiplyMany: any +``` + +Added in v1.0.0 + ## reverse **Signature** @@ -1382,6 +1427,38 @@ export declare const struct: >>( Added in v1.0.0 +## subtract + +**Signature** + +```ts +export declare const subtract: ( + that: Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + +## sum + +**Signature** + +```ts +export declare const sum: (that: Either) => (self: Either) => Either +``` + +Added in v1.0.0 + +## sumMany + +**Signature** + +```ts +export declare const sumMany: any +``` + +Added in v1.0.0 + ## tap Returns an effect that effectfully "peeks" at the success of this effect. diff --git a/docs/modules/Identity.ts.md b/docs/modules/Identity.ts.md index bcc1e104f..d4d620028 100644 --- a/docs/modules/Identity.ts.md +++ b/docs/modules/Identity.ts.md @@ -49,7 +49,6 @@ Added in v1.0.0 - [liftSemigroup](#liftsemigroup) - [lifting](#lifting) - [lift2](#lift2) - - [lift3](#lift3) - [mapping](#mapping) - [as](#as) - [asUnit](#asunit) @@ -72,7 +71,6 @@ Added in v1.0.0 - [composeKleisliArrow](#composekleisliarrow) - [element](#element) - [flatten](#flatten) - - [imap](#imap) - [liftMonoid](#liftmonoid) - [map](#map) - [struct](#struct) @@ -422,18 +420,6 @@ export declare const lift2: (f: (a: A, b: B) => C) => (fa: A, fb: B) => Added in v1.0.0 -## lift3 - -Lifts a ternary function into `Identity`. - -**Signature** - -```ts -export declare const lift3: (f: (a: A, b: B, c: C) => D) => (fa: A, fb: B, fc: C) => D -``` - -Added in v1.0.0 - # mapping ## as @@ -619,16 +605,6 @@ export declare const flatten: (self: A) => A Added in v1.0.0 -## imap - -**Signature** - -```ts -export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (self: A) => B -``` - -Added in v1.0.0 - ## liftMonoid **Signature** diff --git a/docs/modules/Number.ts.md b/docs/modules/Number.ts.md index 1ca81f7c3..c5574c1f7 100644 --- a/docs/modules/Number.ts.md +++ b/docs/modules/Number.ts.md @@ -35,9 +35,11 @@ Added in v1.0.0 - [divide](#divide) - [increment](#increment) - [multiply](#multiply) + - [multiplyAll](#multiplyall) - [sign](#sign) - [subtract](#subtract) - [sum](#sum) + - [sumAll](#sumall) --- @@ -273,6 +275,16 @@ assert.deepStrictEqual(pipe(2, multiply(3)), 6) Added in v1.0.0 +## multiplyAll + +**Signature** + +```ts +export declare const multiplyAll: (collection: Iterable) => number +``` + +Added in v1.0.0 + ## sign **Signature** @@ -320,3 +332,13 @@ assert.deepStrictEqual(pipe(2, sum(3)), 5) ``` Added in v1.0.0 + +## sumAll + +**Signature** + +```ts +export declare const sumAll: (collection: Iterable) => number +``` + +Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 9896382ab..9572441a0 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -6,14 +6,6 @@ parent: Modules ## Option overview -The `Option` type can be interpreted in a few ways: - -1. `Option` is a container for an optional value of type `A`. If the value of type `A` is present, the `Option` is - an instance of `Some`, containing the present value of type `A`. If the value is absent, the `Option` is an - instance of `None`. -2. Another way to view `Option` is as a representation of a possibly failing computation. -3. An option can also be thought of as a collection or foldable structure with either one or zero elements. - Added in v1.0.0 --- @@ -23,8 +15,6 @@ Added in v1.0.0 - [combinators](#combinators) - [tap](#tap) - [combining](#combining) - - [getFirstNoneMonoid](#getfirstnonemonoid) - - [getFirstNoneSemigroup](#getfirstnonesemigroup) - [getFirstSomeSemigroup](#getfirstsomesemigroup) - [constructors](#constructors) - [none](#none) @@ -50,12 +40,12 @@ Added in v1.0.0 - [error handling](#error-handling) - [catchAll](#catchall) - [firstSomeOf](#firstsomeof) + - [getFailureMonoid](#getfailuremonoid) + - [getFailureSemigroup](#getfailuresemigroup) - [getOrElse](#getorelse) - [orElse](#orelse) - [orElseEither](#orelseeither) - - [orElseSucceed](#orelsesucceed) - [filtering](#filtering) - - [compact](#compact) - [filter](#filter) - [filterMap](#filtermap) - [separate](#separate) @@ -88,17 +78,17 @@ Added in v1.0.0 - [getOrThrow](#getorthrow) - [liftThrowable](#liftthrowable) - [lifting](#lifting) - - [getMonoid](#getmonoid) + - [getOptionalMonoid](#getoptionalmonoid) - [lift2](#lift2) - - [lift3](#lift3) + - [lift2Curried](#lift2curried) - [liftEither](#lifteither) - [liftNullable](#liftnullable) - [liftPredicate](#liftpredicate) + - [map2](#map2) - [mapping](#mapping) - [as](#as) - [asUnit](#asunit) - [flap](#flap) - - [imap](#imap) - [map](#map) - [models](#models) - [None (interface)](#none-interface) @@ -125,10 +115,16 @@ Added in v1.0.0 - [composeKleisliArrow](#composekleisliarrow) - [contains](#contains) - [coproductEither](#coproducteither) + - [divide](#divide) - [element](#element) - [exists](#exists) - [flatten](#flatten) + - [multiply](#multiply) + - [multiplyAll](#multiplyall) - [struct](#struct) + - [subtract](#subtract) + - [sum](#sum) + - [sumAll](#sumall) - [toArray](#toarray) - [tuple](#tuple) - [tupled](#tupled) @@ -155,37 +151,9 @@ Added in v1.0.0 # combining -## getFirstNoneMonoid - -Monoid returning the left-most `None` value. If both operands are `Right`s then the inner values -are concatenated using the provided `Monoid`. - -The `empty` value is `some(M.empty)`. - -**Signature** - -```ts -export declare const getFirstNoneMonoid: (M: any) => any -``` - -Added in v1.0.0 - -## getFirstNoneSemigroup - -Semigroup returning the left-most `None` value. If both operands are `Right`s then the inner values -are concatenated using the provided `Semigroup`. - -**Signature** - -```ts -export declare const getFirstNoneSemigroup: (S: any) => any -``` - -Added in v1.0.0 - ## getFirstSomeSemigroup -Semigroup returning the left-most `Some` value. +Semigroup returning the first `Some` value encountered. **Signature** @@ -465,7 +433,41 @@ Given an Iterable collection of `Option`s, the function returns the first `Some` **Signature** ```ts -export declare const firstSomeOf: (collection: Iterable>) => (self: Option) => Option +export declare const firstSomeOf: (collection: Iterable>) => Option +``` + +Added in v1.0.0 + +## getFailureMonoid + +Monoid that models the combination of computations that can fail, if at least one element is `None` +then the resulting combination is `None`, otherwise if all elements are `Some` then the resulting combination +is the combination of the wrapped elements using the provided `Monoid`. + +The `empty` value is `some(M.empty)`. + +See also `getFailureSemigroup` if you need a `Semigroup` instead of a `Monoid`. + +**Signature** + +```ts +export declare const getFailureMonoid: (M: any) => any +``` + +Added in v1.0.0 + +## getFailureSemigroup + +Semigroup that models the combination of computations that can fail, if at least one element is `None` +then the resulting combination is `None`, otherwise if all elements are `Some` then the resulting combination +is the combination of the wrapped elements using the provided `Semigroup`. + +See also `getFailureMonoid` if you need a `Monoid` instead of a `Semigroup`. + +**Signature** + +```ts +export declare const getFailureSemigroup: (S: any) => any ``` Added in v1.0.0 @@ -542,33 +544,8 @@ export declare const orElseEither: (that: Option) => (self: Option) Added in v1.0.0 -## orElseSucceed - -Executes this effect and returns its value, if it succeeds, but otherwise -succeeds with the specified value. - -**Signature** - -```ts -export declare const orElseSucceed: (onNone: () => B) => (self: Option) => Option -``` - -Added in v1.0.0 - # filtering -## compact - -Alias of `flatten`. - -**Signature** - -```ts -export declare const compact: (self: Option>) => Option -``` - -Added in v1.0.0 - ## filter **Signature** @@ -918,32 +895,25 @@ Added in v1.0.0 # lifting -## getMonoid +## getOptionalMonoid -Monoid returning the left-most non-`None` value. If both operands are `Some`s then the inner values are -combined using the provided `Semigroup` - -| x | y | combine(y)(x) | -| ------- | ------- | ------------------- | -| none | none | none | -| some(a) | none | some(a) | -| none | some(a) | some(a) | -| some(a) | some(b) | some(combine(b)(a)) | +Monoid that models the combination of values that may be absent, elements that are `None` are ignored +while elements that are `Some` are combined using the provided `Semigroup`. **Signature** ```ts -export declare const getMonoid: (Semigroup: any) => any +export declare const getOptionalMonoid: (Semigroup: any) => any ``` **Example** ```ts -import { getMonoid, some, none } from '@fp-ts/core/Option' +import { getOptionalMonoid, some, none } from '@fp-ts/core/Option' import * as N from '@fp-ts/core/Number' import { pipe } from '@fp-ts/core/Function' -const M = getMonoid(N.SemigroupSum) +const M = getOptionalMonoid(N.SemigroupSum) assert.deepStrictEqual(M.combine(none(), none()), none()) assert.deepStrictEqual(M.combine(some(1), none()), some(1)) assert.deepStrictEqual(M.combine(none(), some(1)), some(1)) @@ -954,7 +924,7 @@ Added in v1.0.0 ## lift2 -Lifts a binary function into `Option`. +Lifts a binary function into `Option` as uncurried binary function. **Signature** @@ -964,16 +934,16 @@ export declare const lift2: (f: (a: A, b: B) => C) => (fa: Option, f Added in v1.0.0 -## lift3 +## lift2Curried -Lifts a ternary function into `Option`. +Lifts a binary function into `Option` as curried binary function. **Signature** ```ts -export declare const lift3: ( - f: (a: A, b: B, c: C) => D -) => (fa: Option, fb: Option, fc: Option) => Option +export declare const lift2Curried: ( + f: (a: A, b: B) => C +) => (that: Option) => (self: Option) => Option ``` Added in v1.0.0 @@ -1044,6 +1014,16 @@ assert.deepStrictEqual(getOption(1), O.some(1)) Added in v1.0.0 +## map2 + +**Signature** + +```ts +export declare const map2: (fb: Option, f: (a: A, b: B) => C) => (fa: Option) => Option +``` + +Added in v1.0.0 + # mapping ## as @@ -1080,16 +1060,6 @@ export declare const flap: (a: A) => (fab: Option<(a: A) => B>) => Option< Added in v1.0.0 -## imap - -**Signature** - -```ts -export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (self: Option) => Option -``` - -Added in v1.0.0 - ## map Maps the given function to the value of the `Option` if it is a `Some`, otherwise it returns `None`. @@ -1411,6 +1381,16 @@ export declare const coproductEither: (that: Option) => (self: Option) => (self: Option) => Option +``` + +Added in v1.0.0 + ## element Adds an element to the end of a tuple. @@ -1474,6 +1454,26 @@ export declare const flatten: (self: Option>) => Option Added in v1.0.0 +## multiply + +**Signature** + +```ts +export declare const multiply: (that: Option) => (self: Option) => Option +``` + +Added in v1.0.0 + +## multiplyAll + +**Signature** + +```ts +export declare const multiplyAll: any +``` + +Added in v1.0.0 + ## struct **Signature** @@ -1486,6 +1486,36 @@ export declare const struct: >>( Added in v1.0.0 +## subtract + +**Signature** + +```ts +export declare const subtract: (that: Option) => (self: Option) => Option +``` + +Added in v1.0.0 + +## sum + +**Signature** + +```ts +export declare const sum: (that: Option) => (self: Option) => Option +``` + +Added in v1.0.0 + +## sumAll + +**Signature** + +```ts +export declare const sumAll: any +``` + +Added in v1.0.0 + ## toArray **Signature** diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index e661d80a1..a4714925f 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -46,7 +46,6 @@ Added in v1.0.0 - [compose](#compose) - [contramap](#contramap) - [element](#element) - - [imap](#imap) - [not](#not) - [of](#of) - [or](#or) @@ -358,16 +357,6 @@ export declare const element: ( Added in v1.0.0 -## imap - -**Signature** - -```ts -export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (self: Predicate) => Predicate -``` - -Added in v1.0.0 - ## not **Signature** diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 5a5b47479..2f90570f3 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -118,7 +118,6 @@ Added in v1.0.0 - [lifting](#lifting) - [every](#every) - [lift2](#lift2) - - [lift3](#lift3) - [liftEither](#lifteither) - [liftMonoid](#liftmonoid) - [liftNullable](#liftnullable) @@ -129,7 +128,6 @@ Added in v1.0.0 - [mapping](#mapping) - [as](#as) - [flap](#flap) - - [imap](#imap) - [map](#map) - [mapNonEmpty](#mapnonempty) - [mapNonEmptyWithIndex](#mapnonemptywithindex) @@ -1344,20 +1342,6 @@ export declare const lift2: (f: (a: A, b: B) => C) => (fa: readonly A[] Added in v1.0.0 -## lift3 - -Lifts a ternary function into `ReadonlyArray`. - -**Signature** - -```ts -export declare const lift3: ( - f: (a: A, b: B, c: C) => D -) => (fa: readonly A[], fb: readonly B[], fc: readonly C[]) => D[] -``` - -Added in v1.0.0 - ## liftEither **Signature** @@ -1462,16 +1446,6 @@ export declare const flap: (a: A) => (self: readonly ((a: A) => B)[]) => B Added in v1.0.0 -## imap - -**Signature** - -```ts -export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (self: readonly A[]) => B[] -``` - -Added in v1.0.0 - ## map **Signature** diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index ef4a5b57b..2e2f2bcb9 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -72,7 +72,6 @@ Added in v1.0.0 - [orElse](#orelse) - [orElseEither](#orelseeither) - [orElseFail](#orelsefail) - - [orElseSucceed](#orelsesucceed) - [filtering](#filtering) - [compact](#compact) - [filter](#filter) @@ -118,7 +117,6 @@ Added in v1.0.0 - [liftThrowable](#liftthrowable) - [lifting](#lifting) - [lift2](#lift2) - - [lift3](#lift3) - [liftEither](#lifteither) - [liftNullable](#liftnullable) - [liftOption](#liftoption) @@ -129,7 +127,6 @@ Added in v1.0.0 - [asUnit](#asunit) - [bimap](#bimap) - [flap](#flap) - - [imap](#imap) - [map](#map) - [tupled](#tupled) - [model](#model) @@ -620,19 +617,6 @@ export declare const orElseFail: (onLeft: any) => (self: any) => any Added in v1.0.0 -## orElseSucceed - -Executes this effect and returns its value, if it succeeds, but otherwise -succeeds with the specified value. - -**Signature** - -```ts -export declare const orElseSucceed: (onLeft: any) => (self: any) => any -``` - -Added in v1.0.0 - # filtering ## compact @@ -1058,16 +1042,6 @@ export declare const lift2: (f: (a: A, b: B) => C) => (fa: any, Added in v1.0.0 -## lift3 - -**Signature** - -```ts -export declare const lift3: (f: (a: A, b: B, c: C) => D) => (fa: any, fb: any, fc: any) => any -``` - -Added in v1.0.0 - ## liftEither **Signature** @@ -1176,16 +1150,6 @@ export declare const flap: (a: A) => (self: any) => any Added in v1.0.0 -## imap - -**Signature** - -```ts -export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (self: any) => any -``` - -Added in v1.0.0 - ## map Returns an effect whose right is mapped by the specified `f` function. diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index 54cddac5d..e4b984703 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -19,8 +19,9 @@ Added in v1.0.0 - [andThenDiscard](#andthendiscard) - [ap](#ap) - [lift2](#lift2) - - [lift3](#lift3) + - [lift2Curried](#lift2curried) - [liftSemigroup](#liftsemigroup) + - [map2](#map2) --- @@ -69,14 +70,14 @@ Added in v1.0.0 ```ts export declare const ap: ( F: SemiApplicative -) => (fa: any) => (self: any) => any +) => (that: any) => (self: any) => any ``` Added in v1.0.0 ## lift2 -Lifts a binary function into `F`. +Lifts a binary function into `F` as uncurried binary function. **Signature** @@ -88,16 +89,16 @@ export declare const lift2: ( Added in v1.0.0 -## lift3 +## lift2Curried -Lifts a ternary function into 'F'. +Lifts a binary function into `F` as curried binary function. **Signature** ```ts -export declare const lift3: ( +export declare const lift2Curried: ( F: SemiApplicative -) => (f: (a: A, b: B, c: C) => D) => (fa: any, fb: any, fc: any) => any +) => (f: (a: A, b: B) => C) => (that: any) => (self: any) => any ``` Added in v1.0.0 @@ -113,3 +114,17 @@ export declare const liftSemigroup: (F: SemiApplicative) => ( + F: SemiApplicative +) => (fb: any, f: (a: A, b: B) => C) => (fa: any) => any +``` + +Added in v1.0.0 diff --git a/Either.md b/guides/Either.md similarity index 100% rename from Either.md rename to guides/Either.md diff --git a/FAQ.md b/guides/FAQ.md similarity index 100% rename from FAQ.md rename to guides/FAQ.md diff --git a/Option.md b/guides/Option.md similarity index 100% rename from Option.md rename to guides/Option.md diff --git a/ts-types.md b/guides/ts-types.md similarity index 100% rename from ts-types.md rename to guides/ts-types.md diff --git a/typeclass.md b/guides/typeclass.md similarity index 100% rename from typeclass.md rename to guides/typeclass.md diff --git a/src/Option.ts b/src/Option.ts index 2b2022462..b9a5793fc 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1,12 +1,4 @@ /** - * The `Option` type can be interpreted in a few ways: - * - * 1) `Option` is a container for an optional value of type `A`. If the value of type `A` is present, the `Option` is - * an instance of `Some`, containing the present value of type `A`. If the value is absent, the `Option` is an - * instance of `None`. - * 2) Another way to view `Option` is as a representation of a possibly failing computation. - * 3) An option can also be thought of as a collection or foldable structure with either one or zero elements. - * * @since 1.0.0 */ import type { Either } from "@fp-ts/core/Either" From ce345a8dd5bae7694cdbdd1bf5056b337175810d Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 27 Jan 2023 16:08:51 +0100 Subject: [PATCH 104/255] add default handler to `getOrThrow` --- .changeset/dull-pets-run.md | 5 ++++ docs/modules/Either.ts.md | 2 +- docs/modules/Option.ts.md | 53 +++++++++++++++++-------------------- docs/modules/These.ts.md | 2 +- guides/Option.md | 16 +++++++++-- src/Either.ts | 4 ++- src/Option.ts | 9 ++++--- src/These.ts | 4 ++- test/Either.ts | 5 +++- test/Option.ts | 5 +++- test/These.ts | 7 +++-- 11 files changed, 70 insertions(+), 42 deletions(-) create mode 100644 .changeset/dull-pets-run.md diff --git a/.changeset/dull-pets-run.md b/.changeset/dull-pets-run.md new file mode 100644 index 000000000..7af61da86 --- /dev/null +++ b/.changeset/dull-pets-run.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add default handler to `getOrThrow` diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 0a5fdee91..349745b67 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -907,7 +907,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getOrThrow: (onLeft: (e: E) => unknown) => (self: Either) => A +export declare const getOrThrow: (onLeft?: (e: E) => Error) => (self: Either) => A ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 9572441a0..368ab7029 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -14,11 +14,8 @@ Added in v1.0.0 - [combinators](#combinators) - [tap](#tap) -- [combining](#combining) - - [getFirstSomeSemigroup](#getfirstsomesemigroup) - [constructors](#constructors) - [none](#none) - - [of](#of) - [some](#some) - [conversions](#conversions) - [fromEither](#fromeither) @@ -42,6 +39,7 @@ Added in v1.0.0 - [firstSomeOf](#firstsomeof) - [getFailureMonoid](#getfailuremonoid) - [getFailureSemigroup](#getfailuresemigroup) + - [getFirstSomeSemigroup](#getfirstsomesemigroup) - [getOrElse](#getorelse) - [orElse](#orelse) - [orElseEither](#orelseeither) @@ -121,6 +119,7 @@ Added in v1.0.0 - [flatten](#flatten) - [multiply](#multiply) - [multiplyAll](#multiplyall) + - [of](#of) - [struct](#struct) - [subtract](#subtract) - [sum](#sum) @@ -149,20 +148,6 @@ export declare const tap: (f: (a: A) => Option<_>) => (self: Option) => Added in v1.0.0 -# combining - -## getFirstSomeSemigroup - -Semigroup returning the first `Some` value encountered. - -**Signature** - -```ts -export declare const getFirstSomeSemigroup: () => any -``` - -Added in v1.0.0 - # constructors ## none @@ -177,16 +162,6 @@ export declare const none: () => Option Added in v1.0.0 -## of - -**Signature** - -```ts -export declare const of: (a: A) => Option -``` - -Added in v1.0.0 - ## some Creates a new `Option` that wraps the given value. @@ -472,6 +447,18 @@ export declare const getFailureSemigroup: (S: any) => any Added in v1.0.0 +## getFirstSomeSemigroup + +Semigroup returning the first `Some` value encountered. + +**Signature** + +```ts +export declare const getFirstSomeSemigroup: () => any +``` + +Added in v1.0.0 + ## getOrElse Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` @@ -876,7 +863,7 @@ Returns the contained value if the option is `Some`, otherwise throws an error. **Signature** ```ts -export declare const getOrThrow: (onError: any) => (self: Option) => A +export declare const getOrThrow: (onError?: any) => (self: Option) => A ``` Added in v1.0.0 @@ -1474,6 +1461,16 @@ export declare const multiplyAll: any Added in v1.0.0 +## of + +**Signature** + +```ts +export declare const of: (a: A) => Option +``` + +Added in v1.0.0 + ## struct **Signature** diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 2e2f2bcb9..d874ec69b 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1000,7 +1000,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getOrThrow: (onLeft: (e: E) => unknown) => (self: any) => A +export declare const getOrThrow: (onLeft?: (e: E) => Error) => (self: any) => A ``` Added in v1.0.0 diff --git a/guides/Option.md b/guides/Option.md index 339a09093..10eab1071 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -297,9 +297,22 @@ Please note that these two functions should only be used for debugging purposes We have seen how easy and convenient it is to build pipelines involving the `Option` data type, leaving it to handle any errors that may occur at any step. However, at some point, you will be interested in manually handling the error to understand the overall result obtained from the pipeline and decide what to do accordingly. +The fastest way to get the value wrapped in an option is to call the `getOrThrow` function, but be aware that, as the name suggests, an exception will be thrown in case the `Option` you are querying is a `None`: + +```ts +import { getOrThrow } from "@fp-ts/core/Option"; + +let someValue = Some(10); +let noneValue = None; +console.log(pipe(some(10), getOrThrow()); // 10 +console.log(pipe(none(), getOrThrow()); // throws new Error("getOrThrow called on a None") +``` + +An alternative more safe is that of doing [pattern matching](https://github.com/gvergnaud/ts-pattern#what-is-pattern-matching) on the `Option`. + The `match` function allows us to match on the `None` and `Some` cases of an `Option` value and provide different actions for each. -We can use the `match` function to handle the `Option` value returned by `parseNumber` and decide what to do based on whether it's a `None` or a `Some`. +For example we can use the `match` function to handle the `Option` value returned by `parseNumber` and decide what to do based on whether it's a `None` or a `Some`. ```ts import { pipe } from "@fp-ts/core/Function"; @@ -327,7 +340,6 @@ console.log(output); // Output: Error: Cannot parse 'Not a number' as a number | Name | Given | To | | --------------------- | --------------------------------------------------- | ---------------------- | | `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | -| `getOrThrow` | `Option` | `A` | | `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | | `getOrNull` | `Option` | `A \| null` | | `getOrUndefined` | `Option` | `A \| undefined` | diff --git a/src/Either.ts b/src/Either.ts index 837742040..fc49d6737 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -800,7 +800,9 @@ export const fromThrowable = ( * @category interop * @since 1.0.0 */ -export const getOrThrow = (onLeft: (e: E) => unknown) => +export const getOrThrow = ( + onLeft: (e: E) => Error = () => new Error("getOrThrow called on a Left") +) => (self: Either): A => { if (isRight(self)) { return self.right diff --git a/src/Option.ts b/src/Option.ts index b9a5793fc..d5c50f586 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -163,14 +163,16 @@ export const liftThrowable = , B>( /** * Returns the contained value if the option is `Some`, otherwise throws an error. * - * @param onError - A function that returns the error to be thrown when the option is `None` + * @param onError - An optional function that returns the error to be thrown when the option is `None` * @param self - The option to extract the value from * @throws The error returned by `onError` if the option is `None` * * @category interop * @since 1.0.0 */ -export const getOrThrow = (onError: LazyArg) => +export const getOrThrow = ( + onError: LazyArg = () => new Error("getOrThrow called on a None") +) => (self: Option): A => { if (isSome(self)) { return self.value @@ -258,7 +260,6 @@ export const as: (b: B) => <_>(self: Option<_>) => Option = covariant.as(C export const asUnit: <_>(self: Option<_>) => Option = covariant.asUnit(Covariant) /** - * @category constructors * @since 1.0.0 */ export const of: (a: A) => Option = some @@ -647,7 +648,7 @@ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { /** * Semigroup returning the first `Some` value encountered. * - * @category combining + * @category error handling * @since 1.0.0 */ export const getFirstSomeSemigroup: () => Semigroup> = semiCoproduct diff --git a/src/These.ts b/src/These.ts index 1141212c0..11ced51d2 100644 --- a/src/These.ts +++ b/src/These.ts @@ -255,7 +255,9 @@ export const liftThrowable = , B, E>( * @category interop * @since 1.0.0 */ -export const getOrThrow = (onLeft: (e: E) => unknown) => +export const getOrThrow = ( + onLeft: (e: E) => Error = () => new Error("getOrThrow called on a Left") +) => (self: These): A => { if (isRightOrBoth(self)) { return self.right diff --git a/test/Either.ts b/test/Either.ts index b2356e308..58ec0d15f 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -167,9 +167,12 @@ describe.concurrent("Either", () => { it("getOrThrow", () => { expect(pipe(_.right(1), _.getOrThrow((e: string) => new Error(e)))).toEqual(1) - expect(() => pipe(_.left("e"), _.getOrThrow((e: string) => new Error(e)))).toThrow( + expect(() => pipe(_.left("e"), _.getOrThrow((e: string) => new Error(e)))).toThrowError( new Error("e") ) + expect(() => pipe(_.left("e"), _.getOrThrow())).toThrowError( + new Error("getOrThrow called on a Left") + ) }) it("andThenDiscard", () => { diff --git a/test/Option.ts b/test/Option.ts index 0eacc6127..e5632f4b9 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -198,9 +198,12 @@ describe.concurrent("Option", () => { it("getOrThrow", () => { expect(pipe(_.some(1), _.getOrThrow(() => new Error("e")))).toEqual(1) - expect(() => pipe(_.none(), _.getOrThrow(() => new Error("e")))).toThrow( + expect(() => pipe(_.none(), _.getOrThrow(() => new Error("e")))).toThrowError( new Error("e") ) + expect(() => pipe(_.none(), _.getOrThrow())).toThrowError( + new Error("getOrThrow called on a None") + ) }) it("of", () => { diff --git a/test/These.ts b/test/These.ts index 2ee0c2a62..1a9288db1 100644 --- a/test/These.ts +++ b/test/These.ts @@ -569,10 +569,13 @@ describe("These", () => { it("getOrThrow", () => { expect(pipe(_.right(1), _.getOrThrow((e: string) => new Error(e)))).toEqual(1) - expect(() => pipe(_.left("e"), _.getOrThrow((e: string) => new Error(e)))).toThrow( + expect(pipe(_.both("e", 1), _.getOrThrow((e: string) => new Error(e)))).toEqual(1) + expect(() => pipe(_.left("e"), _.getOrThrow((e: string) => new Error(e)))).toThrowError( new Error("e") ) - expect(pipe(_.both("e", 1), _.getOrThrow((e: string) => new Error(e)))).toEqual(1) + expect(() => pipe(_.left("e"), _.getOrThrow())).toThrowError( + new Error("getOrThrow called on a Left") + ) }) it("getRightOnlyOrThrow", () => { From d4fcf63e16f15ac86a96e89b0b47c7d2647a6fe6 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 27 Jan 2023 17:29:21 +0100 Subject: [PATCH 105/255] Option: make orElse, orElseEither lazy and remove catchAll --- .changeset/stale-otters-sell.md | 5 ++++ docs/modules/Option.ts.md | 49 ++++++++++++++++++++------------- guides/Option.md | 4 +-- src/Option.ts | 27 ++++++------------ test/Option.ts | 17 ++++-------- 5 files changed, 51 insertions(+), 51 deletions(-) create mode 100644 .changeset/stale-otters-sell.md diff --git a/.changeset/stale-otters-sell.md b/.changeset/stale-otters-sell.md new file mode 100644 index 000000000..153dc3ac7 --- /dev/null +++ b/.changeset/stale-otters-sell.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": minor +--- + +Option: make orElse, orElseEither lazy and remove catchAll diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 368ab7029..0f47b0e63 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -35,7 +35,6 @@ Added in v1.0.0 - [bindTo](#bindto) - [let](#let) - [error handling](#error-handling) - - [catchAll](#catchall) - [firstSomeOf](#firstsomeof) - [getFailureMonoid](#getfailuremonoid) - [getFailureSemigroup](#getfailuresemigroup) @@ -389,18 +388,6 @@ Added in v1.0.0 # error handling -## catchAll - -Lazy version of `orElse`. - -**Signature** - -```ts -export declare const catchAll: (that: any) => (self: Option) => Option -``` - -Added in v1.0.0 - ## firstSomeOf Given an Iterable collection of `Option`s, the function returns the first `Some` option found in the collection. @@ -500,7 +487,7 @@ Returns the provided option `that` if `self` is `None`, otherwise returns `self` **Signature** ```ts -export declare const orElse: (that: Option) => (self: Option) => Option +export declare const orElse: (that: any) => (self: Option) => Option ``` **Example** @@ -509,10 +496,34 @@ export declare const orElse: (that: Option) => (self: Option) => Opt import * as O from '@fp-ts/core/Option' import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe(O.none(), O.orElse(O.none())), O.none()) -assert.deepStrictEqual(pipe(O.some('a'), O.orElse(O.none())), O.some('a')) -assert.deepStrictEqual(pipe(O.none(), O.orElse(O.some('b'))), O.some('b')) -assert.deepStrictEqual(pipe(O.some('a'), O.orElse(O.some('b'))), O.some('a')) +assert.deepStrictEqual( + pipe( + O.none(), + O.orElse(() => O.none()) + ), + O.none() +) +assert.deepStrictEqual( + pipe( + O.some('a'), + O.orElse(() => O.none()) + ), + O.some('a') +) +assert.deepStrictEqual( + pipe( + O.none(), + O.orElse(() => O.some('b')) + ), + O.some('b') +) +assert.deepStrictEqual( + pipe( + O.some('a'), + O.orElse(() => O.some('b')) + ), + O.some('a') +) ``` Added in v1.0.0 @@ -526,7 +537,7 @@ This is useful when it's important to know whether the value was retrieved from **Signature** ```ts -export declare const orElseEither: (that: Option) => (self: Option) => Option +export declare const orElseEither: (that: any) => (self: Option) => Option ``` Added in v1.0.0 diff --git a/guides/Option.md b/guides/Option.md index 10eab1071..2332a3e00 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -343,8 +343,8 @@ console.log(output); // Output: Error: Cannot parse 'Not a number' as a number | `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | | `getOrNull` | `Option` | `A \| null` | | `getOrUndefined` | `Option` | `A \| undefined` | -| `orElse` | `Option`, `Option` | `Option` | -| `orElseEither` | `Option`, `Option` | `Option>` | +| `orElse` | `Option`, `LazyArg>` | `Option` | +| `orElseEither` | `Option`, `LazyArg>` | `Option>` | | `firstSomeOf` | `Iterable>` | `Option` | | `getFailureSemigroup` | `Semigroup` | `Semigroup>` | | `getFailureMonoid` | `Monoid` | `Monoid>` | diff --git a/src/Option.ts b/src/Option.ts index d5c50f586..4af624963 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1020,15 +1020,6 @@ export const getOrNull: (self: Option) => A | null = getOrElse(constNull) */ export const getOrUndefined: (self: Option) => A | undefined = getOrElse(constUndefined) -/** - * Lazy version of `orElse`. - * - * @category error handling - * @since 1.0.0 - */ -export const catchAll = (that: LazyArg>) => - (self: Option): Option => isNone(self) ? that() : self - /** * Returns the provided option `that` if `self` is `None`, otherwise returns `self`. * @@ -1042,28 +1033,28 @@ export const catchAll = (that: LazyArg>) => * assert.deepStrictEqual( * pipe( * O.none(), - * O.orElse(O.none()) + * O.orElse(() => O.none()) * ), * O.none() * ) * assert.deepStrictEqual( * pipe( * O.some('a'), - * O.orElse(O.none()) + * O.orElse(() => O.none()) * ), * O.some('a') * ) * assert.deepStrictEqual( * pipe( * O.none(), - * O.orElse(O.some('b')) + * O.orElse(() => O.some('b')) * ), * O.some('b') * ) * assert.deepStrictEqual( * pipe( * O.some('a'), - * O.orElse(O.some('b')) + * O.orElse(() => O.some('b')) * ), * O.some('a') * ) @@ -1071,8 +1062,8 @@ export const catchAll = (that: LazyArg>) => * @category error handling * @since 1.0.0 */ -export const orElse = (that: Option): ((self: Option) => Option) => - catchAll(() => that) +export const orElse = (that: LazyArg>) => + (self: Option): Option => isNone(self) ? that() : self /** * Similar to `orElse`, but instead of returning a simple union, it returns an `Either` object, @@ -1086,12 +1077,12 @@ export const orElse = (that: Option): ((self: Option) => Option( - that: Option + that: LazyArg> ) => (self: Option): Option> => isNone(self) ? - pipe(that, map(either.right)) : - pipe, Option>>(self, map(either.left)) + pipe(that(), map(either.right)) : + pipe(self, map(either.left)) /** * The `Order` instance allows `Option` values to be compared with diff --git a/test/Option.ts b/test/Option.ts index e5632f4b9..42997ca2e 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -150,18 +150,11 @@ describe.concurrent("Option", () => { ) }) - it("catchAll", () => { - Util.deepStrictEqual(pipe(_.some(1), _.catchAll(() => _.some(2))), _.some(1)) - Util.deepStrictEqual(pipe(_.some(1), _.catchAll(() => _.none())), _.some(1)) - Util.deepStrictEqual(pipe(_.none(), _.catchAll(() => _.some(1))), _.some(1)) - Util.deepStrictEqual(pipe(_.none(), _.catchAll(() => _.none())), _.none()) - }) - it("orElseEither", () => { - expect(pipe(_.some(1), _.orElseEither(_.some(2)))).toEqual(_.some(E.left(1))) - expect(pipe(_.some(1), _.orElseEither(_.none()))).toEqual(_.some(E.left(1))) - expect(pipe(_.none(), _.orElseEither(_.some(2)))).toEqual(_.some(E.right(2))) - expect(pipe(_.none(), _.orElseEither(_.none()))).toEqual(_.none()) + expect(pipe(_.some(1), _.orElseEither(() => _.some(2)))).toEqual(_.some(E.left(1))) + expect(pipe(_.some(1), _.orElseEither(() => _.none()))).toEqual(_.some(E.left(1))) + expect(pipe(_.none(), _.orElseEither(() => _.some(2)))).toEqual(_.some(E.right(2))) + expect(pipe(_.none(), _.orElseEither(() => _.none()))).toEqual(_.none()) }) it("inspectSome", () => { @@ -297,7 +290,7 @@ describe.concurrent("Option", () => { b: _.Option, expected: _.Option ) => { - Util.deepStrictEqual(pipe(a, _.orElse(b)), expected) + Util.deepStrictEqual(pipe(a, _.orElse(() => b)), expected) } assertAlt(_.some(1), _.some(2), _.some(1)) assertAlt(_.some(1), _.none(), _.some(1)) From a99a23a15ccd1c9d1f623f39d4727cb3ff0be3f7 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 27 Jan 2023 17:45:53 +0100 Subject: [PATCH 106/255] Either: make orElse, orElseEither lazy and remove catchAll --- .changeset/fresh-zebras-own.md | 5 +++++ docs/modules/Either.ts.md | 25 ++++++------------------- dtslint/ts4.7/SemiApplicative.ts | 22 ---------------------- src/Either.ts | 26 ++++++++------------------ test/Either.ts | 23 ++++++++--------------- 5 files changed, 27 insertions(+), 74 deletions(-) create mode 100644 .changeset/fresh-zebras-own.md delete mode 100644 dtslint/ts4.7/SemiApplicative.ts diff --git a/.changeset/fresh-zebras-own.md b/.changeset/fresh-zebras-own.md new file mode 100644 index 000000000..6254f51fe --- /dev/null +++ b/.changeset/fresh-zebras-own.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": minor +--- + +Either: make orElse, orElseEither lazy and remove catchAll diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 349745b67..325598630 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -45,7 +45,6 @@ Added in v1.0.0 - [bindTo](#bindto) - [let](#let) - [error handling](#error-handling) - - [catchAll](#catchall) - [firstSuccessOf](#firstsuccessof) - [mapLeft](#mapleft) - [orElse](#orelse) @@ -407,20 +406,6 @@ Added in v1.0.0 # error handling -## catchAll - -Recovers from all errors. - -**Signature** - -```ts -export declare const catchAll: ( - onLeft: (e: E1) => Either -) => (self: Either) => Either -``` - -Added in v1.0.0 - ## firstSuccessOf **Signature** @@ -459,7 +444,9 @@ executes the specified effect. **Signature** ```ts -export declare const orElse: (that: Either) => (self: Either) => Either +export declare const orElse: ( + that: (e1: E1) => Either +) => (self: Either) => Either ``` Added in v1.0.0 @@ -472,9 +459,9 @@ fails, in which case, it will produce the value of the specified effect. **Signature** ```ts -export declare const orElseEither: ( - that: Either -) => (self: Either) => Either> +export declare const orElseEither: ( + that: (e1: E1) => Either +) => (self: Either) => Either> ``` Added in v1.0.0 diff --git a/dtslint/ts4.7/SemiApplicative.ts b/dtslint/ts4.7/SemiApplicative.ts deleted file mode 100644 index 6a261798c..000000000 --- a/dtslint/ts4.7/SemiApplicative.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as _ from "@fp-ts/core/typeclass/SemiApplicative" -import type { TypeLambda } from "@fp-ts/core/HKT" - -interface RAW { - (r: R): () => Promise -} - -interface RAWTypeLambda extends TypeLambda { - readonly type: RAW -} - -declare const fa: RAW<{ a: string }, "a", string> -declare const fb: RAW<{ b: number }, "b", number> -declare const fc: RAW<{ c: boolean }, "c", boolean> - -declare const SemiApplicative: _.SemiApplicative - -// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", readonly [string, number, boolean]> -_.lift3(SemiApplicative)((a: string, b: number, c: boolean) => [a, b, c] as const)(fa, fb, fc) - -// $ExpectType RAW<{ a: string; } & { b: number; } & { c: boolean; }, "a" | "b" | "c", readonly [unknown, unknown, unknown]> -_.lift3(SemiApplicative)((a: A, b: B, c: C): readonly [A, B, C] => [a, b, c])(fa, fb, fc) diff --git a/src/Either.ts b/src/Either.ts index fc49d6737..ce95eb945 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -610,16 +610,6 @@ export const getFirstRightSemigroup: () => Semigroup> = semiC export const getOrElse = (onLeft: LazyArg) => (self: Either): A | B => isLeft(self) ? onLeft() : self.right -/** - * Recovers from all errors. - * - * @category error handling - * @since 1.0.0 - */ -export const catchAll = ( - onLeft: (e: E1) => Either -) => (self: Either): Either => isLeft(self) ? onLeft(self.left) : self - /** * Executes this effect and returns its value, if it succeeds, but otherwise * executes the specified effect. @@ -634,9 +624,9 @@ export const catchAll = ( * @category error handling * @since 1.0.0 */ -export const orElse = ( - that: Either -) => (self: Either): Either => isLeft(self) ? that : self +export const orElse = ( + that: (e1: E1) => Either +) => (self: Either): Either => isLeft(self) ? that(self.left) : self /** * Returns an effect that will produce the value of this effect, unless it @@ -645,12 +635,12 @@ export const orElse = ( * @category error handling * @since 1.0.0 */ -export const orElseEither = ( - that: Either +export const orElseEither = ( + that: (e1: E1) => Either ) => - (self: Either): Either> => + (self: Either): Either> => isLeft(self) ? - pipe(that, map(right)) : + pipe(that(self.left), map(right)) : pipe, Either>>(self, map(left)) /** @@ -662,7 +652,7 @@ export const orElseEither = ( */ export const orElseFail = ( onLeft: LazyArg -): (self: Either) => Either => catchAll(() => left(onLeft())) +): (self: Either) => Either => orElse(() => left(onLeft())) /** * @category instances diff --git a/test/Either.ts b/test/Either.ts index 58ec0d15f..8f62183cc 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -190,17 +190,17 @@ describe.concurrent("Either", () => { }) it("orElse", () => { - Util.deepStrictEqual(pipe(_.right(1), _.orElse(_.right(2))), _.right(1)) - Util.deepStrictEqual(pipe(_.right(1), _.orElse(_.left("b"))), _.right(1)) - Util.deepStrictEqual(pipe(_.left("a"), _.orElse(_.right(2))), _.right(2)) - Util.deepStrictEqual(pipe(_.left("a"), _.orElse(_.left("b"))), _.left("b")) + Util.deepStrictEqual(pipe(_.right(1), _.orElse(() => _.right(2))), _.right(1)) + Util.deepStrictEqual(pipe(_.right(1), _.orElse(() => _.left("b"))), _.right(1)) + Util.deepStrictEqual(pipe(_.left("a"), _.orElse(() => _.right(2))), _.right(2)) + Util.deepStrictEqual(pipe(_.left("a"), _.orElse(() => _.left("b"))), _.left("b")) }) it("orElseEither", () => { - expect(pipe(_.right(1), _.orElseEither(_.right(2)))).toEqual(_.right(_.left(1))) - expect(pipe(_.right(1), _.orElseEither(_.left("b")))).toEqual(_.right(_.left(1))) - expect(pipe(_.left("a"), _.orElseEither(_.right(2)))).toEqual(_.right(_.right(2))) - expect(pipe(_.left("a"), _.orElseEither(_.left("b")))).toEqual(_.left("b")) + expect(pipe(_.right(1), _.orElseEither(() => _.right(2)))).toEqual(_.right(_.left(1))) + expect(pipe(_.right(1), _.orElseEither(() => _.left("b")))).toEqual(_.right(_.left(1))) + expect(pipe(_.left("a"), _.orElseEither(() => _.right(2)))).toEqual(_.right(_.right(2))) + expect(pipe(_.left("a"), _.orElseEither(() => _.left("b")))).toEqual(_.left("b")) }) it("map", () => { @@ -279,13 +279,6 @@ describe.concurrent("Either", () => { Util.deepStrictEqual(_.isRight(_.left(1)), false) }) - it("catchAll", () => { - Util.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.right(2))), _.right(1)) - Util.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.left("foo"))), _.right(1)) - Util.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.right(1))), _.right(1)) - Util.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.left("b"))), _.left("b")) - }) - it("swap", () => { Util.deepStrictEqual(_.reverse(_.right("a")), _.left("a")) Util.deepStrictEqual(_.reverse(_.left("b")), _.right("b")) From ae3338c091284e0af7b24e1be818a96d59a77f09 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 27 Jan 2023 18:16:49 +0100 Subject: [PATCH 107/255] Either: rename `firstSuccessOf` to `firstRightOf` --- .changeset/popular-dingos-ring.md | 5 +++++ docs/modules/Either.ts.md | 6 +++--- src/Either.ts | 4 ++-- test/Either.ts | 11 +++++------ 4 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 .changeset/popular-dingos-ring.md diff --git a/.changeset/popular-dingos-ring.md b/.changeset/popular-dingos-ring.md new file mode 100644 index 000000000..a502f4aaa --- /dev/null +++ b/.changeset/popular-dingos-ring.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": minor +--- + +Either: rename `firstSuccessOf` to `firstRightOf` diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 325598630..8a88ac40e 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -45,7 +45,7 @@ Added in v1.0.0 - [bindTo](#bindto) - [let](#let) - [error handling](#error-handling) - - [firstSuccessOf](#firstsuccessof) + - [firstRightOf](#firstrightof) - [mapLeft](#mapleft) - [orElse](#orelse) - [orElseEither](#orelseeither) @@ -406,12 +406,12 @@ Added in v1.0.0 # error handling -## firstSuccessOf +## firstRightOf **Signature** ```ts -export declare const firstSuccessOf: (collection: Iterable>) => (self: Either) => Either +export declare const firstRightOf: (collection: Iterable>) => (self: Either) => Either ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index ce95eb945..944823713 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -542,7 +542,7 @@ export const getFirstLeftMonoid: (M: Monoid) => Monoid> = * @category error handling * @since 1.0.0 */ -export const firstSuccessOf = (collection: Iterable>) => +export const firstRightOf = (collection: Iterable>) => (self: Either): Either => { let out = self if (isRight(out)) { @@ -563,7 +563,7 @@ export const firstSuccessOf = (collection: Iterable>) => export const SemiCoproduct: semiCoproduct.SemiCoproduct = { ...Invariant, coproduct: (self, that) => isRight(self) ? self : that, - coproductMany: (self, collection) => pipe(self, firstSuccessOf(collection)) + coproductMany: (self, collection) => pipe(self, firstRightOf(collection)) } /** diff --git a/test/Either.ts b/test/Either.ts index 8f62183cc..3cbd5afba 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -62,7 +62,6 @@ describe.concurrent("Either", () => { expect(_.SemiCoproduct).exist expect(_.getFirstRightSemigroup).exist // getSemigroup - expect(_.firstSuccessOf).exist expect(_.SemiAlternative).exist @@ -325,15 +324,15 @@ describe.concurrent("Either", () => { Util.deepStrictEqual(_.fromIterable(() => "e")(["a"]), _.right("a")) }) - it("firstSuccessOf", () => { - Util.deepStrictEqual(pipe(_.right(1), _.firstSuccessOf([])), _.right(1)) - Util.deepStrictEqual(pipe(_.left("e"), _.firstSuccessOf([])), _.left("e")) + it("firstRightOf", () => { + Util.deepStrictEqual(pipe(_.right(1), _.firstRightOf([])), _.right(1)) + Util.deepStrictEqual(pipe(_.left("e"), _.firstRightOf([])), _.left("e")) Util.deepStrictEqual( - pipe(_.left("e1"), _.firstSuccessOf([_.left("e2"), _.left("e3"), _.left("e4"), _.right(1)])), + pipe(_.left("e1"), _.firstRightOf([_.left("e2"), _.left("e3"), _.left("e4"), _.right(1)])), _.right(1) ) Util.deepStrictEqual( - pipe(_.left("e1"), _.firstSuccessOf([_.left("e2"), _.left("e3"), _.left("e4")])), + pipe(_.left("e1"), _.firstRightOf([_.left("e2"), _.left("e3"), _.left("e4")])), _.left("e4") ) }) From 14f87fb33061ef1e36a5695c0f28578c9f860cf1 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 27 Jan 2023 19:53:30 +0100 Subject: [PATCH 108/255] Option: add `reduceAll` --- .changeset/perfect-fishes-sing.md | 5 +++ docs/modules/Option.ts.md | 46 +++++++++++++++++++-- guides/Option.md | 66 ++++++++++++++++++++++--------- src/Option.ts | 45 ++++++++++++++++++--- test/Option.ts | 17 ++++++-- 5 files changed, 148 insertions(+), 31 deletions(-) create mode 100644 .changeset/perfect-fishes-sing.md diff --git a/.changeset/perfect-fishes-sing.md b/.changeset/perfect-fishes-sing.md new file mode 100644 index 000000000..e40995071 --- /dev/null +++ b/.changeset/perfect-fishes-sing.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Option: add `reduceAll` diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 0f47b0e63..9fc56b215 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -119,6 +119,8 @@ Added in v1.0.0 - [multiply](#multiply) - [multiplyAll](#multiplyall) - [of](#of) + - [reduce](#reduce) + - [reduceAll](#reduceall) - [struct](#struct) - [subtract](#subtract) - [sum](#sum) @@ -874,7 +876,7 @@ Returns the contained value if the option is `Some`, otherwise throws an error. **Signature** ```ts -export declare const getOrThrow: (onError?: any) => (self: Option) => A +export declare const getOrThrow: (onNone?: any) => (self: Option) => A ``` Added in v1.0.0 @@ -1467,7 +1469,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiplyAll: any +export declare const multiplyAll: (self: Iterable>) => number ``` Added in v1.0.0 @@ -1482,6 +1484,44 @@ export declare const of: (a: A) => Option Added in v1.0.0 +## reduce + +**Signature** + +```ts +export declare const reduce: (b: B, f: (b: B, a: A) => B) => (self: Option) => B +``` + +Added in v1.0.0 + +## reduceAll + +Reduces an `Iterable` of `Option` to a single value of type `B`. + +**Signature** + +```ts +export declare const reduceAll: (b: B, f: (b: B, a: A) => B) => (self: Iterable>) => B +``` + +**Example** + +```ts +import { some, none, reduceAll } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +const iterable = [some(1), none(), some(2), none()] +assert.strictEqual( + pipe( + iterable, + reduceAll(0, (b, a) => b + a) + ), + 3 +) +``` + +Added in v1.0.0 + ## struct **Signature** @@ -1519,7 +1559,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const sumAll: any +export declare const sumAll: (self: Iterable>) => number ``` Added in v1.0.0 diff --git a/guides/Option.md b/guides/Option.md index 2332a3e00..c2d52ac0b 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -308,9 +308,9 @@ console.log(pipe(some(10), getOrThrow()); // 10 console.log(pipe(none(), getOrThrow()); // throws new Error("getOrThrow called on a None") ``` -An alternative more safe is that of doing [pattern matching](https://github.com/gvergnaud/ts-pattern#what-is-pattern-matching) on the `Option`. +A more safe alternative is [pattern matching](https://github.com/gvergnaud/ts-pattern#what-is-pattern-matching) on the `Option`. -The `match` function allows us to match on the `None` and `Some` cases of an `Option` value and provide different actions for each. +The `match` function allows you to match on the `None` and `Some` cases of an `Option` value and provide different actions for each. For example we can use the `match` function to handle the `Option` value returned by `parseNumber` and decide what to do based on whether it's a `None` or a `Some`. @@ -318,12 +318,8 @@ For example we can use the `match` function to handle the `Option` value returne import { pipe } from "@fp-ts/core/Function"; import { match } from "@fp-ts/core/Option"; -// parseNumber returns an Option -const result = parseNumber("Not a number"); - -// Using pipe and match to pattern match on the result const output = pipe( - result, + parseNumber("Not a number"), match( // If the result is a None, return an error string () => `Error: ${error}`, @@ -335,16 +331,50 @@ const output = pipe( console.log(output); // Output: Error: Cannot parse 'Not a number' as a number ``` +There are specializations of `match` to make working with code that does not use `Option` more convenient and faster, particularly `getOrNull` and `getOrUndefined`. + +```ts +import { getOrNull, getOrUndefined } from "fp-ts/core/Option"; + +pipe(some(5), getOrNull); // 5 +pipe(none(), getOrNull); // null + +pipe(some(5), getOrUndefined); // 5 +pipe(none(), getOrUndefined); // undefined +``` + +For greater flexibility, there is also the `getOrElse` function which allows you to set what value corresponds to the `None` case: + +```ts +import { getOrElse } from "fp-ts/core/Option"; + +pipe( + some(5), + getOrElse(() => 0) +); // 5 +pipe( + none(), + getOrElse(() => 0) +); // 0 +``` + **Cheat sheet** (error handling) -| Name | Given | To | -| --------------------- | --------------------------------------------------- | ---------------------- | -| `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | -| `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | -| `getOrNull` | `Option` | `A \| null` | -| `getOrUndefined` | `Option` | `A \| undefined` | -| `orElse` | `Option`, `LazyArg>` | `Option` | -| `orElseEither` | `Option`, `LazyArg>` | `Option>` | -| `firstSomeOf` | `Iterable>` | `Option` | -| `getFailureSemigroup` | `Semigroup` | `Semigroup>` | -| `getFailureMonoid` | `Monoid` | `Monoid>` | +| Name | Given | To | +| ---------------- | --------------------------------------------------- | ---------------- | +| `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | +| `getOrThrow` | `Option`, `onNone?: LazyArg` | `A` | +| `getOrNull` | `Option` | `A \| null` | +| `getOrUndefined` | `Option` | `A \| undefined` | +| `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | + +# Combining two or more `Option`s + +**Cheat sheet** (combining) + +| Name | Given | To | +| -------------- | ----------------------------------------- | ---------------------- | +| `orElse` | `Option`, `LazyArg>` | `Option` | +| `orElseEither` | `Option`, `LazyArg>` | `Option>` | +| `firstSomeOf` | `Iterable>` | `Option` | +| `reduceAll` | `Iterable>`, `B`, `(B, A) => B` | `B` | diff --git a/src/Option.ts b/src/Option.ts index 4af624963..d0ffe5d12 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -163,7 +163,7 @@ export const liftThrowable = , B>( /** * Returns the contained value if the option is `Some`, otherwise throws an error. * - * @param onError - An optional function that returns the error to be thrown when the option is `None` + * @param onNone - An optional function that returns the error to be thrown when the option is `None` * @param self - The option to extract the value from * @throws The error returned by `onError` if the option is `None` * @@ -171,13 +171,13 @@ export const liftThrowable = , B>( * @since 1.0.0 */ export const getOrThrow = ( - onError: LazyArg = () => new Error("getOrThrow called on a None") + onNone: LazyArg = () => new Error("getOrThrow called on a None") ) => (self: Option): A => { if (isSome(self)) { return self.value } - throw onError() + throw onNone() } /** @@ -707,12 +707,18 @@ export const Alternative: alternative.Alternative = { ...Coproduct } +/** + * @since 1.0.0 + */ +export const reduce = (b: B, f: (b: B, a: A) => B) => + (self: Option): B => isNone(self) ? b : f(b, self.value) + /** * @category instances * @since 1.0.0 */ export const Foldable: foldable.Foldable = { - reduce: (b, f) => (self) => isNone(self) ? b : f(b, self.value) + reduce } /** @@ -1207,12 +1213,39 @@ export const subtract = lift2Curried((a: number, b: number) => a - b) */ export const divide = lift2Curried((a: number, b: number) => a / b) +/** + * Reduces an `Iterable` of `Option` to a single value of type `B`. + * + * @since 1.0.0 + * + * @param b - The initial value of the accumulator + * @param f - The reducing function that takes the current accumulator value and the unwrapped value of an `Option` + * @param self - The Iterable of `Option` to be reduced + * + * @example + * import { some, none, reduceAll } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * const iterable = [some(1), none(), some(2), none()] + * assert.strictEqual(pipe(iterable, reduceAll(0, (b, a) => b + a)), 3) + */ +export const reduceAll = (b: B, f: (b: B, a: A) => B) => + (self: Iterable>): B => { + let out: B = b + for (const oa of self) { + if (isSome(oa)) { + out = f(out, oa.value) + } + } + return out + } + /** * @since 1.0.0 */ -export const sumAll = getOptionalMonoid(N.SemigroupSum).combineAll +export const sumAll = reduceAll(0, N.SemigroupSum.combine) /** * @since 1.0.0 */ -export const multiplyAll = getOptionalMonoid(N.SemigroupMultiply).combineAll +export const multiplyAll = reduceAll(1, N.SemigroupMultiply.combine) diff --git a/test/Option.ts b/test/Option.ts index 42997ca2e..1eeaf04b1 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -68,6 +68,8 @@ describe.concurrent("Option", () => { expect(_.Alternative).exist expect(_.Foldable).exist + expect(_.reduce).exist + expect(_.reduceAll).exist expect(_.toArray).exist expect(_.Traversable).exist @@ -592,13 +594,20 @@ describe.concurrent("Option", () => { expect(pipe(_.some(6), _.divide(_.some(3)))).toEqual(_.some(2)) }) + it("reduce", () => { + expect(pipe(_.none(), _.reduce(0, (b, a) => b + a))).toEqual(0) + expect(pipe(_.some(1), _.reduce(0, (b, a) => b + a))).toEqual(1) + }) + it("sumAll", () => { - expect(_.sumAll([_.some(2), _.some(3)])).toEqual(_.some(5)) - expect(_.sumAll([_.some(2), _.none(), _.some(3)])).toEqual(_.some(5)) + expect(_.sumAll([])).toEqual(0) + expect(_.sumAll([_.some(2), _.some(3)])).toEqual(5) + expect(_.sumAll([_.some(2), _.none(), _.some(3)])).toEqual(5) }) it("multiplyAll", () => { - expect(_.multiplyAll([_.some(2), _.some(3)])).toEqual(_.some(6)) - expect(_.multiplyAll([_.some(2), _.none(), _.some(3)])).toEqual(_.some(6)) + expect(_.multiplyAll([])).toEqual(1) + expect(_.multiplyAll([_.some(2), _.some(3)])).toEqual(6) + expect(_.multiplyAll([_.some(2), _.none(), _.some(3)])).toEqual(6) }) }) From 4692b2e6b3c423961a518fd674a659571df3eede Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 28 Jan 2023 08:55:50 +0100 Subject: [PATCH 109/255] refactor algebraic operations --- docs/modules/Bigint.ts.md | 91 ++-- docs/modules/Either.ts.md | 154 +++--- docs/modules/Identity.ts.md | 2 +- docs/modules/Number.ts.md | 207 ++++---- docs/modules/Option.ts.md | 344 +++++++------ docs/modules/These.ts.md | 49 +- docs/modules/typeclass/SemiApplicative.ts.md | 19 +- src/Bigint.ts | 4 + src/Either.ts | 61 +-- src/Identity.ts | 4 +- src/Number.ts | 6 + src/Option.ts | 495 ++++++++++--------- src/These.ts | 41 +- src/typeclass/SemiApplicative.ts | 22 +- test/Either.ts | 30 +- test/Option.ts | 3 +- test/These.ts | 28 ++ test/typeclass/SemiApplicative.ts | 8 - 18 files changed, 810 insertions(+), 758 deletions(-) diff --git a/docs/modules/Bigint.ts.md b/docs/modules/Bigint.ts.md index ccb2493f7..2bde139ef 100644 --- a/docs/modules/Bigint.ts.md +++ b/docs/modules/Bigint.ts.md @@ -16,6 +16,11 @@ Added in v1.0.0

Table of contents

+- [algebraic operations](#algebraic-operations) + - [divide](#divide) + - [multiply](#multiply) + - [subtract](#subtract) + - [sum](#sum) - [guards](#guards) - [isBigint](#isbigint) - [instances](#instances) @@ -27,158 +32,156 @@ Added in v1.0.0 - [SemigroupSum](#semigroupsum) - [utils](#utils) - [decrement](#decrement) - - [divide](#divide) - [increment](#increment) - - [multiply](#multiply) - - [subtract](#subtract) - - [sum](#sum) --- -# guards +# algebraic operations -## isBigint +## divide **Signature** ```ts -export declare const isBigint: (u: unknown) => u is bigint +export declare const divide: (that: bigint) => (self: bigint) => bigint ``` Added in v1.0.0 -# instances - -## Equivalence +## multiply **Signature** ```ts -export declare const Equivalence: any +export declare const multiply: (that: bigint) => (self: bigint) => bigint ``` Added in v1.0.0 -## MonoidMultiply - -`bigint` monoid under multiplication. - -The `empty` value is `1n`. +## subtract **Signature** ```ts -export declare const MonoidMultiply: any +export declare const subtract: (that: bigint) => (self: bigint) => bigint ``` Added in v1.0.0 -## MonoidSum - -`bigint` monoid under addition. - -The `empty` value is `0n`. +## sum **Signature** ```ts -export declare const MonoidSum: any +export declare const sum: (that: bigint) => (self: bigint) => bigint ``` Added in v1.0.0 -## Order +# guards + +## isBigint **Signature** ```ts -export declare const Order: any +export declare const isBigint: (u: unknown) => u is bigint ``` Added in v1.0.0 -## SemigroupMultiply +# instances -`bigint` semigroup under multiplication. +## Equivalence **Signature** ```ts -export declare const SemigroupMultiply: any +export declare const Equivalence: any ``` Added in v1.0.0 -## SemigroupSum +## MonoidMultiply -`bigint` semigroup under addition. +`bigint` monoid under multiplication. + +The `empty` value is `1n`. **Signature** ```ts -export declare const SemigroupSum: any +export declare const MonoidMultiply: any ``` Added in v1.0.0 -# utils +## MonoidSum -## decrement +`bigint` monoid under addition. + +The `empty` value is `0n`. **Signature** ```ts -export declare const decrement: (n: bigint) => bigint +export declare const MonoidSum: any ``` Added in v1.0.0 -## divide +## Order **Signature** ```ts -export declare const divide: (that: bigint) => (self: bigint) => bigint +export declare const Order: any ``` Added in v1.0.0 -## increment +## SemigroupMultiply + +`bigint` semigroup under multiplication. **Signature** ```ts -export declare const increment: (n: bigint) => bigint +export declare const SemigroupMultiply: any ``` Added in v1.0.0 -## multiply +## SemigroupSum + +`bigint` semigroup under addition. **Signature** ```ts -export declare const multiply: (that: bigint) => (self: bigint) => bigint +export declare const SemigroupSum: any ``` Added in v1.0.0 -## subtract +# utils + +## decrement **Signature** ```ts -export declare const subtract: (that: bigint) => (self: bigint) => bigint +export declare const decrement: (n: bigint) => bigint ``` Added in v1.0.0 -## sum +## increment **Signature** ```ts -export declare const sum: (that: bigint) => (self: bigint) => bigint +export declare const increment: (n: bigint) => bigint ``` Added in v1.0.0 diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 8a88ac40e..0ba51257b 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -22,6 +22,11 @@ Added in v1.0.0

Table of contents

+- [algebraic operations](#algebraic-operations) + - [divide](#divide) + - [multiply](#multiply) + - [subtract](#subtract) + - [sum](#sum) - [combining](#combining) - [getFirstLeftMonoid](#getfirstleftmonoid) - [getFirstLeftSemigroup](#getfirstleftsemigroup) @@ -83,14 +88,13 @@ Added in v1.0.0 - [SemiCoproduct](#semicoproduct) - [SemiProduct](#semiproduct) - [Traversable](#traversable) - - [getSemigroup](#getsemigroup) + - [getOptionalSemigroup](#getoptionalsemigroup) - [interop](#interop) - [fromThrowable](#fromthrowable) - [getOrThrow](#getorthrow) - [liftThrowable](#liftthrowable) - [lifting](#lifting) - [lift2](#lift2) - - [lift2Curried](#lift2curried) - [liftNullable](#liftnullable) - [liftOption](#liftoption) - [liftPredicate](#liftpredicate) @@ -124,23 +128,65 @@ Added in v1.0.0 - [ap](#ap) - [composeKleisliArrow](#composekleisliarrow) - [contains](#contains) - - [divide](#divide) - [element](#element) - [exists](#exists) - [flatten](#flatten) - - [multiply](#multiply) - - [multiplyMany](#multiplymany) - [reverse](#reverse) - [struct](#struct) - - [subtract](#subtract) - - [sum](#sum) - - [sumMany](#summany) - [tap](#tap) - [tuple](#tuple) - [unit](#unit) --- +# algebraic operations + +## divide + +**Signature** + +```ts +export declare const divide: ( + that: Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + +## multiply + +**Signature** + +```ts +export declare const multiply: ( + that: Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + +## subtract + +**Signature** + +```ts +export declare const subtract: ( + that: Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + +## sum + +**Signature** + +```ts +export declare const sum: (that: Either) => (self: Either) => Either +``` + +Added in v1.0.0 + # combining ## getFirstLeftMonoid @@ -842,15 +888,15 @@ export declare const Traversable: any Added in v1.0.0 -## getSemigroup +## getOptionalSemigroup -Semigroup returning the left-most non-`Left` value. If both operands are `Right`s then the inner values are -concatenated using the provided `Semigroup` +Semigroup that models the combination of values that may be absent, elements that are `Left` are ignored +while elements that are `Right` are combined using the provided `Semigroup`. **Signature** ```ts -export declare const getSemigroup: (S: any) => any +export declare const getOptionalSemigroup: (S: any) => any ``` Added in v2.0.0 @@ -918,28 +964,14 @@ Added in v1.0.0 ## lift2 -Lifts a binary function into `Either` as uncurried binary function. +Lifts a binary function into `Either`. **Signature** ```ts export declare const lift2: ( - f: (a: A, b: B) => C -) => (fa: Either, fb: Either) => Either -``` - -Added in v1.0.0 - -## lift2Curried - -Lifts a binary function into `Either` as curried binary function. - -**Signature** - -```ts -export declare const lift2Curried: ( - f: (a: A, b: B) => C -) => (that: Either) => (self: Either) => Either + f: (a: A) => (b: B) => C +) => (that: Either) => (self: Either) => Either ``` Added in v1.0.0 @@ -1309,16 +1341,6 @@ export declare const contains:
(equivalence: any) => (a: A) => (self: Eith Added in v1.0.0 -## divide - -**Signature** - -```ts -export declare const divide: (that: Either) => (self: Either) => Either -``` - -Added in v1.0.0 - ## element Adds an element to the end of a tuple. @@ -1367,28 +1389,6 @@ export declare const flatten: (self: Either>) => Ei Added in v1.0.0 -## multiply - -**Signature** - -```ts -export declare const multiply: ( - that: Either -) => (self: Either) => Either -``` - -Added in v1.0.0 - -## multiplyMany - -**Signature** - -```ts -export declare const multiplyMany: any -``` - -Added in v1.0.0 - ## reverse **Signature** @@ -1414,38 +1414,6 @@ export declare const struct: >>( Added in v1.0.0 -## subtract - -**Signature** - -```ts -export declare const subtract: ( - that: Either -) => (self: Either) => Either -``` - -Added in v1.0.0 - -## sum - -**Signature** - -```ts -export declare const sum: (that: Either) => (self: Either) => Either -``` - -Added in v1.0.0 - -## sumMany - -**Signature** - -```ts -export declare const sumMany: any -``` - -Added in v1.0.0 - ## tap Returns an effect that effectfully "peeks" at the success of this effect. diff --git a/docs/modules/Identity.ts.md b/docs/modules/Identity.ts.md index d4d620028..3d7a07b23 100644 --- a/docs/modules/Identity.ts.md +++ b/docs/modules/Identity.ts.md @@ -415,7 +415,7 @@ Lifts a binary function into `Identity`. **Signature** ```ts -export declare const lift2: (f: (a: A, b: B) => C) => (fa: A, fb: B) => C +export declare const lift2: (f: (a: A) => (b: B) => C) => (fa: A) => (fb: B) => C ``` Added in v1.0.0 diff --git a/docs/modules/Number.ts.md b/docs/modules/Number.ts.md index c5574c1f7..d3b7c15b0 100644 --- a/docs/modules/Number.ts.md +++ b/docs/modules/Number.ts.md @@ -16,6 +16,13 @@ Added in v1.0.0

Table of contents

+- [algebraic operations](#algebraic-operations) + - [divide](#divide) + - [multiply](#multiply) + - [multiplyAll](#multiplyall) + - [subtract](#subtract) + - [sum](#sum) + - [sumAll](#sumall) - [guards](#guards) - [isNumber](#isnumber) - [instances](#instances) @@ -32,17 +39,109 @@ Added in v1.0.0 - [SemigroupSum](#semigroupsum) - [utils](#utils) - [decrement](#decrement) - - [divide](#divide) - [increment](#increment) - - [multiply](#multiply) - - [multiplyAll](#multiplyall) - [sign](#sign) - - [subtract](#subtract) - - [sum](#sum) - - [sumAll](#sumall) --- +# algebraic operations + +## divide + +**Signature** + +```ts +export declare const divide: (that: number) => (self: number) => number +``` + +**Example** + +```ts +import { divide } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(6, divide(3)), 2) +``` + +Added in v1.0.0 + +## multiply + +**Signature** + +```ts +export declare const multiply: (that: number) => (self: number) => number +``` + +**Example** + +```ts +import { multiply } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(2, multiply(3)), 6) +``` + +Added in v1.0.0 + +## multiplyAll + +**Signature** + +```ts +export declare const multiplyAll: (collection: Iterable) => number +``` + +Added in v1.0.0 + +## subtract + +**Signature** + +```ts +export declare const subtract: (that: number) => (self: number) => number +``` + +**Example** + +```ts +import { subtract } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(2, subtract(3)), -1) +``` + +Added in v1.0.0 + +## sum + +**Signature** + +```ts +export declare const sum: (that: number) => (self: number) => number +``` + +**Example** + +```ts +import { sum } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(2, sum(3)), 5) +``` + +Added in v1.0.0 + +## sumAll + +**Signature** + +```ts +export declare const sumAll: (collection: Iterable) => number +``` + +Added in v1.0.0 + # guards ## isNumber @@ -218,25 +317,6 @@ assert.deepStrictEqual(pipe(3, decrement), 2) Added in v1.0.0 -## divide - -**Signature** - -```ts -export declare const divide: (that: number) => (self: number) => number -``` - -**Example** - -```ts -import { divide } from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' - -assert.deepStrictEqual(pipe(6, divide(3)), 2) -``` - -Added in v1.0.0 - ## increment **Signature** @@ -256,35 +336,6 @@ assert.deepStrictEqual(pipe(2, increment), 3) Added in v1.0.0 -## multiply - -**Signature** - -```ts -export declare const multiply: (that: number) => (self: number) => number -``` - -**Example** - -```ts -import { multiply } from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' - -assert.deepStrictEqual(pipe(2, multiply(3)), 6) -``` - -Added in v1.0.0 - -## multiplyAll - -**Signature** - -```ts -export declare const multiplyAll: (collection: Iterable) => number -``` - -Added in v1.0.0 - ## sign **Signature** @@ -294,51 +345,3 @@ export declare const sign: (n: number) => any ``` Added in v1.0.0 - -## subtract - -**Signature** - -```ts -export declare const subtract: (that: number) => (self: number) => number -``` - -**Example** - -```ts -import { subtract } from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' - -assert.deepStrictEqual(pipe(2, subtract(3)), -1) -``` - -Added in v1.0.0 - -## sum - -**Signature** - -```ts -export declare const sum: (that: number) => (self: number) => number -``` - -**Example** - -```ts -import { sum } from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' - -assert.deepStrictEqual(pipe(2, sum(3)), 5) -``` - -Added in v1.0.0 - -## sumAll - -**Signature** - -```ts -export declare const sumAll: (collection: Iterable) => number -``` - -Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 9fc56b215..e77cb5ee8 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -12,6 +12,13 @@ Added in v1.0.0

Table of contents

+- [algebraic operations](#algebraic-operations) + - [divide](#divide) + - [multiply](#multiply) + - [multiplyAll](#multiplyall) + - [subtract](#subtract) + - [sum](#sum) + - [sumAll](#sumall) - [combinators](#combinators) - [tap](#tap) - [constructors](#constructors) @@ -21,8 +28,6 @@ Added in v1.0.0 - [fromEither](#fromeither) - [fromIterable](#fromiterable) - [fromNullable](#fromnullable) - - [getOrNull](#getornull) - - [getOrUndefined](#getorundefined) - [toEither](#toeither) - [toRefinement](#torefinement) - [debugging](#debugging) @@ -36,9 +41,6 @@ Added in v1.0.0 - [let](#let) - [error handling](#error-handling) - [firstSomeOf](#firstsomeof) - - [getFailureMonoid](#getfailuremonoid) - - [getFailureSemigroup](#getfailuresemigroup) - - [getFirstSomeSemigroup](#getfirstsomesemigroup) - [getOrElse](#getorelse) - [orElse](#orelse) - [orElseEither](#orelseeither) @@ -70,14 +72,18 @@ Added in v1.0.0 - [SemiCoproduct](#semicoproduct) - [SemiProduct](#semiproduct) - [Traversable](#traversable) + - [getFailureMonoid](#getfailuremonoid) + - [getFailureSemigroup](#getfailuresemigroup) + - [getFirstSomeSemigroup](#getfirstsomesemigroup) - [interop](#interop) - [fromThrowable](#fromthrowable) + - [getOrNull](#getornull) - [getOrThrow](#getorthrow) + - [getOrUndefined](#getorundefined) - [liftThrowable](#liftthrowable) - [lifting](#lifting) - [getOptionalMonoid](#getoptionalmonoid) - [lift2](#lift2) - - [lift2Curried](#lift2curried) - [liftEither](#lifteither) - [liftNullable](#liftnullable) - [liftPredicate](#liftpredicate) @@ -112,19 +118,13 @@ Added in v1.0.0 - [composeKleisliArrow](#composekleisliarrow) - [contains](#contains) - [coproductEither](#coproducteither) - - [divide](#divide) - [element](#element) - [exists](#exists) - [flatten](#flatten) - - [multiply](#multiply) - - [multiplyAll](#multiplyall) - [of](#of) - [reduce](#reduce) - [reduceAll](#reduceall) - [struct](#struct) - - [subtract](#subtract) - - [sum](#sum) - - [sumAll](#sumall) - [toArray](#toarray) - [tuple](#tuple) - [tupled](#tupled) @@ -132,6 +132,68 @@ Added in v1.0.0 --- +# algebraic operations + +## divide + +**Signature** + +```ts +export declare const divide: (that: Option) => (self: Option) => Option +``` + +Added in v1.0.0 + +## multiply + +**Signature** + +```ts +export declare const multiply: (that: Option) => (self: Option) => Option +``` + +Added in v1.0.0 + +## multiplyAll + +**Signature** + +```ts +export declare const multiplyAll: (self: Iterable>) => number +``` + +Added in v1.0.0 + +## subtract + +**Signature** + +```ts +export declare const subtract: (that: Option) => (self: Option) => Option +``` + +Added in v1.0.0 + +## sum + +**Signature** + +```ts +export declare const sum: (that: Option) => (self: Option) => Option +``` + +Added in v1.0.0 + +## sumAll + +**Signature** + +```ts +export declare const sumAll: (self: Iterable>) => number +``` + +Added in v1.0.0 + # combinators ## tap @@ -232,50 +294,6 @@ assert.deepStrictEqual(fromNullable(1), some(1)) Added in v1.0.0 -## getOrNull - -Returns the value of the option if it is a `Some`, otherwise returns `null`. - -**Signature** - -```ts -export declare const getOrNull:
(self: Option) => A | null -``` - -**Example** - -```ts -import { some, none, getOrNull } from '@fp-ts/core/Option' -import { pipe } from '@fp-ts/core/Function' - -assert.strictEqual(pipe(some(1), getOrNull), 1) -assert.strictEqual(pipe(none(), getOrNull), null) -``` - -Added in v1.0.0 - -## getOrUndefined - -Returns the value of the option if it is a `Some`, otherwise returns `undefined`. - -**Signature** - -```ts -export declare const getOrUndefined: (self: Option) => A | undefined -``` - -**Example** - -```ts -import { some, none, getOrUndefined } from '@fp-ts/core/Option' -import { pipe } from '@fp-ts/core/Function' - -assert.strictEqual(pipe(some(1), getOrUndefined), 1) -assert.strictEqual(pipe(none(), getOrUndefined), undefined) -``` - -Added in v1.0.0 - ## toEither **Signature** @@ -402,52 +420,6 @@ export declare const firstSomeOf: (collection: Iterable>) => Option Added in v1.0.0 -## getFailureMonoid - -Monoid that models the combination of computations that can fail, if at least one element is `None` -then the resulting combination is `None`, otherwise if all elements are `Some` then the resulting combination -is the combination of the wrapped elements using the provided `Monoid`. - -The `empty` value is `some(M.empty)`. - -See also `getFailureSemigroup` if you need a `Semigroup` instead of a `Monoid`. - -**Signature** - -```ts -export declare const getFailureMonoid: (M: any) => any -``` - -Added in v1.0.0 - -## getFailureSemigroup - -Semigroup that models the combination of computations that can fail, if at least one element is `None` -then the resulting combination is `None`, otherwise if all elements are `Some` then the resulting combination -is the combination of the wrapped elements using the provided `Semigroup`. - -See also `getFailureMonoid` if you need a `Monoid` instead of a `Semigroup`. - -**Signature** - -```ts -export declare const getFailureSemigroup: (S: any) => any -``` - -Added in v1.0.0 - -## getFirstSomeSemigroup - -Semigroup returning the first `Some` value encountered. - -**Signature** - -```ts -export declare const getFirstSomeSemigroup: () => any -``` - -Added in v1.0.0 - ## getOrElse Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` @@ -837,6 +809,52 @@ export declare const Traversable: any Added in v1.0.0 +## getFailureMonoid + +Monoid that models the combination of computations that can fail, if at least one element is `None` +then the resulting combination is `None`, otherwise if all elements are `Some` then the resulting combination +is the combination of the wrapped elements using the provided `Monoid`. + +The `empty` value is `some(M.empty)`. + +See also `getFailureSemigroup` if you need a `Semigroup` instead of a `Monoid`. + +**Signature** + +```ts +export declare const getFailureMonoid: (M: any) => any +``` + +Added in v1.0.0 + +## getFailureSemigroup + +Semigroup that models the combination of computations that can fail, if at least one element is `None` +then the resulting combination is `None`, otherwise if all elements are `Some` then the resulting combination +is the combination of the wrapped elements using the provided `Semigroup`. + +See also `getFailureMonoid` if you need a `Monoid` instead of a `Semigroup`. + +**Signature** + +```ts +export declare const getFailureSemigroup: (S: any) => any +``` + +Added in v1.0.0 + +## getFirstSomeSemigroup + +Semigroup returning the first `Some` value encountered. + +**Signature** + +```ts +export declare const getFirstSomeSemigroup: () => any +``` + +Added in v1.0.0 + # interop ## fromThrowable @@ -869,6 +887,28 @@ assert.deepStrictEqual( Added in v1.0.0 +## getOrNull + +Returns the value of the option if it is a `Some`, otherwise returns `null`. + +**Signature** + +```ts +export declare const getOrNull: (self: Option) => A | null +``` + +**Example** + +```ts +import { some, none, getOrNull } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +assert.strictEqual(pipe(some(1), getOrNull), 1) +assert.strictEqual(pipe(none(), getOrNull), null) +``` + +Added in v1.0.0 + ## getOrThrow Returns the contained value if the option is `Some`, otherwise throws an error. @@ -881,6 +921,28 @@ export declare const getOrThrow: (onNone?: any) => (self: Option) => A Added in v1.0.0 +## getOrUndefined + +Returns the value of the option if it is a `Some`, otherwise returns `undefined`. + +**Signature** + +```ts +export declare const getOrUndefined: (self: Option) => A | undefined +``` + +**Example** + +```ts +import { some, none, getOrUndefined } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +assert.strictEqual(pipe(some(1), getOrUndefined), 1) +assert.strictEqual(pipe(none(), getOrUndefined), undefined) +``` + +Added in v1.0.0 + ## liftThrowable Lifts a function that may throw to one returning a `Option`. @@ -929,21 +991,7 @@ Lifts a binary function into `Option` as uncurried binary function. **Signature** ```ts -export declare const lift2: (f: (a: A, b: B) => C) => (fa: Option, fb: Option) => Option -``` - -Added in v1.0.0 - -## lift2Curried - -Lifts a binary function into `Option` as curried binary function. - -**Signature** - -```ts -export declare const lift2Curried: ( - f: (a: A, b: B) => C -) => (that: Option) => (self: Option) => Option +export declare const lift2: (f: (a: A) => (b: B) => C) => (that: Option) => (self: Option) => Option ``` Added in v1.0.0 @@ -1381,16 +1429,6 @@ export declare const coproductEither: (that: Option) => (self: Option) => (self: Option) => Option -``` - -Added in v1.0.0 - ## element Adds an element to the end of a tuple. @@ -1454,26 +1492,6 @@ export declare const flatten: (self: Option>) => Option Added in v1.0.0 -## multiply - -**Signature** - -```ts -export declare const multiply: (that: Option) => (self: Option) => Option -``` - -Added in v1.0.0 - -## multiplyAll - -**Signature** - -```ts -export declare const multiplyAll: (self: Iterable>) => number -``` - -Added in v1.0.0 - ## of **Signature** @@ -1496,7 +1514,7 @@ Added in v1.0.0 ## reduceAll -Reduces an `Iterable` of `Option` to a single value of type `B`. +Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. **Signature** @@ -1534,36 +1552,6 @@ export declare const struct: >>( Added in v1.0.0 -## subtract - -**Signature** - -```ts -export declare const subtract: (that: Option) => (self: Option) => Option -``` - -Added in v1.0.0 - -## sum - -**Signature** - -```ts -export declare const sum: (that: Option) => (self: Option) => Option -``` - -Added in v1.0.0 - -## sumAll - -**Signature** - -```ts -export declare const sumAll: (self: Iterable>) => number -``` - -Added in v1.0.0 - ## toArray **Signature** diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index d874ec69b..a71d07091 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -26,6 +26,11 @@ Added in v1.0.0

Table of contents

+- [algebraic operations](#algebraic-operations) + - [divide](#divide) + - [multiply](#multiply) + - [subtract](#subtract) + - [sum](#sum) - [combining](#combining) - [getFirstLeftMonoid](#getfirstleftmonoid) - [getFirstLeftSemigroup](#getfirstleftsemigroup) @@ -166,6 +171,48 @@ Added in v1.0.0 --- +# algebraic operations + +## divide + +**Signature** + +```ts +export declare const divide: (that: any) => (self: any) => any +``` + +Added in v1.0.0 + +## multiply + +**Signature** + +```ts +export declare const multiply: (that: any) => (self: any) => any +``` + +Added in v1.0.0 + +## subtract + +**Signature** + +```ts +export declare const subtract: (that: any) => (self: any) => any +``` + +Added in v1.0.0 + +## sum + +**Signature** + +```ts +export declare const sum: (that: any) => (self: any) => any +``` + +Added in v1.0.0 + # combining ## getFirstLeftMonoid @@ -1037,7 +1084,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const lift2: (f: (a: A, b: B) => C) => (fa: any, fb: any) => any +export declare const lift2: (f: (a: A) => (b: B) => C) => (that: any) => (self: any) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index e4b984703..8e211ae69 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -19,7 +19,6 @@ Added in v1.0.0 - [andThenDiscard](#andthendiscard) - [ap](#ap) - [lift2](#lift2) - - [lift2Curried](#lift2curried) - [liftSemigroup](#liftsemigroup) - [map2](#map2) @@ -77,28 +76,14 @@ Added in v1.0.0 ## lift2 -Lifts a binary function into `F` as uncurried binary function. +Lifts a binary function into `F`. **Signature** ```ts export declare const lift2: ( F: SemiApplicative -) => (f: (a: A, b: B) => C) => (fa: any, fb: any) => any -``` - -Added in v1.0.0 - -## lift2Curried - -Lifts a binary function into `F` as curried binary function. - -**Signature** - -```ts -export declare const lift2Curried: ( - F: SemiApplicative -) => (f: (a: A, b: B) => C) => (that: any) => (self: any) => any +) => (f: (a: A) => (b: B) => C) => (that: any) => (self: any) => any ``` Added in v1.0.0 diff --git a/src/Bigint.ts b/src/Bigint.ts index c6b878dd8..50e27e4e9 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -19,23 +19,27 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" export const isBigint: (u: unknown) => u is bigint = predicate.isBigInt /** + * @category algebraic operations * @since 1.0.0 */ export const sum = (that: bigint) => (self: bigint): bigint => semigroup.bigintSum.combine(self, that) /** + * @category algebraic operations * @since 1.0.0 */ export const multiply = (that: bigint) => (self: bigint): bigint => semigroup.bigintMultiply.combine(self, that) /** + * @category algebraic operations * @since 1.0.0 */ export const subtract = (that: bigint) => (self: bigint): bigint => self - that /** + * @category algebraic operations * @since 1.0.0 */ export const divide = (that: bigint) => (self: bigint): bigint => self / that diff --git a/src/Either.ts b/src/Either.ts index 944823713..29be75d8b 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -476,27 +476,16 @@ export const getFirstLeftSemigroup: (S: Semigroup
) => Semigroup( - f: (a: A, b: B) => C -) => (fa: Either, fb: Either) => Either = semiApplicative + f: (a: A) => (b: B) => C +) => (that: Either) => (self: Either) => Either = semiApplicative .lift2(SemiApplicative) -/** - * Lifts a binary function into `Either` as curried binary function. - * - * @category lifting - * @since 1.0.0 - */ -export const lift2Curried: ( - f: (a: A, b: B) => C -) => (that: Either) => (self: Either) => Either = semiApplicative - .lift2Curried(SemiApplicative) - /** * @category lifting * @since 1.0.0 @@ -1109,44 +1098,42 @@ export const exists = (predicate: Predicate) => (self: Either): boolean => isLeft(self) ? false : predicate(self.right) /** - * @since 1.0.0 + * Semigroup that models the combination of values that may be absent, elements that are `Left` are ignored + * while elements that are `Right` are combined using the provided `Semigroup`. + * + * @category instances + * @since 2.0.0 */ -export const sum = lift2Curried(N.SemigroupSum.combine) +export const getOptionalSemigroup = (S: Semigroup): Semigroup> => + semigroup.fromCombine(( + x, + y + ) => (isLeft(y) ? x : isLeft(x) ? y : right(S.combine(x.right, y.right)))) -/** - * @since 1.0.0 - */ -export const multiply = lift2Curried(N.SemigroupMultiply.combine) +// ------------------------------------------------------------------------------------- +// algebraic operations +// ------------------------------------------------------------------------------------- /** + * @category algebraic operations * @since 1.0.0 */ -export const subtract = lift2Curried((a: number, b: number) => a - b) +export const sum = lift2(N.sum) /** + * @category algebraic operations * @since 1.0.0 */ -export const divide = lift2Curried((a: number, b: number) => a / b) - -/** - * Semigroup returning the left-most non-`Left` value. If both operands are `Right`s then the inner values are - * concatenated using the provided `Semigroup` - * - * @category instances - * @since 2.0.0 - */ -export const getSemigroup = (S: Semigroup): Semigroup> => - semigroup.fromCombine(( - x, - y - ) => (isLeft(y) ? x : isLeft(x) ? y : right(S.combine(x.right, y.right)))) +export const multiply = lift2(N.multiply) /** + * @category algebraic operations * @since 1.0.0 */ -export const sumMany = getSemigroup(N.SemigroupSum).combineMany +export const subtract = lift2(N.subtract) /** + * @category algebraic operations * @since 1.0.0 */ -export const multiplyMany = getSemigroup(N.SemigroupMultiply).combineMany +export const divide = lift2(N.divide) diff --git a/src/Identity.ts b/src/Identity.ts index 44b941d2f..26b231975 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -333,8 +333,8 @@ export const liftSemigroup: (S: Semigroup) => Semigroup> = sem * @since 1.0.0 */ export const lift2: ( - f: (a: A, b: B) => C -) => (fa: Identity, fb: Identity) => Identity = semiApplicative.lift2( + f: (a: A) => (b: B) => C +) => (fa: Identity) => (fb: Identity) => Identity = semiApplicative.lift2( SemiApplicative ) diff --git a/src/Number.ts b/src/Number.ts index 12c58ceac..2b24ae566 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -26,6 +26,7 @@ export const isNumber = predicate.isNumber * * assert.deepStrictEqual(pipe(2, sum(3)), 5) * + * @category algebraic operations * @since 1.0.0 */ export const sum = (that: number) => @@ -38,6 +39,7 @@ export const sum = (that: number) => * * assert.deepStrictEqual(pipe(2, multiply(3)), 6) * + * @category algebraic operations * @since 1.0.0 */ export const multiply = (that: number) => @@ -50,6 +52,7 @@ export const multiply = (that: number) => * * assert.deepStrictEqual(pipe(2, subtract(3)), -1) * + * @category algebraic operations * @since 1.0.0 */ export const subtract = (that: number) => (self: number): number => self - that @@ -61,6 +64,7 @@ export const subtract = (that: number) => (self: number): number => self - that * * assert.deepStrictEqual(pipe(6, divide(3)), 2) * + * @category algebraic operations * @since 1.0.0 */ export const divide = (that: number) => (self: number): number => self / that @@ -183,11 +187,13 @@ export const MonoidMin = bounded.min(Bounded) export const sign = (n: number): Ordering => n < 0 ? -1 : n > 0 ? 1 : 0 /** + * @category algebraic operations * @since 1.0.0 */ export const sumAll: (collection: Iterable) => number = MonoidSum.combineAll /** + * @category algebraic operations * @since 1.0.0 */ export const multiplyAll: (collection: Iterable) => number = MonoidMultiply.combineAll diff --git a/src/Option.ts b/src/Option.ts index d0ffe5d12..82c110c85 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -36,6 +36,10 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" +// ------------------------------------------------------------------------------------- +// model +// ------------------------------------------------------------------------------------- + /** * @category models * @since 1.0.0 @@ -67,6 +71,10 @@ export interface OptionTypeLambda extends TypeLambda { readonly type: Option } +// ------------------------------------------------------------------------------------- +// constructors +// ------------------------------------------------------------------------------------- + /** * Creates a new `Option` that represents a absence of value. * @@ -83,6 +91,10 @@ export const none = (): Option => option.none */ export const some: (a: A) => Option = option.some +// ------------------------------------------------------------------------------------- +// guards +// ------------------------------------------------------------------------------------- + /** * Checks if the specified value is an instance of `Option`, returns `true` if it is, `false` otherwise. * @@ -98,6 +110,38 @@ export const some: (a: A) => Option = option.some */ export const isOption: (u: unknown) => u is Option = option.isOption +/** + * Returns `true` if the option is `None`, `false` otherwise. + * + * @example + * import { some, none, isNone } from '@fp-ts/core/Option' + * + * assert.strictEqual(isNone(some(1)), false) + * assert.strictEqual(isNone(none()), true) + * + * @category guards + * @since 1.0.0 + */ +export const isNone: (self: Option) => self is None = option.isNone + +/** + * Returns `true` if the option is an instance of `Some`, `false` otherwise. + * + * @example + * import { some, none, isSome } from '@fp-ts/core/Option' + * + * assert.strictEqual(isSome(some(1)), true) + * assert.strictEqual(isSome(none()), false) + * + * @category guards + * @since 1.0.0 + */ +export const isSome: (self: Option) => self is Some = option.isSome + +// ------------------------------------------------------------------------------------- +// conversions +// ------------------------------------------------------------------------------------- + /** * Constructs a new `Option` from a nullable type. If the value is `null` or `undefined`, returns `None`, otherwise * returns the value wrapped in a `Some`. @@ -124,6 +168,182 @@ export const fromNullable: (a: A) => Option> = option.fromNull export const toRefinement = (f: (a: A) => Option): Refinement => (a: A): a is B => isSome(f(a)) +/** + * @category conversions + * @since 1.0.0 + */ +export const fromIterable = (collection: Iterable): Option => { + for (const a of collection) { + return some(a) + } + return option.none +} + +/** + * Converts a `Either` to an `Option` discarding the error. + * + * @example + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(O.fromEither(E.right(1)), O.some(1)) + * assert.deepStrictEqual(O.fromEither(E.left('a')), O.none()) + * + * @category conversions + * @since 1.0.0 + */ +export const fromEither: (self: Either) => Option = either.getRight + +/** + * @category conversions + * @since 1.0.0 + */ +export const toEither: (onNone: LazyArg) => (self: Option) => Either = + either.fromOption + +// ------------------------------------------------------------------------------------- +// error handling +// ------------------------------------------------------------------------------------- + +/** + * Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` + * + * @param onNone - Function that returns the default value to return if the `Option` is `None` + * @param self - The `Option` to get the value of + * * + * @example + * import { some, none, getOrElse } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.strictEqual(pipe(some(1), getOrElse(() => 0)), 1) + * assert.strictEqual(pipe(none(), getOrElse(() => 0)), 0) + * + * @category error handling + * @since 1.0.0 + */ +export const getOrElse = (onNone: LazyArg) => + (self: Option): A | B => isNone(self) ? onNone() : self.value + +/** + * Returns the provided option `that` if `self` is `None`, otherwise returns `self`. + * + * @param that - The option to return if `self` option is `None` + * @param self - The first option to be checked + * + * @example + * import * as O from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.deepStrictEqual( + * pipe( + * O.none(), + * O.orElse(() => O.none()) + * ), + * O.none() + * ) + * assert.deepStrictEqual( + * pipe( + * O.some('a'), + * O.orElse(() => O.none()) + * ), + * O.some('a') + * ) + * assert.deepStrictEqual( + * pipe( + * O.none(), + * O.orElse(() => O.some('b')) + * ), + * O.some('b') + * ) + * assert.deepStrictEqual( + * pipe( + * O.some('a'), + * O.orElse(() => O.some('b')) + * ), + * O.some('a') + * ) + * + * @category error handling + * @since 1.0.0 + */ +export const orElse = (that: LazyArg>) => + (self: Option): Option => isNone(self) ? that() : self + +/** + * Similar to `orElse`, but instead of returning a simple union, it returns an `Either` object, + * which contains information about which of the two options has been chosen. + * This is useful when it's important to know whether the value was retrieved from the first option or the second option. + * + * @param that - The second option to be considered if the first option is `None` + * @param self - The first option to be checked + * + * @category error handling + * @since 1.0.0 + */ +export const orElseEither = ( + that: LazyArg> +) => + (self: Option): Option> => + isNone(self) ? + pipe(that(), map(either.right)) : + pipe(self, map(either.left)) + +/** + * Given an Iterable collection of `Option`s, the function returns the first `Some` option found in the collection. + * + * @param collection - An iterable collection of `Option` to be searched + * + * @category error handling + * @since 1.0.0 + */ +export const firstSomeOf = (collection: Iterable>): Option => { + let out: Option = none() + for (out of collection) { + if (isSome(out)) { + return out + } + } + return out +} + +// ------------------------------------------------------------------------------------- +// interop +// ------------------------------------------------------------------------------------- + +/** + * Returns the value of the option if it is a `Some`, otherwise returns `null`. + * + * @param self - The option to extract the value from + * + * @example + * import { some, none, getOrNull } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.strictEqual(pipe(some(1), getOrNull), 1) + * assert.strictEqual(pipe(none(), getOrNull), null) + * + * @category interop + * @since 1.0.0 + */ +export const getOrNull: (self: Option) => A | null = getOrElse(constNull) + +/** + * Returns the value of the option if it is a `Some`, otherwise returns `undefined`. + * + * @param self - The option to extract the value from + * + * @example + * import { some, none, getOrUndefined } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.strictEqual(pipe(some(1), getOrUndefined), 1) + * assert.strictEqual(pipe(none(), getOrUndefined), undefined) + * + * @category interop + * @since 1.0.0 + */ +export const getOrUndefined: (self: Option) => A | undefined = getOrElse(constUndefined) + /** * Converts an exception into an `Option`. If `f` throws, returns `None`, otherwise returns the output wrapped in a * `Some`. @@ -180,6 +400,10 @@ export const getOrThrow = ( throw onNone() } +// ------------------------------------------------------------------------------------- +// instances +// ------------------------------------------------------------------------------------- + /** * Maps the given function to the value of the `Option` if it is a `Some`, otherwise it returns `None`. * @@ -554,19 +778,10 @@ export const getOptionalMonoid = ( * @category lifting * @since 1.0.0 */ -export const lift2: (f: (a: A, b: B) => C) => (fa: Option, fb: Option) => Option = - semiApplicative.lift2(SemiApplicative) - -/** - * Lifts a binary function into `Option` as curried binary function. - * - * @category lifting - * @since 1.0.0 - */ -export const lift2Curried: ( - f: (a: A, b: B) => C -) => (that: Option) => (self: Option) => Option = semiApplicative - .lift2Curried(SemiApplicative) +export const lift2: ( + f: (a: A) => (b: B) => C +) => (that: Option) => (self: Option) => Option = semiApplicative + .lift2(SemiApplicative) /** * @category lifting @@ -591,7 +806,7 @@ export const ap: ( * * See also `getFailureMonoid` if you need a `Monoid` instead of a `Semigroup`. * - * @category error handling + * @category instances * @since 1.0.0 */ export const getFailureSemigroup: (S: Semigroup) => Semigroup> = semiApplicative @@ -615,7 +830,7 @@ export const Applicative: applicative.Applicative = { * * See also `getFailureSemigroup` if you need a `Semigroup` instead of a `Monoid`. * - * @category error handling + * @category instances * @since 1.0.0 */ export const getFailureMonoid: (M: Monoid) => Monoid> = applicative.liftMonoid( @@ -648,7 +863,7 @@ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { /** * Semigroup returning the first `Some` value encountered. * - * @category error handling + * @category instances * @since 1.0.0 */ export const getFirstSomeSemigroup: () => Semigroup> = semiCoproduct @@ -661,24 +876,6 @@ export const coproductEither = (that: Option) => (self: Option): Option> => isNone(self) ? pipe(that, map(either.right)) : pipe(self, map(either.left)) -/** - * Given an Iterable collection of `Option`s, the function returns the first `Some` option found in the collection. - * - * @param collection - An iterable collection of `Option` to be searched - * - * @category error handling - * @since 1.0.0 - */ -export const firstSomeOf = (collection: Iterable>): Option => { - let out: Option = none() - for (out of collection) { - if (isSome(out)) { - return out - } - } - return out -} - /** * @category instances * @since 1.0.0 @@ -807,67 +1004,6 @@ export const traverseTap: ( ) => (self: Option) => Kind> = traversable .traverseTap(Traversable) -/** - * Returns `true` if the option is `None`, `false` otherwise. - * - * @example - * import { some, none, isNone } from '@fp-ts/core/Option' - * - * assert.strictEqual(isNone(some(1)), false) - * assert.strictEqual(isNone(none()), true) - * - * @category guards - * @since 1.0.0 - */ -export const isNone: (self: Option) => self is None = option.isNone - -/** - * Returns `true` if the option is an instance of `Some`, `false` otherwise. - * - * @example - * import { some, none, isSome } from '@fp-ts/core/Option' - * - * assert.strictEqual(isSome(some(1)), true) - * assert.strictEqual(isSome(none()), false) - * - * @category guards - * @since 1.0.0 - */ -export const isSome: (self: Option) => self is Some = option.isSome - -/** - * @category conversions - * @since 1.0.0 - */ -export const fromIterable = (collection: Iterable): Option => { - for (const a of collection) { - return some(a) - } - return option.none -} - -/** - * Converts a `Either` to an `Option` discarding the error. - * - * @example - * import * as O from '@fp-ts/core/Option' - * import * as E from '@fp-ts/core/Either' - * - * assert.deepStrictEqual(O.fromEither(E.right(1)), O.some(1)) - * assert.deepStrictEqual(O.fromEither(E.left('a')), O.none()) - * - * @category conversions - * @since 1.0.0 - */ -export const fromEither: (self: Either) => Option = either.getRight - -/** - * @category conversions - * @since 1.0.0 - */ -export const toEither: (onNone: LazyArg) => (self: Option) => Either = - either.fromOption - /** * Matches the given `Option` and returns either the provided `onNone` value or the result of the provided `onSome` * function when passed the `Option`'s value. @@ -902,25 +1038,6 @@ export const toEither: (onNone: LazyArg) => (self: Option) => Either export const match = (onNone: LazyArg, onSome: (a: A) => C) => (self: Option): B | C => isNone(self) ? onNone() : onSome(self.value) -/** - * Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` - * - * @param onNone - Function that returns the default value to return if the `Option` is `None` - * @param self - The `Option` to get the value of - * * - * @example - * import { some, none, getOrElse } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' - * - * assert.strictEqual(pipe(some(1), getOrElse(() => 0)), 1) - * assert.strictEqual(pipe(none(), getOrElse(() => 0)), 0) - * - * @category error handling - * @since 1.0.0 - */ -export const getOrElse = (onNone: LazyArg) => - (self: Option): A | B => isNone(self) ? onNone() : self.value - /** * Returns a *smart constructor* from a function that returns a nullable value. * @@ -992,104 +1109,6 @@ export const flatMapNullable = (f: (a: A) => B | null | undefined) => (self: Option): Option> => isNone(self) ? option.none : fromNullable(f(self.value)) -/** - * Returns the value of the option if it is a `Some`, otherwise returns `null`. - * - * @param self - The option to extract the value from - * - * @example - * import { some, none, getOrNull } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' - * - * assert.strictEqual(pipe(some(1), getOrNull), 1) - * assert.strictEqual(pipe(none(), getOrNull), null) - * - * @category conversions - * @since 1.0.0 - */ -export const getOrNull: (self: Option) => A | null = getOrElse(constNull) - -/** - * Returns the value of the option if it is a `Some`, otherwise returns `undefined`. - * - * @param self - The option to extract the value from - * - * @example - * import { some, none, getOrUndefined } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' - * - * assert.strictEqual(pipe(some(1), getOrUndefined), 1) - * assert.strictEqual(pipe(none(), getOrUndefined), undefined) - * - * @category conversions - * @since 1.0.0 - */ -export const getOrUndefined: (self: Option) => A | undefined = getOrElse(constUndefined) - -/** - * Returns the provided option `that` if `self` is `None`, otherwise returns `self`. - * - * @param that - The option to return if `self` option is `None` - * @param self - The first option to be checked - * - * @example - * import * as O from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' - * - * assert.deepStrictEqual( - * pipe( - * O.none(), - * O.orElse(() => O.none()) - * ), - * O.none() - * ) - * assert.deepStrictEqual( - * pipe( - * O.some('a'), - * O.orElse(() => O.none()) - * ), - * O.some('a') - * ) - * assert.deepStrictEqual( - * pipe( - * O.none(), - * O.orElse(() => O.some('b')) - * ), - * O.some('b') - * ) - * assert.deepStrictEqual( - * pipe( - * O.some('a'), - * O.orElse(() => O.some('b')) - * ), - * O.some('a') - * ) - * - * @category error handling - * @since 1.0.0 - */ -export const orElse = (that: LazyArg>) => - (self: Option): Option => isNone(self) ? that() : self - -/** - * Similar to `orElse`, but instead of returning a simple union, it returns an `Either` object, - * which contains information about which of the two options has been chosen. - * This is useful when it's important to know whether the value was retrieved from the first option or the second option. - * - * @param that - The second option to be considered if the first option is `None` - * @param self - The first option to be checked - * - * @category error handling - * @since 1.0.0 - */ -export const orElseEither = ( - that: LazyArg> -) => - (self: Option): Option> => - isNone(self) ? - pipe(that(), map(either.right)) : - pipe(self, map(either.left)) - /** * The `Order` instance allows `Option` values to be compared with * `compare`, whenever there is an `Order` instance for @@ -1194,27 +1213,7 @@ export const exists = (predicate: Predicate) => (self: Option): boolean => isNone(self) ? false : predicate(self.value) /** - * @since 1.0.0 - */ -export const sum = lift2Curried(N.SemigroupSum.combine) - -/** - * @since 1.0.0 - */ -export const multiply = lift2Curried(N.SemigroupMultiply.combine) - -/** - * @since 1.0.0 - */ -export const subtract = lift2Curried((a: number, b: number) => a - b) - -/** - * @since 1.0.0 - */ -export const divide = lift2Curried((a: number, b: number) => a / b) - -/** - * Reduces an `Iterable` of `Option` to a single value of type `B`. + * Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. * * @since 1.0.0 * @@ -1240,12 +1239,42 @@ export const reduceAll = (b: B, f: (b: B, a: A) => B) => return out } +// ------------------------------------------------------------------------------------- +// algebraic operations +// ------------------------------------------------------------------------------------- + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const sum = lift2(N.sum) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const multiply = lift2(N.multiply) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const subtract = lift2(N.subtract) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const divide = lift2(N.divide) + /** + * @category algebraic operations * @since 1.0.0 */ export const sumAll = reduceAll(0, N.SemigroupSum.combine) /** + * @category algebraic operations * @since 1.0.0 */ export const multiplyAll = reduceAll(1, N.SemigroupMultiply.combine) diff --git a/src/These.ts b/src/These.ts index 11ced51d2..934b7ffde 100644 --- a/src/These.ts +++ b/src/These.ts @@ -22,6 +22,7 @@ import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { proto, structural } from "@fp-ts/core/internal/effect" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" +import * as N from "@fp-ts/core/Number" import type { Option } from "@fp-ts/core/Option" import type { Predicate, Refinement } from "@fp-ts/core/Predicate" import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" @@ -985,12 +986,12 @@ export const SemiApplicative: semiApplicative.SemiApplicative( - f: (a: A, b: B) => C -) => ( - fa: Validated, - fb: Validated -) => Validated = semiApplicative - .lift2(SemiApplicative) + f: (a: A) => (b: B) => C +) => ( + that: Validated +) => (self: Validated) => Validated = semiApplicative.lift2( + SemiApplicative +) /** * @since 1.0.0 @@ -1268,3 +1269,31 @@ export const Monad: monad.Monad = { of, flatMap } + +// ------------------------------------------------------------------------------------- +// algebraic operations +// ------------------------------------------------------------------------------------- + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const sum = lift2(N.sum) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const multiply = lift2(N.multiply) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const subtract = lift2(N.subtract) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const divide = lift2(N.divide) diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index c97f6479f..ba06075fc 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -69,25 +69,13 @@ export const andThen = (F: SemiApplicative) => ) => Kind => map2(F)(that, SK) /** - * Lifts a binary function into `F` as uncurried binary function. + * Lifts a binary function into `F`. * * @since 1.0.0 */ export const lift2 = (F: SemiApplicative) => - (f: (a: A, b: B) => C) => - ( - fa: Kind, - fb: Kind - ): Kind => pipe(fa, map2(F)(fb, f)) - -/** - * Lifts a binary function into `F` as curried binary function. - * - * @since 1.0.0 - */ -export const lift2Curried = (F: SemiApplicative) => - (f: (a: A, b: B) => C) => + (f: (a: A) => (b: B) => C) => ( - that: Kind - ): (self: Kind) => Kind => - map2(F)(that, f) + that: Kind + ): (self: Kind) => Kind => + map2(F)(that, (a, b) => f(b)(a)) diff --git a/test/Either.ts b/test/Either.ts index 3cbd5afba..c8c8c425b 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -1,10 +1,10 @@ import * as _ from "@fp-ts/core/Either" import { flow, identity, pipe } from "@fp-ts/core/Function" import { structural } from "@fp-ts/core/internal/effect" +import * as N from "@fp-ts/core/Number" import * as O from "@fp-ts/core/Option" import * as String from "@fp-ts/core/String" import * as Util from "@fp-ts/core/test/util" -import { number } from "@fp-ts/core/typeclass/Equivalence" describe.concurrent("Either", () => { it("instances and derived exports", () => { @@ -52,7 +52,6 @@ describe.concurrent("Either", () => { expect(_.SemiApplicative).exist expect(_.getFirstLeftSemigroup).exist // liftSemigroup expect(_.lift2).exist - expect(_.lift2Curried).exist expect(_.ap).exist expect(_.andThenDiscard).exist expect(_.andThen).exist @@ -71,8 +70,6 @@ describe.concurrent("Either", () => { expect(_.traverse).exist expect(_.sequence).exist expect(_.traverseTap).exist - - expect(_.getSemigroup).exist }) it("structural tracking", () => { @@ -255,7 +252,7 @@ describe.concurrent("Either", () => { }) it("contains", () => { - const contains = _.contains(number) + const contains = _.contains(N.Equivalence) Util.deepStrictEqual(pipe(_.left("a"), contains(2)), false) Util.deepStrictEqual(pipe(_.right(2), contains(2)), true) Util.deepStrictEqual(pipe(_.right(2), contains(1)), false) @@ -501,23 +498,22 @@ describe.concurrent("Either", () => { expect(pipe(_.right(2), _.subtract(_.right(3)))).toEqual(_.right(-1)) }) - it("subtract", () => { + it("divide", () => { expect(pipe(_.left("a"), _.divide(_.right(2)))).toEqual(_.left("a")) expect(pipe(_.right(1), _.divide(_.left("a")))).toEqual(_.left("a")) expect(pipe(_.right(6), _.divide(_.right(3)))).toEqual(_.right(2)) }) - it("sumMany", () => { - expect(_.sumMany(_.left("a"), [])).toEqual(_.left("a")) - expect(_.sumMany(_.left("a"), [_.right(2), _.right(3)])).toEqual(_.right(5)) - expect(_.sumMany(_.right(0), [_.right(2), _.right(3)])).toEqual(_.right(5)) - expect(_.sumMany(_.right(0), [_.right(2), _.left("a"), _.right(3)])).toEqual(_.right(5)) - }) + it("getOptionalSemigroup", () => { + const S = _.getOptionalSemigroup(String.Semigroup) + Util.deepStrictEqual(S.combine(_.left("e"), _.left("e")), _.left("e")) + Util.deepStrictEqual(S.combine(_.left("e"), _.right("a")), _.right("a")) + Util.deepStrictEqual(S.combine(_.right("a"), _.left("e")), _.right("a")) + Util.deepStrictEqual(S.combine(_.right("b"), _.right("a")), _.right("ba")) + Util.deepStrictEqual(S.combine(_.right("a"), _.right("b")), _.right("ab")) - it("multiplyMany", () => { - expect(_.multiplyMany(_.left("a"), [])).toEqual(_.left("a")) - expect(_.multiplyMany(_.left("a"), [_.right(2), _.right(3)])).toEqual(_.right(6)) - expect(_.multiplyMany(_.right(1), [_.right(2), _.right(3)])).toEqual(_.right(6)) - expect(_.multiplyMany(_.right(1), [_.right(2), _.left("a"), _.right(3)])).toEqual(_.right(6)) + Util.deepStrictEqual(S.combineMany(_.right("a"), [_.right("b")]), _.right("ab")) + Util.deepStrictEqual(S.combineMany(_.left("e"), [_.right("b")]), _.right("b")) + Util.deepStrictEqual(S.combineMany(_.right("a"), [_.left("e")]), _.right("a")) }) }) diff --git a/test/Option.ts b/test/Option.ts index 1eeaf04b1..04261e6a1 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -50,7 +50,6 @@ describe.concurrent("Option", () => { expect(_.SemiApplicative).exist expect(_.getFailureSemigroup).exist // liftSemigroup expect(_.lift2).exist - expect(_.lift2Curried).exist expect(_.ap).exist expect(_.andThenDiscard).exist expect(_.andThen).exist @@ -588,7 +587,7 @@ describe.concurrent("Option", () => { expect(pipe(_.some(2), _.subtract(_.some(3)))).toEqual(_.some(-1)) }) - it("subtract", () => { + it("divide", () => { expect(pipe(_.none(), _.divide(_.some(2)))).toEqual(_.none()) expect(pipe(_.some(1), _.divide(_.none()))).toEqual(_.none()) expect(pipe(_.some(6), _.divide(_.some(3)))).toEqual(_.some(2)) diff --git a/test/These.ts b/test/These.ts index 1a9288db1..c4679ba06 100644 --- a/test/These.ts +++ b/test/These.ts @@ -821,4 +821,32 @@ describe("These", () => { Util.deepStrictEqual(pipe(_.both("e1", 1), _.filterMap(f, () => "e2")), _.left("e2")) Util.deepStrictEqual(pipe(_.both("e1", 3), _.filterMap(f, () => "e2")), _.both("e1", 4)) }) + + it("sum", () => { + const e: _.Validated = _.left(["a"]) + expect(pipe(e, _.sum(_.right(2)))).toEqual(e) + expect(pipe(_.right(1), _.sum(e))).toEqual(e) + expect(pipe(_.right(2), _.sum(_.right(3)))).toEqual(_.right(5)) + }) + + it("multiply", () => { + const e: _.Validated = _.left(["a"]) + expect(pipe(e, _.multiply(_.right(2)))).toEqual(e) + expect(pipe(_.right(1), _.multiply(e))).toEqual(e) + expect(pipe(_.right(2), _.multiply(_.right(3)))).toEqual(_.right(6)) + }) + + it("subtract", () => { + const e: _.Validated = _.left(["a"]) + expect(pipe(e, _.subtract(_.right(2)))).toEqual(e) + expect(pipe(_.right(1), _.subtract(e))).toEqual(e) + expect(pipe(_.right(2), _.subtract(_.right(3)))).toEqual(_.right(-1)) + }) + + it("divide", () => { + const e: _.Validated = _.left(["a"]) + expect(pipe(e, _.divide(_.right(2)))).toEqual(e) + expect(pipe(_.right(1), _.divide(e))).toEqual(e) + expect(pipe(_.right(6), _.divide(_.right(3)))).toEqual(_.right(2)) + }) }) diff --git a/test/typeclass/SemiApplicative.ts b/test/typeclass/SemiApplicative.ts index 315eac738..2c9e8ee12 100644 --- a/test/typeclass/SemiApplicative.ts +++ b/test/typeclass/SemiApplicative.ts @@ -40,12 +40,4 @@ describe("SemiApplicative", () => { U.deepStrictEqual(S.combineMany(O.some("a"), [O.some("b"), O.some("c")]), O.some("abc")) }) - - it("lift2", () => { - const sum = _.lift2(O.SemiApplicative)((a: number, b: number) => a + b) - U.deepStrictEqual(sum(O.none(), O.none()), O.none()) - U.deepStrictEqual(sum(O.some(1), O.none()), O.none()) - U.deepStrictEqual(sum(O.none(), O.some(2)), O.none()) - U.deepStrictEqual(sum(O.some(1), O.some(2)), O.some(3)) - }) }) From 615d492ea79b47472da256b4dea6f33835f24d23 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 28 Jan 2023 09:15:03 +0100 Subject: [PATCH 110/255] algebraic operations: add support for bigint --- .changeset/khaki-eagles-lay.md | 5 ++++ docs/modules/Either.ts.md | 49 +++++++++++++++++++++++++++------- docs/modules/Option.ts.md | 37 +++++++++++++++++++++++-- docs/modules/These.ts.md | 47 ++++++++++++++++++++++---------- guides/These.md | 15 +++++++++++ src/Either.ts | 30 ++++++++++++++------- src/Option.ts | 43 +++++++++++++++++++++++++++-- src/These.ts | 34 +++++++++++++---------- test/Either.ts | 18 +++++++++++++ test/Option.ts | 27 +++++++++++++++++++ test/These.ts | 21 +++++++++++++++ 11 files changed, 274 insertions(+), 52 deletions(-) create mode 100644 .changeset/khaki-eagles-lay.md create mode 100644 guides/These.md diff --git a/.changeset/khaki-eagles-lay.md b/.changeset/khaki-eagles-lay.md new file mode 100644 index 000000000..ed5f02669 --- /dev/null +++ b/.changeset/khaki-eagles-lay.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +algebraic operations: add support for bigint diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 0ba51257b..6e3f18094 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -6,16 +6,6 @@ parent: Modules ## Either overview -The `Either` data type is a powerful and flexible tool for handling potentially failed computations. -It has two variants, `Left` and `Right`, which can be used to represent different outcomes. - -The `Left` variant is used to represent a failure, and it can contain useful information such as an error message -or a failure code. The `Right` variant is used to represent a successful outcome, and it can contain the result -of the computation. - -Unlike `Option`, `Either` allows you to attach additional information to the failure case, making it more -informative than a simple `null` or `undefined`. - Added in v1.0.0 --- @@ -25,8 +15,11 @@ Added in v1.0.0 - [algebraic operations](#algebraic-operations) - [divide](#divide) - [multiply](#multiply) + - [multiplyBigint](#multiplybigint) - [subtract](#subtract) + - [subtractBigint](#subtractbigint) - [sum](#sum) + - [sumBigint](#sumbigint) - [combining](#combining) - [getFirstLeftMonoid](#getfirstleftmonoid) - [getFirstLeftSemigroup](#getfirstleftsemigroup) @@ -165,6 +158,18 @@ export declare const multiply: ( Added in v1.0.0 +## multiplyBigint + +**Signature** + +```ts +export declare const multiplyBigint: ( + that: Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + ## subtract **Signature** @@ -177,6 +182,18 @@ export declare const subtract: ( Added in v1.0.0 +## subtractBigint + +**Signature** + +```ts +export declare const subtractBigint: ( + that: Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + ## sum **Signature** @@ -187,6 +204,18 @@ export declare const sum: (that: Either) => (self: Either( + that: Either +) => (self: Either) => Either +``` + +Added in v1.0.0 + # combining ## getFirstLeftMonoid diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index e77cb5ee8..16e5d978d 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -16,9 +16,12 @@ Added in v1.0.0 - [divide](#divide) - [multiply](#multiply) - [multiplyAll](#multiplyall) + - [multiplyBigint](#multiplybigint) - [subtract](#subtract) + - [subtractBigint](#subtractbigint) - [sum](#sum) - [sumAll](#sumall) + - [sumBigint](#sumbigint) - [combinators](#combinators) - [tap](#tap) - [constructors](#constructors) @@ -159,7 +162,17 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiplyAll: (self: Iterable>) => number +export declare const multiplyAll: (self: Iterable>) => number +``` + +Added in v1.0.0 + +## multiplyBigint + +**Signature** + +```ts +export declare const multiplyBigint: (that: Option) => (self: Option) => Option ``` Added in v1.0.0 @@ -174,6 +187,16 @@ export declare const subtract: (that: Option) => (self: Option Added in v1.0.0 +## subtractBigint + +**Signature** + +```ts +export declare const subtractBigint: (that: Option) => (self: Option) => Option +``` + +Added in v1.0.0 + ## sum **Signature** @@ -189,7 +212,17 @@ Added in v1.0.0 **Signature** ```ts -export declare const sumAll: (self: Iterable>) => number +export declare const sumAll: (self: Iterable>) => number +``` + +Added in v1.0.0 + +## sumBigint + +**Signature** + +```ts +export declare const sumBigint: (that: Option) => (self: Option) => Option ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index a71d07091..97c25f55d 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -6,20 +6,6 @@ parent: Modules ## These overview -A data structure providing "inclusive-or" as opposed to `Either`'s "exclusive-or". - -If you interpret `Either` as suggesting the computation may either fail or succeed (exclusively), then -`These` may fail, succeed, or do both at the same time. - -There are a few ways to interpret the `Both` case: - -1. You can think of a computation that has a non-fatal error. -2. You can think of a computation that went as far as it could before erroring. -3. You can think of a computation that keeps track of errors as it completes. - -Another way you can think of `These` is saying that we want to handle `E` kind of data, `A` kind of data, or -both `E` and `A` kind of data at the same time. This is particularly useful when it comes to displaying UI's. - Added in v1.0.0 --- @@ -29,8 +15,11 @@ Added in v1.0.0 - [algebraic operations](#algebraic-operations) - [divide](#divide) - [multiply](#multiply) + - [multiplyBigint](#multiplybigint) - [subtract](#subtract) + - [subtractBigint](#subtractbigint) - [sum](#sum) + - [sumBigint](#sumbigint) - [combining](#combining) - [getFirstLeftMonoid](#getfirstleftmonoid) - [getFirstLeftSemigroup](#getfirstleftsemigroup) @@ -193,6 +182,16 @@ export declare const multiply: (that: any) => (self: any) => any Added in v1.0.0 +## multiplyBigint + +**Signature** + +```ts +export declare const multiplyBigint: (that: any) => (self: any) => any +``` + +Added in v1.0.0 + ## subtract **Signature** @@ -203,6 +202,16 @@ export declare const subtract: (that: any) => (self: any) => any Added in v1.0.0 +## subtractBigint + +**Signature** + +```ts +export declare const subtractBigint: (that: any) => (self: any) => any +``` + +Added in v1.0.0 + ## sum **Signature** @@ -213,6 +222,16 @@ export declare const sum: (that: any) => (self: any) => any Added in v1.0.0 +## sumBigint + +**Signature** + +```ts +export declare const sumBigint: (that: any) => (self: any) => any +``` + +Added in v1.0.0 + # combining ## getFirstLeftMonoid diff --git a/guides/These.md b/guides/These.md new file mode 100644 index 000000000..7e6cab46d --- /dev/null +++ b/guides/These.md @@ -0,0 +1,15 @@ +# The `These` data type + +## A data structure providing "inclusive-or" as opposed to `Either`'s "exclusive-or". + +If you interpret `Either` as suggesting the computation may either fail or succeed (exclusively), then +`These` may fail, succeed, or do both at the same time. + +There are a few ways to interpret the `Both` case: + +1. You can think of a computation that has a non-fatal error. +2. You can think of a computation that went as far as it could before erroring. +3. You can think of a computation that keeps track of errors as it completes. + +Another way you can think of `These` is saying that we want to handle `E` kind of data, `A` kind of data, or +both `E` and `A` kind of data at the same time. This is particularly useful when it comes to displaying UI's. diff --git a/src/Either.ts b/src/Either.ts index 29be75d8b..a524cb4a4 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1,16 +1,8 @@ /** - * The `Either` data type is a powerful and flexible tool for handling potentially failed computations. - * It has two variants, `Left` and `Right`, which can be used to represent different outcomes. - * - * The `Left` variant is used to represent a failure, and it can contain useful information such as an error message - * or a failure code. The `Right` variant is used to represent a successful outcome, and it can contain the result - * of the computation. - * - * Unlike `Option`, `Either` allows you to attach additional information to the failure case, making it more - * informative than a simple `null` or `undefined`. - * * @since 1.0.0 */ + +import * as BI from "@fp-ts/core/Bigint" import type { LazyArg } from "@fp-ts/core/Function" import { constNull, constUndefined, identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" @@ -1137,3 +1129,21 @@ export const subtract = lift2(N.subtract) * @since 1.0.0 */ export const divide = lift2(N.divide) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const sumBigint = lift2(BI.sum) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const multiplyBigint = lift2(BI.multiply) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const subtractBigint = lift2(BI.subtract) diff --git a/src/Option.ts b/src/Option.ts index 82c110c85..56b8b5f04 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1,6 +1,7 @@ /** * @since 1.0.0 */ +import * as BI from "@fp-ts/core/Bigint" import type { Either } from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" @@ -1271,10 +1272,48 @@ export const divide = lift2(N.divide) * @category algebraic operations * @since 1.0.0 */ -export const sumAll = reduceAll(0, N.SemigroupSum.combine) +export const sumBigint = lift2(BI.sum) /** * @category algebraic operations * @since 1.0.0 */ -export const multiplyAll = reduceAll(1, N.SemigroupMultiply.combine) +export const multiplyBigint = lift2(BI.multiply) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const subtractBigint = lift2(BI.subtract) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const sumAll = (self: Iterable>): number => { + let out = 0 + for (const oa of self) { + if (isSome(oa)) { + out += oa.value + } + } + return out +} + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const multiplyAll = (self: Iterable>): number => { + let out = 1 + for (const oa of self) { + if (isSome(oa)) { + const a: number = oa.value + if (a === 0) { + return 0 + } + out *= a + } + } + return out +} diff --git a/src/These.ts b/src/These.ts index 934b7ffde..333cc3593 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1,20 +1,8 @@ /** - * A data structure providing "inclusive-or" as opposed to `Either`'s "exclusive-or". - * - * If you interpret `Either` as suggesting the computation may either fail or succeed (exclusively), then - * `These` may fail, succeed, or do both at the same time. - * - * There are a few ways to interpret the `Both` case: - * - * 1) You can think of a computation that has a non-fatal error. - * 2) You can think of a computation that went as far as it could before erroring. - * 3) You can think of a computation that keeps track of errors as it completes. - * - * Another way you can think of `These` is saying that we want to handle `E` kind of data, `A` kind of data, or - * both `E` and `A` kind of data at the same time. This is particularly useful when it comes to displaying UI's. - * * @since 1.0.0 */ + +import * as BI from "@fp-ts/core/Bigint" import type { Either, Left, Right } from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" @@ -1297,3 +1285,21 @@ export const subtract = lift2(N.subtract) * @since 1.0.0 */ export const divide = lift2(N.divide) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const sumBigint = lift2(BI.sum) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const multiplyBigint = lift2(BI.multiply) + +/** + * @category algebraic operations + * @since 1.0.0 + */ +export const subtractBigint = lift2(BI.subtract) diff --git a/test/Either.ts b/test/Either.ts index c8c8c425b..c50168dd0 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -504,6 +504,24 @@ describe.concurrent("Either", () => { expect(pipe(_.right(6), _.divide(_.right(3)))).toEqual(_.right(2)) }) + it("sumBigint", () => { + expect(pipe(_.left("a"), _.sumBigint(_.right(2n)))).toEqual(_.left("a")) + expect(pipe(_.right(1n), _.sumBigint(_.left("a")))).toEqual(_.left("a")) + expect(pipe(_.right(2n), _.sumBigint(_.right(3n)))).toEqual(_.right(5n)) + }) + + it("multiplyBigint", () => { + expect(pipe(_.left("a"), _.multiplyBigint(_.right(2n)))).toEqual(_.left("a")) + expect(pipe(_.right(1n), _.multiplyBigint(_.left("a")))).toEqual(_.left("a")) + expect(pipe(_.right(2n), _.multiplyBigint(_.right(3n)))).toEqual(_.right(6n)) + }) + + it("subtractBigint", () => { + expect(pipe(_.left("a"), _.subtractBigint(_.right(2n)))).toEqual(_.left("a")) + expect(pipe(_.right(1n), _.subtractBigint(_.left("a")))).toEqual(_.left("a")) + expect(pipe(_.right(2n), _.subtractBigint(_.right(3n)))).toEqual(_.right(-1n)) + }) + it("getOptionalSemigroup", () => { const S = _.getOptionalSemigroup(String.Semigroup) Util.deepStrictEqual(S.combine(_.left("e"), _.left("e")), _.left("e")) diff --git a/test/Option.ts b/test/Option.ts index 04261e6a1..65e712b04 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -2,6 +2,7 @@ import { equivalence } from "@fp-ts/core" import * as E from "@fp-ts/core/Either" import { pipe } from "@fp-ts/core/Function" import { structural } from "@fp-ts/core/internal/effect" +import * as N from "@fp-ts/core/Number" import * as _ from "@fp-ts/core/Option" import * as ReadonlyArray from "@fp-ts/core/ReadonlyArray" import * as S from "@fp-ts/core/String" @@ -569,6 +570,13 @@ describe.concurrent("Option", () => { expect(pipe(_.some(1), _.map2(_.some(2), (a, b) => a + b))).toEqual(_.some(3)) }) + it("reduceAll", () => { + const sumAll = _.reduceAll(0, N.SemigroupSum.combine) + expect(sumAll([])).toEqual(0) + expect(sumAll([_.some(2), _.some(3)])).toEqual(5) + expect(sumAll([_.some(2), _.none(), _.some(3)])).toEqual(5) + }) + it("sum", () => { expect(pipe(_.none(), _.sum(_.some(2)))).toEqual(_.none()) expect(pipe(_.some(1), _.sum(_.none()))).toEqual(_.none()) @@ -593,6 +601,24 @@ describe.concurrent("Option", () => { expect(pipe(_.some(6), _.divide(_.some(3)))).toEqual(_.some(2)) }) + it("sumBigint", () => { + expect(pipe(_.none(), _.sumBigint(_.some(2n)))).toEqual(_.none()) + expect(pipe(_.some(1n), _.sumBigint(_.none()))).toEqual(_.none()) + expect(pipe(_.some(2n), _.sumBigint(_.some(3n)))).toEqual(_.some(5n)) + }) + + it("multiplyBigint", () => { + expect(pipe(_.none(), _.multiplyBigint(_.some(2n)))).toEqual(_.none()) + expect(pipe(_.some(1n), _.multiplyBigint(_.none()))).toEqual(_.none()) + expect(pipe(_.some(2n), _.multiplyBigint(_.some(3n)))).toEqual(_.some(6n)) + }) + + it("subtractBigint", () => { + expect(pipe(_.none(), _.subtractBigint(_.some(2n)))).toEqual(_.none()) + expect(pipe(_.some(1n), _.subtractBigint(_.none()))).toEqual(_.none()) + expect(pipe(_.some(2n), _.subtractBigint(_.some(3n)))).toEqual(_.some(-1n)) + }) + it("reduce", () => { expect(pipe(_.none(), _.reduce(0, (b, a) => b + a))).toEqual(0) expect(pipe(_.some(1), _.reduce(0, (b, a) => b + a))).toEqual(1) @@ -608,5 +634,6 @@ describe.concurrent("Option", () => { expect(_.multiplyAll([])).toEqual(1) expect(_.multiplyAll([_.some(2), _.some(3)])).toEqual(6) expect(_.multiplyAll([_.some(2), _.none(), _.some(3)])).toEqual(6) + expect(_.multiplyAll([_.some(2), _.some(0), _.some(3)])).toEqual(0) }) }) diff --git a/test/These.ts b/test/These.ts index c4679ba06..cc34bbe1c 100644 --- a/test/These.ts +++ b/test/These.ts @@ -849,4 +849,25 @@ describe("These", () => { expect(pipe(_.right(1), _.divide(e))).toEqual(e) expect(pipe(_.right(6), _.divide(_.right(3)))).toEqual(_.right(2)) }) + + it("sumBigint", () => { + const e: _.Validated = _.left(["a"]) + expect(pipe(e, _.sumBigint(_.right(2n)))).toEqual(e) + expect(pipe(_.right(1n), _.sumBigint(e))).toEqual(e) + expect(pipe(_.right(2n), _.sumBigint(_.right(3n)))).toEqual(_.right(5n)) + }) + + it("multiplyBigint", () => { + const e: _.Validated = _.left(["a"]) + expect(pipe(e, _.multiplyBigint(_.right(2n)))).toEqual(e) + expect(pipe(_.right(1n), _.multiplyBigint(e))).toEqual(e) + expect(pipe(_.right(2n), _.multiplyBigint(_.right(3n)))).toEqual(_.right(6n)) + }) + + it("subtractBigint", () => { + const e: _.Validated = _.left(["a"]) + expect(pipe(e, _.subtractBigint(_.right(2n)))).toEqual(e) + expect(pipe(_.right(1n), _.subtractBigint(e))).toEqual(e) + expect(pipe(_.right(2n), _.subtractBigint(_.right(3n)))).toEqual(_.right(-1n)) + }) }) From 85bb36ba68f0f168d44f1d7cb458c39c214d352d Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 28 Jan 2023 09:57:28 +0100 Subject: [PATCH 111/255] rename map2 to zipWith --- .changeset/great-carrots-build.md | 5 -- docs/modules/Either.ts.md | 31 +++++----- docs/modules/Option.ts.md | 25 ++++---- docs/modules/These.ts.md | 14 +++++ docs/modules/typeclass/SemiApplicative.ts.md | 63 ++++++++++---------- src/Either.ts | 6 +- src/Option.ts | 8 ++- src/These.ts | 11 ++++ src/typeclass/SemiApplicative.ts | 14 ++--- test/Either.ts | 8 +-- test/Option.ts | 8 +-- test/These.ts | 7 +++ 12 files changed, 118 insertions(+), 82 deletions(-) delete mode 100644 .changeset/great-carrots-build.md diff --git a/.changeset/great-carrots-build.md b/.changeset/great-carrots-build.md deleted file mode 100644 index 4bdfd9e9f..000000000 --- a/.changeset/great-carrots-build.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -Option: renaming diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 6e3f18094..7ea4acd33 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -91,7 +91,6 @@ Added in v1.0.0 - [liftNullable](#liftnullable) - [liftOption](#liftoption) - [liftPredicate](#liftpredicate) - - [map2](#map2) - [mapping](#mapping) - [as](#as) - [asUnit](#asunit) @@ -105,6 +104,8 @@ Added in v1.0.0 - [Right (interface)](#right-interface) - [pattern matching](#pattern-matching) - [match](#match) +- [products](#products) + - [zipWith](#zipwith) - [sequencing](#sequencing) - [andThenDiscard](#andthendiscard) - [flatMap](#flatmap) @@ -1072,19 +1073,6 @@ assert.deepStrictEqual( Added in v1.0.0 -## map2 - -**Signature** - -```ts -export declare const map2: ( - fb: Either, - f: (a: A, b: B) => C -) => (fa: Either) => Either -``` - -Added in v1.0.0 - # mapping ## as @@ -1223,6 +1211,21 @@ assert.strictEqual(pipe(E.left(['error 1', 'error 2']), E.match(onLeft, onRight) Added in v1.0.0 +# products + +## zipWith + +**Signature** + +```ts +export declare const zipWith: ( + fb: Either, + f: (a: A, b: B) => C +) => (fa: Either) => Either +``` + +Added in v1.0.0 + # sequencing ## andThenDiscard diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 16e5d978d..4a7ce6fc0 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -90,7 +90,6 @@ Added in v1.0.0 - [liftEither](#lifteither) - [liftNullable](#liftnullable) - [liftPredicate](#liftpredicate) - - [map2](#map2) - [mapping](#mapping) - [as](#as) - [asUnit](#asunit) @@ -102,6 +101,8 @@ Added in v1.0.0 - [Some (interface)](#some-interface) - [pattern matching](#pattern-matching) - [match](#match) +- [products](#products) + - [zipWith](#zipwith) - [sequencing](#sequencing) - [andThenDiscard](#andthendiscard) - [flatMap](#flatmap) @@ -1095,16 +1096,6 @@ assert.deepStrictEqual(getOption(1), O.some(1)) Added in v1.0.0 -## map2 - -**Signature** - -```ts -export declare const map2: (fb: Option, f: (a: A, b: B) => C) => (fa: Option) => Option -``` - -Added in v1.0.0 - # mapping ## as @@ -1234,6 +1225,18 @@ assert.strictEqual( Added in v1.0.0 +# products + +## zipWith + +**Signature** + +```ts +export declare const zipWith: (fb: Option, f: (a: A, b: B) => C) => (fa: Option) => Option +``` + +Added in v1.0.0 + # sequencing ## andThenDiscard diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 97c25f55d..2c7cc515e 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -131,6 +131,8 @@ Added in v1.0.0 - [match](#match) - [predicates](#predicates) - [exists](#exists) +- [products](#products) + - [zipWith](#zipwith) - [sequencing](#sequencing) - [andThenDiscard](#andthendiscard) - [flatMap](#flatmap) @@ -1302,6 +1304,18 @@ export declare const exists: (predicate: any) => (self: any) => boolean Added in v1.0.0 +# products + +## zipWith + +**Signature** + +```ts +export declare const zipWith: (fb: any, f: (a: A, b: B) => C) => (fa: any) => any +``` + +Added in v1.0.0 + # sequencing ## andThenDiscard diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index 8e211ae69..b6378fc86 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -12,102 +12,103 @@ Added in v1.0.0

Table of contents

+- [lifting](#lifting) + - [lift2](#lift2) + - [liftSemigroup](#liftsemigroup) - [type class](#type-class) - [SemiApplicative (interface)](#semiapplicative-interface) - [utils](#utils) - [andThen](#andthen) - [andThenDiscard](#andthendiscard) - [ap](#ap) - - [lift2](#lift2) - - [liftSemigroup](#liftsemigroup) - - [map2](#map2) + - [zipWith](#zipwith) --- -# type class +# lifting -## SemiApplicative (interface) +## lift2 + +Lifts a binary function into `F`. **Signature** ```ts -export interface SemiApplicative extends SemiProduct, Covariant {} +export declare const lift2: ( + F: SemiApplicative +) => (f: (a: A) => (b: B) => C) => (that: any) => (self: any) => any ``` Added in v1.0.0 -# utils +## liftSemigroup -## andThen +Lift a `Semigroup` into 'F', the inner values are combined using the provided `Semigroup`. **Signature** ```ts -export declare const andThen: ( - F: SemiApplicative -) => (that: any) => (self: any) => any +export declare const liftSemigroup: (F: SemiApplicative) => (S: any) => any ``` Added in v1.0.0 -## andThenDiscard +# type class + +## SemiApplicative (interface) **Signature** ```ts -export declare const andThenDiscard: ( - F: SemiApplicative -) => (that: any) => (self: any) => any +export interface SemiApplicative extends SemiProduct, Covariant {} ``` Added in v1.0.0 -## ap +# utils + +## andThen **Signature** ```ts -export declare const ap: ( +export declare const andThen: ( F: SemiApplicative -) => (that: any) => (self: any) => any +) => (that: any) => (self: any) => any ``` Added in v1.0.0 -## lift2 - -Lifts a binary function into `F`. +## andThenDiscard **Signature** ```ts -export declare const lift2: ( +export declare const andThenDiscard: ( F: SemiApplicative -) => (f: (a: A) => (b: B) => C) => (that: any) => (self: any) => any +) => (that: any) => (self: any) => any ``` Added in v1.0.0 -## liftSemigroup - -Lift a `Semigroup` into 'F', the inner values are combined using the provided `Semigroup`. +## ap **Signature** ```ts -export declare const liftSemigroup: (F: SemiApplicative) => (S: any) => any +export declare const ap: ( + F: SemiApplicative +) => (that: any) => (self: any) => any ``` Added in v1.0.0 -## map2 - -Binary mapping into `F` context. +## zipWith **Signature** ```ts -export declare const map2: ( +export declare const zipWith: ( F: SemiApplicative ) => (fb: any, f: (a: A, b: B) => C) => (fa: any) => any ``` diff --git a/src/Either.ts b/src/Either.ts index a524cb4a4..eed8e11ae 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -479,13 +479,13 @@ export const lift2: ( .lift2(SemiApplicative) /** - * @category lifting + * @category products * @since 1.0.0 */ -export const map2: ( +export const zipWith: ( fb: Either, f: (a: A, b: B) => C -) => (fa: Either) => Either = semiApplicative.map2(SemiApplicative) +) => (fa: Either) => Either = semiApplicative.zipWith(SemiApplicative) /** * @since 1.0.0 diff --git a/src/Option.ts b/src/Option.ts index 56b8b5f04..792189a7b 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -785,11 +785,13 @@ export const lift2: ( .lift2(SemiApplicative) /** - * @category lifting + * @category products * @since 1.0.0 */ -export const map2: (fb: Option, f: (a: A, b: B) => C) => (fa: Option
) => Option = - semiApplicative.map2(SemiApplicative) +export const zipWith: ( + fb: Option, + f: (a: A, b: B) => C +) => (fa: Option) => Option = semiApplicative.zipWith(SemiApplicative) /** * @since 1.0.0 diff --git a/src/These.ts b/src/These.ts index 333cc3593..ea198ea05 100644 --- a/src/These.ts +++ b/src/These.ts @@ -981,6 +981,17 @@ export const lift2: ( SemiApplicative ) +/** + * @category products + * @since 1.0.0 + */ +export const zipWith: ( + fb: Validated, + f: (a: A, b: B) => C +) => (fa: Validated) => Validated = semiApplicative.zipWith( + SemiApplicative +) + /** * @since 1.0.0 */ diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index ba06075fc..3ab3c19ec 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -16,6 +16,7 @@ export interface SemiApplicative extends SemiProduct, C /** * Lift a `Semigroup` into 'F', the inner values are combined using the provided `Semigroup`. * + * @category lifting * @since 1.0.0 */ export const liftSemigroup = (F: SemiApplicative) => @@ -29,11 +30,9 @@ export const liftSemigroup = (F: SemiApplicative) => }) /** - * Binary mapping into `F` context. - * * @since 1.0.0 */ -export const map2 = (F: SemiApplicative) => +export const zipWith = (F: SemiApplicative) => (fb: Kind, f: (a: A, b: B) => C) => (fa: Kind): Kind => pipe(F.product(fa, fb), F.map(([a, b]) => f(a, b))) @@ -46,7 +45,7 @@ export const ap = (F: SemiApplicative) => that: Kind ): ( self: Kind B> - ) => Kind => map2(F)(that, (f, a) => f(a)) + ) => Kind => zipWith(F)(that, (f, a) => f(a)) /** * @since 1.0.0 @@ -56,7 +55,7 @@ export const andThenDiscard = (F: SemiApplicative) => that: Kind ): ( self: Kind - ) => Kind => map2(F)(that, identity) + ) => Kind => zipWith(F)(that, identity) /** * @since 1.0.0 @@ -66,11 +65,12 @@ export const andThen = (F: SemiApplicative) => that: Kind ): ( self: Kind - ) => Kind => map2(F)(that, SK) + ) => Kind => zipWith(F)(that, SK) /** * Lifts a binary function into `F`. * + * @category lifting * @since 1.0.0 */ export const lift2 = (F: SemiApplicative) => @@ -78,4 +78,4 @@ export const lift2 = (F: SemiApplicative) => ( that: Kind ): (self: Kind) => Kind => - map2(F)(that, (a, b) => f(b)(a)) + zipWith(F)(that, (a, b) => f(b)(a)) diff --git a/test/Either.ts b/test/Either.ts index c50168dd0..2ff73eadd 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -474,10 +474,10 @@ describe.concurrent("Either", () => { Util.deepStrictEqual(f(""), _.left(new Error("empty string"))) }) - it("map2", () => { - expect(pipe(_.left("a"), _.map2(_.right(2), (a, b) => a + b))).toEqual(_.left("a")) - expect(pipe(_.right(1), _.map2(_.left("a"), (a, b) => a + b))).toEqual(_.left("a")) - expect(pipe(_.right(1), _.map2(_.right(2), (a, b) => a + b))).toEqual(_.right(3)) + it("zipWith", () => { + expect(pipe(_.left("a"), _.zipWith(_.right(2), (a, b) => a + b))).toEqual(_.left("a")) + expect(pipe(_.right(1), _.zipWith(_.left("a"), (a, b) => a + b))).toEqual(_.left("a")) + expect(pipe(_.right(1), _.zipWith(_.right(2), (a, b) => a + b))).toEqual(_.right(3)) }) it("sum", () => { diff --git a/test/Option.ts b/test/Option.ts index 65e712b04..fed2b3e92 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -564,10 +564,10 @@ describe.concurrent("Option", () => { ) }) - it("map2", () => { - expect(pipe(_.none(), _.map2(_.some(2), (a, b) => a + b))).toEqual(_.none()) - expect(pipe(_.some(1), _.map2(_.none(), (a, b) => a + b))).toEqual(_.none()) - expect(pipe(_.some(1), _.map2(_.some(2), (a, b) => a + b))).toEqual(_.some(3)) + it("zipWith", () => { + expect(pipe(_.none(), _.zipWith(_.some(2), (a, b) => a + b))).toEqual(_.none()) + expect(pipe(_.some(1), _.zipWith(_.none(), (a, b) => a + b))).toEqual(_.none()) + expect(pipe(_.some(1), _.zipWith(_.some(2), (a, b) => a + b))).toEqual(_.some(3)) }) it("reduceAll", () => { diff --git a/test/These.ts b/test/These.ts index cc34bbe1c..8c86ebf68 100644 --- a/test/These.ts +++ b/test/These.ts @@ -822,6 +822,13 @@ describe("These", () => { Util.deepStrictEqual(pipe(_.both("e1", 3), _.filterMap(f, () => "e2")), _.both("e1", 4)) }) + it("zipWith", () => { + const e: _.Validated = _.left(["a"]) + expect(pipe(e, _.zipWith(_.right(2), (a, b) => a + b))).toEqual(e) + expect(pipe(_.right(1), _.zipWith(e, (a, b) => a + b))).toEqual(e) + expect(pipe(_.right(1), _.zipWith(_.right(2), (a, b) => a + b))).toEqual(_.right(3)) + }) + it("sum", () => { const e: _.Validated = _.left(["a"]) expect(pipe(e, _.sum(_.right(2)))).toEqual(e) From b3e7ff34596b9cf90cc94c7349cf340fb0df82ef Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 28 Jan 2023 17:36:31 +0100 Subject: [PATCH 112/255] Identity: remove exports except do notation ones --- .changeset/brown-foxes-explain.md | 5 + docs/modules/Identity.ts.md | 398 ------------------- docs/modules/Option.ts.md | 66 ++- docs/modules/typeclass/SemiApplicative.ts.md | 2 + src/Identity.ts | 312 +-------------- src/Option.ts | 108 ++++- src/typeclass/SemiApplicative.ts | 6 + test/Identity.ts | 55 +-- 8 files changed, 184 insertions(+), 768 deletions(-) create mode 100644 .changeset/brown-foxes-explain.md diff --git a/.changeset/brown-foxes-explain.md b/.changeset/brown-foxes-explain.md new file mode 100644 index 000000000..7d44fcbe0 --- /dev/null +++ b/.changeset/brown-foxes-explain.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": minor +--- + +Identity: remove exports except do notation ones diff --git a/docs/modules/Identity.ts.md b/docs/modules/Identity.ts.md index 3d7a07b23..3409f8528 100644 --- a/docs/modules/Identity.ts.md +++ b/docs/modules/Identity.ts.md @@ -12,24 +12,11 @@ Added in v1.0.0

Table of contents

-- [constructors](#constructors) - - [of](#of) -- [conversions](#conversions) - - [toArray](#toarray) - - [toArrayWith](#toarraywith) - [do notation](#do-notation) - [Do](#do) - - [andThenBind](#andthenbind) - [bind](#bind) - [bindTo](#bindto) - [let](#let) -- [folding](#folding) - - [foldMap](#foldmap) - - [foldMapKind](#foldmapkind) - - [reduce](#reduce) - - [reduceKind](#reducekind) - - [reduceRight](#reduceright) - - [reduceRightKind](#reducerightkind) - [instances](#instances) - [Applicative](#applicative) - [Chainable](#chainable) @@ -46,75 +33,14 @@ Added in v1.0.0 - [Traversable](#traversable) - [getSemiAlternative](#getsemialternative) - [getSemiCoproduct](#getsemicoproduct) - - [liftSemigroup](#liftsemigroup) -- [lifting](#lifting) - - [lift2](#lift2) -- [mapping](#mapping) - - [as](#as) - - [asUnit](#asunit) - - [flap](#flap) - [models](#models) - [Identity (type alias)](#identity-type-alias) -- [sequencing](#sequencing) - - [andThenDiscard](#andthendiscard) - - [flatMap](#flatmap) -- [traversing](#traversing) - - [sequence](#sequence) - - [traverse](#traverse) - - [traverseTap](#traversetap) - [type lambdas](#type-lambdas) - [IdentityTypeLambda (interface)](#identitytypelambda-interface) - [IdentityTypeLambdaFix (interface)](#identitytypelambdafix-interface) -- [utils](#utils) - - [andThen](#andthen) - - [ap](#ap) - - [composeKleisliArrow](#composekleisliarrow) - - [element](#element) - - [flatten](#flatten) - - [liftMonoid](#liftmonoid) - - [map](#map) - - [struct](#struct) - - [tap](#tap) - - [tuple](#tuple) - - [tupled](#tupled) - - [unit](#unit) --- -# constructors - -## of - -**Signature** - -```ts -export declare const of:
(a: A) => A -``` - -Added in v1.0.0 - -# conversions - -## toArray - -**Signature** - -```ts -export declare const toArray: (self: A) => A[] -``` - -Added in v1.0.0 - -## toArrayWith - -**Signature** - -```ts -export declare const toArrayWith: (f: (a: A) => B) => (self: A) => B[] -``` - -Added in v1.0.0 - # do notation ## Do @@ -127,21 +53,6 @@ export declare const Do: {} Added in v1.0.0 -## andThenBind - -A variant of `bind` that sequentially ignores the scope. - -**Signature** - -```ts -export declare const andThenBind: ( - name: Exclude, - that: B -) => (self: A) => { [K in N | keyof A]: K extends keyof A ? A[K] : B } -``` - -Added in v1.0.0 - ## bind **Signature** @@ -178,72 +89,6 @@ export declare const let: ( Added in v1.0.0 -# folding - -## foldMap - -**Signature** - -```ts -export declare const foldMap: (M: any) => (f: (a: A) => M) => (self: A) => M -``` - -Added in v1.0.0 - -## foldMapKind - -**Signature** - -```ts -export declare const foldMapKind: (G: any) => (f: (a: A) => any) => (self: A) => any -``` - -Added in v1.0.0 - -## reduce - -**Signature** - -```ts -export declare const reduce: (b: B, f: (b: B, a: A) => B) => (self: A) => B -``` - -Added in v1.0.0 - -## reduceKind - -**Signature** - -```ts -export declare const reduceKind: ( - G: any -) => (b: B, f: (b: B, a: A) => any) => (self: A) => any -``` - -Added in v1.0.0 - -## reduceRight - -**Signature** - -```ts -export declare const reduceRight: (b: B, f: (b: B, a: A) => B) => (self: A) => B -``` - -Added in v1.0.0 - -## reduceRightKind - -**Signature** - -```ts -export declare const reduceRightKind: ( - G: any -) => (b: B, f: (b: B, a: A) => any) => (self: A) => any -``` - -Added in v1.0.0 - # instances ## Applicative @@ -396,66 +241,6 @@ export declare const getSemiCoproduct: (S: any) => any Added in v1.0.0 -## liftSemigroup - -**Signature** - -```ts -export declare const liftSemigroup: (S: any) => any -``` - -Added in v1.0.0 - -# lifting - -## lift2 - -Lifts a binary function into `Identity`. - -**Signature** - -```ts -export declare const lift2: (f: (a: A) => (b: B) => C) => (fa: A) => (fb: B) => C -``` - -Added in v1.0.0 - -# mapping - -## as - -Maps the success value of this effect to the specified constant value. - -**Signature** - -```ts -export declare const as: (b: B) => <_>(self: _) => B -``` - -Added in v1.0.0 - -## asUnit - -Returns the effect resulting from mapping the success of this effect to unit. - -**Signature** - -```ts -export declare const asUnit: <_>(self: _) => Identity -``` - -Added in v1.0.0 - -## flap - -**Signature** - -```ts -export declare const flap: (a: A) => (fab: (a: A) => B) => B -``` - -Added in v1.0.0 - # models ## Identity (type alias) @@ -468,63 +253,6 @@ export type Identity = A Added in v1.0.0 -# sequencing - -## andThenDiscard - -Sequences the specified effect after this effect, but ignores the value -produced by the effect. - -**Signature** - -```ts -export declare const andThenDiscard: <_>(that: _) => (self: A) => A -``` - -Added in v1.0.0 - -## flatMap - -**Signature** - -```ts -export declare const flatMap: (f: (a: A) => B) => (self: A) => B -``` - -Added in v1.0.0 - -# traversing - -## sequence - -**Signature** - -```ts -export declare const sequence: (F: any) => (fas: any) => any -``` - -Added in v1.0.0 - -## traverse - -**Signature** - -```ts -export declare const traverse: (F: any) => (f: (a: A) => any) => (self: A) => any -``` - -Added in v1.0.0 - -## traverseTap - -**Signature** - -```ts -export declare const traverseTap: (F: any) => (f: (a: A) => any) => (self: A) => any -``` - -Added in v1.0.0 - # type lambdas ## IdentityTypeLambda (interface) @@ -550,129 +278,3 @@ export interface IdentityTypeLambdaFix extends TypeLambda { ``` Added in v1.0.0 - -# utils - -## andThen - -**Signature** - -```ts -export declare const andThen: (that: B) => <_>(self: _) => B -``` - -Added in v1.0.0 - -## ap - -**Signature** - -```ts -export declare const ap: (fa: A) => (self: (a: A) => B) => B -``` - -Added in v1.0.0 - -## composeKleisliArrow - -**Signature** - -```ts -export declare const composeKleisliArrow: (bfc: (b: B) => C) => (afb: (a: A) => B) => (a: A) => C -``` - -Added in v1.0.0 - -## element - -Adds an element to the end of a tuple. - -**Signature** - -```ts -export declare const element: (fb: B) => (self: A) => [...A, B] -``` - -Added in v1.0.0 - -## flatten - -**Signature** - -```ts -export declare const flatten: (self: A) => A -``` - -Added in v1.0.0 - -## liftMonoid - -**Signature** - -```ts -export declare const liftMonoid: (M: any) => any -``` - -Added in v1.0.0 - -## map - -**Signature** - -```ts -export declare const map: (f: (a: A) => B) => (self: A) => B -``` - -Added in v1.0.0 - -## struct - -**Signature** - -```ts -export declare const struct: >(r: R) => { [K in keyof R]: R[K] } -``` - -Added in v1.0.0 - -## tap - -Returns an effect that effectfully "peeks" at the success of this effect. - -**Signature** - -```ts -export declare const tap: (f: (a: A) => _) => (self: A) => A -``` - -Added in v1.0.0 - -## tuple - -**Signature** - -```ts -export declare const tuple: (...tuple: T) => { [I in keyof T]: T[I] } -``` - -Added in v1.0.0 - -## tupled - -**Signature** - -```ts -export declare const tupled: (self: A) => [A] -``` - -Added in v1.0.0 - -## unit - -**Signature** - -```ts -export declare const unit: void -``` - -Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 4a7ce6fc0..8c7effa35 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -249,7 +249,10 @@ Added in v1.0.0 ## none -Creates a new `Option` that represents a absence of value. +Creates a new `Option` that represents the absence of a value. + +This can be useful when working with optional values or to represent a computation that failed. +It returns a new `Option` object that does not contain any value. **Signature** @@ -263,10 +266,12 @@ Added in v1.0.0 Creates a new `Option` that wraps the given value. +This can be useful when working with optional values or to represent a computation that succeeded with a value. + **Signature** ```ts -export declare const some: (a: A) => Option +export declare const some: (value: A) => Option ``` Added in v1.0.0 @@ -297,12 +302,25 @@ Added in v1.0.0 ## fromIterable +Converts an `Iterable` of values into an `Option`. Returns the first value of the `Iterable` wrapped in a `Some` +if the `Iterable` is not empty, otherwise returns `None`. + **Signature** ```ts export declare const fromIterable: (collection: Iterable) => Option ``` +**Example** + +```ts +import { fromIterable, some, none } from '@fp-ts/core/Option' + +const collection = [1, 2, 3] +assert.deepStrictEqual(fromIterable(collection), some(1)) +assert.deepStrictEqual(fromIterable([]), none()) +``` + Added in v1.0.0 ## fromNullable @@ -313,7 +331,7 @@ returns the value wrapped in a `Some`. **Signature** ```ts -export declare const fromNullable: (a: A) => Option> +export declare const fromNullable: (nullableValue: A) => Option> ``` **Example** @@ -330,12 +348,26 @@ Added in v1.0.0 ## toEither +Converts an `Option` to an `Either`, allowing you to provide a value to be used in the case of a `None`. + **Signature** ```ts export declare const toEither: (onNone: any) => (self: Option) => any ``` +**Example** + +```ts +import { pipe } from '@fp-ts/core/Function' +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +const onNone = () => 'error' +assert.deepStrictEqual(pipe(O.some(1), O.toEither(onNone)), E.right(1)) +assert.deepStrictEqual(pipe(O.none(), O.toEither(onNone)), E.left('error')) +``` + Added in v1.0.0 ## toRefinement @@ -540,6 +572,7 @@ Added in v1.0.0 Similar to `orElse`, but instead of returning a simple union, it returns an `Either` object, which contains information about which of the two options has been chosen. + This is useful when it's important to know whether the value was retrieved from the first option or the second option. **Signature** @@ -615,7 +648,7 @@ Checks if the specified value is an instance of `Option`, returns `true` if it i **Signature** ```ts -export declare const isOption: (u: unknown) => u is Option +export declare const isOption: (input: unknown) => input is Option ``` **Example** @@ -953,6 +986,16 @@ Returns the contained value if the option is `Some`, otherwise throws an error. export declare const getOrThrow: (onNone?: any) => (self: Option) => A ``` +**Example** + +```ts +import { pipe } from '@fp-ts/core/Function' +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual(pipe(O.some(1), O.getOrThrow()), 1) +assert.throws(() => pipe(O.none(), O.getOrThrow())) +``` + Added in v1.0.0 ## getOrUndefined @@ -979,7 +1022,7 @@ Added in v1.0.0 ## liftThrowable -Lifts a function that may throw to one returning a `Option`. +A utility function that lifts a function that throws exceptions into a function that returns an `Option`. **Signature** @@ -1020,7 +1063,8 @@ Added in v1.0.0 ## lift2 -Lifts a binary function into `Option` as uncurried binary function. +Applies a function to the contained value of two options, returning a new `option` of the result. +If either of the options is `None`, the result will be `None`. **Signature** @@ -1100,7 +1144,7 @@ Added in v1.0.0 ## as -Maps the success value of this effect to the specified constant value. +Maps the `Some` value of this option to the specified constant value. **Signature** @@ -1112,7 +1156,9 @@ Added in v1.0.0 ## asUnit -Returns the effect resulting from mapping the success of this effect to unit. +Returns the `Option` resulting from mapping the `Some` value to `void`. + +This is useful when the value of the Option is not needed, but the presence or absence of the value is important. **Signature** @@ -1229,6 +1275,8 @@ Added in v1.0.0 ## zipWith +Zips two `Option` values together using a provided function, returning a new `Option` of the result. + **Signature** ```ts @@ -1255,6 +1303,8 @@ Added in v1.0.0 ## flatMap +Applies a function to the value of an `Option` and flattens the result, if the input is `Some`. + **Signature** ```ts diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index b6378fc86..5314a1789 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -105,6 +105,8 @@ Added in v1.0.0 ## zipWith +Zips two `F` values together using a provided function, returning a new `F` of the result. + **Signature** ```ts diff --git a/src/Identity.ts b/src/Identity.ts index 26b231975..116fa2994 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -2,26 +2,24 @@ * @since 1.0.0 */ import { identity } from "@fp-ts/core/Function" -import type { Kind, TypeLambda } from "@fp-ts/core/HKT" +import type { TypeLambda } from "@fp-ts/core/HKT" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" -import * as applicative from "@fp-ts/core/typeclass/Applicative" +import type * as applicative from "@fp-ts/core/typeclass/Applicative" import * as chainable from "@fp-ts/core/typeclass/Chainable" -import type * as coproduct_ from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" -import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" -import * as foldable from "@fp-ts/core/typeclass/Foldable" +import type * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" +import type * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" -import type { Monoid } from "@fp-ts/core/typeclass/Monoid" import * as of_ from "@fp-ts/core/typeclass/Of" import type * as pointed from "@fp-ts/core/typeclass/Pointed" -import * as product_ from "@fp-ts/core/typeclass/Product" +import type * as product_ from "@fp-ts/core/typeclass/Product" import type * as semiAlternative from "@fp-ts/core/typeclass/SemiAlternative" -import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" +import type * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import type * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" -import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" -import * as traversable from "@fp-ts/core/typeclass/Traversable" +import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import type * as traversable from "@fp-ts/core/typeclass/Traversable" /** * @category models @@ -45,17 +43,14 @@ export interface IdentityTypeLambdaFix extends TypeLambda { readonly type: Identity } -/** - * @since 1.0.0 - */ -export const map = (f: (a: A) => B) => (self: Identity): Identity => f(self) - /** * @category instances * @since 1.0.0 */ -export const Covariant: covariant.Covariant = covariant.make( - map +export const Covariant: covariant.Covariant = covariant.make< + IdentityTypeLambda +>( + f => self => f(self) ) /** @@ -66,11 +61,6 @@ export const Invariant: invariant.Invariant = { imap: Covariant.imap } -/** - * @since 1.0.0 - */ -export const tupled: (self: Identity) => Identity<[A]> = invariant.tupled(Invariant) - /** * @category do notation * @since 1.0.0 @@ -96,49 +86,14 @@ export { let_ as let } -/** - * @category mapping - * @since 1.0.0 - */ -export const flap: (a: A) => (fab: Identity<(a: A) => B>) => Identity = covariant.flap( - Covariant -) - -/** - * Maps the success value of this effect to the specified constant value. - * - * @category mapping - * @since 1.0.0 - */ -export const as: (b: B) => <_>(self: Identity<_>) => Identity = covariant.as(Covariant) - -/** - * Returns the effect resulting from mapping the success of this effect to unit. - * - * @category mapping - * @since 1.0.0 - */ -export const asUnit: <_>(self: Identity<_>) => Identity = covariant.asUnit(Covariant) - -/** - * @category constructors - * @since 1.0.0 - */ -export const of: (a: A) => Identity = identity - /** * @category instances * @since 1.0.0 */ export const Of: of_.Of = { - of + of: identity } -/** - * @since 1.0.0 - */ -export const unit: Identity = of_.unit(Of) - /** * @category do notation * @since 1.0.0 @@ -154,41 +109,14 @@ export const Pointed: pointed.Pointed = { ...Covariant } -/** - * @category sequencing - * @since 1.0.0 - */ -export const flatMap = (f: (a: A) => Identity) => - (self: Identity): Identity => f(self) - /** * @category instances * @since 1.0.0 */ export const FlatMap: flatMap_.FlatMap = { - flatMap + flatMap: f => self => f(self) } -/** - * @since 1.0.0 - */ -export const flatten: (self: Identity>) => Identity = flatMap_ - .flatten(FlatMap) - -/** - * @since 1.0.0 - */ -export const andThen: (that: Identity) => <_>(self: Identity<_>) => Identity = flatMap_ - .andThen(FlatMap) - -/** - * @since 1.0.0 - */ -export const composeKleisliArrow: ( - bfc: (b: B) => Identity -) => (afb: (a: A) => Identity) => (a: A) => Identity = flatMap_ - .composeKleisliArrow(FlatMap) - /** * @category instances * @since 1.0.0 @@ -211,27 +139,6 @@ export const bind: ( Chainable ) -/** - * Returns an effect that effectfully "peeks" at the success of this effect. - * - * @since 1.0.0 - */ -export const tap: (f: (a: A) => Identity<_>) => (self: Identity) => Identity = chainable - .tap( - Chainable - ) - -/** - * Sequences the specified effect after this effect, but ignores the value - * produced by the effect. - * - * @category sequencing - * @since 1.0.0 - */ -export const andThenDiscard: <_>(that: Identity<_>) => (self: Identity) => Identity = - chainable - .andThenDiscard(Chainable) - /** * @category instances * @since 1.0.0 @@ -241,11 +148,6 @@ export const Monad: monad.Monad = { ...FlatMap } -const productMany = ( - self: Identity, - collection: Iterable> -): Identity<[A, ...Array]> => [self, ...collection] - /** * @category instances * @since 1.0.0 @@ -253,36 +155,9 @@ const productMany = ( export const SemiProduct: semiProduct.SemiProduct = { ...Invariant, product: (self, that) => [self, that], - productMany + productMany: (self, collection) => [self, ...collection] } -/** - * A variant of `bind` that sequentially ignores the scope. - * - * @category do notation - * @since 1.0.0 - */ -export const andThenBind: ( - name: Exclude, - that: Identity -) => ( - self: Identity -) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct - .andThenBind(SemiProduct) - -/** - * Adds an element to the end of a tuple. - * - * @since 1.0.0 - */ -export const element: ( - fb: Identity -) => >(self: Identity) => Identity<[...A, B]> = semiProduct - .element(SemiProduct) - -const productAll = (collection: Iterable>): Identity> => - readonlyArray.fromIterable(collection) - /** * @category instances * @since 1.0.0 @@ -290,26 +165,9 @@ const productAll = (collection: Iterable>): Identity> => export const Product: product_.Product = { ...Of, ...SemiProduct, - productAll + productAll: readonlyArray.fromIterable } -/** - * @since 1.0.0 - */ -export const tuple: >>( - ...tuple: T -) => Identity<{ [I in keyof T]: [T[I]] extends [Identity] ? A : never }> = product_.tuple( - Product -) - -/** - * @since 1.0.0 - */ -export const struct: >>( - r: R -) => Identity<{ [K in keyof R]: [R[K]] extends [Identity] ? A : never }> = product_ - .struct(Product) - /** * @category instances * @since 1.0.0 @@ -319,34 +177,6 @@ export const SemiApplicative: semiApplicative.SemiApplicative(S: Semigroup) => Semigroup> = semiApplicative - .liftSemigroup(SemiApplicative) - -/** - * Lifts a binary function into `Identity`. - * - * @category lifting - * @since 1.0.0 - */ -export const lift2: ( - f: (a: A) => (b: B) => C -) => (fa: Identity) => (fb: Identity) => Identity = semiApplicative.lift2( - SemiApplicative -) - -/** - * @since 1.0.0 - */ -export const ap: ( - fa: Identity -) => (self: Identity<(a: A) => B>) => Identity = semiApplicative.ap( - SemiApplicative -) - /** * @category instances * @since 1.0.0 @@ -356,13 +186,6 @@ export const Applicative: applicative.Applicative = { ...Product } -/** - * @since 1.0.0 - */ -export const liftMonoid: (M: Monoid) => Monoid> = applicative.liftMonoid( - Applicative -) - /** * @category instances * @since 1.0.0 @@ -386,116 +209,19 @@ export const getSemiAlternative = ( map: Covariant.map }) -/** - * @category folding - * @since 1.0.0 - */ -export const reduce = (b: B, f: (b: B, a: A) => B) => (self: Identity): B => f(b, self) - -/** - * @category folding - * @since 1.0.0 - */ -export const reduceRight = (b: B, f: (b: B, a: A) => B) => - (self: Identity): B => f(b, self) - /** * @category instances * @since 1.0.0 */ export const Foldable: foldable.Foldable = { - reduce + reduce: (b, f) => self => f(b, self) } -/** - * @category folding - * @since 1.0.0 - */ -export const foldMap: (M: Monoid) => (f: (a: A) => M) => (self: Identity) => M = - foldable - .foldMap(Foldable) - -/** - * @category conversions - * @since 1.0.0 - */ -export const toArray: (self: Identity) => Array = foldable.toArray(Foldable) - -/** - * @category conversions - * @since 1.0.0 - */ -export const toArrayWith: (f: (a: A) => B) => (self: Identity) => Array = foldable - .toArrayWith(Foldable) - -/** - * @category folding - * @since 1.0.0 - */ -export const reduceKind: ( - G: monad.Monad -) => ( - b: B, - f: (b: B, a: A) => Kind -) => (self: Identity) => Kind = foldable.reduceKind(Foldable) - -/** - * @category folding - * @since 1.0.0 - */ -export const reduceRightKind: ( - G: monad.Monad -) => ( - b: B, - f: (b: B, a: A) => Kind -) => (self: Identity) => Kind = foldable.reduceRightKind(Foldable) - -/** - * @category folding - * @since 1.0.0 - */ -export const foldMapKind: ( - G: coproduct_.Coproduct -) => ( - f: (a: A) => Kind -) => (self: Identity) => Kind = foldable.foldMapKind(Foldable) - -/** - * @category traversing - * @since 1.0.0 - */ -export const traverse = ( - F: applicative.Applicative -) => - ( - f: (a: A) => Kind - ) => (self: Identity): Kind> => f(self) - -/** - * @category traversing - * @since 1.0.0 - */ -export const sequence: ( - F: applicative.Applicative -) => (fas: Identity>) => Kind> = traversable - .sequence(traverse) - /** * @category instances * @since 1.0.0 */ export const Traversable: traversable.Traversable = { - traverse, - sequence + traverse: () => f => self => f(self), + sequence: () => identity } - -/** - * @category traversing - * @since 1.0.0 - */ -export const traverseTap: ( - F: applicative.Applicative -) => ( - f: (a: A) => Kind -) => (self: Identity) => Kind> = traversable - .traverseTap(Traversable) diff --git a/src/Option.ts b/src/Option.ts index 792189a7b..5262ce0d8 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -77,7 +77,10 @@ export interface OptionTypeLambda extends TypeLambda { // ------------------------------------------------------------------------------------- /** - * Creates a new `Option` that represents a absence of value. + * Creates a new `Option` that represents the absence of a value. + * + * This can be useful when working with optional values or to represent a computation that failed. + * It returns a new `Option` object that does not contain any value. * * @category constructors * @since 1.0.0 @@ -87,10 +90,14 @@ export const none = (): Option => option.none /** * Creates a new `Option` that wraps the given value. * + * This can be useful when working with optional values or to represent a computation that succeeded with a value. + * + * @param value - The value to wrap. + * * @category constructors * @since 1.0.0 */ -export const some: (a: A) => Option = option.some +export const some: (value: A) => Option = option.some // ------------------------------------------------------------------------------------- // guards @@ -99,6 +106,8 @@ export const some: (a: A) => Option = option.some /** * Checks if the specified value is an instance of `Option`, returns `true` if it is, `false` otherwise. * + * @param input - The value to check. + * * @example * import { some, none, isOption } from '@fp-ts/core/Option' * @@ -109,11 +118,13 @@ export const some: (a: A) => Option = option.some * @category guards * @since 1.0.0 */ -export const isOption: (u: unknown) => u is Option = option.isOption +export const isOption: (input: unknown) => input is Option = option.isOption /** * Returns `true` if the option is `None`, `false` otherwise. * + * @param self - The option to check. + * * @example * import { some, none, isNone } from '@fp-ts/core/Option' * @@ -128,6 +139,8 @@ export const isNone: (self: Option) => self is None = option.isNone /** * Returns `true` if the option is an instance of `Some`, `false` otherwise. * + * @param self - The option to check. + * * @example * import { some, none, isSome } from '@fp-ts/core/Option' * @@ -147,6 +160,8 @@ export const isSome: (self: Option) => self is Some = option.isSome * Constructs a new `Option` from a nullable type. If the value is `null` or `undefined`, returns `None`, otherwise * returns the value wrapped in a `Some`. * + * @param nullableValue - The nullable value to be converted to an `Option`. + * * @example * import { none, some, fromNullable } from '@fp-ts/core/Option' * @@ -157,7 +172,7 @@ export const isSome: (self: Option) => self is Some = option.isSome * @category conversions * @since 1.0.0 */ -export const fromNullable: (a: A) => Option> = option.fromNullable +export const fromNullable: (nullableValue: A) => Option> = option.fromNullable /** * Returns a `Refinement` from a `Option` returning function. @@ -170,6 +185,18 @@ export const toRefinement = (f: (a: A) => Option): Refinement (a: A): a is B => isSome(f(a)) /** + * Converts an `Iterable` of values into an `Option`. Returns the first value of the `Iterable` wrapped in a `Some` + * if the `Iterable` is not empty, otherwise returns `None`. + * + * @param collection - The `Iterable` to be converted to an `Option`. + * + * @example + * import { fromIterable, some, none } from '@fp-ts/core/Option' + * + * const collection = [1, 2, 3] + * assert.deepStrictEqual(fromIterable(collection), some(1)) + * assert.deepStrictEqual(fromIterable([]), none()) + * * @category conversions * @since 1.0.0 */ @@ -183,6 +210,8 @@ export const fromIterable = (collection: Iterable): Option => { /** * Converts a `Either` to an `Option` discarding the error. * + * @param self - The `Either` to convert to an `Option`. + * * @example * import * as O from '@fp-ts/core/Option' * import * as E from '@fp-ts/core/Either' @@ -196,6 +225,20 @@ export const fromIterable = (collection: Iterable): Option => { export const fromEither: (self: Either) => Option = either.getRight /** + * Converts an `Option` to an `Either`, allowing you to provide a value to be used in the case of a `None`. + * + * @param onNone - a function that produces an error value when the option is `None`. + * @param self - the `Option` to convert. + * + * @example + * import { pipe } from '@fp-ts/core/Function' + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * + * const onNone = () => 'error' + * assert.deepStrictEqual(pipe(O.some(1), O.toEither(onNone)), E.right(1)) + * assert.deepStrictEqual(pipe(O.none(), O.toEither(onNone)), E.left('error')) + * * @category conversions * @since 1.0.0 */ @@ -209,9 +252,9 @@ export const toEither: (onNone: LazyArg) => (self: Option) => Either /** * Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` * - * @param onNone - Function that returns the default value to return if the `Option` is `None` - * @param self - The `Option` to get the value of - * * + * @param onNone - Function that returns the default value to return if the `Option` is `None`. + * @param self - The `Option` to get the value of. + * * @example * import { some, none, getOrElse } from '@fp-ts/core/Option' * import { pipe } from '@fp-ts/core/Function' @@ -228,8 +271,8 @@ export const getOrElse = (onNone: LazyArg) => /** * Returns the provided option `that` if `self` is `None`, otherwise returns `self`. * - * @param that - The option to return if `self` option is `None` - * @param self - The first option to be checked + * @param that - The option to return if `self` is `None`. + * @param self - The first option to be checked. * * @example * import * as O from '@fp-ts/core/Option' @@ -273,10 +316,11 @@ export const orElse = (that: LazyArg>) => /** * Similar to `orElse`, but instead of returning a simple union, it returns an `Either` object, * which contains information about which of the two options has been chosen. + * * This is useful when it's important to know whether the value was retrieved from the first option or the second option. * - * @param that - The second option to be considered if the first option is `None` - * @param self - The first option to be checked + * @param that - The second option to be considered if the first option is `None`. + * @param self - The first option to be checked. * * @category error handling * @since 1.0.0 @@ -292,7 +336,7 @@ export const orElseEither = ( /** * Given an Iterable collection of `Option`s, the function returns the first `Some` option found in the collection. * - * @param collection - An iterable collection of `Option` to be searched + * @param collection - An iterable collection of `Option` to be searched. * * @category error handling * @since 1.0.0 @@ -314,7 +358,7 @@ export const firstSomeOf = (collection: Iterable>): Option => { /** * Returns the value of the option if it is a `Some`, otherwise returns `null`. * - * @param self - The option to extract the value from + * @param self - The option to extract the value from. * * @example * import { some, none, getOrNull } from '@fp-ts/core/Option' @@ -331,7 +375,7 @@ export const getOrNull: (self: Option) => A | null = getOrElse(constNull) /** * Returns the value of the option if it is a `Some`, otherwise returns `undefined`. * - * @param self - The option to extract the value from + * @param self - The option to extract the value from. * * @example * import { some, none, getOrUndefined } from '@fp-ts/core/Option' @@ -372,7 +416,7 @@ export const fromThrowable = (f: () => A): Option => { } /** - * Lifts a function that may throw to one returning a `Option`. + * A utility function that lifts a function that throws exceptions into a function that returns an `Option`. * * @category interop * @since 1.0.0 @@ -384,9 +428,16 @@ export const liftThrowable = , B>( /** * Returns the contained value if the option is `Some`, otherwise throws an error. * - * @param onNone - An optional function that returns the error to be thrown when the option is `None` - * @param self - The option to extract the value from - * @throws The error returned by `onError` if the option is `None` + * @param onNone - An optional function that returns the error to be thrown when the `Option` is `None`. + * @param self - The `Option` to extract the value from. + * @throws The error returned by `onNone` if the option is `None`. + * + * @example + * import { pipe } from '@fp-ts/core/Function' + * import * as O from '@fp-ts/core/Option' + * + * assert.deepStrictEqual(pipe(O.some(1), O.getOrThrow()), 1) + * assert.throws(() => pipe(O.none(), O.getOrThrow())) * * @category interop * @since 1.0.0 @@ -469,7 +520,7 @@ export const flap: (a: A) => (fab: Option<(a: A) => B>) => Option = cov ) /** - * Maps the success value of this effect to the specified constant value. + * Maps the `Some` value of this option to the specified constant value. * * @category mapping * @since 1.0.0 @@ -477,7 +528,9 @@ export const flap: (a: A) => (fab: Option<(a: A) => B>) => Option = cov export const as: (b: B) => <_>(self: Option<_>) => Option = covariant.as(Covariant) /** - * Returns the effect resulting from mapping the success of this effect to unit. + * Returns the `Option` resulting from mapping the `Some` value to `void`. + * + * This is useful when the value of the Option is not needed, but the presence or absence of the value is important. * * @category mapping * @since 1.0.0 @@ -518,6 +571,8 @@ export const Pointed: pointed.Pointed = { } /** + * Applies a function to the value of an `Option` and flattens the result, if the input is `Some`. + * * @category sequencing * @since 1.0.0 */ @@ -774,7 +829,12 @@ export const getOptionalMonoid = ( ) /** - * Lifts a binary function into `Option` as uncurried binary function. + * Applies a function to the contained value of two options, returning a new `option` of the result. + * If either of the options is `None`, the result will be `None`. + * + * @param f - A function to apply to the contained values of the options + * @param that - An option to lift the function over + * @param self - An option to lift the function over * * @category lifting * @since 1.0.0 @@ -785,6 +845,12 @@ export const lift2: ( .lift2(SemiApplicative) /** + * Zips two `Option` values together using a provided function, returning a new `Option` of the result. + * + * @param fa - The left-hand side of the zip operation + * @param fb - The right-hand side of the zip operation + * @param f - The function used to combine the values of the two `Option`s + * * @category products * @since 1.0.0 */ diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 3ab3c19ec..554630a1d 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -30,6 +30,12 @@ export const liftSemigroup = (F: SemiApplicative) => }) /** + * Zips two `F` values together using a provided function, returning a new `F` of the result. + * + * @param fa - The left-hand side of the zip operation + * @param fb - The right-hand side of the zip operation + * @param f - The function used to combine the values of the two `Option`s + * * @since 1.0.0 */ export const zipWith = (F: SemiApplicative) => diff --git a/test/Identity.ts b/test/Identity.ts index 0e8b0be3a..45a7caa5e 100644 --- a/test/Identity.ts +++ b/test/Identity.ts @@ -7,75 +7,38 @@ import * as U from "./util" describe.concurrent("Identity", () => { it("instances and derived exports", () => { expect(_.Invariant).exist - expect(_.tupled).exist expect(_.bindTo).exist expect(_.Covariant).exist - expect(_.map).exist expect(_.let).exist - expect(_.flap).exist - expect(_.as).exist - expect(_.asUnit).exist expect(_.Of).exist - expect(_.of).exist expect(_.Do).exist expect(_.Pointed).exist expect(_.FlatMap).exist - expect(_.flatMap).exist - expect(_.flatten).exist - expect(_.andThen).exist - expect(_.composeKleisliArrow).exist expect(_.Chainable).exist expect(_.bind).exist - expect(_.tap).exist - expect(_.andThenDiscard).exist expect(_.Monad).exist expect(_.SemiProduct).exist - expect(_.andThenBind).exist - expect(_.element).exist expect(_.Product).exist - expect(_.tuple).exist - expect(_.struct).exist expect(_.SemiApplicative).exist - expect(_.liftSemigroup).exist - expect(_.lift2).exist - expect(_.ap).exist - expect(_.andThenDiscard).exist - expect(_.andThen).exist expect(_.Applicative).exist - expect(_.liftMonoid).exist expect(_.Foldable).exist - expect(_.reduce).exist - expect(_.reduceRight).exist - expect(_.foldMap).exist - expect(_.toArray).exist - expect(_.toArrayWith).exist - expect(_.reduceKind).exist - expect(_.reduceRightKind).exist - expect(_.foldMapKind).exist expect(_.Traversable).exist - expect(_.traverse).exist - expect(_.sequence).exist - expect(_.traverseTap).exist - }) - - it("unit", () => { - U.deepStrictEqual(_.unit, undefined) }) it("of", () => { - U.deepStrictEqual(_.of("a"), "a") + U.deepStrictEqual(_.Of.of("a"), "a") }) it("SemiProduct", () => { @@ -89,7 +52,7 @@ describe.concurrent("Identity", () => { it("flatMap", () => { U.deepStrictEqual( - pipe("a", _.flatMap((a) => a + "b")), + pipe("a", _.Chainable.flatMap((a) => a + "b")), "ab" ) }) @@ -112,20 +75,16 @@ describe.concurrent("Identity", () => { }) it("reduce", () => { - U.deepStrictEqual(pipe("b", _.reduce("a", (b, a) => b + a)), "ab") U.deepStrictEqual(pipe("b", _.Foldable.reduce("a", (b, a) => b + a)), "ab") }) - it("reduceRight", () => { - const f = (a: string, acc: string) => acc + a - U.deepStrictEqual(pipe("a", _.reduceRight("", f)), "a") - }) - it("traverse", () => { - U.deepStrictEqual(pipe(1, _.traverse(O.Applicative)(O.some)), O.some(1)) - U.deepStrictEqual(pipe(1, _.traverse(O.Applicative)(() => O.none())), O.none()) - U.deepStrictEqual(pipe(1, _.Traversable.traverse(O.Applicative)(O.some)), O.some(1)) U.deepStrictEqual(pipe(1, _.Traversable.traverse(O.Applicative)(() => O.none())), O.none()) }) + + it("sequence", () => { + U.deepStrictEqual(_.Traversable.sequence(O.Applicative)(O.some(1)), O.some(1)) + U.deepStrictEqual(_.Traversable.sequence(O.Applicative)(O.none()), O.none()) + }) }) From 2bb91d1e15ec62bfa762bb17aec6c97305b94692 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 29 Jan 2023 09:06:35 +0100 Subject: [PATCH 113/255] Function: flip apply --- .changeset/plenty-bats-try.md | 5 ++ docs/modules/Either.ts.md | 10 ++-- docs/modules/Function.ts.md | 23 ++++++-- docs/modules/Option.ts.md | 48 +++++++-------- src/Either.ts | 10 ++-- src/Function.ts | 20 +++++-- src/Option.ts | 48 +++++++-------- test/Function.ts | 108 +++++++++++++++++----------------- 8 files changed, 148 insertions(+), 124 deletions(-) create mode 100644 .changeset/plenty-bats-try.md diff --git a/.changeset/plenty-bats-try.md b/.changeset/plenty-bats-try.md new file mode 100644 index 000000000..d02914d45 --- /dev/null +++ b/.changeset/plenty-bats-try.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": minor +--- + +Function: flip apply diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 7ea4acd33..a787d4819 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -1205,8 +1205,8 @@ const onLeft = (errors: ReadonlyArray): string => `Errors: ${errors.join const onRight = (value: number): string => `Ok: ${value}` -assert.strictEqual(pipe(E.right(1), E.match(onLeft, onRight)), 'Ok: 1') -assert.strictEqual(pipe(E.left(['error 1', 'error 2']), E.match(onLeft, onRight)), 'Errors: error 1, error 2') +assert.deepStrictEqual(pipe(E.right(1), E.match(onLeft, onRight)), 'Ok: 1') +assert.deepStrictEqual(pipe(E.left(['error 1', 'error 2']), E.match(onLeft, onRight)), 'Errors: error 1, error 2') ``` Added in v1.0.0 @@ -1404,9 +1404,9 @@ import * as E from '@fp-ts/core/Either' const f = E.exists((n: number) => n > 2) -assert.strictEqual(f(E.left('a')), false) -assert.strictEqual(f(E.right(1)), false) -assert.strictEqual(f(E.right(3)), true) +assert.deepStrictEqual(f(E.left('a')), false) +assert.deepStrictEqual(f(E.right(1)), false) +assert.deepStrictEqual(f(E.right(3)), true) ``` Added in v1.0.0 diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index f7e99655a..182037955 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -184,10 +184,21 @@ Added in v1.0.0 ## apply +Apply a function to a given value. + **Signature** ```ts -export declare const apply: (a: A) => (self: (a: A) => B) => B +export declare const apply: (self: (a: A) => B) => (a: A) => B +``` + +**Example** + +```ts +import { pipe, apply } from '@fp-ts/core/Function' +import { increment } from '@fp-ts/core/Number' + +assert.deepStrictEqual(pipe(2, apply(increment)), 3) ``` Added in v1.0.0 @@ -302,7 +313,7 @@ import { flip } from '@fp-ts/core/Function' const f = (a: number) => (b: string) => a - b.length -assert.strictEqual(flip(f)('aaa')(2), -1) +assert.deepStrictEqual(flip(f)('aaa')(2), -1) ``` Added in v1.0.0 @@ -387,7 +398,7 @@ const double = (n: number): number => n * 2 const f = flow(len, double) -assert.strictEqual(f('aaa'), 6) +assert.deepStrictEqual(f('aaa'), 6) ``` Added in v1.0.0 @@ -662,10 +673,10 @@ const len = (s: string): number => s.length const double = (n: number): number => n * 2 // without pipe -assert.strictEqual(double(len('aaa')), 6) +assert.deepStrictEqual(double(len('aaa')), 6) // with pipe -assert.strictEqual(pipe('aaa', len, double), 6) +assert.deepStrictEqual(pipe('aaa', len, double), 6) ``` Added in v1.0.0 @@ -687,7 +698,7 @@ import { tupled } from '@fp-ts/core/Function' const add = tupled((x: number, y: number): number => x + y) -assert.strictEqual(add([1, 2]), 3) +assert.deepStrictEqual(add([1, 2]), 3) ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 8c7effa35..928989ffa 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -502,14 +502,14 @@ export declare const getOrElse: (onNone: any) => (self: Option) => B | import { some, none, getOrElse } from '@fp-ts/core/Option' import { pipe } from '@fp-ts/core/Function' -assert.strictEqual( +assert.deepStrictEqual( pipe( some(1), getOrElse(() => 0) ), 1 ) -assert.strictEqual( +assert.deepStrictEqual( pipe( none(), getOrElse(() => 0) @@ -635,8 +635,8 @@ export declare const isNone: (self: Option) => self is None ```ts import { some, none, isNone } from '@fp-ts/core/Option' -assert.strictEqual(isNone(some(1)), false) -assert.strictEqual(isNone(none()), true) +assert.deepStrictEqual(isNone(some(1)), false) +assert.deepStrictEqual(isNone(none()), true) ``` Added in v1.0.0 @@ -656,9 +656,9 @@ export declare const isOption: (input: unknown) => input is Option ```ts import { some, none, isOption } from '@fp-ts/core/Option' -assert.strictEqual(isOption(some(1)), true) -assert.strictEqual(isOption(none()), true) -assert.strictEqual(isOption({}), false) +assert.deepStrictEqual(isOption(some(1)), true) +assert.deepStrictEqual(isOption(none()), true) +assert.deepStrictEqual(isOption({}), false) ``` Added in v1.0.0 @@ -678,8 +678,8 @@ export declare const isSome: (self: Option) => self is Some ```ts import { some, none, isSome } from '@fp-ts/core/Option' -assert.strictEqual(isSome(some(1)), true) -assert.strictEqual(isSome(none()), false) +assert.deepStrictEqual(isSome(some(1)), true) +assert.deepStrictEqual(isSome(none()), false) ``` Added in v1.0.0 @@ -970,8 +970,8 @@ export declare const getOrNull: (self: Option) => A | null import { some, none, getOrNull } from '@fp-ts/core/Option' import { pipe } from '@fp-ts/core/Function' -assert.strictEqual(pipe(some(1), getOrNull), 1) -assert.strictEqual(pipe(none(), getOrNull), null) +assert.deepStrictEqual(pipe(some(1), getOrNull), 1) +assert.deepStrictEqual(pipe(none(), getOrNull), null) ``` Added in v1.0.0 @@ -1014,8 +1014,8 @@ export declare const getOrUndefined: (self: Option) => A | undefined import { some, none, getOrUndefined } from '@fp-ts/core/Option' import { pipe } from '@fp-ts/core/Function' -assert.strictEqual(pipe(some(1), getOrUndefined), 1) -assert.strictEqual(pipe(none(), getOrUndefined), undefined) +assert.deepStrictEqual(pipe(some(1), getOrUndefined), 1) +assert.deepStrictEqual(pipe(none(), getOrUndefined), undefined) ``` Added in v1.0.0 @@ -1246,7 +1246,7 @@ export declare const match: (onNone: any, onSome: (a: A) => C) => ( import { some, none, match } from '@fp-ts/core/Option' import { pipe } from '@fp-ts/core/Function' -assert.strictEqual( +assert.deepStrictEqual( pipe( some(1), match( @@ -1257,7 +1257,7 @@ assert.strictEqual( 'a some containing 1' ) -assert.strictEqual( +assert.deepStrictEqual( pipe( none(), match( @@ -1402,11 +1402,11 @@ import * as N from '@fp-ts/core/Number' import { pipe } from '@fp-ts/core/Function' const O = liftOrder(N.Order) -assert.strictEqual(O.compare(none(), none()), 0) -assert.strictEqual(O.compare(none(), some(1)), -1) -assert.strictEqual(O.compare(some(1), none()), 1) -assert.strictEqual(O.compare(some(1), some(2)), -1) -assert.strictEqual(O.compare(some(1), some(1)), 0) +assert.deepStrictEqual(O.compare(none(), none()), 0) +assert.deepStrictEqual(O.compare(none(), some(1)), -1) +assert.deepStrictEqual(O.compare(some(1), none()), 1) +assert.deepStrictEqual(O.compare(some(1), some(2)), -1) +assert.deepStrictEqual(O.compare(some(1), some(1)), 0) ``` Added in v1.0.0 @@ -1543,21 +1543,21 @@ export declare const exists: (predicate: any) => (self: Option) => boolean import { some, none, exists } from '@fp-ts/core/Option' import { pipe } from '@fp-ts/core/Function' -assert.strictEqual( +assert.deepStrictEqual( pipe( some(1), exists((n) => n > 0) ), true ) -assert.strictEqual( +assert.deepStrictEqual( pipe( some(1), exists((n) => n > 1) ), false ) -assert.strictEqual( +assert.deepStrictEqual( pipe( none(), exists((n) => n > 0) @@ -1615,7 +1615,7 @@ import { some, none, reduceAll } from '@fp-ts/core/Option' import { pipe } from '@fp-ts/core/Function' const iterable = [some(1), none(), some(2), none()] -assert.strictEqual( +assert.deepStrictEqual( pipe( iterable, reduceAll(0, (b, a) => b + a) diff --git a/src/Either.ts b/src/Either.ts index eed8e11ae..9b78b7f45 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -664,14 +664,14 @@ export const Foldable: foldable.Foldable = { * * const onRight = (value: number): string => `Ok: ${value}` * - * assert.strictEqual( + * assert.deepStrictEqual( * pipe( * E.right(1), * E.match(onLeft , onRight) * ), * 'Ok: 1' * ) - * assert.strictEqual( + * assert.deepStrictEqual( * pipe( * E.left(['error 1', 'error 2']), * E.match(onLeft , onRight) @@ -1080,9 +1080,9 @@ export const contains = (equivalence: Equivalence) => * * const f = E.exists((n: number) => n > 2) * - * assert.strictEqual(f(E.left('a')), false) - * assert.strictEqual(f(E.right(1)), false) - * assert.strictEqual(f(E.right(3)), true) + * assert.deepStrictEqual(f(E.left('a')), false) + * assert.deepStrictEqual(f(E.right(1)), false) + * assert.deepStrictEqual(f(E.right(3)), true) * * @since 1.0.0 */ diff --git a/src/Function.ts b/src/Function.ts index 3b2ca4835..0266cbea2 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -83,9 +83,17 @@ export const getMonoid = (Monoid: monoid.Monoid) => } /** + * Apply a function to a given value. + * + * @example + * import { pipe, apply } from '@fp-ts/core/Function' + * import { increment } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(pipe(2, apply(increment)), 3) + * * @since 1.0.0 */ -export const apply = (a: A) => (self: (a: A) => B): B => self(a) +export const apply = (self: (a: A) => B) => (a: A): B => self(a) /** * A lazy argument @@ -166,7 +174,7 @@ export const constVoid: LazyArg = constUndefined * * const f = (a: number) => (b: string) => a - b.length * - * assert.strictEqual(flip(f)('aaa')(2), -1) + * assert.deepStrictEqual(flip(f)('aaa')(2), -1) * * @since 1.0.0 */ @@ -185,7 +193,7 @@ export const flip = , B extends Array, C>( * * const f = flow(len, double) * - * assert.strictEqual(f('aaa'), 6) + * assert.deepStrictEqual(f('aaa'), 6) * * @see {@link pipe} * @since 1.0.0 @@ -316,7 +324,7 @@ export const absurd = (_: never): A => { * * const add = tupled((x: number, y: number): number => x + y) * - * assert.strictEqual(add([1, 2]), 3) + * assert.deepStrictEqual(add([1, 2]), 3) * * @since 1.0.0 */ @@ -341,10 +349,10 @@ export const untupled = , B>(f: (a: A) => B): ( * const double = (n: number): number => n * 2 * * // without pipe - * assert.strictEqual(double(len('aaa')), 6) + * assert.deepStrictEqual(double(len('aaa')), 6) * * // with pipe - * assert.strictEqual(pipe('aaa', len, double), 6) + * assert.deepStrictEqual(pipe('aaa', len, double), 6) * * @see {@link flow} * @since 1.0.0 diff --git a/src/Option.ts b/src/Option.ts index 5262ce0d8..d8f198c47 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -111,9 +111,9 @@ export const some: (value: A) => Option = option.some * @example * import { some, none, isOption } from '@fp-ts/core/Option' * - * assert.strictEqual(isOption(some(1)), true) - * assert.strictEqual(isOption(none()), true) - * assert.strictEqual(isOption({}), false) + * assert.deepStrictEqual(isOption(some(1)), true) + * assert.deepStrictEqual(isOption(none()), true) + * assert.deepStrictEqual(isOption({}), false) * * @category guards * @since 1.0.0 @@ -128,8 +128,8 @@ export const isOption: (input: unknown) => input is Option = option.isO * @example * import { some, none, isNone } from '@fp-ts/core/Option' * - * assert.strictEqual(isNone(some(1)), false) - * assert.strictEqual(isNone(none()), true) + * assert.deepStrictEqual(isNone(some(1)), false) + * assert.deepStrictEqual(isNone(none()), true) * * @category guards * @since 1.0.0 @@ -144,8 +144,8 @@ export const isNone: (self: Option) => self is None = option.isNone * @example * import { some, none, isSome } from '@fp-ts/core/Option' * - * assert.strictEqual(isSome(some(1)), true) - * assert.strictEqual(isSome(none()), false) + * assert.deepStrictEqual(isSome(some(1)), true) + * assert.deepStrictEqual(isSome(none()), false) * * @category guards * @since 1.0.0 @@ -259,8 +259,8 @@ export const toEither: (onNone: LazyArg) => (self: Option) => Either * import { some, none, getOrElse } from '@fp-ts/core/Option' * import { pipe } from '@fp-ts/core/Function' * - * assert.strictEqual(pipe(some(1), getOrElse(() => 0)), 1) - * assert.strictEqual(pipe(none(), getOrElse(() => 0)), 0) + * assert.deepStrictEqual(pipe(some(1), getOrElse(() => 0)), 1) + * assert.deepStrictEqual(pipe(none(), getOrElse(() => 0)), 0) * * @category error handling * @since 1.0.0 @@ -364,8 +364,8 @@ export const firstSomeOf = (collection: Iterable>): Option => { * import { some, none, getOrNull } from '@fp-ts/core/Option' * import { pipe } from '@fp-ts/core/Function' * - * assert.strictEqual(pipe(some(1), getOrNull), 1) - * assert.strictEqual(pipe(none(), getOrNull), null) + * assert.deepStrictEqual(pipe(some(1), getOrNull), 1) + * assert.deepStrictEqual(pipe(none(), getOrNull), null) * * @category interop * @since 1.0.0 @@ -381,8 +381,8 @@ export const getOrNull: (self: Option) => A | null = getOrElse(constNull) * import { some, none, getOrUndefined } from '@fp-ts/core/Option' * import { pipe } from '@fp-ts/core/Function' * - * assert.strictEqual(pipe(some(1), getOrUndefined), 1) - * assert.strictEqual(pipe(none(), getOrUndefined), undefined) + * assert.deepStrictEqual(pipe(some(1), getOrUndefined), 1) + * assert.deepStrictEqual(pipe(none(), getOrUndefined), undefined) * * @category interop * @since 1.0.0 @@ -1085,7 +1085,7 @@ export const traverseTap: ( * import { some, none, match } from '@fp-ts/core/Option' * import { pipe } from '@fp-ts/core/Function' * - * assert.strictEqual( + * assert.deepStrictEqual( * pipe( * some(1), * match(() => 'a none', a => `a some containing ${a}`) @@ -1093,7 +1093,7 @@ export const traverseTap: ( * 'a some containing 1' * ) * - * assert.strictEqual( + * assert.deepStrictEqual( * pipe( * none(), * match(() => 'a none', a => `a some containing ${a}`) @@ -1191,11 +1191,11 @@ export const flatMapNullable = (f: (a: A) => B | null | undefined) => * import { pipe } from '@fp-ts/core/Function' * * const O = liftOrder(N.Order) - * assert.strictEqual(O.compare(none(), none()), 0) - * assert.strictEqual(O.compare(none(), some(1)), -1) - * assert.strictEqual(O.compare(some(1), none()), 1) - * assert.strictEqual(O.compare(some(1), some(2)), -1) - * assert.strictEqual(O.compare(some(1), some(1)), 0) + * assert.deepStrictEqual(O.compare(none(), none()), 0) + * assert.deepStrictEqual(O.compare(none(), some(1)), -1) + * assert.deepStrictEqual(O.compare(some(1), none()), 1) + * assert.deepStrictEqual(O.compare(some(1), some(2)), -1) + * assert.deepStrictEqual(O.compare(some(1), some(1)), 0) * * @category sorting * @since 1.0.0 @@ -1254,21 +1254,21 @@ export const contains = (equivalence: Equivalence) => * import { some, none, exists } from '@fp-ts/core/Option' * import { pipe } from '@fp-ts/core/Function' * - * assert.strictEqual( + * assert.deepStrictEqual( * pipe( * some(1), * exists(n => n > 0) * ), * true * ) - * assert.strictEqual( + * assert.deepStrictEqual( * pipe( * some(1), * exists(n => n > 1) * ), * false * ) - * assert.strictEqual( + * assert.deepStrictEqual( * pipe( * none(), * exists(n => n > 0) @@ -1295,7 +1295,7 @@ export const exists = (predicate: Predicate) => * import { pipe } from '@fp-ts/core/Function' * * const iterable = [some(1), none(), some(2), none()] - * assert.strictEqual(pipe(iterable, reduceAll(0, (b, a) => b + a)), 3) + * assert.deepStrictEqual(pipe(iterable, reduceAll(0, (b, a) => b + a)), 3) */ export const reduceAll = (b: B, f: (b: B, a: A) => B) => (self: Iterable>): B => { diff --git a/test/Function.ts b/test/Function.ts index a5bcd369a..6a749a6be 100644 --- a/test/Function.ts +++ b/test/Function.ts @@ -1,4 +1,4 @@ -import * as Function from "@fp-ts/core/Function" +import * as _ from "@fp-ts/core/Function" import * as Number from "@fp-ts/core/Number" import * as String from "@fp-ts/core/String" import { deepStrictEqual, double } from "@fp-ts/core/test/util" @@ -9,7 +9,7 @@ const g = double describe.concurrent("Function", () => { it("getSemigroup", () => { - const S = Function.getSemigroup(Number.SemigroupSum)() + const S = _.getSemigroup(Number.SemigroupSum)() const f = (s: string) => s === "a" ? 0 : 1 const g = S.combine(String.length, f) deepStrictEqual(g(""), 1) @@ -19,7 +19,7 @@ describe.concurrent("Function", () => { }) it("getMonoid", () => { - const M = Function.getMonoid(Number.MonoidSum)() + const M = _.getMonoid(Number.MonoidSum)() const f = (s: string) => s === "a" ? 0 : 1 const g = M.combine(String.length, f) deepStrictEqual(g(""), 1) @@ -31,80 +31,80 @@ describe.concurrent("Function", () => { }) it("apply", () => { - deepStrictEqual(Function.apply("a")(String.length), 1) + deepStrictEqual(_.pipe("a", _.apply(String.length)), 1) }) it("flip", () => { const f = (a: number) => (b: string) => a - b.length const g = (a: number, i = 0) => (b: number) => a ** b + i - deepStrictEqual(Function.flip(f)("aaa")(2), -1) - deepStrictEqual(Function.flip(g)(2)(2, 1), 5) + deepStrictEqual(_.flip(f)("aaa")(2), -1) + deepStrictEqual(_.flip(g)(2)(2, 1), 5) }) it("compose", () => { - deepStrictEqual(Function.pipe(String.length, Function.compose(double))("aaa"), 6) + deepStrictEqual(_.pipe(String.length, _.compose(double))("aaa"), 6) }) it("unsafeCoerce", () => { - deepStrictEqual(Function.unsafeCoerce, Function.identity) + deepStrictEqual(_.unsafeCoerce, _.identity) }) it("constant", () => { - deepStrictEqual(Function.constant("a")(), "a") + deepStrictEqual(_.constant("a")(), "a") }) it("constTrue", () => { - deepStrictEqual(Function.constTrue(), true) + deepStrictEqual(_.constTrue(), true) }) it("constFalse", () => { - deepStrictEqual(Function.constFalse(), false) + deepStrictEqual(_.constFalse(), false) }) it("constNull", () => { - deepStrictEqual(Function.constNull(), null) + deepStrictEqual(_.constNull(), null) }) it("constUndefined", () => { - deepStrictEqual(Function.constUndefined(), undefined) + deepStrictEqual(_.constUndefined(), undefined) }) it("constVoid", () => { - deepStrictEqual(Function.constVoid(), undefined) + deepStrictEqual(_.constVoid(), undefined) }) it("absurd", () => { - assert.throws(() => Function.absurd(null as any as never)) + assert.throws(() => _.absurd(null as any as never)) }) it("hole", () => { - assert.throws(() => Function.hole()) + assert.throws(() => _.hole()) }) it("SK", () => { - expect(Function.SK(1, 2)).toEqual(2) + expect(_.SK(1, 2)).toEqual(2) }) it("flow", () => { - deepStrictEqual(Function.flow(f)(2), 3) - deepStrictEqual(Function.flow(f, g)(2), 6) - deepStrictEqual(Function.flow(f, g, f)(2), 7) - deepStrictEqual(Function.flow(f, g, f, g)(2), 14) - deepStrictEqual(Function.flow(f, g, f, g, f)(2), 15) - deepStrictEqual(Function.flow(f, g, f, g, f, g)(2), 30) - deepStrictEqual(Function.flow(f, g, f, g, f, g, f)(2), 31) - deepStrictEqual(Function.flow(f, g, f, g, f, g, f, g)(2), 62) - deepStrictEqual(Function.flow(f, g, f, g, f, g, f, g, f)(2), 63) + deepStrictEqual(_.flow(f)(2), 3) + deepStrictEqual(_.flow(f, g)(2), 6) + deepStrictEqual(_.flow(f, g, f)(2), 7) + deepStrictEqual(_.flow(f, g, f, g)(2), 14) + deepStrictEqual(_.flow(f, g, f, g, f)(2), 15) + deepStrictEqual(_.flow(f, g, f, g, f, g)(2), 30) + deepStrictEqual(_.flow(f, g, f, g, f, g, f)(2), 31) + deepStrictEqual(_.flow(f, g, f, g, f, g, f, g)(2), 62) + deepStrictEqual(_.flow(f, g, f, g, f, g, f, g, f)(2), 63) // this is just to satisfy noImplicitReturns and 100% coverage - deepStrictEqual((Function.flow as any)(...[f, g, f, g, f, g, f, g, f, g]), undefined) + deepStrictEqual((_.flow as any)(...[f, g, f, g, f, g, f, g, f, g]), undefined) }) it("tupled", () => { const f1 = (a: number): number => a * 2 const f2 = (a: number, b: number): number => a + b - const u1 = Function.tupled(f1) - const u2 = Function.tupled(f2) + const u1 = _.tupled(f1) + const u2 = _.tupled(f2) deepStrictEqual(u1([1]), 2) deepStrictEqual(u2([1, 2]), 3) }) @@ -112,45 +112,45 @@ describe.concurrent("Function", () => { it("untupled", () => { const f1 = (a: readonly [number]): number => a[0] * 2 const f2 = (a: readonly [number, number]): number => a[0] + a[1] - const u1 = Function.untupled(f1) - const u2 = Function.untupled(f2) + const u1 = _.untupled(f1) + const u2 = _.untupled(f2) deepStrictEqual(u1(1), 2) deepStrictEqual(u2(1, 2), 3) }) it("pipe", () => { - deepStrictEqual(Function.pipe(2), 2) - deepStrictEqual(Function.pipe(2, f), 3) - deepStrictEqual(Function.pipe(2, f, g), 6) - deepStrictEqual(Function.pipe(2, f, g, f), 7) - deepStrictEqual(Function.pipe(2, f, g, f, g), 14) - deepStrictEqual(Function.pipe(2, f, g, f, g, f), 15) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g), 30) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f), 31) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g), 62) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f), 63) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g), 126) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f), 127) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g), 254) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f), 255) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g), 510) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f), 511) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g), 1022) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f), 1023) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g), 2046) - deepStrictEqual(Function.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f), 2047) + deepStrictEqual(_.pipe(2), 2) + deepStrictEqual(_.pipe(2, f), 3) + deepStrictEqual(_.pipe(2, f, g), 6) + deepStrictEqual(_.pipe(2, f, g, f), 7) + deepStrictEqual(_.pipe(2, f, g, f, g), 14) + deepStrictEqual(_.pipe(2, f, g, f, g, f), 15) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g), 30) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f), 31) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g), 62) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f), 63) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g), 126) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f), 127) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g), 254) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f), 255) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g), 510) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f), 511) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g), 1022) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f), 1023) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g), 2046) + deepStrictEqual(_.pipe(2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f), 2047) deepStrictEqual( - (Function.pipe as any)(...[2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g]), + (_.pipe as any)(...[2, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g, f, g]), 4094 ) }) it("dual", () => { - const f = Function.dual< + const f = _.dual< (self: number, that: number) => number, (that: number) => (self: number) => number >(2, (a: number, b: number): number => a - b) deepStrictEqual(f(3, 2), 1) - deepStrictEqual(Function.pipe(3, f(2)), 1) + deepStrictEqual(_.pipe(3, f(2)), 1) }) }) From 9569811ea5506fb4206c1b9dbde7dbdbe7e9a8bc Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 29 Jan 2023 09:11:33 +0100 Subject: [PATCH 114/255] Covariant: flip flap --- .changeset/poor-crabs-drum.md | 5 +++++ docs/modules/Either.ts.md | 2 +- docs/modules/Option.ts.md | 2 +- docs/modules/ReadonlyArray.ts.md | 2 +- docs/modules/These.ts.md | 2 +- docs/modules/typeclass/Covariant.ts.md | 2 +- src/Either.ts | 6 ++---- src/Option.ts | 5 ++--- src/ReadonlyArray.ts | 6 +++--- src/These.ts | 6 ++---- src/typeclass/Covariant.ts | 5 +++-- test/typeclass/Covariant.ts | 4 ++-- 12 files changed, 24 insertions(+), 23 deletions(-) create mode 100644 .changeset/poor-crabs-drum.md diff --git a/.changeset/poor-crabs-drum.md b/.changeset/poor-crabs-drum.md new file mode 100644 index 000000000..a9e23201c --- /dev/null +++ b/.changeset/poor-crabs-drum.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": minor +--- + +Covariant: flip flap diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index a787d4819..de81e01f5 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -1117,7 +1117,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const flap: (a: A) => (self: Either B>) => Either +export declare const flap: (self: Either B>) => (a: A) => Either ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 928989ffa..e8c73f456 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -1173,7 +1173,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const flap: (a: A) => (fab: Option<(a: A) => B>) => Option +export declare const flap: (self: Option<(a: A) => B>) => (a: A) => Option ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 2f90570f3..ddf8d7e70 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -1441,7 +1441,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const flap: (a: A) => (self: readonly ((a: A) => B)[]) => B[] +export declare const flap: (self: readonly ((a: A) => B)[]) => (a: A) => B[] ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 2c7cc515e..f36d347cb 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1213,7 +1213,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const flap: (a: A) => (self: any) => any +export declare const flap: (self: any) => (a: A) => any ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index 77af9c2d2..26665b76a 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -66,7 +66,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const flap: (F: Covariant) => (a: A) => (self: any) => any +export declare const flap: (F: Covariant) => (self: any) => (a: A) => any ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index 9b78b7f45..0a21211eb 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -160,10 +160,8 @@ export const bindTo: ( * @category mapping * @since 1.0.0 */ -export const flap: (a: A) => (self: Either B>) => Either = covariant - .flap( - Covariant - ) +export const flap: (self: Either B>) => (a: A) => Either = covariant + .flap(Covariant) /** * Maps the Right value of this effect to the specified constant value. diff --git a/src/Option.ts b/src/Option.ts index d8f198c47..ac89f6556 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -515,9 +515,8 @@ export { * @category mapping * @since 1.0.0 */ -export const flap: (a: A) => (fab: Option<(a: A) => B>) => Option = covariant.flap( - Covariant -) +export const flap: (self: Option<(a: A) => B>) => (a: A) => Option = covariant + .flap(Covariant) /** * Maps the `Some` value of this option to the specified constant value. diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 3c85f113b..2cca14ffa 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1317,9 +1317,9 @@ export { * @category mapping * @since 1.0.0 */ -export const flap: (a: A) => ( - self: ReadonlyArray<(a: A) => B> -) => Array = covariant.flap(Covariant) as any +export const flap: (self: ReadonlyArray<(a: A) => B>) => (a: A) => Array = covariant.flap( + Covariant +) as any /** * Maps the success value of this effect to the specified constant value. diff --git a/src/These.ts b/src/These.ts index ea198ea05..808ceb78f 100644 --- a/src/These.ts +++ b/src/These.ts @@ -634,10 +634,8 @@ export const bindTo: ( * @category mapping * @since 1.0.0 */ -export const flap: (a: A) => (self: These B>) => These = covariant - .flap( - Covariant - ) +export const flap: (self: These B>) => (a: A) => These = covariant + .flap(Covariant) /** * Maps the right value of this effect to the specified constant value. diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index d1200e9e4..972540128 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -1,6 +1,7 @@ /** * @since 1.0.0 */ +import { pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" @@ -50,8 +51,8 @@ export const make = (map: Covariant["map"]): Covariant< * @since 1.0.0 */ export const flap = (F: Covariant) => - (a: A): ((self: Kind B>) => Kind) => - F.map(f => f(a)) + (self: Kind B>) => + (a: A): Kind => pipe(self, F.map(f => f(a))) /** * @category mapping diff --git a/test/typeclass/Covariant.ts b/test/typeclass/Covariant.ts index 5fc4acac0..c803cfbb0 100644 --- a/test/typeclass/Covariant.ts +++ b/test/typeclass/Covariant.ts @@ -21,8 +21,8 @@ describe("Covariant", () => { it("flap", () => { const flap = _.flap(O.Covariant) - U.deepStrictEqual(pipe(O.none(), flap(1)), O.none()) - U.deepStrictEqual(pipe(O.some(U.double), flap(1)), O.some(2)) + U.deepStrictEqual(pipe(1, flap(O.none())), O.none()) + U.deepStrictEqual(pipe(1, flap(O.some(U.double))), O.some(2)) }) it("as", () => { From cb797b7623ed43fc9e9c974c8e22a4a1b56eae36 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 29 Jan 2023 10:13:02 +0100 Subject: [PATCH 115/255] Option: fix flatMapNullable example --- docs/modules/Option.ts.md | 42 ++++++++++------------ src/Option.ts | 74 ++++++++++++++++++--------------------- 2 files changed, 54 insertions(+), 62 deletions(-) diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index e8c73f456..0b5562c2b 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -476,7 +476,7 @@ Added in v1.0.0 ## firstSomeOf -Given an Iterable collection of `Option`s, the function returns the first `Some` option found in the collection. +Given an Iterable collection of `Option`s, the function returns the first `Some` found in the collection. **Signature** @@ -522,7 +522,7 @@ Added in v1.0.0 ## orElse -Returns the provided option `that` if `self` is `None`, otherwise returns `self`. +Returns the provided `Option` `that` if `self` is `None`, otherwise returns `self`. **Signature** @@ -571,9 +571,9 @@ Added in v1.0.0 ## orElseEither Similar to `orElse`, but instead of returning a simple union, it returns an `Either` object, -which contains information about which of the two options has been chosen. +which contains information about which of the two `Option`s has been chosen. -This is useful when it's important to know whether the value was retrieved from the first option or the second option. +This is useful when it's important to know whether the value was retrieved from the first `Option` or the second option. **Signature** @@ -622,7 +622,7 @@ Added in v1.0.0 ## isNone -Returns `true` if the option is `None`, `false` otherwise. +Returns `true` if the `Option` is `None`, `false` otherwise. **Signature** @@ -665,7 +665,7 @@ Added in v1.0.0 ## isSome -Returns `true` if the option is an instance of `Some`, `false` otherwise. +Returns `true` if the `Option` is an instance of `Some`, `false` otherwise. **Signature** @@ -956,7 +956,7 @@ Added in v1.0.0 ## getOrNull -Returns the value of the option if it is a `Some`, otherwise returns `null`. +Returns the value of the `Option` if it is a `Some`, otherwise returns `null`. **Signature** @@ -978,7 +978,7 @@ Added in v1.0.0 ## getOrThrow -Returns the contained value if the option is `Some`, otherwise throws an error. +Returns the contained value if the `Option` is `Some`, otherwise throws an error. **Signature** @@ -1000,7 +1000,7 @@ Added in v1.0.0 ## getOrUndefined -Returns the value of the option if it is a `Some`, otherwise returns `undefined`. +Returns the value of the `Option` if it is a `Some`, otherwise returns `undefined`. **Signature** @@ -1063,8 +1063,8 @@ Added in v1.0.0 ## lift2 -Applies a function to the contained value of two options, returning a new `option` of the result. -If either of the options is `None`, the result will be `None`. +Applies a function to the contained value of two `Option`s, returning a new `Option` of the result. +If either of the `Option`s is `None`, the result will be `None`. **Signature** @@ -1144,7 +1144,7 @@ Added in v1.0.0 ## as -Maps the `Some` value of this option to the specified constant value. +Maps the `Some` value of this `Option` to the specified constant value. **Signature** @@ -1158,7 +1158,7 @@ Added in v1.0.0 Returns the `Option` resulting from mapping the `Some` value to `void`. -This is useful when the value of the Option is not needed, but the presence or absence of the value is important. +This is useful when the value of the `Option` is not needed, but the presence or absence of the value is important. **Signature** @@ -1289,7 +1289,7 @@ Added in v1.0.0 ## andThenDiscard -Sequences the specified `that` option but ignores its value. +Sequences the specified `that` `Option` but ignores its value. It is useful when we want to chain multiple operations, but only care about the result of `self`. @@ -1338,7 +1338,7 @@ export declare const flatMapNullable: ( **Example** ```ts -import { some, none, fromNullable, flatMapNullable } from '@fp-ts/core/Option' +import { some, none, flatMapNullable } from '@fp-ts/core/Option' import { pipe } from '@fp-ts/core/Function' interface Employee { @@ -1355,10 +1355,8 @@ const employee1: Employee = { company: { address: { street: { name: 'high street assert.deepStrictEqual( pipe( - fromNullable(employee1.company), - flatMapNullable((company) => company.address), - flatMapNullable((address) => address.street), - flatMapNullable((street) => street.name) + some(employee1), + flatMapNullable((employee) => employee.company?.address?.street?.name) ), some('high street') ) @@ -1367,10 +1365,8 @@ const employee2: Employee = { company: { address: { street: {} } } } assert.deepStrictEqual( pipe( - fromNullable(employee2.company), - flatMapNullable((company) => company.address), - flatMapNullable((address) => address.street), - flatMapNullable((street) => street.name) + some(employee2), + flatMapNullable((employee) => employee.company?.address?.street?.name) ), none() ) diff --git a/src/Option.ts b/src/Option.ts index ac89f6556..b98c7c3cf 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -121,9 +121,9 @@ export const some: (value: A) => Option = option.some export const isOption: (input: unknown) => input is Option = option.isOption /** - * Returns `true` if the option is `None`, `false` otherwise. + * Returns `true` if the `Option` is `None`, `false` otherwise. * - * @param self - The option to check. + * @param self - The `Option` to check. * * @example * import { some, none, isNone } from '@fp-ts/core/Option' @@ -137,9 +137,9 @@ export const isOption: (input: unknown) => input is Option = option.isO export const isNone: (self: Option) => self is None = option.isNone /** - * Returns `true` if the option is an instance of `Some`, `false` otherwise. + * Returns `true` if the `Option` is an instance of `Some`, `false` otherwise. * - * @param self - The option to check. + * @param self - The `Option` to check. * * @example * import { some, none, isSome } from '@fp-ts/core/Option' @@ -227,7 +227,7 @@ export const fromEither: (self: Either) => Option = either.getRig /** * Converts an `Option` to an `Either`, allowing you to provide a value to be used in the case of a `None`. * - * @param onNone - a function that produces an error value when the option is `None`. + * @param onNone - a function that produces an error value when the `Option` is `None`. * @param self - the `Option` to convert. * * @example @@ -269,10 +269,10 @@ export const getOrElse = (onNone: LazyArg) => (self: Option): A | B => isNone(self) ? onNone() : self.value /** - * Returns the provided option `that` if `self` is `None`, otherwise returns `self`. + * Returns the provided `Option` `that` if `self` is `None`, otherwise returns `self`. * - * @param that - The option to return if `self` is `None`. - * @param self - The first option to be checked. + * @param that - The `Option` to return if `self` is `None`. + * @param self - The first `Option` to be checked. * * @example * import * as O from '@fp-ts/core/Option' @@ -315,12 +315,12 @@ export const orElse = (that: LazyArg>) => /** * Similar to `orElse`, but instead of returning a simple union, it returns an `Either` object, - * which contains information about which of the two options has been chosen. + * which contains information about which of the two `Option`s has been chosen. * - * This is useful when it's important to know whether the value was retrieved from the first option or the second option. + * This is useful when it's important to know whether the value was retrieved from the first `Option` or the second option. * - * @param that - The second option to be considered if the first option is `None`. - * @param self - The first option to be checked. + * @param that - The second `Option` to be considered if the first `Option` is `None`. + * @param self - The first `Option` to be checked. * * @category error handling * @since 1.0.0 @@ -334,7 +334,7 @@ export const orElseEither = ( pipe(self, map(either.left)) /** - * Given an Iterable collection of `Option`s, the function returns the first `Some` option found in the collection. + * Given an Iterable collection of `Option`s, the function returns the first `Some` found in the collection. * * @param collection - An iterable collection of `Option` to be searched. * @@ -356,9 +356,9 @@ export const firstSomeOf = (collection: Iterable>): Option => { // ------------------------------------------------------------------------------------- /** - * Returns the value of the option if it is a `Some`, otherwise returns `null`. + * Returns the value of the `Option` if it is a `Some`, otherwise returns `null`. * - * @param self - The option to extract the value from. + * @param self - The `Option` to extract the value from. * * @example * import { some, none, getOrNull } from '@fp-ts/core/Option' @@ -373,9 +373,9 @@ export const firstSomeOf = (collection: Iterable>): Option => { export const getOrNull: (self: Option) => A | null = getOrElse(constNull) /** - * Returns the value of the option if it is a `Some`, otherwise returns `undefined`. + * Returns the value of the `Option` if it is a `Some`, otherwise returns `undefined`. * - * @param self - The option to extract the value from. + * @param self - The `Option` to extract the value from. * * @example * import { some, none, getOrUndefined } from '@fp-ts/core/Option' @@ -426,11 +426,11 @@ export const liftThrowable = , B>( ): ((...a: A) => Option) => (...a) => fromThrowable(() => f(...a)) /** - * Returns the contained value if the option is `Some`, otherwise throws an error. + * Returns the contained value if the `Option` is `Some`, otherwise throws an error. * * @param onNone - An optional function that returns the error to be thrown when the `Option` is `None`. * @param self - The `Option` to extract the value from. - * @throws The error returned by `onNone` if the option is `None`. + * @throws The error returned by `onNone` if the `Option` is `None`. * * @example * import { pipe } from '@fp-ts/core/Function' @@ -460,7 +460,7 @@ export const getOrThrow = ( * Maps the given function to the value of the `Option` if it is a `Some`, otherwise it returns `None`. * * @param f - The function to map over the value of the `Option` - * @param self - An option to map + * @param self - An `Option` to map * * @category mapping * @since 1.0.0 @@ -519,7 +519,7 @@ export const flap: (self: Option<(a: A) => B>) => (a: A) => Option = co .flap(Covariant) /** - * Maps the `Some` value of this option to the specified constant value. + * Maps the `Some` value of this `Option` to the specified constant value. * * @category mapping * @since 1.0.0 @@ -529,7 +529,7 @@ export const as: (b: B) => <_>(self: Option<_>) => Option = covariant.as(C /** * Returns the `Option` resulting from mapping the `Some` value to `void`. * - * This is useful when the value of the Option is not needed, but the presence or absence of the value is important. + * This is useful when the value of the `Option` is not needed, but the presence or absence of the value is important. * * @category mapping * @since 1.0.0 @@ -626,12 +626,12 @@ export const bind: ( .bind(Chainable) /** - * Sequences the specified `that` option but ignores its value. + * Sequences the specified `that` `Option` but ignores its value. * * It is useful when we want to chain multiple operations, but only care about the result of `self`. * - * @param that - The option that will be ignored in the chain and discarded - * @param self - The option we care about + * @param that - The `Option` that will be ignored in the chain and discarded + * @param self - The `Option` we care about * * @category sequencing * @since 1.0.0 @@ -828,12 +828,12 @@ export const getOptionalMonoid = ( ) /** - * Applies a function to the contained value of two options, returning a new `option` of the result. - * If either of the options is `None`, the result will be `None`. + * Applies a function to the contained value of two `Option`s, returning a new `Option` of the result. + * If either of the `Option`s is `None`, the result will be `None`. * - * @param f - A function to apply to the contained values of the options - * @param that - An option to lift the function over - * @param self - An option to lift the function over + * @param f - A function to apply to the contained values of the `Option`s + * @param that - An `Option` to lift the function over + * @param self - An `Option` to lift the function over * * @category lifting * @since 1.0.0 @@ -1133,7 +1133,7 @@ export const liftNullable = , B>( * This is `flatMap` + `fromNullable`, useful when working with optional values. * * @example - * import { some, none, fromNullable, flatMapNullable } from '@fp-ts/core/Option' + * import { some, none, flatMapNullable } from '@fp-ts/core/Option' * import { pipe } from '@fp-ts/core/Function' * * interface Employee { @@ -1150,10 +1150,8 @@ export const liftNullable = , B>( * * assert.deepStrictEqual( * pipe( - * fromNullable(employee1.company), - * flatMapNullable(company => company.address), - * flatMapNullable(address => address.street), - * flatMapNullable(street => street.name) + * some(employee1), + * flatMapNullable(employee => employee.company?.address?.street?.name), * ), * some('high street') * ) @@ -1162,10 +1160,8 @@ export const liftNullable = , B>( * * assert.deepStrictEqual( * pipe( - * fromNullable(employee2.company), - * flatMapNullable(company => company.address), - * flatMapNullable(address => address.street), - * flatMapNullable(street => street.name) + * some(employee2), + * flatMapNullable(employee => employee.company?.address?.street?.name), * ), * none() * ) From 14de6de207c63d460ecabcb6b13f5d9abb697f05 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 29 Jan 2023 11:17:07 +0100 Subject: [PATCH 116/255] Option: remove coproductEither --- .changeset/mean-buckets-shake.md | 5 ++ docs/modules/Option.ts.md | 119 ++++++++++++++++++++------- src/Option.ts | 135 +++++++++++++++++++++++-------- test/Option.ts | 7 -- 4 files changed, 196 insertions(+), 70 deletions(-) create mode 100644 .changeset/mean-buckets-shake.md diff --git a/.changeset/mean-buckets-shake.md b/.changeset/mean-buckets-shake.md new file mode 100644 index 000000000..9baf53a07 --- /dev/null +++ b/.changeset/mean-buckets-shake.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": minor +--- + +Option: remove coproductEither diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 0b5562c2b..e7d212f3f 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -121,7 +121,6 @@ Added in v1.0.0 - [ap](#ap) - [composeKleisliArrow](#composekleisliarrow) - [contains](#contains) - - [coproductEither](#coproducteither) - [element](#element) - [exists](#exists) - [flatten](#flatten) @@ -160,12 +159,23 @@ Added in v1.0.0 ## multiplyAll +Multiply all numbers in an iterable of `Option` ignoring the `None` values. + **Signature** ```ts export declare const multiplyAll: (self: Iterable>) => number ``` +**Example** + +```ts +import { multiplyAll, some, none } from '@fp-ts/core/Option' + +const iterable = [some(2), none(), some(3), none()] +assert.deepStrictEqual(multiplyAll(iterable), 6) +``` + Added in v1.0.0 ## multiplyBigint @@ -210,12 +220,23 @@ Added in v1.0.0 ## sumAll +Sum all numbers in an iterable of `Option` ignoring the `None` values. + **Signature** ```ts export declare const sumAll: (self: Iterable>) => number ``` +**Example** + +```ts +import { sumAll, some, none } from '@fp-ts/core/Option' + +const iterable = [some(2), none(), some(3), none()] +assert.deepStrictEqual(sumAll(iterable), 5) +``` + Added in v1.0.0 ## sumBigint @@ -587,6 +608,10 @@ Added in v1.0.0 ## filter +Filters an `Option` using a predicate. If the predicate is not satisfied or the `Option` is `None` returns `None`. + +If you need to change the type of the `Option` in addition to filtering, see `filterMap`. + **Signature** ```ts @@ -600,6 +625,10 @@ Added in v1.0.0 ## filterMap +Maps over the value of an `Option` and filters out `None`s. + +Useful when in addition to filtering you also want to change the type of the `Option`. + **Signature** ```ts @@ -1076,12 +1105,28 @@ Added in v1.0.0 ## liftEither +Lifts an `Either` function to an `Option` function. + **Signature** ```ts export declare const liftEither: (f: (...a: A) => any) => (...a: A) => Option ``` +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +const parse = (s: string) => (isNaN(+s) ? E.left(`Error: ${s} is not a number`) : E.right(+s)) + +const parseNumber = O.liftEither(parse) + +assert.deepEqual(parseNumber('12'), O.some(12)) +assert.deepEqual(parseNumber('not a number'), O.none()) +``` + Added in v1.0.0 ## liftNullable @@ -1315,12 +1360,27 @@ Added in v1.0.0 ## flatMapEither +Applies a provided function that returns an `Either` to the contents of an `Option`, flattening the result into another `Option`. + **Signature** ```ts export declare const flatMapEither: (f: (a: A) => any) => (self: Option) => Option ``` +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' +import { pipe } from '@fp-ts/core/Function' + +const f = (n: number) => (n > 2 ? E.left('Too big') : E.right(n + 1)) + +assert.deepStrictEqual(pipe(O.some(1), O.flatMapEither(f)), O.some(2)) +assert.deepStrictEqual(pipe(O.some(3), O.flatMapEither(f)), O.none()) +``` + Added in v1.0.0 ## flatMapNullable @@ -1491,7 +1551,7 @@ Added in v1.0.0 ## contains -Returns a function that checks if an `Option` contains a given value using a provided `equivalence` function. +Returns a function that checks if an `Option` contains a given value using a provided `Equivalence` instance. **Signature** @@ -1499,14 +1559,16 @@ Returns a function that checks if an `Option` contains a given value using a pro export declare const contains: (equivalence: any) => (a: A) => (self: Option) => boolean ``` -Added in v1.0.0 - -## coproductEither - -**Signature** +**Example** ```ts -export declare const coproductEither: (that: Option) => (self: Option) => Option +import { some, none, contains } from '@fp-ts/core/Option' +import { Equivalence } from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe(some(2), contains(Equivalence)(2)), true) +assert.deepStrictEqual(pipe(some(1), contains(Equivalence)(2)), false) +assert.deepStrictEqual(pipe(none(), contains(Equivalence)(2)), false) ``` Added in v1.0.0 @@ -1525,7 +1587,7 @@ Added in v1.0.0 ## exists -Returns `true` if the predicate is satisfied by the wrapped value +Check if a value in an `Option` type meets a certain predicate. **Signature** @@ -1539,27 +1601,11 @@ export declare const exists: (predicate: any) => (self: Option) => boolean import { some, none, exists } from '@fp-ts/core/Option' import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual( - pipe( - some(1), - exists((n) => n > 0) - ), - true -) -assert.deepStrictEqual( - pipe( - some(1), - exists((n) => n > 1) - ), - false -) -assert.deepStrictEqual( - pipe( - none(), - exists((n) => n > 0) - ), - false -) +const isEven = (n: number) => n % 2 === 0 + +assert.deepStrictEqual(pipe(some(2), exists(isEven)), true) +assert.deepStrictEqual(pipe(some(1), exists(isEven)), false) +assert.deepStrictEqual(pipe(none(), exists(isEven)), false) ``` Added in v1.0.0 @@ -1636,12 +1682,25 @@ Added in v1.0.0 ## toArray +Transforms an `Option` into an `Array`. +If the input is `None`, an empty array is returned. +If the input is `Some`, the value is wrapped in an array. + **Signature** ```ts export declare const toArray: (self: Option) => A[] ``` +**Example** + +```ts +import { some, none, toArray } from '@fp-ts/core/Option' + +assert.deepStrictEqual(toArray(some(1)), [1]) +assert.deepStrictEqual(toArray(none()), []) +``` + Added in v1.0.0 ## tuple diff --git a/src/Option.ts b/src/Option.ts index b98c7c3cf..596fe050a 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -937,13 +937,6 @@ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { export const getFirstSomeSemigroup: () => Semigroup> = semiCoproduct .getSemigroup(SemiCoproduct) -/** - * @since 1.0.0 - */ -export const coproductEither = (that: Option) => - (self: Option): Option> => - isNone(self) ? pipe(that, map(either.right)) : pipe(self, map(either.left)) - /** * @category instances * @since 1.0.0 @@ -987,6 +980,18 @@ export const Foldable: foldable.Foldable = { } /** + * Transforms an `Option` into an `Array`. + * If the input is `None`, an empty array is returned. + * If the input is `Some`, the value is wrapped in an array. + * + * @param self - The `Option` to convert to an array. + * + * @example + * import { some, none, toArray } from '@fp-ts/core/Option' + * + * assert.deepStrictEqual(toArray(some(1)), [1]) + * assert.deepStrictEqual(toArray(none()), []) + * * @since 1.0.0 */ export const toArray: (self: Option) => Array = foldable.toArray(Foldable) @@ -1007,6 +1012,13 @@ export const separate: (self: Option>) => [Option, Option< .separate({ ...Covariant, ...Compactable }) /** + * Maps over the value of an `Option` and filters out `None`s. + * + * Useful when in addition to filtering you also want to change the type of the `Option`. + * + * @param f - A function to apply to the value of the `Option`. + * @param self - The `Option` to map over. + * * @category filtering * @since 1.0.0 */ @@ -1022,6 +1034,13 @@ export const Filterable: filterable.Filterable = { } /** + * Filters an `Option` using a predicate. If the predicate is not satisfied or the `Option` is `None` returns `None`. + * + * If you need to change the type of the `Option` in addition to filtering, see `filterMap`. + * + * @param predicate - A predicate function to apply to the `Option` value. + * @param fb - The `Option` to filter. + * * @category filtering * @since 1.0.0 */ @@ -1220,6 +1239,22 @@ export const liftPredicate: { } = (predicate: Predicate) => (b: B) => predicate(b) ? some(b) : option.none /** + * Lifts an `Either` function to an `Option` function. + * + * @param f - Any variadic function that returns an `Either`. + * + * @example + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * + * const parse = (s: string) => + * isNaN(+s) ? E.left(`Error: ${s} is not a number`) : E.right(+s) + * + * const parseNumber = O.liftEither(parse) + * + * assert.deepEqual(parseNumber('12'), O.some(12)) + * assert.deepEqual(parseNumber('not a number'), O.none()) + * * @category lifting * @since 1.0.0 */ @@ -1228,6 +1263,21 @@ export const liftEither = , E, B>( ) => (...a: A): Option => fromEither(f(...a)) /** + * Applies a provided function that returns an `Either` to the contents of an `Option`, flattening the result into another `Option`. + * + * @param f - The function to be applied to the contents of the `Option`. + * @param self - The `Option` to apply the function to. + * + * @example + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * import { pipe } from '@fp-ts/core/Function' + * + * const f = (n: number) => (n > 2 ? E.left('Too big') : E.right(n + 1)) + * + * assert.deepStrictEqual(pipe(O.some(1), O.flatMapEither(f)), O.some(2)) + * assert.deepStrictEqual(pipe(O.some(3), O.flatMapEither(f)), O.none()) + * * @category sequencing * @since 1.0.0 */ @@ -1235,7 +1285,19 @@ export const flatMapEither = (f: (a: A) => Either) => (self: Option): Option => pipe(self, flatMap(liftEither(f))) /** - * Returns a function that checks if an `Option` contains a given value using a provided `equivalence` function. + * Returns a function that checks if an `Option` contains a given value using a provided `Equivalence` instance. + * + * @param equivalence - An `Equivalence` instance to compare values of the `Option`. + * @param a - The value to compare against the `Option`. + * + * @example + * import { some, none, contains } from '@fp-ts/core/Option' + * import { Equivalence } from '@fp-ts/core/Number' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.deepStrictEqual(pipe(some(2), contains(Equivalence)(2)), true) + * assert.deepStrictEqual(pipe(some(1), contains(Equivalence)(2)), false) + * assert.deepStrictEqual(pipe(none(), contains(Equivalence)(2)), false) * * @since 1.0.0 */ @@ -1243,33 +1305,20 @@ export const contains = (equivalence: Equivalence) => (a: A) => (self: Option): boolean => isNone(self) ? false : equivalence(self.value, a) /** - * Returns `true` if the predicate is satisfied by the wrapped value + * Check if a value in an `Option` type meets a certain predicate. + * + * @param predicate - The condition to check. + * @param self - The `Option` to check. * * @example * import { some, none, exists } from '@fp-ts/core/Option' * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual( - * pipe( - * some(1), - * exists(n => n > 0) - * ), - * true - * ) - * assert.deepStrictEqual( - * pipe( - * some(1), - * exists(n => n > 1) - * ), - * false - * ) - * assert.deepStrictEqual( - * pipe( - * none(), - * exists(n => n > 0) - * ), - * false - * ) + * const isEven = (n: number) => n % 2 === 0 + * + * assert.deepStrictEqual(pipe(some(2), exists(isEven)), true) + * assert.deepStrictEqual(pipe(some(1), exists(isEven)), false) + * assert.deepStrictEqual(pipe(none(), exists(isEven)), false) * * @since 1.0.0 */ @@ -1281,9 +1330,9 @@ export const exists = (predicate: Predicate) => * * @since 1.0.0 * - * @param b - The initial value of the accumulator - * @param f - The reducing function that takes the current accumulator value and the unwrapped value of an `Option` - * @param self - The Iterable of `Option` to be reduced + * @param b - The initial value of the accumulator. + * @param f - The reducing function that takes the current accumulator value and the unwrapped value of an `Option`. + * @param self - The Iterable of `Option` to be reduced. * * @example * import { some, none, reduceAll } from '@fp-ts/core/Option' @@ -1350,6 +1399,16 @@ export const multiplyBigint = lift2(BI.multiply) export const subtractBigint = lift2(BI.subtract) /** + * Sum all numbers in an iterable of `Option` ignoring the `None` values. + * + * @param self - The iterable of `Option` to be summed. + * + * @example + * import { sumAll, some, none } from '@fp-ts/core/Option' + * + * const iterable = [some(2), none(), some(3), none()] + * assert.deepStrictEqual(sumAll(iterable), 5) + * * @category algebraic operations * @since 1.0.0 */ @@ -1364,6 +1423,16 @@ export const sumAll = (self: Iterable>): number => { } /** + * Multiply all numbers in an iterable of `Option` ignoring the `None` values. + * + * @param self - The iterable of `Option` to be multiplied. + * + * @example + * import { multiplyAll, some, none } from '@fp-ts/core/Option' + * + * const iterable = [some(2), none(), some(3), none()] + * assert.deepStrictEqual(multiplyAll(iterable), 6) + * * @category algebraic operations * @since 1.0.0 */ diff --git a/test/Option.ts b/test/Option.ts index fed2b3e92..c06d7bda7 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -117,13 +117,6 @@ describe.concurrent("Option", () => { Util.deepStrictEqual(pipe(E.right(1), _.isOption), false) }) - it("coproductEither", () => { - Util.deepStrictEqual(pipe(_.none(), _.coproductEither(_.none())), _.none()) - Util.deepStrictEqual(pipe(_.none(), _.coproductEither(_.some("a"))), _.some(E.right("a"))) - Util.deepStrictEqual(pipe(_.some(1), _.coproductEither(_.none())), _.some(E.left(1))) - Util.deepStrictEqual(pipe(_.some(1), _.coproductEither(_.some("a"))), _.some(E.left(1))) - }) - it("coproductMany", () => { const coproductMany = _.SemiCoproduct.coproductMany Util.deepStrictEqual(coproductMany(_.some(1), []), _.some(1)) From 556ee2fd2bead31cd78fd452ad7c45404132ee3b Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 29 Jan 2023 17:50:59 +0100 Subject: [PATCH 117/255] chore --- src/Either.ts | 46 +++++++++++++++++++----------- src/Identity.ts | 38 ++++++++++++++++--------- src/Option.ts | 54 ++++++++++++++++++++++++------------ src/Predicate.ts | 4 ++- src/ReadonlyArray.ts | 38 ++++++++++++++++--------- src/These.ts | 33 ++++++++++++++-------- src/typeclass/Equivalence.ts | 4 ++- src/typeclass/Order.ts | 4 ++- src/typeclass/Semigroup.ts | 6 ++-- 9 files changed, 151 insertions(+), 76 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 0a21211eb..857b91493 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -255,8 +255,9 @@ export const Do: Either = of_.Do(Of) * @since 1.0.0 */ export const Pointed: pointed.Pointed = { - ...Of, - ...Covariant + of, + imap: Invariant.imap, + map } /** @@ -302,8 +303,9 @@ export const composeKleisliArrow: ( * @since 1.0.0 */ export const Chainable: chainable.Chainable = { - ...FlatMap, - ...Covariant + imap: Invariant.imap, + map, + flatMap } /** @@ -335,8 +337,10 @@ export const andThenDiscard: ( * @since 1.0.0 */ export const Monad: monad.Monad = { - ...Pointed, - ...FlatMap + imap: Invariant.imap, + of, + map, + flatMap } const productMany = ( @@ -361,7 +365,7 @@ const productMany = ( * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - ...Invariant, + imap: Invariant.imap, product: (self, that) => isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self, productMany @@ -411,8 +415,10 @@ const productAll = ( * @since 1.0.0 */ export const Product: product_.Product = { - ...Of, - ...SemiProduct, + of, + imap: Invariant.imap, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll } @@ -443,8 +449,10 @@ export const struct: >>( * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { - ...SemiProduct, - ...Covariant + imap: Invariant.imap, + map: Covariant.map, + product: SemiProduct.product, + productMany: SemiProduct.productMany } /** @@ -499,8 +507,12 @@ export const ap: ( * @since 1.0.0 */ export const Applicative: applicative.Applicative = { - ...SemiApplicative, - ...Product + imap: Invariant.imap, + of, + map, + product: SemiProduct.product, + productMany: SemiProduct.productMany, + productAll } /** @@ -540,7 +552,7 @@ export const firstRightOf = (collection: Iterable>) => * @since 1.0.0 */ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { - ...Invariant, + imap: Invariant.imap, coproduct: (self, that) => isRight(self) ? self : that, coproductMany: (self, collection) => pipe(self, firstRightOf(collection)) } @@ -638,8 +650,10 @@ export const orElseFail = ( * @since 1.0.0 */ export const SemiAlternative: semiAlternative.SemiAlternative = { - ...Covariant, - ...SemiCoproduct + map, + imap: Invariant.imap, + coproduct: SemiCoproduct.coproduct, + coproductMany: SemiCoproduct.coproductMany } /** diff --git a/src/Identity.ts b/src/Identity.ts index 116fa2994..be9a592d1 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -105,8 +105,9 @@ export const Do: Identity<{}> = of_.Do(Of) * @since 1.0.0 */ export const Pointed: pointed.Pointed = { - ...Of, - ...Covariant + of: Of.of, + imap: Invariant.imap, + map: Covariant.map } /** @@ -122,8 +123,9 @@ export const FlatMap: flatMap_.FlatMap = { * @since 1.0.0 */ export const Chainable: chainable.Chainable = { - ...FlatMap, - ...Covariant + imap: Invariant.imap, + map: Covariant.map, + flatMap: FlatMap.flatMap } /** @@ -144,8 +146,10 @@ export const bind: ( * @since 1.0.0 */ export const Monad: monad.Monad = { - ...Pointed, - ...FlatMap + imap: Invariant.imap, + of: Of.of, + map: Covariant.map, + flatMap: FlatMap.flatMap } /** @@ -153,7 +157,7 @@ export const Monad: monad.Monad = { * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - ...Invariant, + imap: Invariant.imap, product: (self, that) => [self, that], productMany: (self, collection) => [self, ...collection] } @@ -163,8 +167,10 @@ export const SemiProduct: semiProduct.SemiProduct = { * @since 1.0.0 */ export const Product: product_.Product = { - ...Of, - ...SemiProduct, + of: Of.of, + imap: Invariant.imap, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll: readonlyArray.fromIterable } @@ -173,8 +179,10 @@ export const Product: product_.Product = { * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { - ...SemiProduct, - ...Covariant + imap: Invariant.imap, + map: Covariant.map, + product: SemiProduct.product, + productMany: SemiProduct.productMany } /** @@ -182,8 +190,12 @@ export const SemiApplicative: semiApplicative.SemiApplicative = { - ...SemiApplicative, - ...Product + imap: Invariant.imap, + of: Of.of, + map: Covariant.map, + product: SemiProduct.product, + productMany: SemiProduct.productMany, + productAll: Product.productAll } /** diff --git a/src/Option.ts b/src/Option.ts index 596fe050a..636d200da 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -565,8 +565,9 @@ export const Do: Option<{}> = of_.Do(Of) * @since 1.0.0 */ export const Pointed: pointed.Pointed = { - ...Of, - ...Covariant + of, + imap: Invariant.imap, + map } /** @@ -611,8 +612,9 @@ export const composeKleisliArrow: ( * @since 1.0.0 */ export const Chainable: chainable.Chainable = { - ...FlatMap, - ...Covariant + imap: Invariant.imap, + map, + flatMap } /** @@ -698,8 +700,10 @@ export const inspectNone = ( * @since 1.0.0 */ export const Monad: monad.Monad = { - ...Pointed, - ...FlatMap + imap: Invariant.imap, + of, + map, + flatMap } const productMany = ( @@ -724,7 +728,7 @@ const productMany = ( * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - ...Invariant, + imap: Invariant.imap, product: (self, that) => isSome(self) && isSome(that) ? some([self.value, that.value]) : option.none, productMany @@ -768,8 +772,10 @@ const productAll = (collection: Iterable>): Option> => { * @since 1.0.0 */ export const Product: product_.Product = { - ...Of, - ...SemiProduct, + of, + imap: Invariant.imap, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll } @@ -795,8 +801,10 @@ export const struct: >>( * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { - ...SemiProduct, - ...Covariant + imap: Invariant.imap, + map: Covariant.map, + product: SemiProduct.product, + productMany: SemiProduct.productMany } /** @@ -885,8 +893,12 @@ export const getFailureSemigroup: (S: Semigroup) => Semigroup> = * @since 1.0.0 */ export const Applicative: applicative.Applicative = { - ...SemiApplicative, - ...Product + imap: Invariant.imap, + of, + map, + product: SemiProduct.product, + productMany: SemiProduct.productMany, + productAll } /** @@ -923,7 +935,7 @@ const coproductMany = (self: Option, collection: Iterable>): Opt * @since 1.0.0 */ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { - ...Invariant, + imap: Invariant.imap, coproduct: (self, that) => isSome(self) ? self : that, coproductMany } @@ -952,8 +964,10 @@ export const Coproduct: coproduct_.Coproduct = { * @since 1.0.0 */ export const SemiAlternative: semiAlternative.SemiAlternative = { - ...Covariant, - ...SemiCoproduct + map, + imap: Invariant.imap, + coproduct: SemiCoproduct.coproduct, + coproductMany: SemiCoproduct.coproductMany } /** @@ -961,8 +975,12 @@ export const SemiAlternative: semiAlternative.SemiAlternative * @since 1.0.0 */ export const Alternative: alternative.Alternative = { - ...SemiAlternative, - ...Coproduct + map, + imap: Invariant.imap, + coproduct: SemiCoproduct.coproduct, + coproductMany: SemiCoproduct.coproductMany, + coproductAll: Coproduct.coproductAll, + zero: Coproduct.zero } /** diff --git a/src/Predicate.ts b/src/Predicate.ts index a2b8c8f5f..43a0506fe 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -189,8 +189,10 @@ const productAll = ( * @since 1.0.0 */ export const Product: product_.Product = { - ...SemiProduct, of, + imap: Invariant.imap, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll } diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 2cca14ffa..a0528a1db 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1336,8 +1336,9 @@ export const as: (b: B) => (self: ReadonlyArray) => Array = covar * @since 1.0.0 */ export const Pointed: pointed.Pointed = { - ...Of, - ...Covariant + of, + imap: Invariant.imap, + map } /** @@ -1421,8 +1422,9 @@ export const composeKleisliArrow: ( * @since 1.0.0 */ export const Chainable: chainable.Chainable = { - ...FlatMap, - ...Covariant + imap: Invariant.imap, + map, + flatMap } /** @@ -1706,7 +1708,7 @@ const productAll = ( * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - ...Invariant, + imap: Invariant.imap, product, productMany } @@ -1730,8 +1732,10 @@ export const andThenBind: ( * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { - ...SemiProduct, - ...Covariant + imap: Invariant.imap, + map: Covariant.map, + product: SemiProduct.product, + productMany: SemiProduct.productMany } /** @@ -1769,8 +1773,10 @@ export const liftSemigroup: (S: Semigroup) => Semigroup> * @since 1.0.0 */ export const Product: product_.Product = { - ...Of, - ...SemiProduct, + of, + imap: Invariant.imap, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll } @@ -1779,8 +1785,12 @@ export const Product: product_.Product = { * @since 1.0.0 */ export const Applicative: applicative.Applicative = { - ...SemiApplicative, - ...Product + imap: Invariant.imap, + of, + map, + product: SemiProduct.product, + productMany: SemiProduct.productMany, + productAll } /** @@ -1797,8 +1807,10 @@ export const liftMonoid: (M: Monoid) => Monoid> = applica * @since 1.0.0 */ export const Monad: monad.Monad = { - ...Pointed, - ...FlatMap + imap: Invariant.imap, + of, + map, + flatMap } /** diff --git a/src/These.ts b/src/These.ts index 808ceb78f..7c9d41d5c 100644 --- a/src/These.ts +++ b/src/These.ts @@ -696,8 +696,9 @@ export const Do: These = of_.Do(Of) * @since 1.0.0 */ export const Pointed: pointed.Pointed = { - ...Of, - ...Covariant + of, + imap: Invariant.imap, + map } /** @@ -843,7 +844,7 @@ export const firstRightOrBothOf = (collection: Iterable>) => * @since 1.0.0 */ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { - ...Invariant, + imap: Invariant.imap, coproduct: (self, that) => isRightOrBoth(self) ? self : that, coproductMany: (self, collection) => pipe(self, firstRightOrBothOf(collection)) } @@ -860,8 +861,10 @@ export const getFirstRightOrBothSemigroup: () => Semigroup> = * @since 1.0.0 */ export const SemiAlternative: semiAlternative.SemiAlternative = { - ...Covariant, - ...SemiCoproduct + map, + imap: Invariant.imap, + coproduct: SemiCoproduct.coproduct, + coproductMany: SemiCoproduct.coproductMany } /** @@ -963,8 +966,10 @@ export const SemiProduct: semiProduct.SemiProduct = { * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { - map, - ...SemiProduct + imap: Invariant.imap, + map: Covariant.map, + product: SemiProduct.product, + productMany: SemiProduct.productMany } /** @@ -1085,8 +1090,10 @@ export const element: ( * @since 1.0.0 */ export const Product: product_.Product = { - ...SemiProduct, of, + imap: Invariant.imap, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll } @@ -1138,8 +1145,12 @@ export const flatMap = ( * @since 1.0.0 */ export const Applicative: applicative.Applicative = { - ...SemiApplicative, - ...Product + imap: Invariant.imap, + of, + map, + product: SemiProduct.product, + productMany: SemiProduct.productMany, + productAll } /** @@ -1262,8 +1273,8 @@ export const tap: ( */ export const Monad: monad.Monad = { imap: Invariant.imap, - map, of, + map, flatMap } diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 78146c738..d99d84066 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -204,7 +204,9 @@ export const SemiProduct: semiProduct.SemiProduct = { * @since 1.0.0 */ export const Product: product.Product = { - ...SemiProduct, of: () => empty, + imap: Invariant.imap, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll: (collection: Iterable>) => tuple>(...collection) } diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 0adbb5945..8229d0a4b 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -215,8 +215,10 @@ export const SemiProduct: semiProduct.SemiProduct = { * @since 1.0.0 */ export const Product: product.Product = { - ...SemiProduct, of: () => empty, + imap: Invariant.imap, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll: (collection: Iterable>) => tuple>(...collection) } diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index ea3916963..a6c06a8af 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -325,7 +325,7 @@ export const Invariant: invariant.Invariant = { * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - ...Invariant, + imap: Invariant.imap, product: tuple, productMany: (self, collection) => tuple(self, ...collection) } @@ -335,7 +335,9 @@ export const SemiProduct: semiProduct.SemiProduct = { * @since 1.0.0 */ export const Product: product.Product = { - ...SemiProduct, of: constant, + imap: Invariant.imap, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll: (collection: Iterable>) => tuple>(...collection) } From cb54505063f747e6bfc82b9d856e203042f3793e Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 29 Jan 2023 19:49:37 +0100 Subject: [PATCH 118/255] guodes/Option: add interop section --- docs/modules/Option.ts.md | 72 +++++++++------ guides/Option.md | 128 +++++++++++++++++++++++--- src/Option.ts | 183 ++++++++++++++++++++------------------ test/Option.ts | 12 +-- 4 files changed, 262 insertions(+), 133 deletions(-) diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index e7d212f3f..b5816c550 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -30,7 +30,6 @@ Added in v1.0.0 - [conversions](#conversions) - [fromEither](#fromeither) - [fromIterable](#fromiterable) - - [fromNullable](#fromnullable) - [toEither](#toeither) - [toRefinement](#torefinement) - [debugging](#debugging) @@ -79,6 +78,7 @@ Added in v1.0.0 - [getFailureSemigroup](#getfailuresemigroup) - [getFirstSomeSemigroup](#getfirstsomesemigroup) - [interop](#interop) + - [fromNullable](#fromnullable) - [fromThrowable](#fromthrowable) - [getOrNull](#getornull) - [getOrThrow](#getorthrow) @@ -344,29 +344,6 @@ assert.deepStrictEqual(fromIterable([]), none()) Added in v1.0.0 -## fromNullable - -Constructs a new `Option` from a nullable type. If the value is `null` or `undefined`, returns `None`, otherwise -returns the value wrapped in a `Some`. - -**Signature** - -```ts -export declare const fromNullable: (nullableValue: A) => Option> -``` - -**Example** - -```ts -import { none, some, fromNullable } from '@fp-ts/core/Option' - -assert.deepStrictEqual(fromNullable(undefined), none()) -assert.deepStrictEqual(fromNullable(null), none()) -assert.deepStrictEqual(fromNullable(1), some(1)) -``` - -Added in v1.0.0 - ## toEither Converts an `Option` to an `Either`, allowing you to provide a value to be used in the case of a `None`. @@ -953,6 +930,29 @@ Added in v1.0.0 # interop +## fromNullable + +Constructs a new `Option` from a nullable type. If the value is `null` or `undefined`, returns `None`, otherwise +returns the value wrapped in a `Some`. + +**Signature** + +```ts +export declare const fromNullable: (nullableValue: A) => Option> +``` + +**Example** + +```ts +import { none, some, fromNullable } from '@fp-ts/core/Option' + +assert.deepStrictEqual(fromNullable(undefined), none()) +assert.deepStrictEqual(fromNullable(null), none()) +assert.deepStrictEqual(fromNullable(1), some(1)) +``` + +Added in v1.0.0 + ## fromThrowable Converts an exception into an `Option`. If `f` throws, returns `None`, otherwise returns the output wrapped in a @@ -1053,12 +1053,26 @@ Added in v1.0.0 A utility function that lifts a function that throws exceptions into a function that returns an `Option`. +This function is useful for any function that might throw an exception, allowing the developer to handle +the exception in a more functional way. + **Signature** ```ts export declare const liftThrowable: (f: (...a: A) => B) => (...a: A) => Option ``` +**Example** + +```ts +import { liftThrowable, some, none } from '@fp-ts/core/Option' + +const parse = liftThrowable(JSON.parse) + +assert.deepStrictEqual(parse('1'), some(1)) +assert.deepStrictEqual(parse(''), none()) +``` + Added in v1.0.0 # lifting @@ -1131,7 +1145,7 @@ Added in v1.0.0 ## liftNullable -Returns a _smart constructor_ from a function that returns a nullable value. +This API is useful for lifting a function that returns `null` or `undefined` into the `Option` context. **Signature** @@ -1146,15 +1160,15 @@ export declare const liftNullable: ( ```ts import { liftNullable, none, some } from '@fp-ts/core/Option' -const f = (s: string): number | undefined => { +const parse = (s: string): number | undefined => { const n = parseFloat(s) return isNaN(n) ? undefined : n } -const g = liftNullable(f) +const parseOption = liftNullable(parse) -assert.deepStrictEqual(g('1'), some(1)) -assert.deepStrictEqual(g('a'), none()) +assert.deepStrictEqual(parseOption('1'), some(1)) +assert.deepStrictEqual(parseOption('not a number'), none()) ``` Added in v1.0.0 diff --git a/guides/Option.md b/guides/Option.md index c2d52ac0b..456d1fdec 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -187,7 +187,7 @@ What happens if we add a call to the `parseNumber` function to a pipeline that a const result = pipe( some("2"), map((s) => parseNumber(s)), - map((n) => n * 2) // type-checker error! + map((n) => n2) // type-checker error! ); ``` @@ -211,7 +211,7 @@ import { flatMap } from "@fp-ts/core/Option"; const result = pipe( some("2"), flatMap((s) => parseNumber(s)), - map((n) => n * 2) // ok! now `n` has type `number` + map((n) => n2) // ok! now `n` has type `number` ); ``` @@ -232,7 +232,7 @@ The `flatMap` function offers the same convenience as the `map` function, which const success: Option = pipe( some("2"), flatMap((s) => parseNumber(s)), // parse the input to number - map((x) => x * 2), // double the parsed number + map((x) => x2), // double the parsed number map((x) => x - 3) // subtract 3 ); // some(1) ``` @@ -243,7 +243,7 @@ const success: Option = pipe( const failure: Option = pipe( some("a"), flatMap((s) => parseNumber(s)), // parse the input to number - map((x) => x * 2), // This will not be executed because parseNumber will return None + map((x) => x2), // This will not be executed because parseNumber will return None map((x) => x - 3) // This will not be executed ); // none() ``` @@ -254,7 +254,7 @@ const failure: Option = pipe( const noneStart: Option = pipe( none, flatMap((s) => parseNumber(s)), // This will not be executed because it starts with None - map((x) => x * 2), // This will not be executed + map((x) => x2), // This will not be executed map((x) => x - 3) // This will not be executed ); // none() ``` @@ -284,7 +284,7 @@ const failure: Option = pipe( inspectSome(console.log), flatMap((s) => parseNumber(s)), inspectNone(() => console.error("none")), - map((x) => x * 2), + map((x) => x2), map((x) => x - 3) ); // "a" @@ -302,8 +302,6 @@ The fastest way to get the value wrapped in an option is to call the `getOrThrow ```ts import { getOrThrow } from "@fp-ts/core/Option"; -let someValue = Some(10); -let noneValue = None; console.log(pipe(some(10), getOrThrow()); // 10 console.log(pipe(none(), getOrThrow()); // throws new Error("getOrThrow called on a None") ``` @@ -334,7 +332,7 @@ console.log(output); // Output: Error: Cannot parse 'Not a number' as a number There are specializations of `match` to make working with code that does not use `Option` more convenient and faster, particularly `getOrNull` and `getOrUndefined`. ```ts -import { getOrNull, getOrUndefined } from "fp-ts/core/Option"; +import { getOrNull, getOrUndefined } from "@fp-ts/core/Option"; pipe(some(5), getOrNull); // 5 pipe(none(), getOrNull); // null @@ -346,7 +344,7 @@ pipe(none(), getOrUndefined); // undefined For greater flexibility, there is also the `getOrElse` function which allows you to set what value corresponds to the `None` case: ```ts -import { getOrElse } from "fp-ts/core/Option"; +import { getOrElse } from "@fp-ts/core/Option"; pipe( some(5), @@ -368,6 +366,116 @@ pipe( | `getOrUndefined` | `Option` | `A \| undefined` | | `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | +# Interop + +A need that arises quickly when using the `Option` data type is the ability to interoperate with code that does not share the same style, in particular code that for example uses `undefined` or `null` to indicate that a value is optional, or code that throws exceptions. + +The `Option` data type offers a series of APIs to make this task easier, let's start with the first of the two cases, that is when the need is to interoperate with code that use a nullable type to indicate that a value is optional. + +It is possible to create an `Option` from a nullable value using the `fromNullable` API, let's see an example: + +```ts +import { fromNullable } from "@fp-ts/core/Option"; + +console.log(fromNullable(null)); // none() +console.log(fromNullable(undefined)); // none() +console.log(fromNullable(1)); // some(1) +``` + +Instead of a single value, we can also modify the definition of a function that returns a nullable value to a function that returns an `Option` (a process that goes by the name of "lifting"): + +```ts +import { liftNullable, none, some } from "@fp-ts/core/Option"; + +const parse = (s: string): number | undefined => { + const n = parseFloat(s); + return isNaN(n) ? undefined : n; +}; + +// const parseOption: (s: string) => Option +const parseOption = liftNullable(parse); + +console.log(parseOption("1")); // some(1) +console.log(parseOption("not a number")); // none() +``` + +On the other hand, if we have a value of type `Option` and we want to convert it into a nullable value we have two possibilities: + +- convert `None` to `null` +- convert `None` to `undefined` + +The two APIs `getOrNull` and `getOrUndefined` respectively achieve these two tasks: + +```ts +import { getOrNull, getOrUndefined, some, none } from "@fp-ts/core/Option"; + +console.log(getOrNull(some(1))); // 1 +console.log(getOrNull(none())); // null + +console.log(getOrUndefined(some(1))); // 1 +console.log(getOrUndefined(none())); // undefined +``` + +**Cheat sheet** (interop - nullable) + +| Name | Given | To | +| ----------------- | -------------------------------------------------- | ------------------------------------ | +| `fromNullable` | `A` | `Option>` | +| `liftNullable` | `(...a: A) => B \| null \| undefined` | `(...a: A) => Option` | +| `flatMapNullable` | `Option`, `(...a: A) => B \| null \| undefined` | `Option>` | +| `getOrNull` | `Option` | `A \| null` | +| `getOrUndefined` | `Option` | `A \| undefined` | + +Now let's see the other case, that is when we need to interoperate with code that throws exceptions. + +In a previous section, we saw how to convert the following function that can throw exceptions: + +```ts +function parseNumber(s: string): number { + const n = parseFloat(s); + if (isNaN(n)) { + throw new Error(); + } + return n; +} +``` + +into a function that returns a `Option`: + +```ts +function parseNumber(s: string): Option { + const n = parseFloat(s); + return isNaN(n) ? none() : some(n); +} +``` + +However, this involves tedious, error-prone, and boilerplate-heavy work. It would be much more convenient not to have to rewrite the `parseNumber` function from scratch but only to transform it into the desired result in one step, and that's exactly what the `fromThrowable` API takes care of doing: + +```ts +import { liftThrowable, some, none } from "@fp-ts/core/Option"; + +const parse = liftThrowable(JSON.parse); + +console.log(parse("1")); // some(1) +console.log(parse("")); // none() +``` + +On the other hand, if we have a value of type `Option` and want to get the wrapped value, accepting the fact that if the `Option` is a `None` we will get an exception, we can use the `getOrThrow` API: + +```ts +import { getOrThrow } from "@fp-ts/core/Option"; + +console.log(pipe(some(10), getOrThrow()); // 10 +console.log(pipe(none(), getOrThrow()); // throws new Error("getOrThrow called on a None") +``` + +**Cheat sheet** (interop - throwing) + +| Name | Given | To | +| --------------- | -------------------------------------- | ------------------------ | +| `liftThrowable` | `(...a: A) => B` (may throw) | `(...a: A) => Option` | +| `getOrThrow` | `Option`, `onNone?: LazyArg` | `A` | + # Combining two or more `Option`s **Cheat sheet** (combining) diff --git a/src/Option.ts b/src/Option.ts index 636d200da..3487c98cd 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -156,24 +156,6 @@ export const isSome: (self: Option) => self is Some = option.isSome // conversions // ------------------------------------------------------------------------------------- -/** - * Constructs a new `Option` from a nullable type. If the value is `null` or `undefined`, returns `None`, otherwise - * returns the value wrapped in a `Some`. - * - * @param nullableValue - The nullable value to be converted to an `Option`. - * - * @example - * import { none, some, fromNullable } from '@fp-ts/core/Option' - * - * assert.deepStrictEqual(fromNullable(undefined), none()) - * assert.deepStrictEqual(fromNullable(null), none()) - * assert.deepStrictEqual(fromNullable(1), some(1)) - * - * @category conversions - * @since 1.0.0 - */ -export const fromNullable: (nullableValue: A) => Option> = option.fromNullable - /** * Returns a `Refinement` from a `Option` returning function. * This function ensures that a `Refinement` definition is type-safe. @@ -355,6 +337,47 @@ export const firstSomeOf = (collection: Iterable>): Option => { // interop // ------------------------------------------------------------------------------------- +/** + * Constructs a new `Option` from a nullable type. If the value is `null` or `undefined`, returns `None`, otherwise + * returns the value wrapped in a `Some`. + * + * @param nullableValue - The nullable value to be converted to an `Option`. + * + * @example + * import { none, some, fromNullable } from '@fp-ts/core/Option' + * + * assert.deepStrictEqual(fromNullable(undefined), none()) + * assert.deepStrictEqual(fromNullable(null), none()) + * assert.deepStrictEqual(fromNullable(1), some(1)) + * + * @category interop + * @since 1.0.0 + */ +export const fromNullable: (nullableValue: A) => Option> = option.fromNullable + +/** + * This API is useful for lifting a function that returns `null` or `undefined` into the `Option` context. + * + * @example + * import { liftNullable, none, some } from '@fp-ts/core/Option' + * + * const parse = (s: string): number | undefined => { + * const n = parseFloat(s) + * return isNaN(n) ? undefined : n + * } + * + * const parseOption = liftNullable(parse) + * + * assert.deepStrictEqual(parseOption('1'), some(1)) + * assert.deepStrictEqual(parseOption('not a number'), none()) + * + * @category lifting + * @since 1.0.0 + */ +export const liftNullable = , B>( + f: (...a: A) => B | null | undefined +): ((...a: A) => Option>) => (...a) => fromNullable(f(...a)) + /** * Returns the value of the `Option` if it is a `Some`, otherwise returns `null`. * @@ -389,6 +412,50 @@ export const getOrNull: (self: Option) => A | null = getOrElse(constNull) */ export const getOrUndefined: (self: Option) => A | undefined = getOrElse(constUndefined) +/** + * This is `flatMap` + `fromNullable`, useful when working with optional values. + * + * @example + * import { some, none, flatMapNullable } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * interface Employee { + * company?: { + * address?: { + * street?: { + * name?: string + * } + * } + * } + * } + * + * const employee1: Employee = { company: { address: { street: { name: 'high street' } } } } + * + * assert.deepStrictEqual( + * pipe( + * some(employee1), + * flatMapNullable(employee => employee.company?.address?.street?.name), + * ), + * some('high street') + * ) + * + * const employee2: Employee = { company: { address: { street: {} } } } + * + * assert.deepStrictEqual( + * pipe( + * some(employee2), + * flatMapNullable(employee => employee.company?.address?.street?.name), + * ), + * none() + * ) + * + * @category sequencing + * @since 1.0.0 + */ +export const flatMapNullable = (f: (a: A) => B | null | undefined) => + (self: Option): Option> => + isNone(self) ? option.none : fromNullable(f(self.value)) + /** * Converts an exception into an `Option`. If `f` throws, returns `None`, otherwise returns the output wrapped in a * `Some`. @@ -418,6 +485,19 @@ export const fromThrowable = (f: () => A): Option => { /** * A utility function that lifts a function that throws exceptions into a function that returns an `Option`. * + * This function is useful for any function that might throw an exception, allowing the developer to handle + * the exception in a more functional way. + * + * @param f - the function that can throw exceptions. + * + * @example + * import { liftThrowable, some, none } from "@fp-ts/core/Option"; + * + * const parse = liftThrowable(JSON.parse) + * + * assert.deepStrictEqual(parse("1"), some(1)) + * assert.deepStrictEqual(parse(""), none()) + * * @category interop * @since 1.0.0 */ @@ -1143,73 +1223,6 @@ export const traverseTap: ( export const match = (onNone: LazyArg, onSome: (a: A) => C) => (self: Option): B | C => isNone(self) ? onNone() : onSome(self.value) -/** - * Returns a *smart constructor* from a function that returns a nullable value. - * - * @example - * import { liftNullable, none, some } from '@fp-ts/core/Option' - * - * const f = (s: string): number | undefined => { - * const n = parseFloat(s) - * return isNaN(n) ? undefined : n - * } - * - * const g = liftNullable(f) - * - * assert.deepStrictEqual(g('1'), some(1)) - * assert.deepStrictEqual(g('a'), none()) - * - * @category lifting - * @since 1.0.0 - */ -export const liftNullable = , B>( - f: (...a: A) => B | null | undefined -): ((...a: A) => Option>) => (...a) => fromNullable(f(...a)) - -/** - * This is `flatMap` + `fromNullable`, useful when working with optional values. - * - * @example - * import { some, none, flatMapNullable } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' - * - * interface Employee { - * company?: { - * address?: { - * street?: { - * name?: string - * } - * } - * } - * } - * - * const employee1: Employee = { company: { address: { street: { name: 'high street' } } } } - * - * assert.deepStrictEqual( - * pipe( - * some(employee1), - * flatMapNullable(employee => employee.company?.address?.street?.name), - * ), - * some('high street') - * ) - * - * const employee2: Employee = { company: { address: { street: {} } } } - * - * assert.deepStrictEqual( - * pipe( - * some(employee2), - * flatMapNullable(employee => employee.company?.address?.street?.name), - * ), - * none() - * ) - * - * @category sequencing - * @since 1.0.0 - */ -export const flatMapNullable = (f: (a: A) => B | null | undefined) => - (self: Option): Option> => - isNone(self) ? option.none : fromNullable(f(self.value)) - /** * The `Order` instance allows `Option` values to be compared with * `compare`, whenever there is an `Order` instance for diff --git a/test/Option.ts b/test/Option.ts index c06d7bda7..3b70f649b 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -512,15 +512,9 @@ describe.concurrent("Option", () => { }) it("liftThrowable", () => { - const f = _.liftThrowable((s: string) => { - const len = s.length - if (len > 0) { - return len - } - throw new Error("empty string") - }) - Util.deepStrictEqual(f("a"), _.some(1)) - Util.deepStrictEqual(f(""), _.none()) + const parse = _.liftThrowable(JSON.parse) + Util.deepStrictEqual(parse("1"), _.some(1)) + Util.deepStrictEqual(parse(""), _.none()) }) it("liftEither", () => { From 31b5fffc175f4740c8f31f05afba48b6b8cb9cd6 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 30 Jan 2023 08:37:07 +0100 Subject: [PATCH 119/255] Option: remove fromThrowable --- .changeset/hot-lobsters-greet.md | 5 +++ docs/modules/Option.ts.md | 31 ---------------- src/Option.ts | 61 +++++++++++--------------------- test/Option.ts | 11 ------ 4 files changed, 25 insertions(+), 83 deletions(-) create mode 100644 .changeset/hot-lobsters-greet.md diff --git a/.changeset/hot-lobsters-greet.md b/.changeset/hot-lobsters-greet.md new file mode 100644 index 000000000..be446f79d --- /dev/null +++ b/.changeset/hot-lobsters-greet.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": minor +--- + +Option: remove fromThrowable diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index b5816c550..2320d2ddd 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -79,7 +79,6 @@ Added in v1.0.0 - [getFirstSomeSemigroup](#getfirstsomesemigroup) - [interop](#interop) - [fromNullable](#fromnullable) - - [fromThrowable](#fromthrowable) - [getOrNull](#getornull) - [getOrThrow](#getorthrow) - [getOrUndefined](#getorundefined) @@ -953,36 +952,6 @@ assert.deepStrictEqual(fromNullable(1), some(1)) Added in v1.0.0 -## fromThrowable - -Converts an exception into an `Option`. If `f` throws, returns `None`, otherwise returns the output wrapped in a -`Some`. - -**Signature** - -```ts -export declare const fromThrowable: (f: () => A) => Option -``` - -**Example** - -```ts -import { none, some, fromThrowable } from '@fp-ts/core/Option' - -assert.deepStrictEqual( - fromThrowable(() => { - throw new Error() - }), - none() -) -assert.deepStrictEqual( - fromThrowable(() => 1), - some(1) -) -``` - -Added in v1.0.0 - ## getOrNull Returns the value of the `Option` if it is a `Some`, otherwise returns `null`. diff --git a/src/Option.ts b/src/Option.ts index 3487c98cd..4f1386466 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -186,7 +186,7 @@ export const fromIterable = (collection: Iterable): Option => { for (const a of collection) { return some(a) } - return option.none + return none() } /** @@ -453,34 +453,7 @@ export const getOrUndefined: (self: Option) => A | undefined = getOrElse(c * @since 1.0.0 */ export const flatMapNullable = (f: (a: A) => B | null | undefined) => - (self: Option): Option> => - isNone(self) ? option.none : fromNullable(f(self.value)) - -/** - * Converts an exception into an `Option`. If `f` throws, returns `None`, otherwise returns the output wrapped in a - * `Some`. - * - * @example - * import { none, some, fromThrowable } from '@fp-ts/core/Option' - * - * assert.deepStrictEqual( - * fromThrowable(() => { - * throw new Error() - * }), - * none() - * ) - * assert.deepStrictEqual(fromThrowable(() => 1), some(1)) - * - * @category interop - * @since 1.0.0 - */ -export const fromThrowable = (f: () => A): Option => { - try { - return some(f()) - } catch (e) { - return option.none - } -} + (self: Option): Option> => isNone(self) ? none() : fromNullable(f(self.value)) /** * A utility function that lifts a function that throws exceptions into a function that returns an `Option`. @@ -503,7 +476,14 @@ export const fromThrowable = (f: () => A): Option => { */ export const liftThrowable = , B>( f: (...a: A) => B -): ((...a: A) => Option) => (...a) => fromThrowable(() => f(...a)) +): ((...a: A) => Option) => + (...a) => { + try { + return some(f(...a)) + } catch (e) { + return none() + } + } /** * Returns the contained value if the `Option` is `Some`, otherwise throws an error. @@ -546,7 +526,7 @@ export const getOrThrow = ( * @since 1.0.0 */ export const map = (f: (a: A) => B) => - (self: Option): Option => isNone(self) ? option.none : some(f(self.value)) + (self: Option): Option => isNone(self) ? none() : some(f(self.value)) /** * @category instances @@ -657,7 +637,7 @@ export const Pointed: pointed.Pointed = { * @since 1.0.0 */ export const flatMap = (f: (a: A) => Option) => - (self: Option): Option => isNone(self) ? option.none : f(self.value) + (self: Option): Option => isNone(self) ? none() : f(self.value) /** * @category instances @@ -791,12 +771,12 @@ const productMany = ( collection: Iterable> ): Option<[A, ...Array]> => { if (isNone(self)) { - return option.none + return none() } const out: [A, ...Array] = [self.value] for (const o of collection) { if (isNone(o)) { - return option.none + return none() } out.push(o.value) } @@ -809,8 +789,7 @@ const productMany = ( */ export const SemiProduct: semiProduct.SemiProduct = { imap: Invariant.imap, - product: (self, that) => - isSome(self) && isSome(that) ? some([self.value, that.value]) : option.none, + product: (self, that) => isSome(self) && isSome(that) ? some([self.value, that.value]) : none(), productMany } @@ -840,7 +819,7 @@ const productAll = (collection: Iterable>): Option> => { const out: Array = [] for (const o of collection) { if (isNone(o)) { - return option.none + return none() } out.push(o.value) } @@ -912,7 +891,7 @@ export const getOptionalMonoid = ( semigroup.fromCombine((self, that) => isNone(self) ? that : isNone(that) ? self : some(Semigroup.combine(self.value, that.value)) ), - option.none + none() ) /** @@ -1121,7 +1100,7 @@ export const separate: (self: Option>) => [Option, Option< * @since 1.0.0 */ export const filterMap = (f: (a: A) => Option) => - (self: Option): Option => isNone(self) ? option.none : f(self.value) + (self: Option): Option => isNone(self) ? none() : f(self.value) /** * @category instances @@ -1158,7 +1137,7 @@ export const traverse = ( f: (a: A) => Kind ) => (self: Option): Kind> => - isNone(self) ? F.of>(option.none) : pipe(f(self.value), F.map(some)) + isNone(self) ? F.of>(none()) : pipe(f(self.value), F.map(some)) /** * @category traversing @@ -1267,7 +1246,7 @@ export const liftOrder = (O: Order): Order> => export const liftPredicate: { (refinement: Refinement): (c: C) => Option (predicate: Predicate): (b: B) => Option -} = (predicate: Predicate) => (b: B) => predicate(b) ? some(b) : option.none +} = (predicate: Predicate) => (b: B) => predicate(b) ? some(b) : none() /** * Lifts an `Either` function to an `Option` function. diff --git a/test/Option.ts b/test/Option.ts index 3b70f649b..afa75d6ac 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -465,17 +465,6 @@ describe.concurrent("Option", () => { Util.deepStrictEqual(pipe(_.some(2), _.exists(predicate)), true) }) - it("fromThrowable", () => { - Util.deepStrictEqual( - _.fromThrowable(() => JSON.parse("2")), - _.some(2) - ) - Util.deepStrictEqual( - _.fromThrowable(() => JSON.parse("(")), - _.none() - ) - }) - it("fromEither", () => { Util.deepStrictEqual(_.fromEither(E.right(1)), _.some(1)) Util.deepStrictEqual(_.fromEither(E.left("e")), _.none()) From 7761cfed0dcedf7103c26457c529ba3c752bd3bf Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 30 Jan 2023 09:25:27 +0100 Subject: [PATCH 120/255] chore --- src/Either.ts | 10 +++++--- src/Option.ts | 11 +++++++-- src/ReadonlyArray.ts | 53 +++++++++++++++++++++--------------------- src/These.ts | 40 +++++++++++++++---------------- src/internal/Either.ts | 13 +---------- src/internal/Option.ts | 12 +--------- 6 files changed, 64 insertions(+), 75 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 857b91493..4267a29c7 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -6,6 +6,7 @@ import * as BI from "@fp-ts/core/Bigint" import type { LazyArg } from "@fp-ts/core/Function" import { constNull, constUndefined, identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" +import { structural } from "@fp-ts/core/internal/effect" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" import * as N from "@fp-ts/core/Number" @@ -97,7 +98,9 @@ export const of: (a: A) => Either = right * @category guards * @since 1.0.0 */ -export const isEither: (u: unknown) => u is Either = either.isEither +export const isEither = (u: unknown): u is Either => + typeof u === "object" && u != null && structural in u && "_tag" in u && + (u["_tag"] === "Left" || u["_tag"] === "Right") /** * Returns `true` if the either is an instance of `Left`, `false` otherwise. @@ -712,8 +715,9 @@ export const match = (onLeft: (e: E) => B, onRight: (a: A) => C) * @category conversions * @since 1.0.0 */ -export const fromNullable: (onNullable: LazyArg) => (a: A) => Either> = - either.fromNullable +export const fromNullable = (onNullable: LazyArg) => + (a: A): Either> => + a == null ? left(onNullable()) : right(a as NonNullable) /** * @category lifting diff --git a/src/Option.ts b/src/Option.ts index 4f1386466..92bd42a3b 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -6,6 +6,7 @@ import type { Either } from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" +import { structural } from "@fp-ts/core/internal/effect" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" import * as N from "@fp-ts/core/Number" @@ -118,7 +119,9 @@ export const some: (value: A) => Option = option.some * @category guards * @since 1.0.0 */ -export const isOption: (input: unknown) => input is Option = option.isOption +export const isOption = (u: unknown): u is Option => + typeof u === "object" && u != null && structural in u && "_tag" in u && + (u["_tag"] === "None" || u["_tag"] === "Some") /** * Returns `true` if the `Option` is `None`, `false` otherwise. @@ -353,7 +356,11 @@ export const firstSomeOf = (collection: Iterable>): Option => { * @category interop * @since 1.0.0 */ -export const fromNullable: (nullableValue: A) => Option> = option.fromNullable +export const fromNullable = ( + nullableValue: A +): Option< + NonNullable +> => (nullableValue == null ? none() : some(nullableValue as NonNullable)) /** * This API is useful for lifting a function that returns `null` or `undefined` into the `Option` context. diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index a0528a1db..2a714bad0 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -4,11 +4,10 @@ * @since 1.0.0 */ import type { Either } from "@fp-ts/core/Either" +import * as E from "@fp-ts/core/Either" import { identity, pipe } from "@fp-ts/core/Function" import type { LazyArg } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" -import * as either from "@fp-ts/core/internal/Either" -import * as option from "@fp-ts/core/internal/Option" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type { Option } from "@fp-ts/core/Option" import * as O from "@fp-ts/core/Option" @@ -119,7 +118,7 @@ export const fromIterable: (collection: Iterable) => Array = readonlyAr */ export const fromOption = ( self: Option -): Array => (option.isNone(self) ? [] : [self.value]) +): Array => (O.isNone(self) ? [] : [self.value]) /** * @category conversions @@ -127,7 +126,7 @@ export const fromOption = ( */ export const fromEither = ( self: Either -): Array => (either.isLeft(self) ? [] : [self.right]) +): Array => (E.isLeft(self) ? [] : [self.right]) /** * @category pattern matching @@ -286,7 +285,7 @@ const clamp = (i: number, as: ReadonlyArray): number => export const get = (index: number) => (self: ReadonlyArray): Option => { const i = Math.floor(index) - return isOutOfBound(i, self) ? option.none : option.some(self[i]) + return isOutOfBound(i, self) ? O.none() : O.some(self[i]) } /** @@ -345,7 +344,7 @@ export const headNonEmpty: (self: NonEmptyReadonlyArray) => A = unsafeGet( * @since 1.0.0 */ export const last = (self: ReadonlyArray): Option => - isNonEmpty(self) ? option.some(lastNonEmpty(self)) : option.none + isNonEmpty(self) ? O.some(lastNonEmpty(self)) : O.none() /** * @category getters @@ -361,7 +360,7 @@ export const lastNonEmpty = (as: NonEmptyReadonlyArray): A => as[as.length */ export const tail = (self: Iterable): Option> => { const input = fromIterable(self) - return isNonEmpty(input) ? option.some(tailNonEmpty(input)) : option.none + return isNonEmpty(input) ? O.some(tailNonEmpty(input)) : O.none() } /** @@ -378,7 +377,7 @@ export const tailNonEmpty = (self: NonEmptyReadonlyArray): Array => sel */ export const init = (self: Iterable): Option> => { const input = fromIterable(self) - return isNonEmpty(input) ? option.some(initNonEmpty(input)) : option.none + return isNonEmpty(input) ? O.some(initNonEmpty(input)) : O.none() } /** @@ -542,11 +541,11 @@ export const findFirstIndex = (predicate: Predicate) => let i = 0 for (const a of self) { if (predicate(a)) { - return option.some(i) + return O.some(i) } i++ } - return option.none + return O.none() } /** @@ -560,10 +559,10 @@ export const findLastIndex = (predicate: Predicate) => const input = fromIterable(self) for (let i = input.length - 1; i >= 0; i--) { if (predicate(input[i])) { - return option.some(i) + return O.some(i) } } - return option.none + return O.none() } /** @@ -584,10 +583,10 @@ export function findFirst(predicate: Predicate): (self: Iterable) => Op const input = fromIterable(self) for (let i = 0; i < input.length; i++) { if (predicate(input[i])) { - return option.some(input[i]) + return O.some(input[i]) } } - return option.none + return O.none() } } @@ -609,10 +608,10 @@ export function findLast(predicate: Predicate): (self: Iterable) => Opt const input = fromIterable(self) for (let i = input.length - 1; i >= 0; i--) { if (predicate(input[i])) { - return option.some(input[i]) + return O.some(input[i]) } } - return option.none + return O.none() } } @@ -627,10 +626,10 @@ export const insertAt = (i: number, b: B) => const out: Array = Array.from(self) // v--- `= self.length` ok, it means inserting in last position if (i < 0 || i > out.length) { - return option.none + return O.none() } out.splice(i, 0, b) - return option.some(out) as any + return O.some(out) as any } /** @@ -721,7 +720,7 @@ export const reverseNonEmpty = ( export const rights = (self: Iterable>): Array => { const out: Array = [] for (const a of self) { - if (either.isRight(a)) { + if (E.isRight(a)) { out.push(a.right) } } @@ -737,7 +736,7 @@ export const rights = (self: Iterable>): Array => { export const lefts = (self: Iterable>): Array => { const out: Array = [] for (const a of self) { - if (either.isLeft(a)) { + if (E.isLeft(a)) { out.push(a.left) } } @@ -1448,7 +1447,7 @@ export const filterMapWithIndex = (f: (a: A, i: number) => Option) => const out: Array = [] for (let i = 0; i < as.length; i++) { const o = f(as[i], i) - if (option.isSome(o)) { + if (O.isSome(o)) { out.push(o.value) } } @@ -1486,7 +1485,7 @@ export const separate = ( const left: Array = [] const right: Array = [] for (const e of self) { - if (either.isLeft(e)) { + if (E.isLeft(e)) { left.push(e.left) } else { right.push(e.right) @@ -1528,7 +1527,7 @@ export const filterWithIndex: { } = ( predicate: (a: A, i: number) => boolean ): ((self: ReadonlyArray) => Array) => - filterMapWithIndex((b, i) => (predicate(b, i) ? option.some(b) : option.none)) + filterMapWithIndex((b, i) => (predicate(b, i) ? O.some(b) : O.none())) /** * @category filtering @@ -1557,7 +1556,7 @@ export const partitionWithIndex: { } = ( predicate: (a: A, i: number) => boolean ): ((self: ReadonlyArray) => [Array, Array]) => - partitionMapWithIndex((b, i) => (predicate(b, i) ? either.right(b) : either.left(b))) + partitionMapWithIndex((b, i) => (predicate(b, i) ? E.right(b) : E.left(b))) /** * @category filtering @@ -1577,7 +1576,7 @@ export const partitionMapWithIndex = (f: (a: A, i: number) => Either = [] for (let i = 0; i < self.length; i++) { const e = f(self[i], i) - if (either.isLeft(e)) { + if (E.isLeft(e)) { left.push(e.left) } else { right.push(e.right) @@ -2018,7 +2017,7 @@ export const liftEither = , E, B>( ) => (...a: A): Array => { const e = f(...a) - return either.isLeft(e) ? [] : [e.right] + return E.isLeft(e) ? [] : [e.right] } /** @@ -2104,7 +2103,7 @@ export const unfold = (b: B, f: (b: B) => Option): Array< const out: Array = [] let next: B = b let o: Option - while (option.isSome(o = f(next))) { + while (O.isSome(o = f(next))) { const [a, b] = o.value out.push(a) next = b diff --git a/src/These.ts b/src/These.ts index 7c9d41d5c..8e616999b 100644 --- a/src/These.ts +++ b/src/These.ts @@ -4,13 +4,13 @@ import * as BI from "@fp-ts/core/Bigint" import type { Either, Left, Right } from "@fp-ts/core/Either" +import * as E from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { proto, structural } from "@fp-ts/core/internal/effect" -import * as either from "@fp-ts/core/internal/Either" -import * as option from "@fp-ts/core/internal/Option" import * as N from "@fp-ts/core/Number" +import * as O from "@fp-ts/core/Option" import type { Option } from "@fp-ts/core/Option" import type { Predicate, Refinement } from "@fp-ts/core/Predicate" import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" @@ -77,13 +77,13 @@ export interface ValidatedTypeLambda extends TypeLambda { * @category constructors * @since 1.0.0 */ -export const left: (left: E) => These = either.left +export const left: (left: E) => These = E.left /** * @category constructors * @since 1.0.0 */ -export const right: (right: A) => These = either.right +export const right: (right: A) => These = E.right /** * Alias of `right`. @@ -125,14 +125,14 @@ export const warn = (e: E, a: A): Validated => both([e], a) * @since 1.0.0 */ export const leftOrBoth = (e: LazyArg) => - (self: Option): These => option.isNone(self) ? left(e()) : both(e(), self.value) + (self: Option): These => O.isNone(self) ? left(e()) : both(e(), self.value) /** * @category constructors * @since 1.0.0 */ export const rightOrBoth = (a: () => A) => - (self: Option): These => option.isNone(self) ? right(a()) : both(self.value, a()) + (self: Option): These => O.isNone(self) ? right(a()) : both(self.value, a()) /** * @category pattern matching @@ -278,7 +278,7 @@ export const fromNullable = (onNullable: LazyArg) => * @since 1.0.0 */ export const fromEither = (self: Either): Validated => - either.isLeft(self) ? left([self.left]) : self + E.isLeft(self) ? left([self.left]) : self /** * @category conversions @@ -295,7 +295,7 @@ export const toEither = ( export const absolve: (self: These) => Either = toEither(( _, a -) => either.right(a)) +) => E.right(a)) /** * @category conversions @@ -304,7 +304,7 @@ export const absolve: (self: These) => Either = toEither(( export const condemn: (self: These) => Either = toEither(( e, _ -) => either.left(e)) +) => E.left(e)) /** * @category lifting @@ -355,7 +355,7 @@ export const fromIterable = (onEmpty: LazyArg) => * @since 1.0.0 */ export const fromOption = (onNone: LazyArg) => - (self: Option): These => option.isNone(self) ? left(onNone()) : right(self.value) + (self: Option): These => O.isNone(self) ? left(onNone()) : right(self.value) /** * @category conversions @@ -421,7 +421,7 @@ export const flatMapThese = ( */ export const getRight = ( self: These -): Option => isLeft(self) ? option.none : option.some(self.right) +): Option => isLeft(self) ? O.none() : O.some(self.right) /** * Returns the `A` value if and only if the value is constructed with `Right` @@ -431,7 +431,7 @@ export const getRight = ( */ export const getRightOnly = ( self: These -): Option => isRight(self) ? option.some(self.right) : option.none +): Option => isRight(self) ? O.some(self.right) : O.none() /** * @category getters @@ -439,7 +439,7 @@ export const getRightOnly = ( */ export const getLeft = ( self: These -): Option => isRight(self) ? option.none : option.some(self.left) +): Option => isRight(self) ? O.none() : O.some(self.left) /** * Returns the `E` value if and only if the value is constructed with `Left` @@ -449,7 +449,7 @@ export const getLeft = ( */ export const getLeftOnly = ( self: These -): Option => isLeft(self) ? option.some(self.left) : option.none +): Option => isLeft(self) ? O.some(self.left) : O.none() /** * @category getters @@ -457,7 +457,7 @@ export const getLeftOnly = ( */ export const getBoth = ( self: These -): Option => isBoth(self) ? option.some([self.left, self.right]) : option.none +): Option => isBoth(self) ? O.some([self.left, self.right]) : O.none() /** * @category getters @@ -807,8 +807,8 @@ export const orElseEither = ( ) => (self: These): These> => isLeft(self) ? - pipe(that, map(either.right)) : - pipe(self, map(either.left)) + pipe(that, map(E.right)) : + pipe(self, map(E.left)) /** * Executes this effect and returns its value, if it succeeds, but otherwise @@ -875,7 +875,7 @@ export const compact = (onNone: LazyArg) => (self: These>): These => isLeft(self) ? self : - option.isNone(self.right) ? + O.isNone(self.right) ? left(onNone()) : isBoth(self) ? both(self.left, self.right.value) : @@ -914,10 +914,10 @@ export const filterMap = ( } if (isRight(self)) { const ob = f(self.right) - return option.isNone(ob) ? left(onNone()) : right(ob.value) + return O.isNone(ob) ? left(onNone()) : right(ob.value) } const ob = f(self.right) - return option.isNone(ob) ? left(onNone()) : both(self.left, ob.value) + return O.isNone(ob) ? left(onNone()) : both(self.left, ob.value) } const product = ( diff --git a/src/internal/Either.ts b/src/internal/Either.ts index e2a60961a..e0cce556b 100644 --- a/src/internal/Either.ts +++ b/src/internal/Either.ts @@ -3,16 +3,10 @@ */ import type { Either, Left, Right } from "@fp-ts/core/Either" -import type { LazyArg } from "@fp-ts/core/Function" -import { proto, structural } from "@fp-ts/core/internal/effect" +import { proto } from "@fp-ts/core/internal/effect" import * as option from "@fp-ts/core/internal/Option" import type { Option } from "@fp-ts/core/Option" -/** @internal */ -export const isEither = (u: unknown): u is Either => - typeof u === "object" && u != null && structural in u && "_tag" in u && - (u["_tag"] === "Left" || u["_tag"] === "Right") - /** @internal */ export const isLeft = (ma: Either): ma is Left => ma._tag === "Left" @@ -37,11 +31,6 @@ export const getRight = ( self: Either ): Option => (isLeft(self) ? option.none : option.some(self.right)) -/** @internal */ -export const fromNullable = (onNullable: LazyArg) => - (a: A): Either> => - a == null ? left(onNullable()) : right(a as NonNullable) - /** @internal */ export const fromOption = (onNone: () => E) => (fa: Option): Either => option.isNone(fa) ? left(onNone()) : right(fa.value) diff --git a/src/internal/Option.ts b/src/internal/Option.ts index abed7ec08..f444fb8d6 100644 --- a/src/internal/Option.ts +++ b/src/internal/Option.ts @@ -2,14 +2,9 @@ * @since 1.0.0 */ -import { proto, structural } from "@fp-ts/core/internal/effect" +import { proto } from "@fp-ts/core/internal/effect" import type { None, Option, Some } from "@fp-ts/core/Option" -/** @internal */ -export const isOption = (u: unknown): u is Option => - typeof u === "object" && u != null && structural in u && "_tag" in u && - (u["_tag"] === "None" || u["_tag"] === "Some") - /** @internal */ export const isNone = (fa: Option): fa is None => fa._tag === "None" @@ -21,8 +16,3 @@ export const none: Option = Object.setPrototypeOf({ _tag: "None" }, proto /** @internal */ export const some = (a: A): Option => Object.setPrototypeOf({ _tag: "Some", value: a }, proto) - -/** @internal */ -export const fromNullable = ( - a: A -): Option> => (a == null ? none : some(a as NonNullable)) From f21349ac025014b1ff23f375b3ca60edb5163eb5 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 30 Jan 2023 17:43:30 +0100 Subject: [PATCH 121/255] chore --- src/Either.ts | 73 +++++++++++++++++++++++++++--------------- src/Option.ts | 76 ++++++++++++++++++++++++-------------------- src/Predicate.ts | 24 +++++++++----- src/ReadonlyArray.ts | 37 +++++++++++---------- src/These.ts | 64 +++++++++++++++++++++++-------------- test/Option.ts | 5 ++- 6 files changed, 168 insertions(+), 111 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index 4267a29c7..b3374aa43 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -127,20 +127,23 @@ export const isRight: (self: Either) => self is Right = either.is export const map = (f: (a: A) => B) => (self: Either): Either => isRight(self) ? right(f(self.right)) : self +const imap = covariant.imap(map) + /** * @category instances * @since 1.0.0 */ -export const Covariant: covariant.Covariant = covariant.make( +export const Covariant: covariant.Covariant = { + imap, map -) +} /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap: Covariant.imap + imap } /** @@ -259,7 +262,7 @@ export const Do: Either = of_.Do(Of) */ export const Pointed: pointed.Pointed = { of, - imap: Invariant.imap, + imap, map } @@ -306,7 +309,7 @@ export const composeKleisliArrow: ( * @since 1.0.0 */ export const Chainable: chainable.Chainable = { - imap: Invariant.imap, + imap, map, flatMap } @@ -340,7 +343,7 @@ export const andThenDiscard: ( * @since 1.0.0 */ export const Monad: monad.Monad = { - imap: Invariant.imap, + imap, of, map, flatMap @@ -363,14 +366,19 @@ const productMany = ( return right(out) } +const product = ( + self: Either, + that: Either +): Either => + isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self + /** * @category instances * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - imap: Invariant.imap, - product: (self, that) => - isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self, + imap, + product, productMany } @@ -419,9 +427,9 @@ const productAll = ( */ export const Product: product_.Product = { of, - imap: Invariant.imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + imap, + product, + productMany, productAll } @@ -452,10 +460,10 @@ export const struct: >>( * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { - imap: Invariant.imap, - map: Covariant.map, - product: SemiProduct.product, - productMany: SemiProduct.productMany + imap, + map, + product, + productMany } /** @@ -510,11 +518,11 @@ export const ap: ( * @since 1.0.0 */ export const Applicative: applicative.Applicative = { - imap: Invariant.imap, + imap, of, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll } @@ -550,14 +558,24 @@ export const firstRightOf = (collection: Iterable>) => return out } +const coproduct = ( + self: Either, + that: Either +): Either => isRight(self) ? self : that + +const coproductMany = ( + self: Either, + collection: Iterable> +): Either => pipe(self, firstRightOf(collection)) + /** * @category instances * @since 1.0.0 */ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { - imap: Invariant.imap, - coproduct: (self, that) => isRight(self) ? self : that, - coproductMany: (self, collection) => pipe(self, firstRightOf(collection)) + imap, + coproduct, + coproductMany } /** @@ -654,17 +672,20 @@ export const orElseFail = ( */ export const SemiAlternative: semiAlternative.SemiAlternative = { map, - imap: Invariant.imap, - coproduct: SemiCoproduct.coproduct, - coproductMany: SemiCoproduct.coproductMany + imap, + coproduct, + coproductMany } +const reduce = (b: B, f: (b: B, a: A) => B) => + (self: Either): B => isLeft(self) ? b : f(b, self.right) + /** * @category instances * @since 1.0.0 */ export const Foldable: foldable.Foldable = { - reduce: (b, f) => (self) => isLeft(self) ? b : f(b, self.right) + reduce } /** diff --git a/src/Option.ts b/src/Option.ts index 92bd42a3b..01f468b6f 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -535,20 +535,23 @@ export const getOrThrow = ( export const map = (f: (a: A) => B) => (self: Option): Option => isNone(self) ? none() : some(f(self.value)) +const imap = covariant.imap(map) + /** * @category instances * @since 1.0.0 */ -export const Covariant: covariant.Covariant = covariant.make( +export const Covariant: covariant.Covariant = { + imap, map -) +} /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap: Covariant.imap + imap } /** @@ -613,7 +616,7 @@ export const of: (a: A) => Option = some * @since 1.0.0 */ export const Of: of_.Of = { - of: some + of } /** @@ -633,7 +636,7 @@ export const Do: Option<{}> = of_.Do(Of) */ export const Pointed: pointed.Pointed = { of, - imap: Invariant.imap, + imap, map } @@ -679,7 +682,7 @@ export const composeKleisliArrow: ( * @since 1.0.0 */ export const Chainable: chainable.Chainable = { - imap: Invariant.imap, + imap, map, flatMap } @@ -767,12 +770,15 @@ export const inspectNone = ( * @since 1.0.0 */ export const Monad: monad.Monad = { - imap: Invariant.imap, + imap, of, map, flatMap } +const product = (self: Option, that: Option): Option<[A, B]> => + isSome(self) && isSome(that) ? some([self.value, that.value]) : none() + const productMany = ( self: Option, collection: Iterable> @@ -795,8 +801,8 @@ const productMany = ( * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - imap: Invariant.imap, - product: (self, that) => isSome(self) && isSome(that) ? some([self.value, that.value]) : none(), + imap, + product, productMany } @@ -839,9 +845,9 @@ const productAll = (collection: Iterable>): Option> => { */ export const Product: product_.Product = { of, - imap: Invariant.imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + imap, + product, + productMany, productAll } @@ -867,10 +873,10 @@ export const struct: >>( * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { - imap: Invariant.imap, - map: Covariant.map, - product: SemiProduct.product, - productMany: SemiProduct.productMany + imap, + map, + product, + productMany } /** @@ -959,11 +965,11 @@ export const getFailureSemigroup: (S: Semigroup) => Semigroup> = * @since 1.0.0 */ export const Applicative: applicative.Applicative = { - imap: Invariant.imap, + imap, of, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll } @@ -983,6 +989,9 @@ export const getFailureMonoid: (M: Monoid) => Monoid> = applicat Applicative ) +const coproduct = (self: Option, that: Option): Option => + isSome(self) ? self : that + const coproductMany = (self: Option, collection: Iterable>): Option => { let out = self if (isSome(out)) { @@ -1001,8 +1010,8 @@ const coproductMany = (self: Option, collection: Iterable>): Opt * @since 1.0.0 */ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { - imap: Invariant.imap, - coproduct: (self, that) => isSome(self) ? self : that, + imap, + coproduct, coproductMany } @@ -1020,7 +1029,9 @@ export const getFirstSomeSemigroup: () => Semigroup> = semiCoproduc * @since 1.0.0 */ export const Coproduct: coproduct_.Coproduct = { - ...SemiCoproduct, + imap, + coproduct, + coproductMany, zero: none, coproductAll: firstSomeOf } @@ -1031,9 +1042,9 @@ export const Coproduct: coproduct_.Coproduct = { */ export const SemiAlternative: semiAlternative.SemiAlternative = { map, - imap: Invariant.imap, - coproduct: SemiCoproduct.coproduct, - coproductMany: SemiCoproduct.coproductMany + imap, + coproduct, + coproductMany } /** @@ -1042,17 +1053,14 @@ export const SemiAlternative: semiAlternative.SemiAlternative */ export const Alternative: alternative.Alternative = { map, - imap: Invariant.imap, - coproduct: SemiCoproduct.coproduct, - coproductMany: SemiCoproduct.coproductMany, - coproductAll: Coproduct.coproductAll, - zero: Coproduct.zero + imap, + coproduct, + coproductMany, + coproductAll: firstSomeOf, + zero: none } -/** - * @since 1.0.0 - */ -export const reduce = (b: B, f: (b: B, a: A) => B) => +const reduce = (b: B, f: (b: B, a: A) => B) => (self: Option): B => isNone(self) ? b : f(b, self.value) /** diff --git a/src/Predicate.ts b/src/Predicate.ts index 43a0506fe..b5f917eee 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -86,20 +86,23 @@ export const compose = (bc: Refinement) => export const contramap = (f: (b: B) => A) => (self: Predicate): Predicate => (b) => self(f(b)) +const imap = contravariant.imap(contramap) + /** * @category instances * @since 1.0.0 */ -export const Contravariant: contravariant.Contravariant = contravariant.make( +export const Contravariant: contravariant.Contravariant = { + imap, contramap -) +} /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap: Contravariant.imap + imap } /** @@ -143,6 +146,11 @@ export const Do: Predicate<{}> = of_.Do(Of) */ export const unit: Predicate = of_.unit(Of) +const product = ( + self: Predicate, + that: Predicate +): Predicate<[A, B]> => ([a, b]) => self(a) && that(b) + const productMany = ( self: Predicate, collection: Iterable> @@ -166,8 +174,8 @@ const productMany = ( * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - imap: Invariant.imap, - product: (self, that) => ([a, b]) => self(a) && that(b), + imap, + product, productMany } @@ -190,9 +198,9 @@ const productAll = ( */ export const Product: product_.Product = { of, - imap: Invariant.imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + imap, + product, + productMany, productAll } diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 2a714bad0..064d1275d 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1265,20 +1265,23 @@ export const Of: of_.Of = { */ export const Do: ReadonlyArray<{}> = of_.Do(Of) +const imap = covariant.imap(map) + /** * @category instances * @since 1.0.0 */ -export const Covariant: covariant.Covariant = covariant.make( +export const Covariant: covariant.Covariant = { + imap, map -) +} /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap: Covariant.imap + imap } /** @@ -1336,7 +1339,7 @@ export const as: (b: B) => (self: ReadonlyArray) => Array = covar */ export const Pointed: pointed.Pointed = { of, - imap: Invariant.imap, + imap, map } @@ -1421,7 +1424,7 @@ export const composeKleisliArrow: ( * @since 1.0.0 */ export const Chainable: chainable.Chainable = { - imap: Invariant.imap, + imap, map, flatMap } @@ -1707,7 +1710,7 @@ const productAll = ( * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - imap: Invariant.imap, + imap, product, productMany } @@ -1731,10 +1734,10 @@ export const andThenBind: ( * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { - imap: Invariant.imap, - map: Covariant.map, - product: SemiProduct.product, - productMany: SemiProduct.productMany + imap, + map, + product, + productMany } /** @@ -1773,9 +1776,9 @@ export const liftSemigroup: (S: Semigroup) => Semigroup> */ export const Product: product_.Product = { of, - imap: Invariant.imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + imap, + product, + productMany, productAll } @@ -1784,11 +1787,11 @@ export const Product: product_.Product = { * @since 1.0.0 */ export const Applicative: applicative.Applicative = { - imap: Invariant.imap, + imap, of, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll } @@ -1806,7 +1809,7 @@ export const liftMonoid: (M: Monoid) => Monoid> = applica * @since 1.0.0 */ export const Monad: monad.Monad = { - imap: Invariant.imap, + imap, of, map, flatMap diff --git a/src/These.ts b/src/These.ts index 8e616999b..b1831e303 100644 --- a/src/These.ts +++ b/src/These.ts @@ -600,18 +600,23 @@ export const map: (f: (a: A) => B) => (self: These) => These(map) + /** * @category instances * @since 1.0.0 */ -export const Covariant: covariant.Covariant = covariant.make(map) +export const Covariant: covariant.Covariant = { + imap, + map +} /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap: Covariant.imap + imap } /** @@ -697,7 +702,7 @@ export const Do: These = of_.Do(Of) */ export const Pointed: pointed.Pointed = { of, - imap: Invariant.imap, + imap, map } @@ -766,12 +771,15 @@ export const contains = (equivalence: Equivalence) => export const exists = (predicate: Predicate) => (self: These): boolean => isLeft(self) ? false : predicate(self.right) +const reduce = (b: B, f: (b: B, a: A) => B) => + (self: These): B => isLeft(self) ? b : f(b, self.right) + /** * @category instances * @since 1.0.0 */ export const Foldable: foldable.Foldable = { - reduce: (b, f) => (self) => isLeft(self) ? b : f(b, self.right) + reduce } /** @@ -839,14 +847,24 @@ export const firstRightOrBothOf = (collection: Iterable>) => return out } +const coproduct = ( + self: These, + that: These +): These => isRightOrBoth(self) ? self : that + +const coproductMany = ( + self: These, + collection: Iterable> +): These => pipe(self, firstRightOrBothOf(collection)) + /** * @category instances * @since 1.0.0 */ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { - imap: Invariant.imap, - coproduct: (self, that) => isRightOrBoth(self) ? self : that, - coproductMany: (self, collection) => pipe(self, firstRightOrBothOf(collection)) + imap, + coproduct, + coproductMany } /** @@ -862,9 +880,9 @@ export const getFirstRightOrBothSemigroup: () => Semigroup> = */ export const SemiAlternative: semiAlternative.SemiAlternative = { map, - imap: Invariant.imap, - coproduct: SemiCoproduct.coproduct, - coproductMany: SemiCoproduct.coproductMany + imap, + coproduct, + coproductMany } /** @@ -956,7 +974,7 @@ const productMany = ( * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - imap: Invariant.imap, + imap, product, productMany } @@ -966,10 +984,10 @@ export const SemiProduct: semiProduct.SemiProduct = { * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { - imap: Invariant.imap, - map: Covariant.map, - product: SemiProduct.product, - productMany: SemiProduct.productMany + imap, + map, + product, + productMany } /** @@ -1091,9 +1109,9 @@ export const element: ( */ export const Product: product_.Product = { of, - imap: Invariant.imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + imap, + product, + productMany, productAll } @@ -1145,11 +1163,11 @@ export const flatMap = ( * @since 1.0.0 */ export const Applicative: applicative.Applicative = { - imap: Invariant.imap, + imap, of, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll } @@ -1203,7 +1221,7 @@ export const composeKleisliArrow: ( * @since 1.0.0 */ export const Chainable: chainable.Chainable = { - imap: Invariant.imap, + imap, map, flatMap } @@ -1272,7 +1290,7 @@ export const tap: ( * @since 1.0.0 */ export const Monad: monad.Monad = { - imap: Invariant.imap, + imap, of, map, flatMap diff --git a/test/Option.ts b/test/Option.ts index afa75d6ac..119439005 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -68,7 +68,6 @@ describe.concurrent("Option", () => { expect(_.Alternative).exist expect(_.Foldable).exist - expect(_.reduce).exist expect(_.reduceAll).exist expect(_.toArray).exist @@ -596,8 +595,8 @@ describe.concurrent("Option", () => { }) it("reduce", () => { - expect(pipe(_.none(), _.reduce(0, (b, a) => b + a))).toEqual(0) - expect(pipe(_.some(1), _.reduce(0, (b, a) => b + a))).toEqual(1) + expect(pipe(_.none(), _.Foldable.reduce(0, (b, a) => b + a))).toEqual(0) + expect(pipe(_.some(1), _.Foldable.reduce(0, (b, a) => b + a))).toEqual(1) }) it("sumAll", () => { From 18f70fcb18c5e8f26980fd88c1192808df241631 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 30 Jan 2023 17:47:51 +0100 Subject: [PATCH 122/255] Either: remove `fromThrowable` --- .changeset/yellow-elephants-travel.md | 5 +++ docs/modules/Either.ts.md | 33 -------------------- docs/modules/Option.ts.md | 13 +------- src/Either.ts | 44 +++++---------------------- test/Either.ts | 16 ---------- 5 files changed, 14 insertions(+), 97 deletions(-) create mode 100644 .changeset/yellow-elephants-travel.md diff --git a/.changeset/yellow-elephants-travel.md b/.changeset/yellow-elephants-travel.md new file mode 100644 index 000000000..de9881813 --- /dev/null +++ b/.changeset/yellow-elephants-travel.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": minor +--- + +Either: remove `fromThrowable` diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index de81e01f5..ff27ccd69 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -83,7 +83,6 @@ Added in v1.0.0 - [Traversable](#traversable) - [getOptionalSemigroup](#getoptionalsemigroup) - [interop](#interop) - - [fromThrowable](#fromthrowable) - [getOrThrow](#getorthrow) - [liftThrowable](#liftthrowable) - [lifting](#lifting) @@ -933,38 +932,6 @@ Added in v2.0.0 # interop -## fromThrowable - -Constructs a new `Either` from a function that might throw. - -**Signature** - -```ts -export declare const fromThrowable: (f: () => A, onThrow: (error: unknown) => E) => Either -``` - -**Example** - -```ts -import * as E from '@fp-ts/core/Either' -import { identity } from '@fp-ts/core/Function' - -const unsafeHead = (as: ReadonlyArray): A => { - if (as.length > 0) { - return as[0] - } else { - throw new Error('empty array') - } -} - -const head = (as: ReadonlyArray): E.Either => E.fromThrowable(() => unsafeHead(as), identity) - -assert.deepStrictEqual(head([]), E.left(new Error('empty array'))) -assert.deepStrictEqual(head([1, 2, 3]), E.right(1)) -``` - -Added in v1.0.0 - ## getOrThrow **Signature** diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 2320d2ddd..289a84295 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -124,7 +124,6 @@ Added in v1.0.0 - [exists](#exists) - [flatten](#flatten) - [of](#of) - - [reduce](#reduce) - [reduceAll](#reduceall) - [struct](#struct) - [toArray](#toarray) @@ -653,7 +652,7 @@ Checks if the specified value is an instance of `Option`, returns `true` if it i **Signature** ```ts -export declare const isOption: (input: unknown) => input is Option +export declare const isOption: (u: unknown) => u is Option ``` **Example** @@ -1613,16 +1612,6 @@ export declare const of: (a: A) => Option Added in v1.0.0 -## reduce - -**Signature** - -```ts -export declare const reduce: (b: B, f: (b: B, a: A) => B) => (self: Option) => B -``` - -Added in v1.0.0 - ## reduceAll Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. diff --git a/src/Either.ts b/src/Either.ts index b3374aa43..a62e6c724 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -769,41 +769,6 @@ export const flatMapNullable = ( export const toRefinement = (f: (a: A) => Either): Refinement => (a: A): a is B => isRight(f(a)) -/** - * Constructs a new `Either` from a function that might throw. - * - * @example - * import * as E from '@fp-ts/core/Either' - * import { identity } from '@fp-ts/core/Function' - * - * const unsafeHead = (as: ReadonlyArray): A => { - * if (as.length > 0) { - * return as[0] - * } else { - * throw new Error('empty array') - * } - * } - * - * const head = (as: ReadonlyArray): E.Either => - * E.fromThrowable(() => unsafeHead(as), identity) - * - * assert.deepStrictEqual(head([]), E.left(new Error('empty array'))) - * assert.deepStrictEqual(head([1, 2, 3]), E.right(1)) - * - * @category interop - * @since 1.0.0 - */ -export const fromThrowable = ( - f: () => A, - onThrow: (error: unknown) => E -): Either => { - try { - return right(f()) - } catch (e) { - return left(onThrow(e)) - } -} - /** * @category interop * @since 1.0.0 @@ -827,7 +792,14 @@ export const getOrThrow = ( export const liftThrowable = , B, E>( f: (...a: A) => B, onThrow: (error: unknown) => E -): ((...a: A) => Either) => (...a) => fromThrowable(() => f(...a), onThrow) +): ((...a: A) => Either) => + (...a) => { + try { + return right(f(...a)) + } catch (e) { + return left(onThrow(e)) + } + } /** * @category getters diff --git a/test/Either.ts b/test/Either.ts index 2ff73eadd..fa0e9ef8b 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -292,22 +292,6 @@ describe.concurrent("Either", () => { Util.deepStrictEqual(_.fromNullable(() => "default")(1), _.right(1)) }) - it("fromThrowable", () => { - Util.deepStrictEqual( - _.fromThrowable(() => { - return 1 - }, identity), - _.right(1) - ) - - Util.deepStrictEqual( - _.fromThrowable(() => { - throw "string error" - }, identity), - _.left("string error") - ) - }) - it("filterMap", () => { const p = (n: number) => n > 2 const f = (n: number) => (p(n) ? O.some(n + 1) : O.none()) From f04dcb2dd887d843e946c628dc076ebcf3b6320f Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 30 Jan 2023 17:54:00 +0100 Subject: [PATCH 123/255] liftPredicate: pass input to callback --- docs/modules/Either.ts.md | 4 ++-- docs/modules/These.ts.md | 4 ++-- src/Either.ts | 8 ++++---- src/These.ts | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index ff27ccd69..06b2ac234 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -1005,8 +1005,8 @@ Added in v1.0.0 ```ts export declare const liftPredicate: { - (refinement: any, onFalse: any): (c: C) => Either - (predicate: any, onFalse: any): (b: B) => Either + (refinement: any, onFalse: (c: C) => E): (c: C) => Either + (predicate: any, onFalse: (b: B) => E): (b: B) => Either } ``` diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index f36d347cb..97fbe5ca8 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1152,8 +1152,8 @@ Added in v1.0.0 ```ts export declare const liftPredicate: { - (refinement: any, onFalse: any): (c: C) => any - (predicate: any, onFalse: any): (b: B) => any + (refinement: any, onFalse: (c: C) => E): (c: C) => any + (predicate: any, onFalse: (b: B) => E): (b: B) => any } ``` diff --git a/src/Either.ts b/src/Either.ts index a62e6c724..2938abf2b 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1049,11 +1049,11 @@ export const getOrUndefined: (self: Either) => A | undefined = getOr export const liftPredicate: { ( refinement: Refinement, - onFalse: LazyArg + onFalse: (c: C) => E ): (c: C) => Either - (predicate: Predicate, onFalse: LazyArg): (b: B) => Either -} = (predicate: Predicate, onFalse: LazyArg) => - (b: B) => predicate(b) ? right(b) : left(onFalse()) + (predicate: Predicate, onFalse: (b: B) => E): (b: B) => Either +} = (predicate: Predicate, onFalse: (b: B) => E) => + (b: B) => predicate(b) ? right(b) : left(onFalse(b)) /** * @category lifting diff --git a/src/These.ts b/src/These.ts index b1831e303..bceab3382 100644 --- a/src/These.ts +++ b/src/These.ts @@ -332,11 +332,11 @@ export const flatMapNullable = ( export const liftPredicate: { ( refinement: Refinement, - onFalse: LazyArg + onFalse: (c: C) => E ): (c: C) => These - (predicate: Predicate, onFalse: LazyArg): (b: B) => These -} = (predicate: Predicate, onFalse: LazyArg) => - (b: B) => predicate(b) ? right(b) : left(onFalse()) + (predicate: Predicate, onFalse: (b: B) => E): (b: B) => These +} = (predicate: Predicate, onFalse: (b: B) => E) => + (b: B) => predicate(b) ? right(b) : left(onFalse(b)) /** * @category conversions From f438d7d31f37d113a8abe3598784befb73f1e61b Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 30 Jan 2023 18:34:16 +0100 Subject: [PATCH 124/255] ReadonlyRecord: add map, mapWithKey --- docs/modules/ReadonlyRecord.ts.md | 91 ++++++++++++++++++++++++++++- src/ReadonlyRecord.ts | 97 ++++++++++++++++++++++++++++++- test/ReadonlyRecord.ts | 9 +++ 3 files changed, 195 insertions(+), 2 deletions(-) diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md index 36723a0b7..4e0644c7e 100644 --- a/docs/modules/ReadonlyRecord.ts.md +++ b/docs/modules/ReadonlyRecord.ts.md @@ -19,6 +19,8 @@ Added in v1.0.0 - [models](#models) - [ReadonlyRecord (interface)](#readonlyrecord-interface) - [utils](#utils) + - [map](#map) + - [mapWithKey](#mapwithkey) - [modifyOption](#modifyoption) - [replaceOption](#replaceoption) @@ -28,7 +30,7 @@ Added in v1.0.0 ## get -This function provides a safe way to read a value at a particular key from a record. +Retrieve a value at a particular key from a `ReadonlyRecord`, returning it wrapped in an `Option`. **Signature** @@ -36,6 +38,19 @@ This function provides a safe way to read a value at a particular key from a rec export declare const get: (key: string) => (self: ReadonlyRecord) => any ``` +**Example** + +```ts +import { get } from '@fp-ts/core/ReadonlyRecord' +import { some, none } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +const person = { name: 'John Doe', age: 35 } + +assert.deepStrictEqual(pipe(person, get('name')), some('John Doe')) +assert.deepStrictEqual(pipe(person, get('email')), none()) +``` + Added in v1.0.0 # models @@ -54,6 +69,52 @@ Added in v1.0.0 # utils +## map + +Maps a `ReadonlyRecord` into another `Record` by applying a transformation function to each of its values. + +**Signature** + +```ts +export declare const map: (f: (a: A) => B) => (self: ReadonlyRecord) => Record +``` + +**Example** + +```ts +import { map } from '@fp-ts/core/ReadonlyRecord' +import { pipe } from '@fp-ts/core/Function' + +const f = (n: number) => `-${n}-` + +assert.deepStrictEqual(pipe({ a: 3, b: 5 }, map(f)), { a: '-3-', b: '-5-' }) +``` + +Added in v1.0.0 + +## mapWithKey + +Maps the values of a `ReadonlyRecord` to a new `Record` by applying a transformation function to each of its keys and values. + +**Signature** + +```ts +export declare const mapWithKey: (f: (k: string, a: A) => B) => (self: ReadonlyRecord) => Record +``` + +**Example** + +```ts +import { mapWithKey } from '@fp-ts/core/ReadonlyRecord' +import { pipe } from '@fp-ts/core/Function' + +const f = (k: string, n: number) => `${k.toUpperCase()}-${n}` + +assert.deepStrictEqual(pipe({ a: 3, b: 5 }, mapWithKey(f)), { a: 'A-3', b: 'B-5' }) +``` + +Added in v1.0.0 + ## modifyOption Apply a function to the element at the specified key, creating a new record, @@ -65,14 +126,42 @@ or return `None` if the key doesn't exist. export declare const modifyOption: (key: string, f: (a: A) => B) => (self: ReadonlyRecord) => any ``` +**Example** + +```ts +import { modifyOption } from '@fp-ts/core/ReadonlyRecord' +import { pipe } from '@fp-ts/core/Function' +import { some, none } from '@fp-ts/core/Option' + +const f = (x: number) => x * 2 + +assert.deepStrictEqual(pipe({ a: 3 }, modifyOption('a', f)), some({ a: 6 })) +assert.deepStrictEqual(pipe({ a: 3 }, modifyOption('b', f)), none()) +``` + Added in v1.0.0 ## replaceOption +Replaces a value in the record with the new value passed as parameter. + **Signature** ```ts export declare const replaceOption: (key: string, b: B) => (self: ReadonlyRecord) => any ``` +**Example** + +```ts +import { replaceOption } from '@fp-ts/core/ReadonlyRecord' +import { some, none } from '@fp-ts/core/Option' + +const record = { a: 1, b: 2, c: 3 } +const replaceA = replaceOption('a', 10) + +assert.deepStrictEqual(replaceA(record), some({ a: 10, b: 2, c: 3 })) +assert.deepStrictEqual(replaceA({}), none()) +``` + Added in v1.0.0 diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index 9936e7372..5483b02cf 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -16,7 +16,20 @@ export interface ReadonlyRecord { } /** - * This function provides a safe way to read a value at a particular key from a record. + * Retrieve a value at a particular key from a `ReadonlyRecord`, returning it wrapped in an `Option`. + * + * @param key - Key to retrieve from `ReadonlyRecord`. + * @param self - The `ReadonlyRecord` to retrieve value from. + * + * @example + * import { get } from "@fp-ts/core/ReadonlyRecord" + * import { some, none } from "@fp-ts/core/Option" + * import { pipe } from "@fp-ts/core/Function" + * + * const person = { name: "John Doe", age: 35 } + * + * assert.deepStrictEqual(pipe(person, get("name")), some("John Doe")) + * assert.deepStrictEqual(pipe(person, get("email")), none()) * * @category getters * @since 1.0.0 @@ -26,6 +39,22 @@ export const get = (key: string) => Object.prototype.hasOwnProperty.call(self, key) ? O.some(self[key]) : O.none() /** + * Replaces a value in the record with the new value passed as parameter. + * + * @param key - The key to search for in the record. + * @param b - The new value to replace the existing value with. + * @param self - The `ReadonlyRecord` to be updated. + * + * @example + * import { replaceOption } from "@fp-ts/core/ReadonlyRecord" + * import { some, none } from "@fp-ts/core/Option" + * + * const record = { a: 1, b: 2, c: 3 } + * const replaceA = replaceOption('a', 10) + * + * assert.deepStrictEqual(replaceA(record), some({ a: 10, b: 2, c: 3 })) + * assert.deepStrictEqual(replaceA({}), none()) + * * @since 1.0.0 */ export const replaceOption = ( @@ -37,6 +66,26 @@ export const replaceOption = ( * Apply a function to the element at the specified key, creating a new record, * or return `None` if the key doesn't exist. * + * @param key - The key of the element to modify. + * @param f - The function to apply to the element. + * @param self - The `ReadonlyRecord` to be updated. + * + * @example + * import { modifyOption } from "@fp-ts/core/ReadonlyRecord" + * import { pipe } from "@fp-ts/core/Function" + * import { some, none } from "@fp-ts/core/Option" + * + * const f = (x: number) => x * 2 + * + * assert.deepStrictEqual( + * pipe({ a: 3 }, modifyOption('a', f)), + * some({ a: 6 }) + * ) + * assert.deepStrictEqual( + * pipe({ a: 3 }, modifyOption('b', f)), + * none() + * ) + * * @since 1.0.0 */ export const modifyOption = (key: string, f: (a: A) => B) => @@ -48,3 +97,49 @@ export const modifyOption = (key: string, f: (a: A) => B) => out[key] = f(self[key]) return O.some(out) } + +/** + * Maps the values of a `ReadonlyRecord` to a new `Record` by applying a transformation function to each of its keys and values. + * + * @param f - A transformation function that will be applied to each of the key/values in the `ReadonlyRecord`. + * @param self - The `ReadonlyRecord` to be mapped. + * + * @example + * import { mapWithKey } from "@fp-ts/core/ReadonlyRecord" + * import { pipe } from "@fp-ts/core/Function" + * + * const f = (k: string, n: number) => `${k.toUpperCase()}-${n}` + * + * assert.deepStrictEqual(pipe({ a: 3, b: 5 }, mapWithKey(f)), { a: "A-3", b: "B-5" }) + * + * @since 1.0.0 + */ +export const mapWithKey = (f: (k: string, a: A) => B) => + (self: ReadonlyRecord): Record => { + const out: Record = {} + for (const k in self) { + if (Object.prototype.hasOwnProperty.call(self, k)) { + out[k] = f(k, self[k]) + } + } + return out + } + +/** + * Maps a `ReadonlyRecord` into another `Record` by applying a transformation function to each of its values. + * + * @param f - A transformation function that will be applied to each of the values in the `ReadonlyRecord`. + * @param self - The `ReadonlyRecord` to be mapped. + * + * @example + * import { map } from "@fp-ts/core/ReadonlyRecord" + * import { pipe } from "@fp-ts/core/Function" + * + * const f = (n: number) => `-${n}-` + * + * assert.deepStrictEqual(pipe({ a: 3, b: 5 }, map(f)), { a: "-3-", b: "-5-" }) + * + * @since 1.0.0 + */ +export const map = (f: (a: A) => B): (self: ReadonlyRecord) => Record => + mapWithKey((_, a) => f(a)) diff --git a/test/ReadonlyRecord.ts b/test/ReadonlyRecord.ts index c8127e047..bf1072720 100644 --- a/test/ReadonlyRecord.ts +++ b/test/ReadonlyRecord.ts @@ -21,4 +21,13 @@ describe.concurrent("ReadonlyRecord", () => { O.some({ a: "1" }) ) }) + + it("mapWithKey", () => { + expect(pipe({ a: 1, b: 2 }, RR.mapWithKey((k, n) => `${k}-${n}`))).toEqual, + ({ a: "a-1", b: "b-2" }) + }) + + it("map", () => { + expect(pipe({ a: 1, b: 2 }, RR.map(n => n * 2))).toEqual, ({ a: 2, b: 4 }) + }) }) From 23ab1701d13d11b9f151b8d6d9069f07387e552f Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 30 Jan 2023 18:43:18 +0100 Subject: [PATCH 125/255] add @effect/language-service --- package.json | 1 + pnpm-lock.yaml | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/package.json b/package.json index 44de22737..75890dad2 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "@changesets/cli": "^2.25.2", "@effect-ts/build-utils": "0.40.3", "@effect-ts/core": "^0.60.2", + "@effect/language-service": "^0.0.17", "@repo-tooling/eslint-plugin-dprint": "^0.0.4", "@types/benchmark": "^2.1.2", "@types/glob": "^8.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 25ec441ac..224565d26 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,6 +19,7 @@ importers: '@changesets/cli': ^2.25.2 '@effect-ts/build-utils': 0.40.3 '@effect-ts/core': ^0.60.2 + '@effect/language-service': ^0.0.17 '@repo-tooling/eslint-plugin-dprint': ^0.0.4 '@types/benchmark': ^2.1.2 '@types/glob': ^8.0.0 @@ -62,6 +63,7 @@ importers: '@changesets/cli': 2.25.2 '@effect-ts/build-utils': 0.40.3_wzvflwv62ngf22ppz3frldq37m_smskbqsf3q6kbozdrpluio47kq '@effect-ts/core': 0.60.4 + '@effect/language-service': 0.0.17 '@repo-tooling/eslint-plugin-dprint': 0.0.4_typescript@4.9.3 '@types/benchmark': 2.1.2 '@types/glob': 8.0.0 @@ -663,6 +665,13 @@ packages: resolution: {integrity: sha512-gGnOCvDv6829EeeC+NgTnwIt4XxclR0KqrG7BRemmNX5cm75cF0CKiuEB/o902wjAlt+MdrxTtFC+XsYdLnxzA==} dev: true + /@effect/language-service/0.0.17: + resolution: {integrity: sha512-98c6VtueGDvCGDfkQijsQ5uP/g4J2VhSbI83f/Rv84Gg0uJ+BbA9jno1dQubvaPRGBMIVE+1egZUduSWY6tfEg==} + dependencies: + '@fp-ts/core': 0.0.11 + '@fp-ts/data': 0.0.41 + dev: true + /@esbuild/android-arm/0.15.16: resolution: {integrity: sha512-nyB6CH++2mSgx3GbnrJsZSxzne5K0HMyNIWafDHqYy7IwxFc4fd/CgHVZXr8Eh+Q3KbIAcAe3vGyqIPhGblvMQ==} engines: {node: '>=12'} @@ -707,6 +716,16 @@ packages: - supports-color dev: true + /@fp-ts/core/0.0.11: + resolution: {integrity: sha512-BCAJBYzghwoJpcUOARJ1tui50HoYJFlV2pJlVMlsEkDFhD8MTtq8xQVpZCRF66RmtkxtGBYINCQ+5H1lRaL35Q==} + dev: true + + /@fp-ts/data/0.0.41: + resolution: {integrity: sha512-0S93kOQ91D7wp60q/PSVWvMsJjSWJutjt4qX/BvVNV7+fymuC2hTfW2HlE2OcMK11xCNiI6Rq2AkvyzoMhOlpg==} + dependencies: + '@fp-ts/core': 0.0.11 + dev: true + /@humanwhocodes/config-array/0.11.7: resolution: {integrity: sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==} engines: {node: '>=10.10.0'} From f3cc9d2cf2440586f2681f447ae9056d94a631d7 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 07:40:14 +0100 Subject: [PATCH 126/255] rename `element` to `appendElement` --- .changeset/pink-chefs-report.md | 5 +++ docs/modules/Either.ts.md | 28 ++++++------ docs/modules/Option.ts.md | 28 ++++++------ docs/modules/Predicate.ts.md | 26 +++++------ docs/modules/These.ts.md | 20 ++++----- docs/modules/Tuple.ts.md | 55 ++++++++++++------------ docs/modules/typeclass/Monoid.ts.md | 9 +++- docs/modules/typeclass/SemiProduct.ts.md | 8 ++-- docs/modules/typeclass/Semigroup.ts.md | 1 + dtslint/ts4.7/Tuple.ts | 12 ++++++ src/Either.ts | 6 +-- src/Option.ts | 6 +-- src/Predicate.ts | 6 +-- src/These.ts | 6 +-- src/Tuple.ts | 44 +++++++++++-------- src/typeclass/Monoid.ts | 9 +++- src/typeclass/SemiProduct.ts | 4 +- src/typeclass/Semigroup.ts | 1 + test/Either.ts | 2 +- test/Option.ts | 2 +- test/Predicate.ts | 2 +- test/These.ts | 2 +- test/Tuple.ts | 9 ++-- test/typeclass/SemiProduct.ts | 12 +++--- 24 files changed, 173 insertions(+), 130 deletions(-) create mode 100644 .changeset/pink-chefs-report.md diff --git a/.changeset/pink-chefs-report.md b/.changeset/pink-chefs-report.md new file mode 100644 index 000000000..c24598d1a --- /dev/null +++ b/.changeset/pink-chefs-report.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": minor +--- + +rename `element` to `appendElement` diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 06b2ac234..4e68f13c2 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -119,9 +119,9 @@ Added in v1.0.0 - [utils](#utils) - [andThen](#andthen) - [ap](#ap) + - [appendElement](#appendelement) - [composeKleisliArrow](#composekleisliarrow) - [contains](#contains) - - [element](#element) - [exists](#exists) - [flatten](#flatten) - [reverse](#reverse) @@ -1316,40 +1316,40 @@ export declare const ap: (fa: Either) => (self: Either( - bfc: (b: B) => Either -) => (afb: (a: A) => Either) => (a: A) => Either +export declare const appendElement: ( + that: Either +) => (self: Either) => Either ``` Added in v1.0.0 -## contains - -Returns a function that checks if an `Either` contains a given value using a provided `equivalence` function. +## composeKleisliArrow **Signature** ```ts -export declare const contains: (equivalence: any) => (a: A) => (self: Either) => boolean +export declare const composeKleisliArrow: ( + bfc: (b: B) => Either +) => (afb: (a: A) => Either) => (a: A) => Either ``` Added in v1.0.0 -## element +## contains -Adds an element to the end of a tuple. +Returns a function that checks if an `Either` contains a given value using a provided `equivalence` function. **Signature** ```ts -export declare const element: ( - that: Either -) => (self: Either) => Either +export declare const contains: (equivalence: any) => (a: A) => (self: Either) => boolean ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 289a84295..16ffabd35 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -118,9 +118,9 @@ Added in v1.0.0 - [utils](#utils) - [andThen](#andthen) - [ap](#ap) + - [appendElement](#appendelement) - [composeKleisliArrow](#composekleisliarrow) - [contains](#contains) - - [element](#element) - [exists](#exists) - [flatten](#flatten) - [of](#of) @@ -1519,6 +1519,20 @@ export declare const ap: (fa: Option) => (self: Option<(a: A) => B>) => Added in v1.0.0 +## appendElement + +Appends an element to the end of a tuple. + +**Signature** + +```ts +export declare const appendElement: ( + fb: Option +) => (self: Option) => Option<[...A, B]> +``` + +Added in v1.0.0 + ## composeKleisliArrow **Signature** @@ -1555,18 +1569,6 @@ assert.deepStrictEqual(pipe(none(), contains(Equivalence)(2)), false) Added in v1.0.0 -## element - -Adds an element to the end of a tuple. - -**Signature** - -```ts -export declare const element: (fb: Option) => (self: Option) => Option<[...A, B]> -``` - -Added in v1.0.0 - ## exists Check if a value in an `Option` type meets a certain predicate. diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index a4714925f..64df37c62 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -43,9 +43,9 @@ Added in v1.0.0 - [and](#and) - [andThenBind](#andthenbind) - [any](#any) + - [appendElement](#appendelement) - [compose](#compose) - [contramap](#contramap) - - [element](#element) - [not](#not) - [of](#of) - [or](#or) @@ -321,38 +321,38 @@ export declare const any: (collection: Iterable>) => Predicate( - bc: Refinement -) => (ab: Refinement) => Refinement +export declare const appendElement: ( + that: Predicate +) => (self: Predicate) => Predicate ``` Added in v1.0.0 -## contramap +## compose **Signature** ```ts -export declare const contramap: (f: (b: B) => A) => (self: Predicate) => Predicate +export declare const compose: ( + bc: Refinement +) => (ab: Refinement) => Refinement ``` Added in v1.0.0 -## element - -Adds an element to the end of a tuple. +## contramap **Signature** ```ts -export declare const element: ( - that: Predicate -) => (self: Predicate) => Predicate +export declare const contramap: (f: (b: B) => A) => (self: Predicate) => Predicate ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 97fbe5ca8..29ebd8f58 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -150,9 +150,9 @@ Added in v1.0.0 - [utils](#utils) - [andThen](#andthen) - [ap](#ap) + - [appendElement](#appendelement) - [composeKleisliArrow](#composekleisliarrow) - [contains](#contains) - - [element](#element) - [flatten](#flatten) - [reverse](#reverse) - [struct](#struct) @@ -1464,36 +1464,36 @@ export declare const ap: (fa: any) => (self: any) => any Added in v1.0.0 -## composeKleisliArrow +## appendElement + +Appends an element to the end of a tuple. **Signature** ```ts -export declare const composeKleisliArrow: (bfc: (b: B) => any) => (afb: (a: A) => any) => (a: A) => any +export declare const appendElement: (that: any) => (self: any) => any ``` Added in v1.0.0 -## contains - -Returns a function that checks if a `These` contains a given value using a provided `equivalence` function. +## composeKleisliArrow **Signature** ```ts -export declare const contains: (equivalence: any) => (a: A) => (self: any) => boolean +export declare const composeKleisliArrow: (bfc: (b: B) => any) => (afb: (a: A) => any) => (a: A) => any ``` Added in v1.0.0 -## element +## contains -Adds an element to the end of a tuple. +Returns a function that checks if a `These` contains a given value using a provided `equivalence` function. **Signature** ```ts -export declare const element: (that: any) => (self: any) => any +export declare const contains: (equivalence: any) => (a: A) => (self: any) => boolean ``` Added in v1.0.0 diff --git a/docs/modules/Tuple.ts.md b/docs/modules/Tuple.ts.md index 2bf29beac..4e308b0e8 100644 --- a/docs/modules/Tuple.ts.md +++ b/docs/modules/Tuple.ts.md @@ -16,14 +16,13 @@ Added in v1.0.0 - [constructors](#constructors) - [tuple](#tuple) -- [utils](#utils) - - [element](#element) +- [instances](#instances) - [getEquivalence](#getequivalence) - [getMonoid](#getmonoid) - [getOrder](#getorder) - [getSemigroup](#getsemigroup) - - [nonEmptyProduct](#nonemptyproduct) - - [product](#product) +- [utils](#utils) + - [appendElement](#appendelement) --- @@ -39,33 +38,29 @@ export declare const tuple: (...elements: A) => A Added in v1.0.0 -# utils +# instances -## element +## getEquivalence -Appends an element to the end of a tuple. +Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple +by applying each `Equivalence` to the corresponding element of the tuple. **Signature** ```ts -export declare const element: ( - that: readonly B[] -) => (self: readonly A[]) => [...A, B][] +export declare const getEquivalence: any ``` Added in v1.0.0 -## getEquivalence - -**Signature** +## getMonoid -```ts -export declare const getEquivalence: any -``` +This function creates and returns a new `Monoid` for a tuple of values based on the given `Monoid`s for each element in the tuple. +The returned `Monoid` combines two tuples of the same type by applying the corresponding `Monoid` passed as arguments to each element in the tuple. -Added in v1.0.0 +The `empty` value of the returned `Monoid` is the tuple of `empty` values of the input `Monoid`s. -## getMonoid +It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. **Signature** @@ -77,6 +72,11 @@ Added in v1.0.0 ## getOrder +This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. +The returned `Order` compares two tuples of the same type by applying the corresponding `Order` to each element in the tuple. +It is useful when you need to compare two tuples of the same type and you have a specific way of comparing each element +of the tuple. + **Signature** ```ts @@ -87,6 +87,11 @@ Added in v1.0.0 ## getSemigroup +This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. +The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. + +It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. + **Signature** ```ts @@ -95,22 +100,16 @@ export declare const getSemigroup: any Added in v1.0.0 -## nonEmptyProduct - -**Signature** - -```ts -export declare const nonEmptyProduct: any -``` +# utils -Added in v1.0.0 +## appendElement -## product +Appends an element to the end of a tuple. **Signature** ```ts -export declare const product: any +export declare const appendElement: (that: B) => (self: A) => [...A, B] ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index 77141067d..ef7adee6a 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -40,7 +40,7 @@ Added in v1.0.0 ## array Given a type `A`, this function creates and returns a `Monoid` for `Array`. -The returned `Monoid`'s empty value is the empty array. +The returned `Monoid`'s `empty` value is the empty array. **Signature** @@ -91,7 +91,12 @@ Added in v1.0.0 ## tuple -Given a tuple of `Monoid`s returns a `Monoid` for the tuple. +This function creates and returns a new `Monoid` for a tuple of values based on the given `Monoid`s for each element in the tuple. +The returned `Monoid` combines two tuples of the same type by applying the corresponding `Monoid` passed as arguments to each element in the tuple. + +The `empty` value of the returned `Monoid` is the tuple of `empty` values of the input `Monoid`s. + +It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. **Signature** diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index 197394475..78b8ebdd8 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -18,7 +18,7 @@ Added in v1.0.0 - [SemiProduct (interface)](#semiproduct-interface) - [utils](#utils) - [andThenBind](#andthenbind) - - [element](#element) + - [appendElement](#appendelement) - [nonEmptyStruct](#nonemptystruct) - [nonEmptyTuple](#nonemptytuple) - [productComposition](#productcomposition) @@ -82,14 +82,14 @@ export declare const andThenBind: ( Added in v1.0.0 -## element +## appendElement -Adds an element to the end of a tuple. +Appends an element to the end of a tuple. **Signature** ```ts -export declare const element: ( +export declare const appendElement: ( F: SemiProduct ) => (that: any) => (self: any) => any ``` diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index 9da24d4d5..b799b8126 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -113,6 +113,7 @@ Added in v1.0.0 This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. + It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. **Signature** diff --git a/dtslint/ts4.7/Tuple.ts b/dtslint/ts4.7/Tuple.ts index ffe7ae68b..653b581f1 100644 --- a/dtslint/ts4.7/Tuple.ts +++ b/dtslint/ts4.7/Tuple.ts @@ -1,4 +1,16 @@ import * as T from '@fp-ts/core/Tuple' +import { pipe } from '@fp-ts/core/Function' + +// +// tuple +// // $ExpectType [string, number, boolean] T.tuple('a', 1, true) + +// +// appendElement +// + +// $ExpectType [string, number, boolean] +pipe(T.tuple('a', 1), T.appendElement(true)) diff --git a/src/Either.ts b/src/Either.ts index 2938abf2b..cb540d581 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -397,16 +397,16 @@ export const andThenBind: ( .andThenBind(SemiProduct) /** - * Adds an element to the end of a tuple. + * Appends an element to the end of a tuple. * * @since 1.0.0 */ -export const element: ( +export const appendElement: ( that: Either ) => >( self: Either ) => Either = semiProduct - .element(SemiProduct) + .appendElement(SemiProduct) const productAll = ( collection: Iterable> diff --git a/src/Option.ts b/src/Option.ts index 01f468b6f..2e07ed083 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -819,14 +819,14 @@ export const andThenBind: ( .andThenBind(SemiProduct) /** - * Adds an element to the end of a tuple. + * Appends an element to the end of a tuple. * * @since 1.0.0 */ -export const element: ( +export const appendElement: ( fb: Option ) => >(self: Option) => Option<[...A, B]> = semiProduct - .element(SemiProduct) + .appendElement(SemiProduct) const productAll = (collection: Iterable>): Option> => { const out: Array = [] diff --git a/src/Predicate.ts b/src/Predicate.ts index b5f917eee..25fb04981 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -218,13 +218,13 @@ export const andThenBind: ( ) /** - * Adds an element to the end of a tuple. + * Appends an element to the end of a tuple. * * @since 1.0.0 */ -export const element: (that: Predicate) => >( +export const appendElement: (that: Predicate) => >( self: Predicate -) => Predicate = semiProduct.element(SemiProduct) as any +) => Predicate = semiProduct.appendElement(SemiProduct) as any /** * @since 1.0.0 diff --git a/src/These.ts b/src/These.ts index bceab3382..cabac74d2 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1092,16 +1092,16 @@ export const andThenBindThese = ( andThenBind(name, fromThese(that)) /** - * Adds an element to the end of a tuple. + * Appends an element to the end of a tuple. * * @since 1.0.0 */ -export const element: ( +export const appendElement: ( that: Validated ) => >( self: Validated ) => Validated = semiProduct - .element(SemiProduct) + .appendElement(SemiProduct) /** * @category instances diff --git a/src/Tuple.ts b/src/Tuple.ts index d2d20992b..53ad2515a 100644 --- a/src/Tuple.ts +++ b/src/Tuple.ts @@ -3,13 +3,10 @@ * * @since 1.0.0 */ -import * as RA from "@fp-ts/core/ReadonlyArray" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as order from "@fp-ts/core/typeclass/Order" -import * as product_ from "@fp-ts/core/typeclass/Product" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" -import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** * @category constructors @@ -18,40 +15,53 @@ import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" export const tuple = >(...elements: A): A => elements /** - * Appends an element to the end of a tuple. + * Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple + * by applying each `Equivalence` to the corresponding element of the tuple. * - * @since 1.0.0 - */ -export const element: (that: ReadonlyArray) => >( - self: ReadonlyArray -) => Array<[...A, B]> = semiProduct.element(RA.SemiProduct) as any - -/** + * @category instances * @since 1.0.0 */ export const getEquivalence = equivalence.tuple /** + * This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. + * The returned `Order` compares two tuples of the same type by applying the corresponding `Order` to each element in the tuple. + * It is useful when you need to compare two tuples of the same type and you have a specific way of comparing each element + * of the tuple. + * + * @category instances * @since 1.0.0 */ export const getOrder = order.tuple /** + * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. + * The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. + * + * It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. + * + * @category instances * @since 1.0.0 */ export const getSemigroup = semigroup.tuple /** + * This function creates and returns a new `Monoid` for a tuple of values based on the given `Monoid`s for each element in the tuple. + * The returned `Monoid` combines two tuples of the same type by applying the corresponding `Monoid` passed as arguments to each element in the tuple. + * + * The `empty` value of the returned `Monoid` is the tuple of `empty` values of the input `Monoid`s. + * + * It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. + * + * @category instances * @since 1.0.0 */ export const getMonoid = monoid.tuple /** + * Appends an element to the end of a tuple. + * * @since 1.0.0 */ -export const nonEmptyProduct = semiProduct.nonEmptyTuple - -/** - * @since 1.0.0 - */ -export const product = product_.tuple +export const appendElement = (that: B) => + >(self: A): [...A, B] => [...self, that] diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index fd2c7cfa0..071932238 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -147,7 +147,12 @@ export const booleanAny: Monoid = { } /** - * Given a tuple of `Monoid`s returns a `Monoid` for the tuple. + * This function creates and returns a new `Monoid` for a tuple of values based on the given `Monoid`s for each element in the tuple. + * The returned `Monoid` combines two tuples of the same type by applying the corresponding `Monoid` passed as arguments to each element in the tuple. + * + * The `empty` value of the returned `Monoid` is the tuple of `empty` values of the input `Monoid`s. + * + * It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. * * @category combinators * @since 1.0.0 @@ -161,7 +166,7 @@ export const tuple = >( /** * Given a type `A`, this function creates and returns a `Monoid` for `Array`. - * The returned `Monoid`'s empty value is the empty array. + * The returned `Monoid`'s `empty` value is the empty array. * * @category combinators * @since 1.0.0 diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index f16678bbd..c41b10aee 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -114,11 +114,11 @@ export const andThenBind = (F: SemiProduct) => ) /** - * Adds an element to the end of a tuple. + * Appends an element to the end of a tuple. * * @since 1.0.0 */ -export const element = (F: SemiProduct) => +export const appendElement = (F: SemiProduct) => ( that: Kind ) => diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index a6c06a8af..e17c902bb 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -174,6 +174,7 @@ export const booleanAny: Semigroup = { /** * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. * The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. + * * It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. * * @category combinators diff --git a/test/Either.ts b/test/Either.ts index fa0e9ef8b..79f3bf137 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -423,7 +423,7 @@ describe.concurrent("Either", () => { }) it("element", () => { - expect(pipe(_.right(1), _.tupled, _.element(_.right("b")))).toEqual( + expect(pipe(_.right(1), _.tupled, _.appendElement(_.right("b")))).toEqual( _.right([1, "b"]) ) }) diff --git a/test/Option.ts b/test/Option.ts index 119439005..6db17069f 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -488,7 +488,7 @@ describe.concurrent("Option", () => { }) it("element", () => { - expect(pipe(_.some(1), _.tupled, _.element(_.some("b")))).toEqual( + expect(pipe(_.some(1), _.tupled, _.appendElement(_.some("b")))).toEqual( _.some([1, "b"]) ) }) diff --git a/test/Predicate.ts b/test/Predicate.ts index eff0e7e70..a3d77776d 100644 --- a/test/Predicate.ts +++ b/test/Predicate.ts @@ -32,7 +32,7 @@ describe.concurrent("Predicate", () => { expect(_.SemiProduct).exist expect(_.andThenBind).exist - expect(_.element).exist + expect(_.appendElement).exist expect(_.Product).exist expect(_.tuple).exist diff --git a/test/These.ts b/test/These.ts index 8c86ebf68..69e025535 100644 --- a/test/These.ts +++ b/test/These.ts @@ -45,7 +45,7 @@ describe("These", () => { expect(_.SemiProduct).exist expect(_.andThenBind).exist - expect(_.element).exist + expect(_.appendElement).exist expect(_.Product).exist expect(_.tuple).exist diff --git a/test/Tuple.ts b/test/Tuple.ts index 9a1212646..63295c648 100644 --- a/test/Tuple.ts +++ b/test/Tuple.ts @@ -1,17 +1,20 @@ +import { pipe } from "@fp-ts/core/Function" import * as T from "@fp-ts/core/Tuple" describe.concurrent("Tuple", () => { it("exports", () => { - expect(T.element).exists + expect(T.appendElement).exists expect(T.getEquivalence).exists expect(T.getOrder).exists expect(T.getSemigroup).exists expect(T.getMonoid).exists - expect(T.nonEmptyProduct).exists - expect(T.product).exists }) it("tuple", () => { expect(T.tuple("a", 1, true)).toEqual(["a", 1, true]) }) + + it("appendElement", () => { + expect(pipe(T.tuple("a", 1), T.appendElement(true))).toEqual(["a", 1, true]) + }) }) diff --git a/test/typeclass/SemiProduct.ts b/test/typeclass/SemiProduct.ts index 57a00fbdc..c05066dc7 100644 --- a/test/typeclass/SemiProduct.ts +++ b/test/typeclass/SemiProduct.ts @@ -166,16 +166,16 @@ describe("SemiProduct", () => { }) }) - describe("element", () => { + describe("appendElement", () => { it("Covariant (Option)", () => { - const element = _.element(O.SemiProduct) - U.deepStrictEqual(pipe(O.some([1, 2]), element(O.none())), O.none()) - expect(pipe(O.some([1, 2]), element(O.some(3)))).toEqual(O.some([1, 2, 3])) + const appendElement = _.appendElement(O.SemiProduct) + U.deepStrictEqual(pipe(O.some([1, 2]), appendElement(O.none())), O.none()) + expect(pipe(O.some([1, 2]), appendElement(O.some(3)))).toEqual(O.some([1, 2, 3])) }) it("Contravariant (Predicate)", () => { - const element = _.element(P.SemiProduct) - const p = pipe(P.tuple(String.isString, String.isString), element(Number.isNumber)) + const appendElement = _.appendElement(P.SemiProduct) + const p = pipe(P.tuple(String.isString, String.isString), appendElement(Number.isNumber)) U.deepStrictEqual(p(["a", "b", 3]), true) U.deepStrictEqual(p(["a", "b", "c"]), false) U.deepStrictEqual(p([1, "b", 1]), false) From f1230191aaff0fdb5e521d11118e939aa50ea6f5 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 08:17:18 +0100 Subject: [PATCH 127/255] ReadonlyRecord: add fromIterable --- docs/modules/Either.ts.md | 2 +- docs/modules/ReadonlyRecord.ts.md | 30 ++++++++++++ docs/modules/Struct.ts.md | 45 +++++++++-------- docs/modules/Tuple.ts.md | 32 ++++++------ docs/modules/typeclass/Equivalence.ts.md | 52 ++++++++++---------- docs/modules/typeclass/Monoid.ts.md | 7 ++- docs/modules/typeclass/Semigroup.ts.md | 1 + src/Either.ts | 2 +- src/ReadonlyRecord.ts | 62 ++++++++++++++++++++++++ src/Struct.ts | 38 +++++++++++---- src/Tuple.ts | 22 +++++++-- src/typeclass/Equivalence.ts | 12 ++--- src/typeclass/Monoid.ts | 7 ++- src/typeclass/Semigroup.ts | 1 + test/ReadonlyRecord.ts | 18 +++++-- test/Struct.ts | 2 - 16 files changed, 239 insertions(+), 94 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 4e68f13c2..4470c2adc 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -928,7 +928,7 @@ while elements that are `Right` are combined using the provided `Semigroup`. export declare const getOptionalSemigroup: (S: any) => any ``` -Added in v2.0.0 +Added in v1.0.0 # interop diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md index 4e0644c7e..600147a9c 100644 --- a/docs/modules/ReadonlyRecord.ts.md +++ b/docs/modules/ReadonlyRecord.ts.md @@ -14,6 +14,8 @@ Added in v1.0.0

Table of contents

+- [constructors](#constructors) + - [fromIterable](#fromiterable) - [getters](#getters) - [get](#get) - [models](#models) @@ -26,6 +28,34 @@ Added in v1.0.0 --- +# constructors + +## fromIterable + +Takes an iterable and a projection function, `f`, and returns a record. +The projection function maps each value of the iterable to a tuple of a key and a value, which is then added to the resulting record. + +**Signature** + +```ts +export declare const fromIterable: (iterable: Iterable
, f: (a: A) => readonly [string, B]) => Record +``` + +**Example** + +```ts +import { fromIterable } from '@fp-ts/core/ReadonlyRecord' + +const input = [1, 2, 3, 4] + +assert.deepStrictEqual( + fromIterable(input, (a) => [String(a), a * 2]), + { '1': 2, '2': 4, '3': 6, '4': 8 } +) +``` + +Added in v1.0.0 + # getters ## get diff --git a/docs/modules/Struct.ts.md b/docs/modules/Struct.ts.md index 64c4c7df8..923dcd74d 100644 --- a/docs/modules/Struct.ts.md +++ b/docs/modules/Struct.ts.md @@ -14,22 +14,24 @@ Added in v1.0.0

Table of contents

-- [utils](#utils) +- [combinators](#combinators) - [getEquivalence](#getequivalence) - [getMonoid](#getmonoid) - [getOrder](#getorder) - [getSemigroup](#getsemigroup) - - [nonEmptyProduct](#nonemptyproduct) +- [utils](#utils) - [omit](#omit) - [pick](#pick) - - [product](#product) --- -# utils +# combinators ## getEquivalence +Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct +by applying each `Equivalence` to the corresponding property of the struct. + **Signature** ```ts @@ -40,6 +42,13 @@ Added in v1.0.0 ## getMonoid +This function creates and returns a new `Monoid` for a struct of values based on the given `Monoid`s for each property in the struct. +The returned `Monoid` combines two structs of the same type by applying the corresponding `Monoid` passed as arguments to each property in the struct. + +The `empty` value of the returned `Monoid` is a struct where each property is the `empty` value of the corresponding `Monoid` in the input `monoids` object. + +It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. + **Signature** ```ts @@ -50,6 +59,9 @@ Added in v1.0.0 ## getOrder +This function creates and returns a new `Order` for a struct of values based on the given `Order`s +for each property in the struct. + **Signature** ```ts @@ -60,24 +72,21 @@ Added in v1.0.0 ## getSemigroup -**Signature** - -```ts -export declare const getSemigroup: any -``` - -Added in v1.0.0 +This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. +The returned `Semigroup` combines two structs of the same type by applying the corresponding `Semigroup` passed as arguments to each property in the struct. -## nonEmptyProduct +It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. **Signature** ```ts -export declare const nonEmptyProduct: any +export declare const getSemigroup: any ``` Added in v1.0.0 +# utils + ## omit Create a new object by omitting properties of an existing object. @@ -105,13 +114,3 @@ export declare const pick: ( ``` Added in v1.0.0 - -## product - -**Signature** - -```ts -export declare const product: any -``` - -Added in v1.0.0 diff --git a/docs/modules/Tuple.ts.md b/docs/modules/Tuple.ts.md index 4e308b0e8..a144803f3 100644 --- a/docs/modules/Tuple.ts.md +++ b/docs/modules/Tuple.ts.md @@ -14,31 +14,19 @@ Added in v1.0.0

Table of contents

-- [constructors](#constructors) - - [tuple](#tuple) -- [instances](#instances) +- [combinators](#combinators) - [getEquivalence](#getequivalence) - [getMonoid](#getmonoid) - [getOrder](#getorder) - [getSemigroup](#getsemigroup) +- [constructors](#constructors) + - [tuple](#tuple) - [utils](#utils) - [appendElement](#appendelement) --- -# constructors - -## tuple - -**Signature** - -```ts -export declare const tuple:
(...elements: A) => A -``` - -Added in v1.0.0 - -# instances +# combinators ## getEquivalence @@ -100,6 +88,18 @@ export declare const getSemigroup: any Added in v1.0.0 +# constructors + +## tuple + +**Signature** + +```ts +export declare const tuple: (...elements: A) => A +``` + +Added in v1.0.0 + # utils ## appendElement diff --git a/docs/modules/typeclass/Equivalence.ts.md b/docs/modules/typeclass/Equivalence.ts.md index 177f3c61e..991fdddfe 100644 --- a/docs/modules/typeclass/Equivalence.ts.md +++ b/docs/modules/typeclass/Equivalence.ts.md @@ -17,13 +17,13 @@ Added in v1.0.0

Table of contents

- [combinators](#combinators) - - [contramap](#contramap) -- [constructors](#constructors) - [array](#array) + - [contramap](#contramap) - [record](#record) - - [strict](#strict) - [struct](#struct) - [tuple](#tuple) +- [constructors](#constructors) + - [strict](#strict) - [instances](#instances) - [Contravariant](#contravariant) - [Invariant](#invariant) @@ -45,18 +45,6 @@ Added in v1.0.0 # combinators -## contramap - -**Signature** - -```ts -export declare const contramap: (f: (b: B) => A) => (self: Equivalence
) => Equivalence -``` - -Added in v1.0.0 - -# constructors - ## array Given an `Equivalence` of type `A`, returns a new `Equivalence` of type `ReadonlyArray`. @@ -71,28 +59,26 @@ export declare const array: (equivalence: Equivalence) => Equivalence(equivalence: Equivalence) => Equivalence +export declare const contramap: (f: (b: B) => A) => (self: Equivalence) => Equivalence ``` Added in v1.0.0 -## strict +## record -Return an `Equivalence` that uses strict equality (===) to compare values +Given an `Equivalence` of type `A`, returns a new `Equivalence` of type `{ readonly [x: string]: A }`. +The returned `Equivalence` compares records by first checking their number of keys and then applying the provided `Equivalence` to each value. +If all comparisons return true, the records are considered equal. **Signature** ```ts -export declare const strict: () => Equivalence +export declare const record: (equivalence: Equivalence) => Equivalence ``` Added in v1.0.0 @@ -127,6 +113,20 @@ export declare const tuple: ( Added in v1.0.0 +# constructors + +## strict + +Return an `Equivalence` that uses strict equality (===) to compare values + +**Signature** + +```ts +export declare const strict: () => Equivalence +``` + +Added in v1.0.0 + # instances ## Contravariant @@ -197,7 +197,7 @@ Added in v1.0.0 export declare const getMonoid: () => any ``` -Added in v2.6.0 +Added in v1.0.0 ## getSemigroup @@ -207,7 +207,7 @@ Added in v2.6.0 export declare const getSemigroup: () => any ``` -Added in v2.10.0 +Added in v1.0.0 ## number diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index ef7adee6a..d5e04b983 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -77,7 +77,12 @@ Added in v1.0.0 ## struct -Given a struct of `Monoid`s returns a `Monoid` for the struct. +This function creates and returns a new `Monoid` for a struct of values based on the given `Monoid`s for each property in the struct. +The returned `Monoid` combines two structs of the same type by applying the corresponding `Monoid` passed as arguments to each property in the struct. + +The `empty` value of the returned `Monoid` is a struct where each property is the `empty` value of the corresponding `Monoid` in the input `monoids` object. + +It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. **Signature** diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index b799b8126..cfc4fe6ad 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -97,6 +97,7 @@ Added in v1.0.0 This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. The returned `Semigroup` combines two structs of the same type by applying the corresponding `Semigroup` passed as arguments to each property in the struct. + It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. **Signature** diff --git a/src/Either.ts b/src/Either.ts index cb540d581..660e67bf0 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1103,7 +1103,7 @@ export const exists = (predicate: Predicate) => * while elements that are `Right` are combined using the provided `Semigroup`. * * @category instances - * @since 2.0.0 + * @since 1.0.0 */ export const getOptionalSemigroup = (S: Semigroup): Semigroup> => semigroup.fromCombine(( diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index 5483b02cf..bd97c5852 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -15,6 +15,38 @@ export interface ReadonlyRecord { readonly [x: string]: A } +/** + * Takes an iterable and a projection function, `f`, and returns a record. + * The projection function maps each value of the iterable to a tuple of a key and a value, which is then added to the resulting record. + * + * @param iterable - An iterable of values to be mapped to a record. + * @param f - A projection function that maps values of the iterable to a tuple of a key and a value. + * + * @example + * import { fromIterable } from '@fp-ts/core/ReadonlyRecord' + * + * const input = [1, 2, 3, 4] + * + * assert.deepStrictEqual( + * fromIterable(input, a => [String(a), a * 2]), + * { '1': 2, '2': 4, '3': 6, '4': 8 } + * ) + * + * @category constructors + * @since 1.0.0 + */ +export const fromIterable = ( + iterable: Iterable, + f: (a: A) => readonly [string, B] +): Record => { + const out: Record = {} + for (const a of iterable) { + const [k, b] = f(a) + out[k] = b + } + return out +} + /** * Retrieve a value at a particular key from a `ReadonlyRecord`, returning it wrapped in an `Option`. * @@ -143,3 +175,33 @@ export const mapWithKey = (f: (k: string, a: A) => B) => */ export const map = (f: (a: A) => B): (self: ReadonlyRecord) => Record => mapWithKey((_, a) => f(a)) + +/* + + TODO: + + - size + - isEmpty + - collect + - toArray + - has + - remove + - pop + - empty + - filterMapWithIndex + - filterMap + - filterWithIndex + - filter + - partition + - partitionWithIndex + - partitionMap + - partitionMapWithIndex + - traverseWithKey + - traverse + - sequence + - compact + - separate + - traverseFilterMap + - traversePartitionMap + +*/ diff --git a/src/Struct.ts b/src/Struct.ts index c4294f1c9..bc320799a 100644 --- a/src/Struct.ts +++ b/src/Struct.ts @@ -6,9 +6,7 @@ import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as order from "@fp-ts/core/typeclass/Order" -import * as product_ from "@fp-ts/core/typeclass/Product" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" -import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** * Create a new object by picking properties of an existing object. @@ -43,31 +41,51 @@ export const omit = ]>( } /** + * Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct + * by applying each `Equivalence` to the corresponding property of the struct. + * + * @category combinators * @since 1.0.0 */ export const getEquivalence = equivalence.struct /** + * This function creates and returns a new `Order` for a struct of values based on the given `Order`s + * for each property in the struct. + * + * @category combinators * @since 1.0.0 */ export const getOrder = order.struct /** + * This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. + * The returned `Semigroup` combines two structs of the same type by applying the corresponding `Semigroup` passed as arguments to each property in the struct. + * + * It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. + * + * @category combinators * @since 1.0.0 */ export const getSemigroup = semigroup.struct /** + * This function creates and returns a new `Monoid` for a struct of values based on the given `Monoid`s for each property in the struct. + * The returned `Monoid` combines two structs of the same type by applying the corresponding `Monoid` passed as arguments to each property in the struct. + * + * The `empty` value of the returned `Monoid` is a struct where each property is the `empty` value of the corresponding `Monoid` in the input `monoids` object. + * + * It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. + * + * @category combinators * @since 1.0.0 */ export const getMonoid = monoid.struct -/** - * @since 1.0.0 - */ -export const nonEmptyProduct = semiProduct.nonEmptyStruct +/* -/** - * @since 1.0.0 - */ -export const product = product_.struct + TODO: + + - at + +*/ diff --git a/src/Tuple.ts b/src/Tuple.ts index 53ad2515a..017fc108a 100644 --- a/src/Tuple.ts +++ b/src/Tuple.ts @@ -18,7 +18,7 @@ export const tuple = >(...elements: A): A => elemen * Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple * by applying each `Equivalence` to the corresponding element of the tuple. * - * @category instances + * @category combinators * @since 1.0.0 */ export const getEquivalence = equivalence.tuple @@ -29,7 +29,7 @@ export const getEquivalence = equivalence.tuple * It is useful when you need to compare two tuples of the same type and you have a specific way of comparing each element * of the tuple. * - * @category instances + * @category combinators * @since 1.0.0 */ export const getOrder = order.tuple @@ -40,7 +40,7 @@ export const getOrder = order.tuple * * It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. * - * @category instances + * @category combinators * @since 1.0.0 */ export const getSemigroup = semigroup.tuple @@ -53,7 +53,7 @@ export const getSemigroup = semigroup.tuple * * It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. * - * @category instances + * @category combinators * @since 1.0.0 */ export const getMonoid = monoid.tuple @@ -65,3 +65,17 @@ export const getMonoid = monoid.tuple */ export const appendElement = (that: B) => >(self: A): [...A, B] => [...self, that] + +/* + + TODO: + + - at + - first + - second + - swap + - bimap + - mapLeft + - map + +*/ diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index d99d84066..a75dcbc34 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -73,7 +73,7 @@ export const symbol: Equivalence = strict() * Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple * by applying each `Equivalence` to the corresponding element of the tuple. * - * @category constructors + * @category combinators * @since 1.0.0 */ export const tuple = >( @@ -86,7 +86,7 @@ export const tuple = >( * The returned `Equivalence` compares arrays by first checking their length and then applying the provided `Equivalence` to each element. * If all comparisons return true, the arrays are considered equal. * - * @category constructors + * @category combinators * @since 1.0.0 */ export const array = ( @@ -98,7 +98,7 @@ export const array = ( * Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct * by applying each `Equivalence` to the corresponding property of the struct. * - * @category constructors + * @category combinators * @since 1.0.0 */ export const struct = ( @@ -118,7 +118,7 @@ export const struct = ( * The returned `Equivalence` compares records by first checking their number of keys and then applying the provided `Equivalence` to each value. * If all comparisons return true, the records are considered equal. * - * @category constructors + * @category combinators * @since 1.0.0 */ export const record = ( @@ -139,7 +139,7 @@ export const record = ( /** * @category instances - * @since 2.10.0 + * @since 1.0.0 */ export const getSemigroup = (): Semigroup> => ({ combine: (self, that) => (x, y) => self(x, y) && that(x, y), @@ -161,7 +161,7 @@ const empty: Equivalence = () => true /** * @category instances - * @since 2.6.0 + * @since 1.0.0 */ export const getMonoid = (): Monoid> => monoid.fromSemigroup(getSemigroup(), empty) diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index 071932238..0ac481c29 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -191,7 +191,12 @@ export const array = (): Monoid> => { export const readonlyArray: () => Monoid> = array as any /** - * Given a struct of `Monoid`s returns a `Monoid` for the struct. + * This function creates and returns a new `Monoid` for a struct of values based on the given `Monoid`s for each property in the struct. + * The returned `Monoid` combines two structs of the same type by applying the corresponding `Monoid` passed as arguments to each property in the struct. + * + * The `empty` value of the returned `Monoid` is a struct where each property is the `empty` value of the corresponding `Monoid` in the input `monoids` object. + * + * It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. * * @category combinators * @since 1.0.0 diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index e17c902bb..a0c6217c5 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -206,6 +206,7 @@ export const readonlyArray: () => Semigroup> = array as any /** * This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. * The returned `Semigroup` combines two structs of the same type by applying the corresponding `Semigroup` passed as arguments to each property in the struct. + * * It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. * * @category combinators diff --git a/test/ReadonlyRecord.ts b/test/ReadonlyRecord.ts index bf1072720..dd9a3f277 100644 --- a/test/ReadonlyRecord.ts +++ b/test/ReadonlyRecord.ts @@ -23,11 +23,23 @@ describe.concurrent("ReadonlyRecord", () => { }) it("mapWithKey", () => { - expect(pipe({ a: 1, b: 2 }, RR.mapWithKey((k, n) => `${k}-${n}`))).toEqual, - ({ a: "a-1", b: "b-2" }) + expect(pipe({ a: 1, b: 2 }, RR.mapWithKey((k, n) => `${k}-${n}`))).toEqual({ + a: "a-1", + b: "b-2" + }) }) it("map", () => { - expect(pipe({ a: 1, b: 2 }, RR.map(n => n * 2))).toEqual, ({ a: 2, b: 4 }) + expect(pipe({ a: 1, b: 2 }, RR.map(n => n * 2))).toEqual({ a: 2, b: 4 }) + }) + + it("fromIterable", () => { + const input = [1, 2, 3, 4] + expect(RR.fromIterable(input, a => [String(a), a * 2])).toEqual({ + "1": 2, + "2": 4, + "3": 6, + "4": 8 + }) }) }) diff --git a/test/Struct.ts b/test/Struct.ts index a9526236b..c9e2e7740 100644 --- a/test/Struct.ts +++ b/test/Struct.ts @@ -7,8 +7,6 @@ describe.concurrent("Struct", () => { expect(S.getOrder).exists expect(S.getSemigroup).exists expect(S.getMonoid).exists - expect(S.nonEmptyProduct).exists - expect(S.product).exists }) it("pick", () => { From fb5692208024255899c4230fce28d630f31c8563 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 09:19:16 +0100 Subject: [PATCH 128/255] ReadonlyRecord: apply dual --- docs/modules/Function.ts.md | 4 +- docs/modules/ReadonlyRecord.ts.md | 92 ++++++++++-------- src/ReadonlyRecord.ts | 149 +++++++++++++++++++----------- tsconfig.base.json | 3 +- 4 files changed, 155 insertions(+), 93 deletions(-) diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 182037955..72e391e6e 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -303,7 +303,9 @@ Flips the arguments of a curried function. **Signature** ```ts -export declare const flip: (f: (a: A) => (b: B) => C) => (b: B) => (a: A) => C +export declare const flip: ( + f: (...a: A) => (...b: B) => C +) => (...b: B) => (...a: A) => C ``` **Example** diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md index 600147a9c..ae0cadb5a 100644 --- a/docs/modules/ReadonlyRecord.ts.md +++ b/docs/modules/ReadonlyRecord.ts.md @@ -18,11 +18,12 @@ Added in v1.0.0 - [fromIterable](#fromiterable) - [getters](#getters) - [get](#get) +- [mapping](#mapping) + - [map](#map) + - [mapWithKey](#mapwithkey) - [models](#models) - [ReadonlyRecord (interface)](#readonlyrecord-interface) - [utils](#utils) - - [map](#map) - - [mapWithKey](#mapwithkey) - [modifyOption](#modifyoption) - [replaceOption](#replaceoption) @@ -32,13 +33,16 @@ Added in v1.0.0 ## fromIterable -Takes an iterable and a projection function, `f`, and returns a record. +Takes an iterable and a projection function and returns a record. The projection function maps each value of the iterable to a tuple of a key and a value, which is then added to the resulting record. **Signature** ```ts -export declare const fromIterable: (iterable: Iterable, f: (a: A) => readonly [string, B]) => Record +export declare const fromIterable: { + (self: Iterable, f: (a: A) => readonly [string, B]): Record + (f: (a: A) => readonly [string, B]): (self: Iterable) => Record +} ``` **Example** @@ -65,7 +69,10 @@ Retrieve a value at a particular key from a `ReadonlyRecord`, returning it wrapp **Signature** ```ts -export declare const get: (key: string) => (self: ReadonlyRecord) => any +export declare const get: { + (self: ReadonlyRecord, key: string): any + (key: string): (self: ReadonlyRecord) => any +} ``` **Example** @@ -73,31 +80,16 @@ export declare const get: (key: string) => (self: ReadonlyRecord) => any ```ts import { get } from '@fp-ts/core/ReadonlyRecord' import { some, none } from '@fp-ts/core/Option' -import { pipe } from '@fp-ts/core/Function' const person = { name: 'John Doe', age: 35 } -assert.deepStrictEqual(pipe(person, get('name')), some('John Doe')) -assert.deepStrictEqual(pipe(person, get('email')), none()) +assert.deepStrictEqual(get(person, 'name'), some('John Doe')) +assert.deepStrictEqual(get(person, 'email'), none()) ``` Added in v1.0.0 -# models - -## ReadonlyRecord (interface) - -**Signature** - -```ts -export interface ReadonlyRecord { - readonly [x: string]: A -} -``` - -Added in v1.0.0 - -# utils +# mapping ## map @@ -106,18 +98,20 @@ Maps a `ReadonlyRecord` into another `Record` by applying a transformation funct **Signature** ```ts -export declare const map: (f: (a: A) => B) => (self: ReadonlyRecord) => Record +export declare const map: { + (self: ReadonlyRecord, f: (a: A) => B): Record + (f: (a: A) => B): (self: ReadonlyRecord) => Record +} ``` **Example** ```ts import { map } from '@fp-ts/core/ReadonlyRecord' -import { pipe } from '@fp-ts/core/Function' const f = (n: number) => `-${n}-` -assert.deepStrictEqual(pipe({ a: 3, b: 5 }, map(f)), { a: '-3-', b: '-5-' }) +assert.deepStrictEqual(map({ a: 3, b: 5 }, f), { a: '-3-', b: '-5-' }) ``` Added in v1.0.0 @@ -129,22 +123,40 @@ Maps the values of a `ReadonlyRecord` to a new `Record` by applying a transforma **Signature** ```ts -export declare const mapWithKey: (f: (k: string, a: A) => B) => (self: ReadonlyRecord) => Record +export declare const mapWithKey: { + (self: ReadonlyRecord, f: (k: string, a: A) => B): Record + (f: (k: string, a: A) => B): (self: ReadonlyRecord) => Record +} ``` **Example** ```ts import { mapWithKey } from '@fp-ts/core/ReadonlyRecord' -import { pipe } from '@fp-ts/core/Function' const f = (k: string, n: number) => `${k.toUpperCase()}-${n}` -assert.deepStrictEqual(pipe({ a: 3, b: 5 }, mapWithKey(f)), { a: 'A-3', b: 'B-5' }) +assert.deepStrictEqual(mapWithKey({ a: 3, b: 5 }, f), { a: 'A-3', b: 'B-5' }) ``` Added in v1.0.0 +# models + +## ReadonlyRecord (interface) + +**Signature** + +```ts +export interface ReadonlyRecord { + readonly [x: string]: A +} +``` + +Added in v1.0.0 + +# utils + ## modifyOption Apply a function to the element at the specified key, creating a new record, @@ -153,20 +165,22 @@ or return `None` if the key doesn't exist. **Signature** ```ts -export declare const modifyOption: (key: string, f: (a: A) => B) => (self: ReadonlyRecord) => any +export declare const modifyOption: { + (self: ReadonlyRecord, key: string, f: (a: A) => B): any + (key: string, f: (a: A) => B): (self: ReadonlyRecord) => any +} ``` **Example** ```ts import { modifyOption } from '@fp-ts/core/ReadonlyRecord' -import { pipe } from '@fp-ts/core/Function' import { some, none } from '@fp-ts/core/Option' const f = (x: number) => x * 2 -assert.deepStrictEqual(pipe({ a: 3 }, modifyOption('a', f)), some({ a: 6 })) -assert.deepStrictEqual(pipe({ a: 3 }, modifyOption('b', f)), none()) +assert.deepStrictEqual(modifyOption({ a: 3 }, 'a', f), some({ a: 6 })) +assert.deepStrictEqual(modifyOption({ a: 3 }, 'b', f), none()) ``` Added in v1.0.0 @@ -178,7 +192,10 @@ Replaces a value in the record with the new value passed as parameter. **Signature** ```ts -export declare const replaceOption: (key: string, b: B) => (self: ReadonlyRecord) => any +export declare const replaceOption: { + (self: ReadonlyRecord, key: string, b: B): any + (key: string, b: B): (self: ReadonlyRecord) => any +} ``` **Example** @@ -187,11 +204,8 @@ export declare const replaceOption: (key: string, b: B) => (self: Readonly import { replaceOption } from '@fp-ts/core/ReadonlyRecord' import { some, none } from '@fp-ts/core/Option' -const record = { a: 1, b: 2, c: 3 } -const replaceA = replaceOption('a', 10) - -assert.deepStrictEqual(replaceA(record), some({ a: 10, b: 2, c: 3 })) -assert.deepStrictEqual(replaceA({}), none()) +assert.deepStrictEqual(replaceOption({ a: 1, b: 2, c: 3 }, 'a', 10), some({ a: 10, b: 2, c: 3 })) +assert.deepStrictEqual(replaceOption({}, 'a', 10), none()) ``` Added in v1.0.0 diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index bd97c5852..294cf3911 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -4,6 +4,7 @@ * @since 1.0.0 */ +import { dual } from "@fp-ts/core/Function" import type { Option } from "@fp-ts/core/Option" import * as O from "@fp-ts/core/Option" @@ -16,10 +17,10 @@ export interface ReadonlyRecord { } /** - * Takes an iterable and a projection function, `f`, and returns a record. + * Takes an iterable and a projection function and returns a record. * The projection function maps each value of the iterable to a tuple of a key and a value, which is then added to the resulting record. * - * @param iterable - An iterable of values to be mapped to a record. + * @param self - An iterable of values to be mapped to a record. * @param f - A projection function that maps values of the iterable to a tuple of a key and a value. * * @example @@ -35,93 +36,88 @@ export interface ReadonlyRecord { * @category constructors * @since 1.0.0 */ -export const fromIterable = ( - iterable: Iterable, +export const fromIterable: { + (self: Iterable, f: (a: A) => readonly [string, B]): Record + (f: (a: A) => readonly [string, B]): (self: Iterable) => Record +} = dual< + (self: Iterable, f: (a: A) => readonly [string, B]) => Record, + (f: (a: A) => readonly [string, B]) => (self: Iterable) => Record +>(2, ( + self: Iterable, f: (a: A) => readonly [string, B] ): Record => { const out: Record = {} - for (const a of iterable) { + for (const a of self) { const [k, b] = f(a) out[k] = b } return out -} +}) /** * Retrieve a value at a particular key from a `ReadonlyRecord`, returning it wrapped in an `Option`. * - * @param key - Key to retrieve from `ReadonlyRecord`. * @param self - The `ReadonlyRecord` to retrieve value from. + * @param key - Key to retrieve from `ReadonlyRecord`. * * @example * import { get } from "@fp-ts/core/ReadonlyRecord" * import { some, none } from "@fp-ts/core/Option" - * import { pipe } from "@fp-ts/core/Function" * * const person = { name: "John Doe", age: 35 } * - * assert.deepStrictEqual(pipe(person, get("name")), some("John Doe")) - * assert.deepStrictEqual(pipe(person, get("email")), none()) + * assert.deepStrictEqual(get(person, "name"), some("John Doe")) + * assert.deepStrictEqual(get(person, "email"), none()) * * @category getters * @since 1.0.0 */ -export const get = (key: string) => - (self: ReadonlyRecord): Option => +export const get: { + (self: ReadonlyRecord, key: string): Option + (key: string): (self: ReadonlyRecord) => Option +} = dual< + (self: ReadonlyRecord, key: string) => Option, + (key: string) => (self: ReadonlyRecord) => Option +>( + 2, + (self: ReadonlyRecord, key: string): Option => Object.prototype.hasOwnProperty.call(self, key) ? O.some(self[key]) : O.none() - -/** - * Replaces a value in the record with the new value passed as parameter. - * - * @param key - The key to search for in the record. - * @param b - The new value to replace the existing value with. - * @param self - The `ReadonlyRecord` to be updated. - * - * @example - * import { replaceOption } from "@fp-ts/core/ReadonlyRecord" - * import { some, none } from "@fp-ts/core/Option" - * - * const record = { a: 1, b: 2, c: 3 } - * const replaceA = replaceOption('a', 10) - * - * assert.deepStrictEqual(replaceA(record), some({ a: 10, b: 2, c: 3 })) - * assert.deepStrictEqual(replaceA({}), none()) - * - * @since 1.0.0 - */ -export const replaceOption = ( - key: string, - b: B -): (self: ReadonlyRecord) => Option> => modifyOption(key, () => b) +) /** * Apply a function to the element at the specified key, creating a new record, * or return `None` if the key doesn't exist. * + * @param self - The `ReadonlyRecord` to be updated. * @param key - The key of the element to modify. * @param f - The function to apply to the element. - * @param self - The `ReadonlyRecord` to be updated. * * @example * import { modifyOption } from "@fp-ts/core/ReadonlyRecord" - * import { pipe } from "@fp-ts/core/Function" * import { some, none } from "@fp-ts/core/Option" * * const f = (x: number) => x * 2 * * assert.deepStrictEqual( - * pipe({ a: 3 }, modifyOption('a', f)), + * modifyOption({ a: 3 }, 'a', f), * some({ a: 6 }) * ) * assert.deepStrictEqual( - * pipe({ a: 3 }, modifyOption('b', f)), + * modifyOption({ a: 3 }, 'b', f), * none() * ) * * @since 1.0.0 */ -export const modifyOption = (key: string, f: (a: A) => B) => - (self: ReadonlyRecord): Option> => { +export const modifyOption: { + (self: ReadonlyRecord, key: string, f: (a: A) => B): Option> + (key: string, f: (a: A) => B): (self: ReadonlyRecord) => Option> +} = dual< + (self: ReadonlyRecord, key: string, f: (a: A) => B) => Option>, + (key: string, f: (a: A) => B) => (self: ReadonlyRecord) => Option> +>( + 3, + (self: ReadonlyRecord, key: string, f: (a: A) => B): Option> => { if (!Object.prototype.hasOwnProperty.call(self, key)) { return O.none() } @@ -129,25 +125,64 @@ export const modifyOption = (key: string, f: (a: A) => B) => out[key] = f(self[key]) return O.some(out) } +) + +/** + * Replaces a value in the record with the new value passed as parameter. + * + * @param self - The `ReadonlyRecord` to be updated. + * @param key - The key to search for in the record. + * @param b - The new value to replace the existing value with. + * + * @example + * import { replaceOption } from "@fp-ts/core/ReadonlyRecord" + * import { some, none } from "@fp-ts/core/Option" + * + * assert.deepStrictEqual( + * replaceOption({ a: 1, b: 2, c: 3 }, 'a', 10), + * some({ a: 10, b: 2, c: 3 }) + * ) + * assert.deepStrictEqual(replaceOption({}, 'a', 10), none()) + * + * @since 1.0.0 + */ +export const replaceOption: { + (self: ReadonlyRecord, key: string, b: B): Option> + (key: string, b: B): (self: ReadonlyRecord) => Option> +} = dual< + (self: ReadonlyRecord, key: string, b: B) => Option>, + (key: string, b: B) => (self: ReadonlyRecord) => Option> +>( + 3, + (self: ReadonlyRecord, key: string, b: B): Option> => + modifyOption(self, key, () => b) +) /** * Maps the values of a `ReadonlyRecord` to a new `Record` by applying a transformation function to each of its keys and values. * - * @param f - A transformation function that will be applied to each of the key/values in the `ReadonlyRecord`. * @param self - The `ReadonlyRecord` to be mapped. + * @param f - A transformation function that will be applied to each of the key/values in the `ReadonlyRecord`. * * @example * import { mapWithKey } from "@fp-ts/core/ReadonlyRecord" - * import { pipe } from "@fp-ts/core/Function" * * const f = (k: string, n: number) => `${k.toUpperCase()}-${n}` * - * assert.deepStrictEqual(pipe({ a: 3, b: 5 }, mapWithKey(f)), { a: "A-3", b: "B-5" }) + * assert.deepStrictEqual(mapWithKey({ a: 3, b: 5 }, f), { a: "A-3", b: "B-5" }) * + * @category mapping * @since 1.0.0 */ -export const mapWithKey = (f: (k: string, a: A) => B) => - (self: ReadonlyRecord): Record => { +export const mapWithKey: { + (self: ReadonlyRecord, f: (k: string, a: A) => B): Record + (f: (k: string, a: A) => B): (self: ReadonlyRecord) => Record +} = dual< + (self: ReadonlyRecord, f: (k: string, a: A) => B) => Record, + (f: (k: string, a: A) => B) => (self: ReadonlyRecord) => Record +>( + 2, + (self: ReadonlyRecord, f: (k: string, a: A) => B): Record => { const out: Record = {} for (const k in self) { if (Object.prototype.hasOwnProperty.call(self, k)) { @@ -156,25 +191,35 @@ export const mapWithKey = (f: (k: string, a: A) => B) => } return out } +) /** * Maps a `ReadonlyRecord` into another `Record` by applying a transformation function to each of its values. * - * @param f - A transformation function that will be applied to each of the values in the `ReadonlyRecord`. * @param self - The `ReadonlyRecord` to be mapped. + * @param f - A transformation function that will be applied to each of the values in the `ReadonlyRecord`. * * @example * import { map } from "@fp-ts/core/ReadonlyRecord" - * import { pipe } from "@fp-ts/core/Function" * * const f = (n: number) => `-${n}-` * - * assert.deepStrictEqual(pipe({ a: 3, b: 5 }, map(f)), { a: "-3-", b: "-5-" }) + * assert.deepStrictEqual(map({ a: 3, b: 5 }, f), { a: "-3-", b: "-5-" }) * + * @category mapping * @since 1.0.0 */ -export const map = (f: (a: A) => B): (self: ReadonlyRecord) => Record => - mapWithKey((_, a) => f(a)) +export const map: { + (self: ReadonlyRecord, f: (a: A) => B): Record + (f: (a: A) => B): (self: ReadonlyRecord) => Record +} = dual< + (self: ReadonlyRecord, f: (a: A) => B) => Record, + (f: (a: A) => B) => (self: ReadonlyRecord) => Record +>( + 2, + (self: ReadonlyRecord, f: (a: A) => B): Record => + mapWithKey(self, (_, a) => f(a)) +) /* diff --git a/tsconfig.base.json b/tsconfig.base.json index 2bb5b91ee..cc688e6e5 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -41,7 +41,8 @@ "@fp-ts/core/test/*": ["./test/*"], "@fp-ts/core/examples/*": ["./examples/*"], "@fp-ts/core/*": ["./src/*"] - } + }, + "plugins": [{ "name": "@effect/language-service" }] }, "include": [], "exclude": ["node_modules", "build", "lib"] From 305b7c2c9a709e722035a92c77affd205258b312 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 11:33:51 +0100 Subject: [PATCH 129/255] fix docs --- docs/modules/Bigint.ts.md | 12 +- docs/modules/Boolean.ts.md | 20 +- docs/modules/Either.ts.md | 126 ++++--- docs/modules/Function.ts.md | 4 +- docs/modules/Identity.ts.md | 32 +- docs/modules/Number.ts.md | 26 +- docs/modules/Option.ts.md | 112 +++--- docs/modules/Ordering.ts.md | 10 +- docs/modules/Predicate.ts.md | 18 +- docs/modules/ReadonlyArray.ts.md | 246 ++++++------ docs/modules/ReadonlyRecord.ts.md | 12 +- docs/modules/String.ts.md | 12 +- docs/modules/Struct.ts.md | 16 +- docs/modules/These.ts.md | 351 +++++++++++------- docs/modules/Tuple.ts.md | 16 +- docs/modules/index.ts.md | 88 ++--- docs/modules/typeclass/Applicative.ts.md | 4 +- docs/modules/typeclass/Bicovariant.ts.md | 19 +- docs/modules/typeclass/Bounded.ts.md | 4 +- docs/modules/typeclass/Chainable.ts.md | 20 +- docs/modules/typeclass/Compactable.ts.md | 12 +- docs/modules/typeclass/Contravariant.ts.md | 16 +- docs/modules/typeclass/Coproduct.ts.md | 2 +- docs/modules/typeclass/Covariant.ts.md | 35 +- docs/modules/typeclass/Equivalence.ts.md | 14 +- docs/modules/typeclass/Filterable.ts.md | 34 +- docs/modules/typeclass/FlatMap.ts.md | 18 +- docs/modules/typeclass/Foldable.ts.md | 47 ++- docs/modules/typeclass/Invariant.ts.md | 19 +- docs/modules/typeclass/Monoid.ts.md | 6 +- docs/modules/typeclass/Of.ts.md | 9 +- docs/modules/typeclass/Order.ts.md | 12 +- docs/modules/typeclass/Product.ts.md | 24 +- docs/modules/typeclass/SemiApplicative.ts.md | 37 +- docs/modules/typeclass/SemiCoproduct.ts.md | 4 +- docs/modules/typeclass/SemiProduct.ts.md | 69 +++- docs/modules/typeclass/Semigroup.ts.md | 10 +- docs/modules/typeclass/Traversable.ts.md | 42 ++- .../typeclass/TraversableFilterable.ts.md | 40 +- patches/docs-ts@0.6.10.patch | 23 +- pnpm-lock.yaml | 6 +- 41 files changed, 989 insertions(+), 638 deletions(-) diff --git a/docs/modules/Bigint.ts.md b/docs/modules/Bigint.ts.md index 2bde139ef..c3c444e65 100644 --- a/docs/modules/Bigint.ts.md +++ b/docs/modules/Bigint.ts.md @@ -97,7 +97,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Equivalence: any +export declare const Equivalence: equivalence.Equivalence ``` Added in v1.0.0 @@ -111,7 +111,7 @@ The `empty` value is `1n`. **Signature** ```ts -export declare const MonoidMultiply: any +export declare const MonoidMultiply: monoid.Monoid ``` Added in v1.0.0 @@ -125,7 +125,7 @@ The `empty` value is `0n`. **Signature** ```ts -export declare const MonoidSum: any +export declare const MonoidSum: monoid.Monoid ``` Added in v1.0.0 @@ -135,7 +135,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Order: any +export declare const Order: order.Order ``` Added in v1.0.0 @@ -147,7 +147,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemigroupMultiply: any +export declare const SemigroupMultiply: semigroup.Semigroup ``` Added in v1.0.0 @@ -159,7 +159,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemigroupSum: any +export declare const SemigroupSum: semigroup.Semigroup ``` Added in v1.0.0 diff --git a/docs/modules/Boolean.ts.md b/docs/modules/Boolean.ts.md index e96a52d2c..4f530ab10 100644 --- a/docs/modules/Boolean.ts.md +++ b/docs/modules/Boolean.ts.md @@ -76,7 +76,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const isBoolean: any +export declare const isBoolean: Refinement ``` Added in v1.0.0 @@ -88,7 +88,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Equivalence: any +export declare const Equivalence: equivalence.Equivalence ``` Added in v1.0.0 @@ -102,7 +102,7 @@ The `empty` value is `true`. **Signature** ```ts -export declare const MonoidAll: any +export declare const MonoidAll: monoid.Monoid ``` Added in v1.0.0 @@ -116,7 +116,7 @@ The `empty` value is `false`. **Signature** ```ts -export declare const MonoidAny: any +export declare const MonoidAny: monoid.Monoid ``` Added in v1.0.0 @@ -126,7 +126,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Order: any +export declare const Order: order.Order ``` Added in v1.0.0 @@ -138,7 +138,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemigroupAll: any +export declare const SemigroupAll: semigroup.Semigroup ``` **Example** @@ -160,7 +160,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemigroupAny: any +export declare const SemigroupAny: semigroup.Semigroup ``` **Example** @@ -187,7 +187,7 @@ If `value` is `false`, `onFalse()` is returned, otherwise `onTrue()`. **Signature** ```ts -export declare const match: (onFalse: any, onTrue: any) => (value: boolean) => A | B +export declare const match: (onFalse: LazyArg, onTrue: LazyArg) => (value: boolean) => A | B ``` **Example** @@ -220,7 +220,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const all: any +export declare const all: (collection: Iterable) => boolean ``` Added in v1.0.0 @@ -230,7 +230,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const any: any +export declare const any: (collection: Iterable) => boolean ``` Added in v1.0.0 diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 4470c2adc..f9a15aab0 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -139,9 +139,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const divide: ( - that: Either -) => (self: Either) => Either +export declare const divide: (that: Either) => (self: Either) => Either ``` Added in v1.0.0 @@ -152,8 +150,8 @@ Added in v1.0.0 ```ts export declare const multiply: ( - that: Either -) => (self: Either) => Either + that: Either +) => (self: Either) => Either ``` Added in v1.0.0 @@ -164,8 +162,8 @@ Added in v1.0.0 ```ts export declare const multiplyBigint: ( - that: Either -) => (self: Either) => Either + that: Either +) => (self: Either) => Either ``` Added in v1.0.0 @@ -176,8 +174,8 @@ Added in v1.0.0 ```ts export declare const subtract: ( - that: Either -) => (self: Either) => Either + that: Either +) => (self: Either) => Either ``` Added in v1.0.0 @@ -188,8 +186,8 @@ Added in v1.0.0 ```ts export declare const subtractBigint: ( - that: Either -) => (self: Either) => Either + that: Either +) => (self: Either) => Either ``` Added in v1.0.0 @@ -199,7 +197,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const sum: (that: Either) => (self: Either) => Either +export declare const sum: (that: Either) => (self: Either) => Either ``` Added in v1.0.0 @@ -210,8 +208,8 @@ Added in v1.0.0 ```ts export declare const sumBigint: ( - that: Either -) => (self: Either) => Either + that: Either +) => (self: Either) => Either ``` Added in v1.0.0 @@ -228,7 +226,7 @@ The `empty` value is `right(M.empty)`. **Signature** ```ts -export declare const getFirstLeftMonoid: (M: any) => any +export declare const getFirstLeftMonoid: (M: Monoid) => Monoid> ``` Added in v1.0.0 @@ -248,7 +246,7 @@ are concatenated using the provided `Semigroup`. **Signature** ```ts -export declare const getFirstLeftSemigroup: (S: any) => any +export declare const getFirstLeftSemigroup: (S: Semigroup) => Semigroup> ``` Added in v1.0.0 @@ -267,7 +265,7 @@ Semigroup returning the left-most `Right` value. **Signature** ```ts -export declare const getFirstRightSemigroup: () => any +export declare const getFirstRightSemigroup: () => Semigroup> ``` Added in v1.0.0 @@ -319,7 +317,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromIterable: (onEmpty: any) => (collection: Iterable) => Either +export declare const fromIterable: (onEmpty: LazyArg) => (collection: Iterable) => Either ``` Added in v1.0.0 @@ -332,7 +330,7 @@ the provided default as a `Left`. **Signature** ```ts -export declare const fromNullable: (onNullable: any) => (a: A) => Either> +export declare const fromNullable: (onNullable: LazyArg) => (a: A) => Either> ``` **Example** @@ -353,7 +351,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromOption: (onNone: any) => (self: any) => Either +export declare const fromOption: (onNone: LazyArg) => (self: Option) => Either ``` **Example** @@ -389,7 +387,7 @@ This function ensures that a `Refinement` definition is type-safe. **Signature** ```ts -export declare const toRefinement: (f: (a: A) => Either) => any +export declare const toRefinement: (f: (a: A) => Either) => Refinement ``` Added in v1.0.0 @@ -549,7 +547,7 @@ fails with the specified error. **Signature** ```ts -export declare const orElseFail: (onLeft: any) => (self: Either) => Either +export declare const orElseFail: (onLeft: LazyArg) => (self: Either) => Either ``` Added in v1.0.0 @@ -575,7 +573,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const compact: (onNone: any) => (self: Either) => Either +export declare const compact: (onNone: LazyArg) => (self: Either>) => Either ``` Added in v1.0.0 @@ -586,8 +584,12 @@ Added in v1.0.0 ```ts export declare const filter: { - (refinement: any, onFalse: any): (self: Either) => Either - (predicate: any, onFalse: any): (self: Either) => Either + (refinement: Refinement, onFalse: LazyArg): ( + self: Either + ) => Either + (predicate: Predicate, onFalse: LazyArg): ( + self: Either + ) => Either } ``` @@ -599,8 +601,8 @@ Added in v1.0.0 ```ts export declare const filterMap: ( - f: (a: A) => any, - onNone: any + f: (a: A) => Option, + onNone: LazyArg ) => (self: Either) => Either ``` @@ -615,7 +617,7 @@ Converts a `Either` to an `Option` discarding the Right. **Signature** ```ts -export declare const getLeft: (self: Either) => any +export declare const getLeft: (self: Either) => Option ``` **Example** @@ -637,7 +639,7 @@ Returns the wrapped value if it's a `Right` or a default value if is a `Left`. **Signature** ```ts -export declare const getOrElse: (onLeft: any) => (self: Either) => B | A +export declare const getOrElse: (onLeft: LazyArg) => (self: Either) => B | A ``` **Example** @@ -691,7 +693,7 @@ Converts a `Either` to an `Option` discarding the error. **Signature** ```ts -export declare const getRight: (self: Either) => any +export declare const getRight: (self: Either) => Option ``` **Example** @@ -762,7 +764,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Applicative: any +export declare const Applicative: applicative.Applicative ``` Added in v1.0.0 @@ -772,7 +774,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Bicovariant: any +export declare const Bicovariant: bicovariant.Bicovariant ``` Added in v1.0.0 @@ -782,7 +784,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Chainable: any +export declare const Chainable: chainable.Chainable ``` Added in v1.0.0 @@ -792,7 +794,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Covariant: any +export declare const Covariant: covariant.Covariant ``` Added in v1.0.0 @@ -802,7 +804,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const FlatMap: any +export declare const FlatMap: flatMap_.FlatMap ``` Added in v1.0.0 @@ -812,7 +814,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Foldable: any +export declare const Foldable: foldable.Foldable ``` Added in v1.0.0 @@ -822,7 +824,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Invariant: any +export declare const Invariant: invariant.Invariant ``` Added in v1.0.0 @@ -832,7 +834,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Monad: any +export declare const Monad: monad.Monad ``` Added in v1.0.0 @@ -842,7 +844,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Of: any +export declare const Of: of_.Of ``` Added in v1.0.0 @@ -852,7 +854,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Pointed: any +export declare const Pointed: pointed.Pointed ``` Added in v1.0.0 @@ -862,7 +864,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: any +export declare const Product: product_.Product ``` Added in v1.0.0 @@ -872,7 +874,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiAlternative: any +export declare const SemiAlternative: semiAlternative.SemiAlternative ``` Added in v1.0.0 @@ -882,7 +884,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiApplicative: any +export declare const SemiApplicative: semiApplicative.SemiApplicative ``` Added in v1.0.0 @@ -892,7 +894,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiCoproduct: any +export declare const SemiCoproduct: semiCoproduct.SemiCoproduct ``` Added in v1.0.0 @@ -902,7 +904,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiProduct: any +export declare const SemiProduct: semiProduct.SemiProduct ``` Added in v1.0.0 @@ -912,7 +914,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Traversable: any +export declare const Traversable: traversable.Traversable ``` Added in v1.0.0 @@ -925,7 +927,7 @@ while elements that are `Right` are combined using the provided `Semigroup`. **Signature** ```ts -export declare const getOptionalSemigroup: (S: any) => any +export declare const getOptionalSemigroup: (S: Semigroup) => Semigroup> ``` Added in v1.0.0 @@ -992,7 +994,7 @@ Added in v1.0.0 ```ts export declare const liftOption: ( - f: (...a: A) => any, + f: (...a: A) => Option, onNone: (...a: A) => E ) => (...a: A) => Either ``` @@ -1005,8 +1007,8 @@ Added in v1.0.0 ```ts export declare const liftPredicate: { - (refinement: any, onFalse: (c: C) => E): (c: C) => Either - (predicate: any, onFalse: (b: B) => E): (b: B) => Either + (refinement: Refinement, onFalse: (c: C) => E): (c: C) => Either + (predicate: Predicate, onFalse: (b: B) => E): (b: B) => Either } ``` @@ -1237,7 +1239,7 @@ Added in v1.0.0 ```ts export declare const flatMapOption: ( - f: (a: A) => any, + f: (a: A) => Option, onNone: (a: A) => E2 ) => (self: Either) => Either ``` @@ -1251,7 +1253,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const sequence: (F: any) => (self: Either) => any +export declare const sequence: ( + F: applicative.Applicative +) => (self: Either>) => Kind> ``` Added in v1.0.0 @@ -1261,9 +1265,11 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverse: ( - F: any -) => (f: (a: A) => any) => (self: Either) => any +export declare const traverse: ( + F: applicative.Applicative +) => ( + f: (a: A) => Kind +) => (self: Either) => Kind> ``` Added in v1.0.0 @@ -1273,9 +1279,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverseTap: ( - F: any -) => (f: (a: A) => any) => (self: Either) => any +export declare const traverseTap: ( + F: applicative.Applicative +) => (f: (a: A) => Kind) => (self: Either) => Kind> ``` Added in v1.0.0 @@ -1349,7 +1355,7 @@ Returns a function that checks if an `Either` contains a given value using a pro **Signature** ```ts -export declare const contains: (equivalence: any) => (a: A) => (self: Either) => boolean +export declare const contains: (equivalence: Equivalence) => (a: A) => (self: Either) => boolean ``` Added in v1.0.0 @@ -1361,7 +1367,7 @@ Returns `false` if `Left` or returns the Either of the application of the given **Signature** ```ts -export declare const exists: (predicate: any) => (self: Either) => boolean +export declare const exists: (predicate: Predicate) => (self: Either) => boolean ``` **Example** diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 72e391e6e..3dab46745 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -51,7 +51,7 @@ Unary functions form a monoid as long as you can provide a monoid for the codoma **Signature** ```ts -export declare const getMonoid: (Monoid: any) => () => any +export declare const getMonoid: (Monoid: monoid.Monoid) => () => monoid.Monoid<(a: A) => M> ``` **Example** @@ -84,7 +84,7 @@ Unary functions form a semigroup as long as you can provide a semigroup for the **Signature** ```ts -export declare const getSemigroup: (Semigroup: any) => () => any +export declare const getSemigroup: (Semigroup: semigroup.Semigroup) => () => semigroup.Semigroup<(a: A) => S> ``` **Example** diff --git a/docs/modules/Identity.ts.md b/docs/modules/Identity.ts.md index 3409f8528..7b291c535 100644 --- a/docs/modules/Identity.ts.md +++ b/docs/modules/Identity.ts.md @@ -96,7 +96,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Applicative: any +export declare const Applicative: applicative.Applicative ``` Added in v1.0.0 @@ -106,7 +106,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Chainable: any +export declare const Chainable: chainable.Chainable ``` Added in v1.0.0 @@ -116,7 +116,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Covariant: any +export declare const Covariant: covariant.Covariant ``` Added in v1.0.0 @@ -126,7 +126,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const FlatMap: any +export declare const FlatMap: flatMap_.FlatMap ``` Added in v1.0.0 @@ -136,7 +136,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Foldable: any +export declare const Foldable: foldable.Foldable ``` Added in v1.0.0 @@ -146,7 +146,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Invariant: any +export declare const Invariant: invariant.Invariant ``` Added in v1.0.0 @@ -156,7 +156,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Monad: any +export declare const Monad: monad.Monad ``` Added in v1.0.0 @@ -166,7 +166,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Of: any +export declare const Of: of_.Of ``` Added in v1.0.0 @@ -176,7 +176,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Pointed: any +export declare const Pointed: pointed.Pointed ``` Added in v1.0.0 @@ -186,7 +186,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: any +export declare const Product: product_.Product ``` Added in v1.0.0 @@ -196,7 +196,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiApplicative: any +export declare const SemiApplicative: semiApplicative.SemiApplicative ``` Added in v1.0.0 @@ -206,7 +206,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiProduct: any +export declare const SemiProduct: semiProduct.SemiProduct ``` Added in v1.0.0 @@ -216,7 +216,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Traversable: any +export declare const Traversable: traversable.Traversable ``` Added in v1.0.0 @@ -226,7 +226,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const getSemiAlternative: (S: any) => any +export declare const getSemiAlternative: ( + S: Semigroup +) => semiAlternative.SemiAlternative> ``` Added in v1.0.0 @@ -236,7 +238,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getSemiCoproduct: (S: any) => any +export declare const getSemiCoproduct: (S: Semigroup) => semiCoproduct.SemiCoproduct> ``` Added in v1.0.0 diff --git a/docs/modules/Number.ts.md b/docs/modules/Number.ts.md index d3b7c15b0..5a9f7c5ee 100644 --- a/docs/modules/Number.ts.md +++ b/docs/modules/Number.ts.md @@ -149,7 +149,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const isNumber: any +export declare const isNumber: predicate.Refinement ``` Added in v1.0.0 @@ -161,7 +161,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Bounded: any +export declare const Bounded: bounded.Bounded ``` Added in v1.0.0 @@ -171,7 +171,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Equivalence: any +export declare const Equivalence: equivalence.Equivalence ``` Added in v1.0.0 @@ -181,7 +181,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const MonoidMax: any +export declare const MonoidMax: monoid.Monoid ``` Added in v1.0.0 @@ -191,7 +191,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const MonoidMin: any +export declare const MonoidMin: monoid.Monoid ``` Added in v1.0.0 @@ -205,7 +205,7 @@ The `empty` value is `1`. **Signature** ```ts -export declare const MonoidMultiply: any +export declare const MonoidMultiply: monoid.Monoid ``` Added in v1.0.0 @@ -219,7 +219,7 @@ The `empty` value is `0`. **Signature** ```ts -export declare const MonoidSum: any +export declare const MonoidSum: monoid.Monoid ``` Added in v1.0.0 @@ -229,7 +229,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Order: any +export declare const Order: order.Order ``` Added in v1.0.0 @@ -239,7 +239,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemigroupMax: any +export declare const SemigroupMax: semigroup.Semigroup ``` Added in v1.0.0 @@ -249,7 +249,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemigroupMin: any +export declare const SemigroupMin: semigroup.Semigroup ``` Added in v1.0.0 @@ -261,7 +261,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemigroupMultiply: any +export declare const SemigroupMultiply: semigroup.Semigroup ``` **Example** @@ -282,7 +282,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemigroupSum: any +export declare const SemigroupSum: semigroup.Semigroup ``` **Example** @@ -341,7 +341,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const sign: (n: number) => any +export declare const sign: (n: number) => Ordering ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 16ffabd35..c6c8429c3 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -140,7 +140,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const divide: (that: Option) => (self: Option) => Option +export declare const divide: (that: Option) => (self: Option) => Option ``` Added in v1.0.0 @@ -150,7 +150,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiply: (that: Option) => (self: Option) => Option +export declare const multiply: (that: Option) => (self: Option) => Option ``` Added in v1.0.0 @@ -181,7 +181,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiplyBigint: (that: Option) => (self: Option) => Option +export declare const multiplyBigint: (that: Option) => (self: Option) => Option ``` Added in v1.0.0 @@ -191,7 +191,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtract: (that: Option) => (self: Option) => Option +export declare const subtract: (that: Option) => (self: Option) => Option ``` Added in v1.0.0 @@ -201,7 +201,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtractBigint: (that: Option) => (self: Option) => Option +export declare const subtractBigint: (that: Option) => (self: Option) => Option ``` Added in v1.0.0 @@ -211,7 +211,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const sum: (that: Option) => (self: Option) => Option +export declare const sum: (that: Option) => (self: Option) => Option ``` Added in v1.0.0 @@ -242,7 +242,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const sumBigint: (that: Option) => (self: Option) => Option +export declare const sumBigint: (that: Option) => (self: Option) => Option ``` Added in v1.0.0 @@ -304,7 +304,7 @@ Converts a `Either` to an `Option` discarding the error. **Signature** ```ts -export declare const fromEither: (self: any) => Option +export declare const fromEither: (self: Either) => Option ``` **Example** @@ -349,7 +349,7 @@ Converts an `Option` to an `Either`, allowing you to provide a value to be used **Signature** ```ts -export declare const toEither: (onNone: any) => (self: Option) => any +export declare const toEither: (onNone: LazyArg) => (self: Option) => Either ``` **Example** @@ -374,7 +374,7 @@ This function ensures that a `Refinement` definition is type-safe. **Signature** ```ts -export declare const toRefinement: (f: (a: A) => Option) => any +export declare const toRefinement: (f: (a: A) => Option) => Refinement ``` Added in v1.0.0 @@ -489,7 +489,7 @@ Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` **Signature** ```ts -export declare const getOrElse: (onNone: any) => (self: Option) => B | A +export declare const getOrElse: (onNone: LazyArg) => (self: Option) => B | A ``` **Example** @@ -523,7 +523,7 @@ Returns the provided `Option` `that` if `self` is `None`, otherwise returns `sel **Signature** ```ts -export declare const orElse: (that: any) => (self: Option) => Option +export declare const orElse: (that: LazyArg>) => (self: Option) => Option ``` **Example** @@ -574,7 +574,7 @@ This is useful when it's important to know whether the value was retrieved from **Signature** ```ts -export declare const orElseEither: (that: any) => (self: Option) => Option +export declare const orElseEither: (that: LazyArg>) => (self: Option) => Option> ``` Added in v1.0.0 @@ -591,8 +591,8 @@ If you need to change the type of the `Option` in addition to filtering, see `fi ```ts export declare const filter: { - (refinement: any): (fc: Option) => Option - (predicate: any): (fb: Option) => Option + (refinement: Refinement): (fc: Option) => Option + (predicate: Predicate): (fb: Option) => Option } ``` @@ -617,7 +617,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const separate: (self: Option) => [Option, Option] +export declare const separate: (self: Option>) => [Option, Option] ``` Added in v1.0.0 @@ -695,7 +695,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Alternative: any +export declare const Alternative: alternative.Alternative ``` Added in v1.0.0 @@ -705,7 +705,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Applicative: any +export declare const Applicative: applicative.Applicative ``` Added in v1.0.0 @@ -715,7 +715,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Chainable: any +export declare const Chainable: chainable.Chainable ``` Added in v1.0.0 @@ -725,7 +725,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Compactable: any +export declare const Compactable: compactable.Compactable ``` Added in v1.0.0 @@ -735,7 +735,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Coproduct: any +export declare const Coproduct: coproduct_.Coproduct ``` Added in v1.0.0 @@ -745,7 +745,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Covariant: any +export declare const Covariant: covariant.Covariant ``` Added in v1.0.0 @@ -755,7 +755,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Filterable: any +export declare const Filterable: filterable.Filterable ``` Added in v1.0.0 @@ -765,7 +765,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const FlatMap: any +export declare const FlatMap: flatMap_.FlatMap ``` Added in v1.0.0 @@ -775,7 +775,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Foldable: any +export declare const Foldable: foldable.Foldable ``` Added in v1.0.0 @@ -785,7 +785,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Invariant: any +export declare const Invariant: invariant.Invariant ``` Added in v1.0.0 @@ -795,7 +795,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Monad: any +export declare const Monad: monad.Monad ``` Added in v1.0.0 @@ -805,7 +805,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Of: any +export declare const Of: of_.Of ``` Added in v1.0.0 @@ -815,7 +815,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Pointed: any +export declare const Pointed: pointed.Pointed ``` Added in v1.0.0 @@ -825,7 +825,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: any +export declare const Product: product_.Product ``` Added in v1.0.0 @@ -835,7 +835,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiAlternative: any +export declare const SemiAlternative: semiAlternative.SemiAlternative ``` Added in v1.0.0 @@ -845,7 +845,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiApplicative: any +export declare const SemiApplicative: semiApplicative.SemiApplicative ``` Added in v1.0.0 @@ -855,7 +855,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiCoproduct: any +export declare const SemiCoproduct: semiCoproduct.SemiCoproduct ``` Added in v1.0.0 @@ -865,7 +865,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiProduct: any +export declare const SemiProduct: semiProduct.SemiProduct ``` Added in v1.0.0 @@ -875,7 +875,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Traversable: any +export declare const Traversable: traversable.Traversable ``` Added in v1.0.0 @@ -893,7 +893,7 @@ See also `getFailureSemigroup` if you need a `Semigroup` instead of a `Monoid`. **Signature** ```ts -export declare const getFailureMonoid: (M: any) => any +export declare const getFailureMonoid: (M: Monoid) => Monoid> ``` Added in v1.0.0 @@ -909,7 +909,7 @@ See also `getFailureMonoid` if you need a `Monoid` instead of a `Semigroup`. **Signature** ```ts -export declare const getFailureSemigroup: (S: any) => any +export declare const getFailureSemigroup: (S: Semigroup) => Semigroup> ``` Added in v1.0.0 @@ -921,7 +921,7 @@ Semigroup returning the first `Some` value encountered. **Signature** ```ts -export declare const getFirstSomeSemigroup: () => any +export declare const getFirstSomeSemigroup: () => Semigroup> ``` Added in v1.0.0 @@ -980,7 +980,7 @@ Returns the contained value if the `Option` is `Some`, otherwise throws an error **Signature** ```ts -export declare const getOrThrow: (onNone?: any) => (self: Option) => A +export declare const getOrThrow: (onNone?: LazyArg) => (self: Option) => A ``` **Example** @@ -1053,7 +1053,7 @@ while elements that are `Some` are combined using the provided `Semigroup`. **Signature** ```ts -export declare const getOptionalMonoid: (Semigroup: any) => any +export declare const getOptionalMonoid: (Semigroup: Semigroup) => Monoid> ``` **Example** @@ -1092,7 +1092,9 @@ Lifts an `Either` function to an `Option` function. **Signature** ```ts -export declare const liftEither: (f: (...a: A) => any) => (...a: A) => Option +export declare const liftEither: ( + f: (...a: A) => Either +) => (...a: A) => Option ``` **Example** @@ -1149,8 +1151,8 @@ Returns a _smart constructor_ based on the given predicate. ```ts export declare const liftPredicate: { - (refinement: any): (c: C) => Option - (predicate: any): (b: B) => Option + (refinement: Refinement): (c: C) => Option + (predicate: Predicate): (b: B) => Option } ``` @@ -1264,7 +1266,7 @@ function when passed the `Option`'s value. **Signature** ```ts -export declare const match: (onNone: any, onSome: (a: A) => C) => (self: Option) => B | C +export declare const match: (onNone: LazyArg, onSome: (a: A) => C) => (self: Option) => B | C ``` **Example** @@ -1347,7 +1349,7 @@ Applies a provided function that returns an `Either` to the contents of an `Opti **Signature** ```ts -export declare const flatMapEither: (f: (a: A) => any) => (self: Option) => Option +export declare const flatMapEither: (f: (a: A) => Either) => (self: Option) => Option ``` **Example** @@ -1429,7 +1431,7 @@ the type the `Option` contains. **Signature** ```ts -export declare const liftOrder: (O: any) => any +export declare const liftOrder: (O: Order) => Order> ``` **Example** @@ -1456,7 +1458,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const sequence: (F: any) => (fas: Option) => any +export declare const sequence: ( + F: applicative.Applicative +) => (fas: Option>) => Kind> ``` Added in v1.0.0 @@ -1466,7 +1470,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverse: (F: any) => (f: (a: A) => any) => (self: Option) => any +export declare const traverse: ( + F: applicative.Applicative +) => (f: (a: A) => Kind) => (self: Option) => Kind> ``` Added in v1.0.0 @@ -1476,9 +1482,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverseTap: ( - F: any -) => (f: (a: A) => any) => (self: Option) => any +export declare const traverseTap: ( + F: applicative.Applicative +) => (f: (a: A) => Kind) => (self: Option) => Kind> ``` Added in v1.0.0 @@ -1552,7 +1558,7 @@ Returns a function that checks if an `Option` contains a given value using a pro **Signature** ```ts -export declare const contains: (equivalence: any) => (a: A) => (self: Option) => boolean +export declare const contains: (equivalence: Equivalence) => (a: A) => (self: Option) => boolean ``` **Example** @@ -1576,7 +1582,7 @@ Check if a value in an `Option` type meets a certain predicate. **Signature** ```ts -export declare const exists: (predicate: any) => (self: Option) => boolean +export declare const exists: (predicate: Predicate) => (self: Option) => boolean ``` **Example** diff --git a/docs/modules/Ordering.ts.md b/docs/modules/Ordering.ts.md index e2bb1b904..7bc126fdf 100644 --- a/docs/modules/Ordering.ts.md +++ b/docs/modules/Ordering.ts.md @@ -31,7 +31,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Monoid: any +export declare const Monoid: monoid.Monoid<0 | 1 | -1> ``` Added in v1.0.0 @@ -41,7 +41,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Semigroup: any +export declare const Semigroup: semigroup.Semigroup<0 | 1 | -1> ``` Added in v1.0.0 @@ -66,9 +66,9 @@ Added in v1.0.0 ```ts export declare const match: ( - onLessThan: any, - onEqual: any, - onGreaterThan: any + onLessThan: LazyArg, + onEqual: LazyArg, + onGreaterThan: LazyArg ) => (o: Ordering) => A | B | C ``` diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index 64df37c62..8e31ffbb1 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -141,7 +141,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Contravariant: any +export declare const Contravariant: contravariant.Contravariant ``` Added in v1.0.0 @@ -151,7 +151,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Invariant: any +export declare const Invariant: invariant.Invariant ``` Added in v1.0.0 @@ -161,7 +161,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Of: any +export declare const Of: of_.Of ``` Added in v1.0.0 @@ -171,7 +171,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: any +export declare const Product: product_.Product ``` Added in v1.0.0 @@ -181,7 +181,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiProduct: any +export declare const SemiProduct: semiProduct.SemiProduct ``` Added in v1.0.0 @@ -191,7 +191,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getMonoidAll: () => any +export declare const getMonoidAll: () => monoid.Monoid> ``` Added in v1.0.0 @@ -201,7 +201,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getMonoidAny: () => any +export declare const getMonoidAny: () => monoid.Monoid> ``` Added in v1.0.0 @@ -211,7 +211,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getSemigroupAll: () => any +export declare const getSemigroupAll: () => semigroup.Semigroup> ``` Added in v1.0.0 @@ -221,7 +221,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getSemigroupAny: () => any +export declare const getSemigroupAny: () => semigroup.Semigroup> ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index ddf8d7e70..c2af2e172 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -301,7 +301,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const unfold: (b: B, f: (b: B) => any) => A[] +export declare const unfold: (b: B, f: (b: B) => Option) => A[] ``` Added in v1.0.0 @@ -313,7 +313,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromEither: (self: any) => A[] +export declare const fromEither: (self: Either) => A[] ``` Added in v1.0.0 @@ -343,7 +343,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromOption: (self: any) => A[] +export declare const fromOption: (self: Option) => A[] ``` Added in v1.0.0 @@ -418,7 +418,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const compact: (self: Iterable) => A[] +export declare const compact: (self: Iterable>) => A[] ``` Added in v1.0.0 @@ -429,8 +429,8 @@ Added in v1.0.0 ```ts export declare const filter: { - (refinement: any): (self: readonly C[]) => B[] - (predicate: any): (self: readonly B[]) => B[] + (refinement: Refinement): (self: readonly C[]) => B[] + (predicate: Predicate): (self: readonly B[]) => B[] } ``` @@ -441,7 +441,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const filterMap: (f: (a: A) => any) => (self: Iterable) => B[] +export declare const filterMap: (f: (a: A) => Option) => (self: Iterable) => B[] ``` Added in v1.0.0 @@ -451,7 +451,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const filterMapWithIndex: (f: (a: A, i: number) => any) => (self: Iterable) => B[] +export declare const filterMapWithIndex: (f: (a: A, i: number) => Option) => (self: Iterable) => B[] ``` Added in v1.0.0 @@ -475,8 +475,8 @@ Added in v1.0.0 ```ts export declare const partition: { - (refinement: any): (self: readonly C[]) => [C[], B[]] - (predicate: any): (self: readonly B[]) => [B[], B[]] + (refinement: Refinement): (self: readonly C[]) => [C[], B[]] + (predicate: Predicate): (self: readonly B[]) => [B[], B[]] } ``` @@ -487,7 +487,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const partitionMap: (f: (a: A) => any) => (self: readonly A[]) => [B[], C[]] +export declare const partitionMap: (f: (a: A) => Either) => (self: readonly A[]) => [B[], C[]] ``` Added in v1.0.0 @@ -497,7 +497,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const partitionMapWithIndex: (f: (a: A, i: number) => any) => (self: readonly A[]) => [B[], C[]] +export declare const partitionMapWithIndex: ( + f: (a: A, i: number) => Either +) => (self: readonly A[]) => [B[], C[]] ``` Added in v1.0.0 @@ -520,7 +522,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const separate: (self: readonly any[]) => [A[], B[]] +export declare const separate: (self: readonly Either[]) => [A[], B[]] ``` Added in v1.0.0 @@ -551,9 +553,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverseFilterMap: ( - F: any -) => (f: (a: A) => any) => (ta: readonly A[]) => any +export declare const traverseFilterMap: ( + F: applicative.Applicative +) => (f: (a: A) => Kind>) => (ta: readonly A[]) => Kind ``` Added in v1.0.0 @@ -563,9 +565,11 @@ Added in v1.0.0 **Signature** ```ts -export declare const traversePartitionMap: ( - F: any -) => (f: (a: A) => any) => (self: readonly A[]) => any +export declare const traversePartitionMap: ( + F: applicative.Applicative +) => ( + f: (a: A) => Kind> +) => (self: readonly A[]) => Kind ``` Added in v1.0.0 @@ -577,7 +581,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const foldMap: (M: any) => (f: (a: A) => M) => (self: readonly A[]) => M +export declare const foldMap: (M: Monoid) => (f: (a: A) => M) => (self: readonly A[]) => M ``` Added in v1.0.0 @@ -587,9 +591,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const foldMapKind: ( - F: any -) => (f: (a: A) => any) => (self: readonly A[]) => any +export declare const foldMapKind: ( + F: Coproduct +) => (f: (a: A) => Kind) => (self: readonly A[]) => Kind ``` Added in v1.0.0 @@ -599,7 +603,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const foldMapNonEmpty: (S: any) => (f: (a: A) => S) => (self: readonly [A, ...A[]]) => S +export declare const foldMapNonEmpty: (S: Semigroup) => (f: (a: A) => S) => (self: readonly [A, ...A[]]) => S ``` Added in v1.0.0 @@ -610,7 +614,7 @@ Added in v1.0.0 ```ts export declare const foldMapNonEmptyWithIndex: ( - S: any + S: Semigroup ) => (f: (a: A, i: number) => S) => (self: readonly [A, ...A[]]) => S ``` @@ -621,7 +625,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const foldMapWithIndex: (Monoid: any) => (f: (a: A, i: number) => M) => (self: readonly A[]) => M +export declare const foldMapWithIndex: ( + Monoid: Monoid +) => (f: (a: A, i: number) => M) => (self: readonly A[]) => M ``` Added in v1.0.0 @@ -641,9 +647,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduceKind: ( - F: any -) => (b: B, f: (b: B, a: A) => any) => (self: readonly A[]) => any +export declare const reduceKind: ( + F: monad.Monad +) => (b: B, f: (b: B, a: A) => Kind) => (self: readonly A[]) => Kind ``` Added in v1.0.0 @@ -663,9 +669,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduceRightKind: ( - F: any -) => (b: B, f: (b: B, a: A) => any) => (self: readonly A[]) => any +export declare const reduceRightKind: ( + F: monad.Monad +) => (b: B, f: (b: B, a: A) => Kind) => (self: readonly A[]) => Kind ``` Added in v1.0.0 @@ -812,7 +818,7 @@ Return the first index for which a predicate holds. **Signature** ```ts -export declare const findFirstIndex: (predicate: any) => (self: Iterable) => any +export declare const findFirstIndex: (predicate: Predicate) => (self: Iterable) => Option ``` Added in v1.0.0 @@ -838,7 +844,7 @@ Return the last index for which a predicate holds. **Signature** ```ts -export declare const findLastIndex: (predicate: any) => (self: Iterable) => any +export declare const findLastIndex: (predicate: Predicate) => (self: Iterable) => Option ``` Added in v1.0.0 @@ -850,7 +856,7 @@ This function provides a safe way to read a value at a particular index from a ` **Signature** ```ts -export declare const get: (index: number) => (self: readonly A[]) => any +export declare const get: (index: number) => (self: readonly A[]) => Option ``` Added in v1.0.0 @@ -862,7 +868,7 @@ Get the first element of a `ReadonlyArray`, or `None` if the `ReadonlyArray` is **Signature** ```ts -export declare const head: (self: readonly A[]) => any +export declare const head: (self: readonly A[]) => Option ``` Added in v1.0.0 @@ -884,7 +890,7 @@ Get all but the last element of an `Iterable`, creating a new `Array`, or `None` **Signature** ```ts -export declare const init: (self: Iterable) => any +export declare const init: (self: Iterable) => Option ``` Added in v1.0.0 @@ -908,7 +914,7 @@ Get the last element in a `ReadonlyArray`, or `None` if the `ReadonlyArray` is e **Signature** ```ts -export declare const last: (self: readonly A[]) => any +export declare const last: (self: readonly A[]) => Option ``` Added in v1.0.0 @@ -930,7 +936,7 @@ Return all the `Left` elements from an `Interable` of `Either`s. **Signature** ```ts -export declare const lefts: (self: Iterable) => E[] +export declare const lefts: (self: Iterable>) => E[] ``` Added in v1.0.0 @@ -954,7 +960,7 @@ Return all the `Right` elements from an `Interable` of `Either`s. **Signature** ```ts -export declare const rights: (self: Iterable) => A[] +export declare const rights: (self: Iterable>) => A[] ``` Added in v1.0.0 @@ -990,7 +996,7 @@ Get all but the first element of an `Iterable`, creating a new `Array`, or `None **Signature** ```ts -export declare const tail: (self: Iterable) => any +export declare const tail: (self: Iterable) => Option ``` Added in v1.0.0 @@ -1079,7 +1085,9 @@ Group equal, consecutive elements of a `NonEmptyReadonlyArray` into `NonEmptyArr **Signature** ```ts -export declare const group: (equivalence: any) => (self: readonly [A, ...A[]]) => [[A, ...A[]], ...[A, ...A[]][]] +export declare const group: ( + equivalence: Equivalence +) => (self: readonly [A, ...A[]]) => [[A, ...A[]], ...[A, ...A[]][]] ``` Added in v1.0.0 @@ -1104,7 +1112,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Applicative: any +export declare const Applicative: applicative.Applicative ``` Added in v1.0.0 @@ -1114,7 +1122,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Chainable: any +export declare const Chainable: chainable.Chainable ``` Added in v1.0.0 @@ -1124,7 +1132,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Compactable: any +export declare const Compactable: compactable.Compactable ``` Added in v1.0.0 @@ -1134,7 +1142,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Covariant: any +export declare const Covariant: covariant.Covariant ``` Added in v1.0.0 @@ -1144,7 +1152,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Filterable: any +export declare const Filterable: filterable.Filterable ``` Added in v1.0.0 @@ -1154,7 +1162,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const FlatMap: any +export declare const FlatMap: flatMap_.FlatMap ``` Added in v1.0.0 @@ -1164,7 +1172,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Foldable: any +export declare const Foldable: foldable.Foldable ``` Added in v1.0.0 @@ -1174,7 +1182,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Invariant: any +export declare const Invariant: invariant.Invariant ``` Added in v1.0.0 @@ -1184,7 +1192,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Monad: any +export declare const Monad: monad.Monad ``` Added in v1.0.0 @@ -1194,7 +1202,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Of: any +export declare const Of: of_.Of ``` Added in v1.0.0 @@ -1204,7 +1212,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Pointed: any +export declare const Pointed: pointed.Pointed ``` Added in v1.0.0 @@ -1214,7 +1222,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: any +export declare const Product: product_.Product ``` Added in v1.0.0 @@ -1224,7 +1232,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiApplicative: any +export declare const SemiApplicative: semiApplicative.SemiApplicative ``` Added in v1.0.0 @@ -1234,7 +1242,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiProduct: any +export declare const SemiProduct: semiProduct.SemiProduct ``` Added in v1.0.0 @@ -1244,7 +1252,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Traversable: any +export declare const Traversable: traversable.Traversable ``` Added in v1.0.0 @@ -1254,7 +1262,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const TraversableFilterable: any +export declare const TraversableFilterable: traversableFilterable.TraversableFilterable ``` Added in v1.0.0 @@ -1264,7 +1272,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getIntersectionSemigroup: (equivalence: any) => any +export declare const getIntersectionSemigroup: (equivalence: Equivalence) => Semigroup ``` Added in v1.0.0 @@ -1276,7 +1284,7 @@ Returns a `Monoid` for `ReadonlyArray`. **Signature** ```ts -export declare const getMonoid: () => any +export declare const getMonoid: () => Monoid ``` Added in v1.0.0 @@ -1288,7 +1296,7 @@ Returns a `Semigroup` for `ReadonlyArray`. **Signature** ```ts -export declare const getSemigroup: () => any +export declare const getSemigroup: () => Semigroup ``` Added in v1.0.0 @@ -1298,7 +1306,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getUnionMonoid: (equivalence: any) => any +export declare const getUnionMonoid: (equivalence: Equivalence) => Monoid ``` Added in v1.0.0 @@ -1308,7 +1316,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getUnionSemigroup: (equivalence: any) => any +export declare const getUnionSemigroup: (equivalence: Equivalence) => Semigroup ``` Added in v1.0.0 @@ -1347,7 +1355,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const liftEither: (f: (...a: A) => any) => (...a: A) => B[] +export declare const liftEither: (f: (...a: A) => Either) => (...a: A) => B[] ``` Added in v1.0.0 @@ -1357,7 +1365,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const liftMonoid: (M: any) => any +export declare const liftMonoid: (M: Monoid) => Monoid ``` Added in v1.0.0 @@ -1379,7 +1387,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const liftOption: (f: (...a: A) => any) => (...a: A) => B[] +export declare const liftOption: (f: (...a: A) => Option) => (...a: A) => B[] ``` Added in v1.0.0 @@ -1394,7 +1402,7 @@ It is useful when you need to compare two arrays of the same type and you have a **Signature** ```ts -export declare const liftOrder: (O: any) => any +export declare const liftOrder: (O: order.Order) => order.Order ``` Added in v1.0.0 @@ -1405,8 +1413,8 @@ Added in v1.0.0 ```ts export declare const liftPredicate: { - (refinement: any): (c: C) => B[] - (predicate: any): (b: B) => B[] + (refinement: Refinement): (c: C) => B[] + (predicate: Predicate): (b: B) => B[] } ``` @@ -1417,7 +1425,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const liftSemigroup: (S: any) => any +export declare const liftSemigroup: (S: Semigroup) => Semigroup ``` Added in v1.0.0 @@ -1528,7 +1536,7 @@ Added in v1.0.0 ```ts export declare const match: ( - onEmpty: any, + onEmpty: LazyArg, onNonEmpty: (head: A, tail: A[]) => C ) => (self: readonly A[]) => B | C ``` @@ -1541,7 +1549,7 @@ Added in v1.0.0 ```ts export declare const matchRight: ( - onEmpty: any, + onEmpty: LazyArg, onNonEmpty: (init: A[], last: A) => C ) => (self: readonly A[]) => B | C ``` @@ -1557,7 +1565,7 @@ Returns a function that checks if a `ReadonlyArray` contains a given value using **Signature** ```ts -export declare const contains: (equivalence: any) => (a: A) => (self: Iterable) => boolean +export declare const contains: (equivalence: Equivalence) => (a: A) => (self: Iterable) => boolean ``` Added in v1.0.0 @@ -1593,7 +1601,7 @@ Check if a predicate holds true for any `ReadonlyArray` member. **Signature** ```ts -export declare const some: (predicate: any) => (self: readonly A[]) => self is readonly [A, ...A[]] +export declare const some: (predicate: Predicate) => (self: readonly A[]) => self is readonly [A, ...A[]] ``` Added in v1.0.0 @@ -1687,7 +1695,7 @@ Sort the elements of an `Iterable` in increasing order, creating a new `Array`. **Signature** ```ts -export declare const sort: (O: any) => (self: Iterable) => A[] +export declare const sort: (O: order.Order) => (self: Iterable) => A[] ``` Added in v1.0.0 @@ -1700,7 +1708,7 @@ using first `orders[0]`, then `orders[1]`, etc... **Signature** ```ts -export declare const sortBy: (...orders: readonly any[]) => (self: Iterable) => A[] +export declare const sortBy: (...orders: readonly order.Order[]) => (self: Iterable) => A[] ``` Added in v1.0.0 @@ -1711,7 +1719,7 @@ Added in v1.0.0 ```ts export declare const sortByNonEmpty: ( - ...orders: readonly any[] + ...orders: readonly order.Order[] ) => (as: readonly [A, ...A[]]) => [A, ...A[]] ``` @@ -1724,7 +1732,7 @@ Sort the elements of a `NonEmptyReadonlyArray` in increasing order, creating a n **Signature** ```ts -export declare const sortNonEmpty: (O: any) => (self: readonly [A, ...A[]]) => [A, ...A[]] +export declare const sortNonEmpty: (O: order.Order) => (self: readonly [A, ...A[]]) => [A, ...A[]] ``` Added in v1.0.0 @@ -1736,7 +1744,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const sequence: (F: any) => (self: readonly any[]) => any +export declare const sequence: ( + F: applicative.Applicative +) => (self: readonly Kind[]) => Kind ``` Added in v1.0.0 @@ -1746,7 +1756,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const sequenceNonEmpty: (F: any) => (self: readonly [any, ...any[]]) => any +export declare const sequenceNonEmpty: ( + F: semiApplicative.SemiApplicative +) => (self: readonly [Kind, ...Kind[]]) => Kind ``` Added in v1.0.0 @@ -1756,9 +1768,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverse: ( - F: any -) => (f: (a: A) => any) => (self: readonly A[]) => any +export declare const traverse: ( + F: applicative.Applicative +) => (f: (a: A) => Kind) => (self: readonly A[]) => Kind ``` Added in v1.0.0 @@ -1768,9 +1780,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverseNonEmpty: ( - F: any -) => (f: (a: A) => any) => (self: readonly [A, ...A[]]) => any +export declare const traverseNonEmpty: ( + F: semiApplicative.SemiApplicative +) => (f: (a: A) => Kind) => (self: readonly [A, ...A[]]) => Kind ``` Added in v1.0.0 @@ -1780,9 +1792,11 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverseNonEmptyWithIndex: ( - F: any -) => (f: (a: A, i: number) => any) => (self: readonly [A, ...A[]]) => any +export declare const traverseNonEmptyWithIndex: ( + F: semiApplicative.SemiApplicative +) => ( + f: (a: A, i: number) => Kind +) => (self: readonly [A, ...A[]]) => Kind ``` Added in v1.0.0 @@ -1792,9 +1806,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverseTap: ( - F: any -) => (f: (a: A) => any) => (self: readonly A[]) => any +export declare const traverseTap: ( + F: applicative.Applicative +) => (f: (a: A) => Kind) => (self: readonly A[]) => Kind ``` Added in v1.0.0 @@ -1804,9 +1818,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverseWithIndex: ( - F: any -) => (f: (a: A, i: number) => any) => (self: readonly A[]) => any +export declare const traverseWithIndex: ( + F: applicative.Applicative +) => (f: (a: A, i: number) => Kind) => (self: readonly A[]) => Kind ``` Added in v1.0.0 @@ -1951,7 +1965,7 @@ The order and references of result values are determined by the first `Iterable` **Signature** ```ts -export declare const difference: (equivalence: any) => (that: Iterable) => (self: Iterable) => A[] +export declare const difference: (equivalence: Equivalence) => (that: Iterable) => (self: Iterable) => A[] ``` Added in v1.0.0 @@ -1974,7 +1988,7 @@ or return `None` if the index is out of bounds. **Signature** ```ts -export declare const insertAt: (i: number, b: B) => (self: Iterable) => any +export declare const insertAt: (i: number, b: B) => (self: Iterable) => Option<[B | A, ...(B | A)[]]> ``` Added in v1.0.0 @@ -1987,7 +2001,7 @@ using the specified separator. **Signature** ```ts -export declare const intercalate: (M: any) => (middle: A) => (self: readonly A[]) => A +export declare const intercalate: (M: Monoid) => (middle: A) => (self: readonly A[]) => A ``` Added in v1.0.0 @@ -1999,7 +2013,7 @@ Places an element in between members of a `NonEmptyReadonlyArray`, then folds th **Signature** ```ts -export declare const intercalateNonEmpty: (S: any) => (middle: A) => (self: readonly [A, ...A[]]) => A +export declare const intercalateNonEmpty: (S: Semigroup) => (middle: A) => (self: readonly [A, ...A[]]) => A ``` Added in v1.0.0 @@ -2012,7 +2026,7 @@ The order and references of result values are determined by the first `Iterable` **Signature** ```ts -export declare const intersection: (equivalence: any) => (that: Iterable) => (self: Iterable) => A[] +export declare const intersection: (equivalence: Equivalence) => (that: Iterable) => (self: Iterable) => A[] ``` Added in v1.0.0 @@ -2056,7 +2070,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const max: (O: any) => (self: readonly [A, ...A[]]) => A +export declare const max: (O: order.Order) => (self: readonly [A, ...A[]]) => A ``` Added in v1.0.0 @@ -2066,7 +2080,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const min: (O: any) => (self: readonly [A, ...A[]]) => A +export declare const min: (O: order.Order) => (self: readonly [A, ...A[]]) => A ``` Added in v1.0.0 @@ -2116,7 +2130,7 @@ or return `None` if the index is out of bounds. **Signature** ```ts -export declare const modifyOption: (i: number, f: (a: A) => B) => (self: Iterable) => any +export declare const modifyOption: (i: number, f: (a: A) => B) => (self: Iterable) => Option<(A | B)[]> ``` Added in v1.0.0 @@ -2189,7 +2203,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const replaceOption: (i: number, b: B) => (self: Iterable) => any +export declare const replaceOption: (i: number, b: B) => (self: Iterable) => Option<(B | A)[]> ``` Added in v1.0.0 @@ -2271,9 +2285,11 @@ Filter values inside a context. **Signature** ```ts -export declare const traverseFilter: ( - F: any -) => (predicate: (a: A) => any) => (self: readonly B[]) => any +export declare const traverseFilter: ( + F: applicative.Applicative +) => ( + predicate: (a: A) => Kind +) => (self: readonly B[]) => Kind ``` Added in v1.0.0 @@ -2283,9 +2299,11 @@ Added in v1.0.0 **Signature** ```ts -export declare const traversePartition: ( - F: any -) => (predicate: (a: A) => any) => (self: readonly B[]) => any +export declare const traversePartition: ( + F: applicative.Applicative +) => ( + predicate: (a: A) => Kind +) => (self: readonly B[]) => Kind ``` Added in v1.0.0 @@ -2295,7 +2313,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const union: (equivalence: any) => (that: readonly A[]) => (self: readonly A[]) => A[] +export declare const union: (equivalence: Equivalence) => (that: readonly A[]) => (self: readonly A[]) => A[] ``` Added in v1.0.0 @@ -2305,7 +2323,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const unionNonEmpty: (equivalence: any) => { +export declare const unionNonEmpty: (equivalence: Equivalence) => { (that: readonly [A, ...A[]]): (self: readonly A[]) => [A, ...A[]] (that: readonly A[]): (self: readonly [A, ...A[]]) => [A, ...A[]] } @@ -2320,7 +2338,7 @@ Remove duplicates from am `Iterable`, keeping the first occurrence of an element **Signature** ```ts -export declare const uniq: (equivalence: any) => (self: Iterable) => A[] +export declare const uniq: (equivalence: Equivalence) => (self: Iterable) => A[] ``` Added in v1.0.0 @@ -2332,7 +2350,7 @@ Remove duplicates from a `NonEmptyReadonlyArray`, keeping the first occurrence o **Signature** ```ts -export declare const uniqNonEmpty: (equivalence: any) => (self: readonly [A, ...A[]]) => [A, ...A[]] +export declare const uniqNonEmpty: (equivalence: Equivalence) => (self: readonly [A, ...A[]]) => [A, ...A[]] ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md index ae0cadb5a..6fa7c630f 100644 --- a/docs/modules/ReadonlyRecord.ts.md +++ b/docs/modules/ReadonlyRecord.ts.md @@ -70,8 +70,8 @@ Retrieve a value at a particular key from a `ReadonlyRecord`, returning it wrapp ```ts export declare const get: { - (self: ReadonlyRecord, key: string): any - (key: string): (self: ReadonlyRecord) => any + (self: ReadonlyRecord, key: string): Option + (key: string): (self: ReadonlyRecord) => Option } ``` @@ -166,8 +166,8 @@ or return `None` if the key doesn't exist. ```ts export declare const modifyOption: { - (self: ReadonlyRecord, key: string, f: (a: A) => B): any - (key: string, f: (a: A) => B): (self: ReadonlyRecord) => any + (self: ReadonlyRecord, key: string, f: (a: A) => B): Option> + (key: string, f: (a: A) => B): (self: ReadonlyRecord) => Option> } ``` @@ -193,8 +193,8 @@ Replaces a value in the record with the new value passed as parameter. ```ts export declare const replaceOption: { - (self: ReadonlyRecord, key: string, b: B): any - (key: string, b: B): (self: ReadonlyRecord) => any + (self: ReadonlyRecord, key: string, b: B): Option> + (key: string, b: B): (self: ReadonlyRecord) => Option> } ``` diff --git a/docs/modules/String.ts.md b/docs/modules/String.ts.md index b6fbb9c7b..9d72ddbb4 100644 --- a/docs/modules/String.ts.md +++ b/docs/modules/String.ts.md @@ -52,7 +52,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const isString: any +export declare const isString: Refinement ``` Added in v1.0.0 @@ -64,7 +64,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Equivalence: any +export declare const Equivalence: equivalence.Equivalence ``` Added in v1.0.0 @@ -78,7 +78,7 @@ The `empty` value is `''`. **Signature** ```ts -export declare const Monoid: any +export declare const Monoid: monoid.Monoid ``` Added in v1.0.0 @@ -88,7 +88,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Order: any +export declare const Order: order.Order ``` Added in v1.0.0 @@ -100,7 +100,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Semigroup: any +export declare const Semigroup: semigroup.Semigroup ``` Added in v1.0.0 @@ -265,7 +265,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const split: (separator: string | RegExp) => (s: string) => any +export declare const split: (separator: string | RegExp) => (s: string) => readonly [string, ...string[]] ``` **Example** diff --git a/docs/modules/Struct.ts.md b/docs/modules/Struct.ts.md index 923dcd74d..de0267e42 100644 --- a/docs/modules/Struct.ts.md +++ b/docs/modules/Struct.ts.md @@ -35,7 +35,9 @@ by applying each `Equivalence` to the corresponding property of the struct. **Signature** ```ts -export declare const getEquivalence: any +export declare const getEquivalence: (equivalences: { + [K in keyof A]: equivalence.Equivalence +}) => equivalence.Equivalence<{ readonly [K in keyof A]: A[K] }> ``` Added in v1.0.0 @@ -52,7 +54,9 @@ It is useful when you need to combine two structs of the same type and you have **Signature** ```ts -export declare const getMonoid: any +export declare const getMonoid: (monoids: { readonly [K in keyof A]: monoid.Monoid }) => monoid.Monoid<{ + readonly [K in keyof A]: A[K] +}> ``` Added in v1.0.0 @@ -65,7 +69,9 @@ for each property in the struct. **Signature** ```ts -export declare const getOrder: any +export declare const getOrder: (orders: { readonly [K in keyof A]: order.Order }) => order.Order<{ + readonly [K in keyof A]: A[K] +}> ``` Added in v1.0.0 @@ -80,7 +86,9 @@ It is useful when you need to combine two structs of the same type and you have **Signature** ```ts -export declare const getSemigroup: any +export declare const getSemigroup: (semigroups: { + readonly [K in keyof A]: semigroup.Semigroup +}) => semigroup.Semigroup<{ readonly [K in keyof A]: A[K] }> ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 29ebd8f58..8736fc5aa 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -169,7 +169,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const divide: (that: any) => (self: any) => any +export declare const divide: ( + that: These +) => (self: These) => These ``` Added in v1.0.0 @@ -179,7 +181,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiply: (that: any) => (self: any) => any +export declare const multiply: ( + that: These +) => (self: These) => These ``` Added in v1.0.0 @@ -189,7 +193,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiplyBigint: (that: any) => (self: any) => any +export declare const multiplyBigint: ( + that: These +) => (self: These) => These ``` Added in v1.0.0 @@ -199,7 +205,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtract: (that: any) => (self: any) => any +export declare const subtract: ( + that: These +) => (self: These) => These ``` Added in v1.0.0 @@ -209,7 +217,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtractBigint: (that: any) => (self: any) => any +export declare const subtractBigint: ( + that: These +) => (self: These) => These ``` Added in v1.0.0 @@ -219,7 +229,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const sum: (that: any) => (self: any) => any +export declare const sum: ( + that: These +) => (self: These) => These ``` Added in v1.0.0 @@ -229,7 +241,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const sumBigint: (that: any) => (self: any) => any +export declare const sumBigint: ( + that: These +) => (self: These) => These ``` Added in v1.0.0 @@ -241,7 +255,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getFirstLeftMonoid: (M: any) => any +export declare const getFirstLeftMonoid: (M: Monoid) => Monoid> ``` Added in v1.0.0 @@ -251,7 +265,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getFirstLeftSemigroup: (S: any) => any +export declare const getFirstLeftSemigroup: (S: Semigroup) => Semigroup> ``` Added in v1.0.0 @@ -261,7 +275,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getFirstRightOrBothSemigroup: () => any +export declare const getFirstRightOrBothSemigroup: () => Semigroup> ``` Added in v1.0.0 @@ -273,7 +287,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const both: (left: E, right: A) => any +export declare const both: (left: E, right: A) => These ``` Added in v1.0.0 @@ -283,7 +297,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const fail: (e: E) => any +export declare const fail: (e: E) => These ``` Added in v1.0.0 @@ -293,7 +307,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const left: (left: E) => any +export declare const left: (left: E) => These ``` Added in v1.0.0 @@ -303,7 +317,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const leftOrBoth: (e: any) => (self: any) => any +export declare const leftOrBoth: (e: LazyArg) => (self: O.Option) => These ``` Added in v1.0.0 @@ -315,7 +329,7 @@ Alias of `right`. **Signature** ```ts -export declare const of: (right: A) => any +export declare const of: (right: A) => These ``` Added in v1.0.0 @@ -325,7 +339,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const right: (right: A) => any +export declare const right: (right: A) => These ``` Added in v1.0.0 @@ -335,7 +349,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const rightOrBoth: (a: () => A) => (self: any) => any +export declare const rightOrBoth: (a: () => A) => (self: O.Option) => These ``` Added in v1.0.0 @@ -347,7 +361,7 @@ Alias of `right`. **Signature** ```ts -export declare const succeed: (a: A) => any +export declare const succeed: (a: A) => These ``` Added in v1.0.0 @@ -357,7 +371,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const warn: (e: E, a: A) => any +export declare const warn: (e: E, a: A) => These ``` Added in v1.0.0 @@ -369,7 +383,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const absolve: (self: any) => any +export declare const absolve: (self: These) => Either ``` Added in v1.0.0 @@ -379,7 +393,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const condemn: (self: any) => any +export declare const condemn: (self: These) => Either ``` Added in v1.0.0 @@ -389,7 +403,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromEither: (self: any) => any +export declare const fromEither: (self: Either) => These ``` Added in v1.0.0 @@ -399,7 +413,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromIterable: (onEmpty: any) => (collection: Iterable) => any +export declare const fromIterable: (onEmpty: LazyArg) => (collection: Iterable) => These ``` Added in v1.0.0 @@ -409,7 +423,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromNullable: (onNullable: any) => (a: A) => any +export declare const fromNullable: (onNullable: LazyArg) => (a: A) => These> ``` Added in v1.0.0 @@ -419,7 +433,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromOption: (onNone: any) => (self: any) => any +export declare const fromOption: (onNone: LazyArg) => (self: O.Option) => These ``` Added in v1.0.0 @@ -429,7 +443,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromThese: (self: any) => any +export declare const fromThese: (self: These) => These ``` Added in v1.0.0 @@ -439,7 +453,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromTuple: (self: readonly [E, A]) => any +export declare const fromTuple: (self: readonly [E, A]) => These ``` Added in v1.0.0 @@ -449,7 +463,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const toEither: (onBoth: (e: E, a: A) => any) => (self: any) => any +export declare const toEither: (onBoth: (e: E, a: A) => Either) => (self: These) => Either ``` Added in v1.0.0 @@ -461,7 +475,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const inspectBoth: (onBoth: (e: E, a: A) => void) => (self: any) => any +export declare const inspectBoth: (onBoth: (e: E, a: A) => void) => (self: These) => These ``` Added in v1.0.0 @@ -471,7 +485,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const inspectLeft: (onLeft: (e: E) => void) => (self: any) => any +export declare const inspectLeft: (onLeft: (e: E) => void) => (self: These) => These ``` Added in v1.0.0 @@ -481,7 +495,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const inspectRight: (onRight: (a: A) => void) => (self: any) => any +export declare const inspectRight: (onRight: (a: A) => void) => (self: These) => These ``` Added in v1.0.0 @@ -491,7 +505,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const inspectRightOrBoth: (onRightOrBoth: (a: A) => void) => (self: any) => any +export declare const inspectRightOrBoth: (onRightOrBoth: (a: A) => void) => (self: These) => These ``` Added in v1.0.0 @@ -503,7 +517,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Do: any +export declare const Do: These ``` Added in v1.0.0 @@ -515,8 +529,10 @@ Added in v1.0.0 ```ts export declare const andThenBind: ( name: Exclude, - that: any -) => (self: any) => any + that: These +) => ( + self: These +) => These ``` Added in v1.0.0 @@ -528,8 +544,10 @@ Added in v1.0.0 ```ts export declare const andThenBindEither: ( name: Exclude, - that: any -) => (self: any) => any + that: Either +) => ( + self: These +) => These ``` Added in v1.0.0 @@ -541,8 +559,10 @@ Added in v1.0.0 ```ts export declare const andThenBindThese: ( name: Exclude, - that: any -) => (self: any) => any + that: These +) => ( + self: These +) => These ``` Added in v1.0.0 @@ -554,8 +574,10 @@ Added in v1.0.0 ```ts export declare const bind: ( name: Exclude, - f: (a: A) => any -) => (self: any) => any + f: (a: A) => These +) => ( + self: These +) => These ``` Added in v1.0.0 @@ -567,8 +589,10 @@ Added in v1.0.0 ```ts export declare const bindEither: ( name: Exclude, - f: (a: A) => any -) => (self: any) => any + f: (a: A) => Either +) => ( + self: These +) => These ``` Added in v1.0.0 @@ -580,8 +604,10 @@ Added in v1.0.0 ```ts export declare const bindThese: ( name: Exclude, - f: (a: A) => any -) => (self: any) => any + f: (a: A) => These +) => ( + self: These +) => These ``` Added in v1.0.0 @@ -591,7 +617,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const bindTo: (name: N) => (self: any) => any +export declare const bindTo: (name: N) => (self: These) => These ``` Added in v1.0.0 @@ -604,7 +630,7 @@ Added in v1.0.0 export declare const let: ( name: Exclude, f: (a: A) => B -) => (self: any) => any +) => (self: These) => These ``` Added in v1.0.0 @@ -618,7 +644,9 @@ Recovers from all errors. **Signature** ```ts -export declare const catchAll: (onLeft: (e: E1) => any) => (self: any) => any +export declare const catchAll: ( + onLeft: (e: E1) => These +) => (self: These) => These ``` Added in v1.0.0 @@ -628,7 +656,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const firstRightOrBothOf: (collection: Iterable) => (self: any) => any +export declare const firstRightOrBothOf: (collection: Iterable>) => (self: These) => These ``` Added in v1.0.0 @@ -641,7 +669,7 @@ function. This can be used to lift a "smaller" error into a "larger" error. **Signature** ```ts -export declare const mapLeft: (f: (e: E) => G) => (self: any) => any +export declare const mapLeft: (f: (e: E) => G) => (self: These) => These ``` Added in v1.0.0 @@ -654,7 +682,7 @@ executes the specified effect. **Signature** ```ts -export declare const orElse: (that: any) => (self: any) => any +export declare const orElse: (that: These) => (self: These) => These ``` Added in v1.0.0 @@ -667,7 +695,9 @@ fails, in which case, it will produce the value of the specified effect. **Signature** ```ts -export declare const orElseEither: (that: any) => (self: any) => any +export declare const orElseEither: ( + that: These +) => (self: These) => These> ``` Added in v1.0.0 @@ -680,7 +710,7 @@ fails with the specified error. **Signature** ```ts -export declare const orElseFail: (onLeft: any) => (self: any) => any +export declare const orElseFail: (onLeft: LazyArg) => (self: These) => These ``` Added in v1.0.0 @@ -692,7 +722,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const compact: (onNone: any) => (self: any) => any +export declare const compact: (onNone: LazyArg) => (self: These>) => These ``` Added in v1.0.0 @@ -703,8 +733,10 @@ Added in v1.0.0 ```ts export declare const filter: { - (refinement: any, onFalse: any): (self: any) => any - (predicate: any, onFalse: any): (self: any) => any + (refinement: Refinement, onFalse: LazyArg): ( + self: These + ) => These + (predicate: Predicate, onFalse: LazyArg): (self: These) => These } ``` @@ -715,7 +747,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const filterMap: (f: (a: A) => any, onNone: any) => (self: any) => any +export declare const filterMap: ( + f: (a: A) => O.Option, + onNone: LazyArg +) => (self: These) => These ``` Added in v1.0.0 @@ -727,7 +762,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getBoth: (self: any) => any +export declare const getBoth: (self: These) => O.Option ``` Added in v1.0.0 @@ -737,7 +772,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getBothOrElse: (e: any, a: any) => (self: any) => readonly [E, A] +export declare const getBothOrElse: (e: LazyArg, a: LazyArg) => (self: These) => readonly [E, A] ``` Added in v1.0.0 @@ -747,7 +782,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getLeft: (self: any) => any +export declare const getLeft: (self: These) => O.Option ``` Added in v1.0.0 @@ -759,7 +794,7 @@ Returns the `E` value if and only if the value is constructed with `Left` **Signature** ```ts -export declare const getLeftOnly: (self: any) => any +export declare const getLeftOnly: (self: These) => O.Option ``` Added in v1.0.0 @@ -769,7 +804,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getOrElse: (onLeft: any) => (self: any) => B | A +export declare const getOrElse: (onLeft: LazyArg) => (self: These) => B | A ``` Added in v1.0.0 @@ -779,7 +814,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getOrNull: (self: any) => A | null +export declare const getOrNull: (self: These) => A | null ``` Added in v1.0.0 @@ -789,7 +824,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getOrUndefined: (self: any) => A | undefined +export declare const getOrUndefined: (self: These) => A | undefined ``` Added in v1.0.0 @@ -799,7 +834,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getRight: (self: any) => any +export declare const getRight: (self: These) => O.Option ``` Added in v1.0.0 @@ -811,7 +846,7 @@ Returns the `A` value if and only if the value is constructed with `Right` **Signature** ```ts -export declare const getRightOnly: (self: any) => any +export declare const getRightOnly: (self: These) => O.Option ``` Added in v1.0.0 @@ -825,7 +860,7 @@ Returns `true` if the these is an instance of `Both`, `false` otherwise **Signature** ```ts -export declare const isBoth: (self: any) => self is Both +export declare const isBoth: (self: These) => self is Both ``` Added in v1.0.0 @@ -837,7 +872,7 @@ Returns `true` if the these is an instance of `Left`, `false` otherwise **Signature** ```ts -export declare const isLeft: (self: any) => self is any +export declare const isLeft: (self: These) => self is Left ``` Added in v1.0.0 @@ -847,7 +882,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const isLeftOrBoth: (self: any) => self is any +export declare const isLeftOrBoth: (self: These) => self is Left | Both ``` Added in v1.0.0 @@ -859,7 +894,7 @@ Returns `true` if the these is an instance of `Right`, `false` otherwise **Signature** ```ts -export declare const isRight: (self: any) => self is any +export declare const isRight: (self: These) => self is Right ``` Added in v1.0.0 @@ -869,7 +904,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const isRightOrBoth: (self: any) => self is any +export declare const isRightOrBoth: (self: These) => self is Right | Both ``` Added in v1.0.0 @@ -882,7 +917,7 @@ otherwise. **Signature** ```ts -export declare const isThese: (u: unknown) => u is any +export declare const isThese: (u: unknown) => u is These ``` Added in v1.0.0 @@ -894,7 +929,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Applicative: any +export declare const Applicative: applicative.Applicative ``` Added in v1.0.0 @@ -904,7 +939,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Bicovariant: any +export declare const Bicovariant: bicovariant.Bicovariant ``` Added in v1.0.0 @@ -914,7 +949,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Chainable: any +export declare const Chainable: chainable.Chainable ``` Added in v1.0.0 @@ -924,7 +959,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Covariant: any +export declare const Covariant: covariant.Covariant ``` Added in v1.0.0 @@ -934,7 +969,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const FlatMap: any +export declare const FlatMap: flatMap_.FlatMap ``` Added in v1.0.0 @@ -944,7 +979,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Foldable: any +export declare const Foldable: foldable.Foldable ``` Added in v1.0.0 @@ -954,7 +989,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Invariant: any +export declare const Invariant: invariant.Invariant ``` Added in v1.0.0 @@ -964,7 +999,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Monad: any +export declare const Monad: monad.Monad ``` Added in v1.0.0 @@ -974,7 +1009,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Of: any +export declare const Of: of_.Of ``` Added in v1.0.0 @@ -984,7 +1019,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Pointed: any +export declare const Pointed: pointed.Pointed ``` Added in v1.0.0 @@ -994,7 +1029,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: any +export declare const Product: product_.Product ``` Added in v1.0.0 @@ -1004,7 +1039,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiAlternative: any +export declare const SemiAlternative: semiAlternative.SemiAlternative ``` Added in v1.0.0 @@ -1014,7 +1049,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiApplicative: any +export declare const SemiApplicative: semiApplicative.SemiApplicative ``` Added in v1.0.0 @@ -1024,7 +1059,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiCoproduct: any +export declare const SemiCoproduct: semiCoproduct.SemiCoproduct ``` Added in v1.0.0 @@ -1034,7 +1069,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiProduct: any +export declare const SemiProduct: semiProduct.SemiProduct ``` Added in v1.0.0 @@ -1044,7 +1079,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Traversable: any +export declare const Traversable: traversable.Traversable ``` Added in v1.0.0 @@ -1058,7 +1093,7 @@ Constructs a new `These` from a function that might throw. **Signature** ```ts -export declare const fromThrowable: (f: () => A, onThrow: (error: unknown) => E) => any +export declare const fromThrowable: (f: () => A, onThrow: (error: unknown) => E) => These ``` Added in v1.0.0 @@ -1068,7 +1103,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getOrThrow: (onLeft?: (e: E) => Error) => (self: any) => A +export declare const getOrThrow: (onLeft?: (e: E) => Error) => (self: These) => A ``` Added in v1.0.0 @@ -1078,7 +1113,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getRightOnlyOrThrow: (onLeft: (e: E) => unknown) => (self: any) => A +export declare const getRightOnlyOrThrow: (onLeft: (e: E) => unknown) => (self: These) => A ``` Added in v1.0.0 @@ -1093,7 +1128,7 @@ Lifts a function that may throw to one returning a `These`. export declare const liftThrowable: ( f: (...a: A) => B, onThrow: (error: unknown) => E -) => (...a: A) => any +) => (...a: A) => These ``` Added in v1.0.0 @@ -1105,7 +1140,11 @@ Added in v1.0.0 **Signature** ```ts -export declare const lift2: (f: (a: A) => (b: B) => C) => (that: any) => (self: any) => any +export declare const lift2: ( + f: (a: A) => (b: B) => C +) => ( + that: These +) => (self: These) => These ``` Added in v1.0.0 @@ -1115,7 +1154,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const liftEither: (f: (...a: A) => any) => (...a: A) => any +export declare const liftEither: ( + f: (...a: A) => Either +) => (...a: A) => These ``` Added in v1.0.0 @@ -1128,7 +1169,7 @@ Added in v1.0.0 export declare const liftNullable: ( f: (...a: A) => B | null | undefined, onNullable: (...a: A) => E -) => (...a: A) => any +) => (...a: A) => These> ``` Added in v1.0.0 @@ -1139,9 +1180,9 @@ Added in v1.0.0 ```ts export declare const liftOption: ( - f: (...a: A) => any, + f: (...a: A) => O.Option, onNone: (...a: A) => E -) => (...a: A) => any +) => (...a: A) => These ``` Added in v1.0.0 @@ -1152,8 +1193,8 @@ Added in v1.0.0 ```ts export declare const liftPredicate: { - (refinement: any, onFalse: (c: C) => E): (c: C) => any - (predicate: any, onFalse: (b: B) => E): (b: B) => any + (refinement: Refinement, onFalse: (c: C) => E): (c: C) => These + (predicate: Predicate, onFalse: (b: B) => E): (b: B) => These } ``` @@ -1164,7 +1205,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const liftThese: (f: (...a: A) => any) => (...a: A) => any +export declare const liftThese: ( + f: (...a: A) => These +) => (...a: A) => These ``` Added in v1.0.0 @@ -1178,7 +1221,7 @@ Maps the right value of this effect to the specified constant value. **Signature** ```ts -export declare const as: (b: B) => (self: any) => any +export declare const as: (b: B) => (self: These) => These ``` Added in v1.0.0 @@ -1190,7 +1233,7 @@ Returns the effect resulting from mapping the right of this effect to unit. **Signature** ```ts -export declare const asUnit: (self: any) => any +export declare const asUnit: (self: These) => These ``` Added in v1.0.0 @@ -1203,7 +1246,7 @@ the specified pair of functions, `f` and `g`. **Signature** ```ts -export declare const bimap: (f: (e: E) => G, g: (a: A) => B) => (self: any) => any +export declare const bimap: (f: (e: E) => G, g: (a: A) => B) => (self: These) => These ``` Added in v1.0.0 @@ -1213,7 +1256,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const flap: (self: any) => (a: A) => any +export declare const flap: (self: These B>) => (a: A) => These ``` Added in v1.0.0 @@ -1225,7 +1268,7 @@ Returns an effect whose right is mapped by the specified `f` function. **Signature** ```ts -export declare const map: (f: (a: A) => B) => (self: any) => any +export declare const map: (f: (a: A) => B) => (self: These) => These ``` Added in v1.0.0 @@ -1235,7 +1278,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const tupled: (self: any) => any +export declare const tupled: (self: These) => These ``` Added in v1.0.0 @@ -1287,7 +1330,7 @@ export declare const match: ( onLeft: (e: E) => B, onRight: (a: A) => C, onBoth: (e: E, a: A) => D -) => (self: any) => B | C | D +) => (self: These) => B | C | D ``` Added in v1.0.0 @@ -1299,7 +1342,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const exists: (predicate: any) => (self: any) => boolean +export declare const exists: (predicate: Predicate) => (self: These) => boolean ``` Added in v1.0.0 @@ -1311,7 +1354,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const zipWith: (fb: any, f: (a: A, b: B) => C) => (fa: any) => any +export declare const zipWith: ( + fb: These, + f: (a: A, b: B) => C +) => (fa: These) => These ``` Added in v1.0.0 @@ -1326,7 +1372,9 @@ produced by the effect. **Signature** ```ts -export declare const andThenDiscard: (that: any) => (self: any) => any +export declare const andThenDiscard: ( + that: These +) => (self: These) => These ``` Added in v1.0.0 @@ -1336,7 +1384,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMap: (f: (a: A) => any) => (self: any) => any +export declare const flatMap: ( + f: (a: A) => These +) => (self: These) => These ``` Added in v1.0.0 @@ -1346,7 +1396,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapEither: (f: (a: A) => any) => (self: any) => any +export declare const flatMapEither: ( + f: (a: A) => Either +) => (self: These) => These ``` Added in v1.0.0 @@ -1359,7 +1411,7 @@ Added in v1.0.0 export declare const flatMapNullable: ( f: (a: A) => B | null | undefined, onNullable: (a: A) => E2 -) => (self: any) => any +) => (self: These) => These> ``` Added in v1.0.0 @@ -1369,7 +1421,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapOption: (f: (a: A) => any, onNone: (a: A) => E2) => (self: any) => any +export declare const flatMapOption: ( + f: (a: A) => O.Option, + onNone: (a: A) => E2 +) => (self: These) => These ``` Added in v1.0.0 @@ -1379,7 +1434,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapThese: (f: (a: A) => any) => (self: any) => any +export declare const flatMapThese: ( + f: (a: A) => These +) => (self: These) => These ``` Added in v1.0.0 @@ -1391,7 +1448,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const sequence: (F: any) => (self: any) => any +export declare const sequence: ( + F: applicative.Applicative +) => (self: These>) => Kind> ``` Added in v1.0.0 @@ -1401,7 +1460,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverse: (F: any) => (f: (a: A) => any) => (self: any) => any +export declare const traverse: ( + F: applicative.Applicative +) => (f: (a: A) => Kind) => (self: These) => Kind> ``` Added in v1.0.0 @@ -1411,7 +1472,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverseTap: (F: any) => (f: (a: A) => any) => (self: any) => any +export declare const traverseTap: ( + F: applicative.Applicative +) => (f: (a: A) => Kind) => (self: These) => Kind> ``` Added in v1.0.0 @@ -1449,7 +1512,9 @@ Added in v3.0.0 **Signature** ```ts -export declare const andThen: (that: any) => (self: any) => any +export declare const andThen: ( + that: These +) => (self: These) => These ``` Added in v1.0.0 @@ -1459,7 +1524,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const ap: (fa: any) => (self: any) => any +export declare const ap: ( + fa: These +) => (self: These B>) => These ``` Added in v1.0.0 @@ -1471,7 +1538,11 @@ Appends an element to the end of a tuple. **Signature** ```ts -export declare const appendElement: (that: any) => (self: any) => any +export declare const appendElement: ( + that: These +) => ( + self: These +) => These ``` Added in v1.0.0 @@ -1481,7 +1552,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const composeKleisliArrow: (bfc: (b: B) => any) => (afb: (a: A) => any) => (a: A) => any +export declare const composeKleisliArrow: ( + bfc: (b: B) => These +) => (afb: (a: A) => These) => (a: A) => These ``` Added in v1.0.0 @@ -1493,7 +1566,7 @@ Returns a function that checks if a `These` contains a given value using a provi **Signature** ```ts -export declare const contains: (equivalence: any) => (a: A) => (self: any) => boolean +export declare const contains: (equivalence: Equivalence) => (a: A) => (self: These) => boolean ``` Added in v1.0.0 @@ -1503,7 +1576,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatten: (self: any) => any +export declare const flatten: ( + self: These> +) => These ``` Added in v1.0.0 @@ -1513,7 +1588,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const reverse: (self: any) => any +export declare const reverse: (self: These) => These ``` Added in v1.0.0 @@ -1523,7 +1598,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const struct: >(r: R) => any +export declare const struct: >>( + r: R +) => These< + readonly [ + [R[keyof R]] extends [These] ? E : never, + ...([R[keyof R]] extends [These] ? E : never)[] + ], + { [K in keyof R]: [R[K]] extends [These] ? A : never } +> ``` Added in v1.0.0 @@ -1535,7 +1618,9 @@ Returns an effect that effectfully "peeks" at the success of this effect. **Signature** ```ts -export declare const tap: (f: (a: A) => any) => (self: any) => any +export declare const tap: ( + f: (a: A) => These +) => (self: These) => These ``` Added in v1.0.0 @@ -1545,7 +1630,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const tuple: (...tuple: T) => any +export declare const tuple: []>( + ...tuple: T +) => These< + readonly [ + [T[number]] extends [These] ? E : never, + ...([T[number]] extends [These] ? E : never)[] + ], + { [I in keyof T]: [T[I]] extends [These] ? A : never } +> ``` Added in v1.0.0 @@ -1555,7 +1648,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const unit: any +export declare const unit: These ``` Added in v1.0.0 diff --git a/docs/modules/Tuple.ts.md b/docs/modules/Tuple.ts.md index a144803f3..a592b416a 100644 --- a/docs/modules/Tuple.ts.md +++ b/docs/modules/Tuple.ts.md @@ -36,7 +36,9 @@ by applying each `Equivalence` to the corresponding element of the tuple. **Signature** ```ts -export declare const getEquivalence: any +export declare const getEquivalence: ( + ...equivalences: { readonly [K in keyof A]: equivalence.Equivalence } +) => equivalence.Equivalence> ``` Added in v1.0.0 @@ -53,7 +55,9 @@ It is useful when you need to combine two tuples of the same type and you have a **Signature** ```ts -export declare const getMonoid: any +export declare const getMonoid: ( + ...monoids: { [K in keyof A]: monoid.Monoid } +) => monoid.Monoid ``` Added in v1.0.0 @@ -68,7 +72,9 @@ of the tuple. **Signature** ```ts -export declare const getOrder: any +export declare const getOrder: ( + ...orders: { readonly [K in keyof A]: order.Order } +) => order.Order> ``` Added in v1.0.0 @@ -83,7 +89,9 @@ It is useful when you need to combine two tuples of the same type and you have a **Signature** ```ts -export declare const getSemigroup: any +export declare const getSemigroup: ( + ...semigroups: { readonly [K in keyof A]: semigroup.Semigroup } +) => semigroup.Semigroup ``` Added in v1.0.0 diff --git a/docs/modules/index.ts.md b/docs/modules/index.ts.md index 63dbcd40a..83422b0af 100644 --- a/docs/modules/index.ts.md +++ b/docs/modules/index.ts.md @@ -68,7 +68,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const alternative: any +export declare const alternative: typeof alternative ``` Added in v1.0.0 @@ -78,7 +78,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const applicative: any +export declare const applicative: typeof applicative ``` Added in v1.0.0 @@ -88,7 +88,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const bicovariant: any +export declare const bicovariant: typeof bicovariant ``` Added in v1.0.0 @@ -98,7 +98,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const bounded: any +export declare const bounded: typeof bounded ``` Added in v1.0.0 @@ -108,7 +108,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const chainable: any +export declare const chainable: typeof chainable ``` Added in v1.0.0 @@ -118,7 +118,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const compactable: any +export declare const compactable: typeof compactable ``` Added in v1.0.0 @@ -128,7 +128,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const contravariant: any +export declare const contravariant: typeof contravariant ``` Added in v1.0.0 @@ -138,7 +138,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const coproduct: any +export declare const coproduct: typeof coproduct ``` Added in v1.0.0 @@ -148,7 +148,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const covariant: any +export declare const covariant: typeof covariant ``` Added in v1.0.0 @@ -158,7 +158,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const equivalence: any +export declare const equivalence: typeof equivalence ``` Added in v1.0.0 @@ -168,7 +168,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const filterable: any +export declare const filterable: typeof filterable ``` Added in v1.0.0 @@ -178,7 +178,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMap: any +export declare const flatMap: typeof flatMap ``` Added in v1.0.0 @@ -188,7 +188,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const foldable: any +export declare const foldable: typeof foldable ``` Added in v1.0.0 @@ -198,7 +198,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const invariant: any +export declare const invariant: typeof invariant ``` Added in v1.0.0 @@ -208,7 +208,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const monad: any +export declare const monad: typeof monad ``` Added in v1.0.0 @@ -218,7 +218,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const monoid: any +export declare const monoid: typeof monoid ``` Added in v1.0.0 @@ -228,7 +228,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const of: any +export declare const of: typeof of ``` Added in v1.0.0 @@ -238,7 +238,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const order: any +export declare const order: typeof order ``` Added in v1.0.0 @@ -248,7 +248,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const pointed: any +export declare const pointed: typeof pointed ``` Added in v1.0.0 @@ -258,7 +258,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const product: any +export declare const product: typeof product ``` Added in v1.0.0 @@ -268,7 +268,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const semiAlternative: any +export declare const semiAlternative: typeof semiAlternative ``` Added in v1.0.0 @@ -278,7 +278,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const semiApplicative: any +export declare const semiApplicative: typeof semiApplicative ``` Added in v1.0.0 @@ -288,7 +288,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const semiCoproduct: any +export declare const semiCoproduct: typeof semiCoproduct ``` Added in v1.0.0 @@ -298,7 +298,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const semiProduct: any +export declare const semiProduct: typeof semiProduct ``` Added in v1.0.0 @@ -308,7 +308,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const semigroup: any +export declare const semigroup: typeof semigroup ``` Added in v1.0.0 @@ -318,7 +318,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const traversable: any +export declare const traversable: typeof traversable ``` Added in v1.0.0 @@ -328,7 +328,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const traversableFilterable: any +export declare const traversableFilterable: typeof traversableFilterable ``` Added in v1.0.0 @@ -340,7 +340,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const bigint: any +export declare const bigint: typeof bigint ``` Added in v1.0.0 @@ -350,7 +350,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const boolean: any +export declare const boolean: typeof boolean ``` Added in v1.0.0 @@ -360,7 +360,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const either: any +export declare const either: typeof either ``` Added in v1.0.0 @@ -370,7 +370,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const function: any +export declare const function: typeof _function ``` Added in v1.0.0 @@ -380,7 +380,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const hkt: any +export declare const hkt: typeof hkt ``` Added in v1.0.0 @@ -390,7 +390,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const identity: any +export declare const identity: typeof identity ``` Added in v1.0.0 @@ -400,7 +400,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const number: any +export declare const number: typeof number ``` Added in v1.0.0 @@ -410,7 +410,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const option: any +export declare const option: typeof option ``` Added in v1.0.0 @@ -420,7 +420,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const ordering: any +export declare const ordering: typeof ordering ``` Added in v1.0.0 @@ -430,7 +430,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const predicate: any +export declare const predicate: typeof predicate ``` Added in v1.0.0 @@ -440,7 +440,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const readonlyArray: any +export declare const readonlyArray: typeof readonlyArray ``` Added in v1.0.0 @@ -450,7 +450,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const readonlyRecord: any +export declare const readonlyRecord: typeof readonlyRecord ``` Added in v1.0.0 @@ -460,7 +460,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const string: any +export declare const string: typeof string ``` Added in v1.0.0 @@ -470,7 +470,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const struct: any +export declare const struct: typeof struct ``` Added in v1.0.0 @@ -480,7 +480,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const symbol: any +export declare const symbol: typeof symbol ``` Added in v1.0.0 @@ -490,7 +490,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const these: any +export declare const these: typeof these ``` Added in v1.0.0 @@ -500,7 +500,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const tuple: any +export declare const tuple: typeof tuple ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Applicative.ts.md b/docs/modules/typeclass/Applicative.ts.md index 4dbabc5d0..7dca794b4 100644 --- a/docs/modules/typeclass/Applicative.ts.md +++ b/docs/modules/typeclass/Applicative.ts.md @@ -40,7 +40,9 @@ Lift a monoid into 'F', the inner values are combined using the provided `Monoid **Signature** ```ts -export declare const liftMonoid: (F: Applicative) => (M: any) => any +export declare const liftMonoid: ( + F: Applicative +) => (M: Monoid) => Monoid> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Bicovariant.ts.md b/docs/modules/typeclass/Bicovariant.ts.md index d28425526..d0b8bb4e2 100644 --- a/docs/modules/typeclass/Bicovariant.ts.md +++ b/docs/modules/typeclass/Bicovariant.ts.md @@ -47,10 +47,15 @@ Returns a default `bimap` composition. **Signature** ```ts -export declare const bimapComposition: ( - CovariantF: any, +export declare const bimapComposition: ( + CovariantF: Covariant, BicovariantG: Bicovariant -) => (f: (e: E1) => E2, g: (a: A) => B) => (self: any) => any +) => ( + f: (e: E1) => E2, + g: (a: A) => B +) => ( + self: Kind> +) => Kind> ``` Added in v1.0.0 @@ -62,7 +67,9 @@ Returns a default `map` implementation. **Signature** ```ts -export declare const map: (F: Bicovariant) => any +export declare const map: ( + F: Bicovariant +) => (f: (a: A) => B) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -72,9 +79,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const mapLeft: ( +export declare const mapLeft: ( F: Bicovariant -) => (f: (e: E1) => E2) => (self: any) => any +) => (f: (e: E1) => E2) => (self: Kind) => Kind ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Bounded.ts.md b/docs/modules/typeclass/Bounded.ts.md index 5553ae96e..97380847c 100644 --- a/docs/modules/typeclass/Bounded.ts.md +++ b/docs/modules/typeclass/Bounded.ts.md @@ -36,7 +36,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const max: (B: Bounded) => any +export declare const max: (B: Bounded) => Monoid ``` Added in v1.0.0 @@ -48,7 +48,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const min: (B: Bounded) => any +export declare const min: (B: Bounded) => Monoid ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Chainable.ts.md b/docs/modules/typeclass/Chainable.ts.md index 8372e97e1..615e82864 100644 --- a/docs/modules/typeclass/Chainable.ts.md +++ b/docs/modules/typeclass/Chainable.ts.md @@ -32,9 +32,11 @@ produced by the effect. **Signature** ```ts -export declare const andThenDiscard: ( +export declare const andThenDiscard: ( F: Chainable -) => (that: any) => (self: any) => any +) => ( + that: Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -58,12 +60,14 @@ Added in v1.0.0 **Signature** ```ts -export declare const bind: ( +export declare const bind: ( F: Chainable ) => ( name: Exclude, - f: (a: A) => any -) => (self: any) => any + f: (a: A) => Kind +) => ( + self: Kind +) => Kind ``` Added in v1.0.0 @@ -75,9 +79,11 @@ Returns an effect that effectfully "peeks" at the success of this effect. **Signature** ```ts -export declare const tap: ( +export declare const tap: ( F: Chainable -) => (f: (a: A) => any) => (self: any) => any +) => ( + f: (a: A) => Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Compactable.ts.md b/docs/modules/typeclass/Compactable.ts.md index 1f9edea9e..aa4a6e38c 100644 --- a/docs/modules/typeclass/Compactable.ts.md +++ b/docs/modules/typeclass/Compactable.ts.md @@ -45,10 +45,12 @@ Returns a default `compact` composition. **Signature** ```ts -export declare const compactComposition: ( - F: any, +export declare const compactComposition: ( + F: Covariant, G: Compactable -) => (self: any) => any +) => ( + self: Kind>> +) => Kind> ``` Added in v1.0.0 @@ -58,7 +60,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const separate: (F: any) => (self: any) => [any, any] +export declare const separate: ( + F: Covariant & Compactable +) => (self: Kind>) => [Kind, Kind] ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Contravariant.ts.md b/docs/modules/typeclass/Contravariant.ts.md index d0f5e18e9..6bac8e419 100644 --- a/docs/modules/typeclass/Contravariant.ts.md +++ b/docs/modules/typeclass/Contravariant.ts.md @@ -29,8 +29,8 @@ Added in v1.0.0 **Signature** ```ts -export declare const make: ( - contramap: (f: (b: B) => A) => (self: any) => any +export declare const make: ( + contramap: (f: (b: B) => A) => (self: Kind) => Kind ) => Contravariant ``` @@ -61,10 +61,14 @@ Returns a default `map` composition. **Signature** ```ts -export declare const contramapComposition: ( +export declare const contramapComposition: ( F: Contravariant, G: Contravariant -) => (f: (a: A) => B) => (self: any) => any +) => ( + f: (a: A) => B +) => ( + self: Kind> +) => Kind> ``` Added in v1.0.0 @@ -76,7 +80,9 @@ Returns a default `imap` implementation. **Signature** ```ts -export declare const imap: (contramap: (f: (b: B) => A) => (self: any) => any) => any +export declare const imap: ( + contramap: (f: (b: B) => A) => (self: Kind) => Kind +) => (to: (a: A) => B, from: (b: B) => A) => (self: Kind) => Kind ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Coproduct.ts.md b/docs/modules/typeclass/Coproduct.ts.md index 4dae57e12..2fd0783a0 100644 --- a/docs/modules/typeclass/Coproduct.ts.md +++ b/docs/modules/typeclass/Coproduct.ts.md @@ -42,7 +42,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getMonoid: (F: Coproduct) => () => any +export declare const getMonoid: (F: Coproduct) => () => Monoid> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index 26665b76a..badb18d3e 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -34,7 +34,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const make: (map: (f: (a: A) => B) => (self: any) => any) => Covariant +export declare const make: ( + map: (f: (a: A) => B) => (self: Kind) => Kind +) => Covariant ``` Added in v1.0.0 @@ -46,7 +48,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const as: (F: Covariant) => (b: B) => (self: any) => any +export declare const as: ( + F: Covariant +) => (b: B) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -56,7 +60,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const asUnit: (F: Covariant) => (self: any) => any +export declare const asUnit: ( + F: Covariant +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -66,7 +72,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const flap: (F: Covariant) => (self: any) => (a: A) => any +export declare const flap: ( + F: Covariant +) => (self: Kind B>) => (a: A) => Kind ``` Added in v1.0.0 @@ -94,7 +102,9 @@ Returns a default `imap` implementation. **Signature** ```ts -export declare const imap: (map: (f: (a: A) => B) => (self: any) => any) => any +export declare const imap: ( + map: (f: (a: A) => B) => (self: Kind) => Kind +) => (to: (a: A) => B, from: (b: B) => A) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -104,9 +114,12 @@ Added in v1.0.0 **Signature** ```ts -export declare const let: ( +export declare const let: ( F: Covariant -) => (name: Exclude, f: (a: A) => B) => (self: any) => any +) => ( + name: Exclude, + f: (a: A) => B +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -118,10 +131,14 @@ Returns a default `map` composition. **Signature** ```ts -export declare const mapComposition: ( +export declare const mapComposition: ( F: Covariant, G: Covariant -) => (f: (a: A) => B) => (self: any) => any +) => ( + f: (a: A) => B +) => ( + self: Kind> +) => Kind> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Equivalence.ts.md b/docs/modules/typeclass/Equivalence.ts.md index 991fdddfe..432e1fbf9 100644 --- a/docs/modules/typeclass/Equivalence.ts.md +++ b/docs/modules/typeclass/Equivalence.ts.md @@ -78,7 +78,7 @@ If all comparisons return true, the records are considered equal. **Signature** ```ts -export declare const record: (equivalence: Equivalence) => Equivalence +export declare const record: (equivalence: Equivalence) => Equivalence> ``` Added in v1.0.0 @@ -134,7 +134,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Contravariant: any +export declare const Contravariant: contravariant.Contravariant ``` Added in v1.0.0 @@ -144,7 +144,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Invariant: any +export declare const Invariant: invariant.Invariant ``` Added in v1.0.0 @@ -154,7 +154,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: any +export declare const Product: product.Product ``` Added in v1.0.0 @@ -164,7 +164,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiProduct: any +export declare const SemiProduct: semiProduct.SemiProduct ``` Added in v1.0.0 @@ -194,7 +194,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getMonoid: () => any +export declare const getMonoid: () => Monoid> ``` Added in v1.0.0 @@ -204,7 +204,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getSemigroup: () => any +export declare const getSemigroup: () => Semigroup> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Filterable.ts.md b/docs/modules/typeclass/Filterable.ts.md index 334992306..a0af17ee5 100644 --- a/docs/modules/typeclass/Filterable.ts.md +++ b/docs/modules/typeclass/Filterable.ts.md @@ -45,11 +45,13 @@ Added in v1.0.0 **Signature** ```ts -export declare const filter: ( +export declare const filter: ( F: Filterable ) => { - (refinement: (a: A) => a is B): (self: any) => any - (predicate: (a: A) => boolean): (self: any) => any + (refinement: (a: A) => a is B): ( + self: Kind + ) => Kind + (predicate: (a: A) => boolean): (self: Kind) => Kind } ``` @@ -62,10 +64,14 @@ Returns a default `filterMap` composition. **Signature** ```ts -export declare const filterMapComposition: ( - F: any, +export declare const filterMapComposition: ( + F: Covariant, G: Filterable -) => (f: (a: A) => any) => (self: any) => any +) => ( + f: (a: A) => Option +) => ( + self: Kind> +) => Kind> ``` Added in v1.0.0 @@ -75,11 +81,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const partition: ( +export declare const partition: ( F: Filterable ) => { - (refinement: (a: A) => a is B): (self: any) => [any, any] - (predicate: (a: A) => boolean): (self: any) => [any, any] + (refinement: (a: A) => a is B): ( + self: Kind + ) => [Kind, Kind] + (predicate: (a: A) => boolean): ( + self: Kind + ) => [Kind, Kind] } ``` @@ -90,9 +100,11 @@ Added in v1.0.0 **Signature** ```ts -export declare const partitionMap: ( +export declare const partitionMap: ( F: Filterable -) => (f: (a: A) => any) => (self: any) => [any, any] +) => ( + f: (a: A) => Either +) => (self: Kind) => [Kind, Kind] ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/FlatMap.ts.md b/docs/modules/typeclass/FlatMap.ts.md index 0c9a88819..1a03f3310 100644 --- a/docs/modules/typeclass/FlatMap.ts.md +++ b/docs/modules/typeclass/FlatMap.ts.md @@ -46,9 +46,11 @@ A variant of `flatMap` that ignores the value produced by this effect. **Signature** ```ts -export declare const andThen: ( +export declare const andThen: ( F: FlatMap -) => (that: any) => (self: any) => any +) => ( + that: Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -58,9 +60,11 @@ Added in v1.0.0 **Signature** ```ts -export declare const composeKleisliArrow: ( +export declare const composeKleisliArrow: ( F: FlatMap -) => (bfc: (b: B) => any) => (afb: (a: A) => any) => (a: A) => any +) => ( + bfc: (b: B) => Kind +) => (afb: (a: A) => Kind) => (a: A) => Kind ``` Added in v1.0.0 @@ -70,7 +74,11 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatten: (F: FlatMap) => (self: any) => any +export declare const flatten: ( + F: FlatMap +) => ( + self: Kind> +) => Kind ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Foldable.ts.md b/docs/modules/typeclass/Foldable.ts.md index 3e9a15f47..64c8cf57b 100644 --- a/docs/modules/typeclass/Foldable.ts.md +++ b/docs/modules/typeclass/Foldable.ts.md @@ -47,9 +47,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const foldMap: ( +export declare const foldMap: ( F: Foldable -) => (M: any) => (f: (a: A) => M) => (self: any) => M +) => (M: Monoid) => (f: (a: A) => M) => (self: Kind) => M ``` Added in v1.0.0 @@ -59,9 +59,13 @@ Added in v1.0.0 **Signature** ```ts -export declare const foldMapKind: ( +export declare const foldMapKind: ( F: Foldable -) => (G: any) => (f: (a: A) => any) => (self: any) => any +) => ( + G: Coproduct +) => ( + f: (a: A) => Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -73,10 +77,13 @@ Returns a default `reduce` composition. **Signature** ```ts -export declare const reduceComposition: ( +export declare const reduceComposition: ( F: Foldable, G: Foldable -) => (b: B, f: (b: B, a: A) => B) => (self: any) => B +) => ( + b: B, + f: (b: B, a: A) => B +) => (self: Kind>) => B ``` Added in v1.0.0 @@ -86,9 +93,14 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduceKind: ( +export declare const reduceKind: ( F: Foldable -) => (G: any) => (b: B, f: (b: B, a: A) => any) => (self: any) => any +) => ( + G: Monad +) => ( + b: B, + f: (b: B, a: A) => Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -98,9 +110,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduceRight: ( +export declare const reduceRight: ( F: Foldable -) => (b: B, f: (b: B, a: A) => B) => (self: any) => B +) => (b: B, f: (b: B, a: A) => B) => (self: Kind) => B ``` Added in v1.0.0 @@ -110,9 +122,14 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduceRightKind: ( +export declare const reduceRightKind: ( F: Foldable -) => (G: any) => (b: B, f: (b: B, a: A) => any) => (self: any) => any +) => ( + G: Monad +) => ( + b: B, + f: (b: B, a: A) => Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -122,7 +139,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const toArray: (F: Foldable) => (self: any) => A[] +export declare const toArray: (F: Foldable) => (self: Kind) => A[] ``` Added in v1.0.0 @@ -132,9 +149,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const toArrayWith: ( +export declare const toArrayWith: ( F: Foldable -) => (f: (a: A) => B) => (self: any) => B[] +) => (f: (a: A) => B) => (self: Kind) => B[] ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Invariant.ts.md b/docs/modules/typeclass/Invariant.ts.md index 461283073..b05f74f35 100644 --- a/docs/modules/typeclass/Invariant.ts.md +++ b/docs/modules/typeclass/Invariant.ts.md @@ -45,9 +45,11 @@ Added in v1.0.0 **Signature** ```ts -export declare const bindTo: ( +export declare const bindTo: ( F: Invariant -) => (name: N) => (self: any) => any +) => ( + name: N +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -59,10 +61,15 @@ Returns a default `imap` composition. **Signature** ```ts -export declare const imapComposition: ( +export declare const imapComposition: ( F: Invariant, G: Invariant -) => (to: (a: A) => B, from: (b: B) => A) => (self: any) => any +) => ( + to: (a: A) => B, + from: (b: B) => A +) => ( + self: Kind> +) => Kind> ``` Added in v1.0.0 @@ -72,7 +79,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const tupled: (F: Invariant) => (self: any) => any +export declare const tupled: ( + F: Invariant +) => (self: Kind) => Kind ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index d5e04b983..fab07550d 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -118,7 +118,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromSemigroup: (S: any, empty: A) => Monoid +export declare const fromSemigroup: (S: Semigroup, empty: A) => Monoid ``` Added in v1.0.0 @@ -132,7 +132,7 @@ The `empty` value is the `minimum` value. **Signature** ```ts -export declare const max: (B: any) => Monoid +export declare const max: (B: Bounded) => Monoid ``` Added in v1.0.0 @@ -146,7 +146,7 @@ The `empty` value is the `maxBound` value. **Signature** ```ts -export declare const min: (B: any) => Monoid +export declare const min: (B: Bounded) => Monoid ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Of.ts.md b/docs/modules/typeclass/Of.ts.md index f00c7a399..80975d22d 100644 --- a/docs/modules/typeclass/Of.ts.md +++ b/docs/modules/typeclass/Of.ts.md @@ -42,7 +42,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Do: (F: Of) => any +export declare const Do: (F: Of) => Kind ``` Added in v1.0.0 @@ -54,7 +54,10 @@ Returns a default `of` composition. **Signature** ```ts -export declare const ofComposition: (F: Of, G: Of) => (a: A) => any +export declare const ofComposition: ( + F: Of, + G: Of +) => (a: A) => Kind> ``` Added in v1.0.0 @@ -64,7 +67,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const unit: (F: Of) => any +export declare const unit: (F: Of) => Kind ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index 3cee18971..10e98253e 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -117,7 +117,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Contravariant: any +export declare const Contravariant: contravariant.Contravariant ``` Added in v1.0.0 @@ -127,7 +127,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Invariant: any +export declare const Invariant: invariant.Invariant ``` Added in v1.0.0 @@ -137,7 +137,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: any +export declare const Product: product.Product ``` Added in v1.0.0 @@ -147,7 +147,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiProduct: any +export declare const SemiProduct: semiProduct.SemiProduct ``` Added in v1.0.0 @@ -177,7 +177,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getMonoid: () => any +export declare const getMonoid: () => Monoid> ``` Added in v1.0.0 @@ -187,7 +187,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getSemigroup: () => any +export declare const getSemigroup: () => Semigroup> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Product.ts.md b/docs/modules/typeclass/Product.ts.md index 7e2960ddf..951a6fd04 100644 --- a/docs/modules/typeclass/Product.ts.md +++ b/docs/modules/typeclass/Product.ts.md @@ -41,9 +41,17 @@ Added in v1.0.0 **Signature** ```ts -export declare const struct: ( +export declare const struct: ( F: Product -) => (fields: R) => any +) => }>( + fields: R +) => Kind< + F, + [R[keyof R]] extends [Kind] ? R : never, + [R[keyof R]] extends [Kind] ? O : never, + [R[keyof R]] extends [Kind] ? E : never, + { [K in keyof R]: [R[K]] extends [Kind] ? A : never } +> ``` Added in v1.0.0 @@ -53,7 +61,17 @@ Added in v1.0.0 **Signature** ```ts -export declare const tuple: (F: Product) => (...components: T) => any +export declare const tuple: ( + F: Product +) => []>( + ...components: T +) => Kind< + F, + [T[number]] extends [Kind] ? R : never, + [T[number]] extends [Kind] ? O : never, + [T[number]] extends [Kind] ? E : never, + { [I in keyof T]: [T[I]] extends [Kind] ? A : never } +> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index 5314a1789..407409d22 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -34,9 +34,13 @@ Lifts a binary function into `F`. **Signature** ```ts -export declare const lift2: ( +export declare const lift2: ( F: SemiApplicative -) => (f: (a: A) => (b: B) => C) => (that: any) => (self: any) => any +) => ( + f: (a: A) => (b: B) => C +) => ( + that: Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -48,7 +52,9 @@ Lift a `Semigroup` into 'F', the inner values are combined using the provided `S **Signature** ```ts -export declare const liftSemigroup: (F: SemiApplicative) => (S: any) => any +export declare const liftSemigroup: ( + F: SemiApplicative +) => (S: Semigroup) => Semigroup> ``` Added in v1.0.0 @@ -72,9 +78,11 @@ Added in v1.0.0 **Signature** ```ts -export declare const andThen: ( +export declare const andThen: ( F: SemiApplicative -) => (that: any) => (self: any) => any +) => ( + that: Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -84,9 +92,11 @@ Added in v1.0.0 **Signature** ```ts -export declare const andThenDiscard: ( +export declare const andThenDiscard: ( F: SemiApplicative -) => (that: any) => (self: any) => any +) => ( + that: Kind +) => (self: Kind) => Kind ``` Added in v1.0.0 @@ -96,9 +106,11 @@ Added in v1.0.0 **Signature** ```ts -export declare const ap: ( +export declare const ap: ( F: SemiApplicative -) => (that: any) => (self: any) => any +) => ( + that: Kind +) => (self: Kind B>) => Kind ``` Added in v1.0.0 @@ -110,9 +122,12 @@ Zips two `F` values together using a provided function, returning a new `F` of t **Signature** ```ts -export declare const zipWith: ( +export declare const zipWith: ( F: SemiApplicative -) => (fb: any, f: (a: A, b: B) => C) => (fa: any) => any +) => ( + fb: Kind, + f: (a: A, b: B) => C +) => (fa: Kind) => Kind ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiCoproduct.ts.md b/docs/modules/typeclass/SemiCoproduct.ts.md index cc6d0f242..f1b124225 100644 --- a/docs/modules/typeclass/SemiCoproduct.ts.md +++ b/docs/modules/typeclass/SemiCoproduct.ts.md @@ -48,7 +48,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const getSemigroup: (F: SemiCoproduct) => () => any +export declare const getSemigroup: ( + F: SemiCoproduct +) => () => Semigroup> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index 78b8ebdd8..a2d2c883d 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -35,10 +35,13 @@ Returns a default `productMany` implementation (useful for tests). **Signature** ```ts -export declare const productMany: ( - Covariant: any, - product: (self: any, that: any) => any -) => (self: any, collection: Iterable) => any +export declare const productMany: ( + Covariant: Covariant, + product: ( + self: Kind, + that: Kind + ) => Kind +) => (self: Kind, collection: Iterable>) => Kind ``` Added in v1.0.0 @@ -72,12 +75,14 @@ Added in v1.0.0 **Signature** ```ts -export declare const andThenBind: ( +export declare const andThenBind: ( F: SemiProduct ) => ( name: Exclude, - that: any -) => (self: any) => any + that: Kind +) => ( + self: Kind +) => Kind ``` Added in v1.0.0 @@ -89,9 +94,13 @@ Appends an element to the end of a tuple. **Signature** ```ts -export declare const appendElement: ( +export declare const appendElement: ( F: SemiProduct -) => (that: any) => (self: any) => any +) => ( + that: Kind +) => ( + self: Kind +) => Kind ``` Added in v1.0.0 @@ -101,9 +110,17 @@ Added in v1.0.0 **Signature** ```ts -export declare const nonEmptyStruct: ( +export declare const nonEmptyStruct: ( F: SemiProduct -) => (fields: EnforceNonEmptyRecord & { readonly [x: string]: any }) => any +) => }>( + fields: EnforceNonEmptyRecord & { readonly [x: string]: Kind } +) => Kind< + F, + [R[keyof R]] extends [Kind] ? R : never, + [R[keyof R]] extends [Kind] ? O : never, + [R[keyof R]] extends [Kind] ? E : never, + { [K in keyof R]: [R[K]] extends [Kind] ? A : never } +> ``` Added in v1.0.0 @@ -113,9 +130,17 @@ Added in v1.0.0 **Signature** ```ts -export declare const nonEmptyTuple: ( +export declare const nonEmptyTuple: ( F: SemiProduct -) => (...components: T) => any +) => , ...Kind[]]>( + ...components: T +) => Kind< + F, + [T[number]] extends [Kind] ? R : never, + [T[number]] extends [Kind] ? O : never, + [T[number]] extends [Kind] ? E : never, + { [I in keyof T]: [T[I]] extends [Kind] ? A : never } +> ``` Added in v1.0.0 @@ -127,10 +152,13 @@ Returns a default `product` composition. **Signature** ```ts -export declare const productComposition: ( - F: any, +export declare const productComposition: ( + F: SemiApplicative, G: SemiProduct -) => (self: any, that: any) => any +) => ( + self: Kind>, + that: Kind> +) => Kind> ``` Added in v1.0.0 @@ -142,10 +170,13 @@ Returns a default `productMany` composition. **Signature** ```ts -export declare const productManyComposition: ( - F: any, +export declare const productManyComposition: ( + F: SemiApplicative, G: SemiProduct -) => (self: any, collection: Iterable) => any +) => ( + self: Kind>, + collection: Iterable>> +) => Kind> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index cfc4fe6ad..b91f9eeda 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -158,7 +158,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const max: (O: any) => Semigroup +export declare const max: (O: Order) => Semigroup ``` Added in v1.0.0 @@ -170,7 +170,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const min: (O: any) => Semigroup +export declare const min: (O: Order) => Semigroup ``` Added in v1.0.0 @@ -182,7 +182,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Invariant: any +export declare const Invariant: invariant.Invariant ``` Added in v1.0.0 @@ -192,7 +192,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: any +export declare const Product: product.Product ``` Added in v1.0.0 @@ -202,7 +202,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const SemiProduct: any +export declare const SemiProduct: semiProduct.SemiProduct ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Traversable.ts.md b/docs/modules/typeclass/Traversable.ts.md index 4a1553bb6..ce63e5216 100644 --- a/docs/modules/typeclass/Traversable.ts.md +++ b/docs/modules/typeclass/Traversable.ts.md @@ -55,9 +55,17 @@ Returns a default `sequence` implementation. **Signature** ```ts -export declare const sequence: ( - traverse: (F: any) => (f: (a: A) => any) => (self: any) => any -) => (F: any) => (self: any) => any +export declare const sequence: ( + traverse: ( + F: Applicative + ) => ( + f: (a: A) => Kind + ) => (self: Kind) => Kind> +) => ( + F: Applicative +) => ( + self: Kind> +) => Kind> ``` Added in v1.0.0 @@ -69,10 +77,14 @@ Returns a default `sequence` composition. **Signature** ```ts -export declare const sequenceComposition: ( - T: any, +export declare const sequenceComposition: ( + T: Traversable & Covariant, G: Traversable -) => (F: any) => (self: any) => any +) => ( + F: Applicative +) => ( + self: Kind>> +) => Kind>> ``` Added in v1.0.0 @@ -84,10 +96,16 @@ Returns a default `traverse` composition. **Signature** ```ts -export declare const traverseComposition: ( +export declare const traverseComposition: ( T: Traversable, G: Traversable -) => (F: any) => (f: (a: A) => any) => (self: any) => any +) => ( + F: Applicative +) => ( + f: (a: A) => Kind +) => ( + self: Kind> +) => Kind>> ``` Added in v1.0.0 @@ -102,9 +120,13 @@ returned by the provided function. **Signature** ```ts -export declare const traverseTap: ( +export declare const traverseTap: ( T: Traversable -) => (F: any) => (f: (a: A) => any) => (self: any) => any +) => ( + F: Applicative +) => ( + f: (a: A) => Kind +) => (self: Kind) => Kind> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/TraversableFilterable.ts.md b/docs/modules/typeclass/TraversableFilterable.ts.md index 5b5f24d21..705b3f17c 100644 --- a/docs/modules/typeclass/TraversableFilterable.ts.md +++ b/docs/modules/typeclass/TraversableFilterable.ts.md @@ -55,11 +55,13 @@ Added in v1.0.0 **Signature** ```ts -export declare const traverseFilter: ( +export declare const traverseFilter: ( T: TraversableFilterable -) => ( - F: any -) => (predicate: (a: A) => any) => (self: any) => any +) => ( + F: Applicative +) => ( + predicate: (a: A) => Kind +) => (self: Kind) => Kind> ``` Added in v1.0.0 @@ -71,9 +73,13 @@ Returns a default `traverseFilterMap` implementation. **Signature** ```ts -export declare const traverseFilterMap: ( - T: any -) => (F: any) => (f: (a: A) => any) => (self: any) => any +export declare const traverseFilterMap: ( + T: Traversable & compactable.Compactable +) => ( + F: Applicative +) => ( + f: (a: A) => Kind> +) => (self: Kind) => Kind> ``` Added in v1.0.0 @@ -83,11 +89,13 @@ Added in v1.0.0 **Signature** ```ts -export declare const traversePartition: ( +export declare const traversePartition: ( T: TraversableFilterable -) => ( - F: any -) => (predicate: (a: A) => any) => (self: any) => any +) => ( + F: Applicative +) => ( + predicate: (a: A) => Kind +) => (self: Kind) => Kind, Kind]> ``` Added in v1.0.0 @@ -99,9 +107,13 @@ Returns a default `traversePartitionMap` implementation. **Signature** ```ts -export declare const traversePartitionMap: ( - T: any -) => (F: any) => (f: (a: A) => any) => (self: any) => any +export declare const traversePartitionMap: ( + T: Traversable & Covariant & compactable.Compactable +) => ( + F: Applicative +) => ( + f: (a: A) => Kind> +) => (self: Kind) => Kind, Kind]> ``` Added in v1.0.0 diff --git a/patches/docs-ts@0.6.10.patch b/patches/docs-ts@0.6.10.patch index 73d4b8fa3..ae7d9cbe1 100644 --- a/patches/docs-ts@0.6.10.patch +++ b/patches/docs-ts@0.6.10.patch @@ -1,5 +1,5 @@ diff --git a/lib/Core.js b/lib/Core.js -index c0f282ca9e3ddd93e44a62e1d05c1cc45b9f5c6a..a75fde491fec9f0d6e14c3adf2cc9b000f1c625e 100644 +index c0f282ca9e3ddd93e44a62e1d05c1cc45b9f5c6a..616f7f6223459e0621522279ea7fc1cf1868abe8 100644 --- a/lib/Core.js +++ b/lib/Core.js @@ -167,7 +167,30 @@ var typeCheckExamples = function (modules) { @@ -33,4 +33,23 @@ index c0f282ca9e3ddd93e44a62e1d05c1cc45b9f5c6a..a75fde491fec9f0d6e14c3adf2cc9b00 + )}); }), RTE.chain(function () { return spawnTsNode; }), RTE.chain(function () { return cleanExamples; })); })); }; - // ------------------------------------------------------------------------------------- \ No newline at end of file + // ------------------------------------------------------------------------------------- +diff --git a/lib/index.js b/lib/index.js +index 51bdb346c4c33e8835bbda0c16aea71bc0c3115e..7d084d363efd3f8aad76051f4253b0b59cd0c5cd 100644 +--- a/lib/index.js ++++ b/lib/index.js +@@ -33,7 +33,13 @@ exports.exit = TE.fold(onLeft, function () { return onRight; }); + * @internal + */ + exports.compilerOptions = { +- strict: true ++ strict: true, ++ paths: { ++ "@fp-ts/core": ["./src/index.ts"], ++ "@fp-ts/core/test/*": ["./test/*"], ++ "@fp-ts/core/examples/*": ["./examples/*"], ++ "@fp-ts/core/*": ["./src/*"] ++ } + }; + var capabilities = { + example: Example_1.Example, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 224565d26..e0753f6a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,7 +5,7 @@ patchedDependencies: hash: wzvflwv62ngf22ppz3frldq37m path: patches/@effect-ts__build-utils@0.40.3.patch docs-ts@0.6.10: - hash: pulkjstupuiumlrt7ngjhrpf2e + hash: dggjhgv5fthp6zyrepab32p45i path: patches/docs-ts@0.6.10.patch importers: @@ -78,7 +78,7 @@ importers: c8: 7.12.0 concurrently: 7.6.0 cpx: 1.5.0 - docs-ts: 0.6.10_pulkjstupuiumlrt7ngjhrpf2e_brpckf4sz23pco3jyty2eys3iq + docs-ts: 0.6.10_dggjhgv5fthp6zyrepab32p45i_brpckf4sz23pco3jyty2eys3iq dtslint: github.com/gcanti/dtslint/4552d162099399c4e14f8486ced673411e5b3659 eslint: 8.28.0 eslint-import-resolver-typescript: 3.5.2_ktrec6dplf4now6nlbc6d67jee @@ -2400,7 +2400,7 @@ packages: dev: true patched: true - /docs-ts/0.6.10_pulkjstupuiumlrt7ngjhrpf2e_brpckf4sz23pco3jyty2eys3iq: + /docs-ts/0.6.10_dggjhgv5fthp6zyrepab32p45i_brpckf4sz23pco3jyty2eys3iq: resolution: {integrity: sha512-DTX9c5AJ92ojMOKqqvwF8t77C8Gdgs9FPB8seymHs+F+Wl6aapc3ZkHUM+p8o+jwcBmPoihxssdK903dfwQ1JQ==} hasBin: true peerDependencies: From 4e994bf2e9995f9e5bc84f0587c78c2607929f1c Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 11:36:29 +0100 Subject: [PATCH 130/255] add dual tag --- src/ReadonlyRecord.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index 294cf3911..3477263da 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -33,6 +33,7 @@ export interface ReadonlyRecord { * { '1': 2, '2': 4, '3': 6, '4': 8 } * ) * + * @dual * @category constructors * @since 1.0.0 */ @@ -69,6 +70,7 @@ export const fromIterable: { * assert.deepStrictEqual(get(person, "name"), some("John Doe")) * assert.deepStrictEqual(get(person, "email"), none()) * + * @dual * @category getters * @since 1.0.0 */ @@ -107,6 +109,7 @@ export const get: { * none() * ) * + * @dual * @since 1.0.0 */ export const modifyOption: { @@ -144,6 +147,7 @@ export const modifyOption: { * ) * assert.deepStrictEqual(replaceOption({}, 'a', 10), none()) * + * @dual * @since 1.0.0 */ export const replaceOption: { @@ -171,6 +175,7 @@ export const replaceOption: { * * assert.deepStrictEqual(mapWithKey({ a: 3, b: 5 }, f), { a: "A-3", b: "B-5" }) * + * @dual * @category mapping * @since 1.0.0 */ @@ -206,6 +211,7 @@ export const mapWithKey: { * * assert.deepStrictEqual(map({ a: 3, b: 5 }, f), { a: "-3-", b: "-5-" }) * + * @dual * @category mapping * @since 1.0.0 */ From 79f7c033459d0d2e5135ca5b4f115752ff215899 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 12:04:30 +0100 Subject: [PATCH 131/255] Either: pass the value of the Left to the getOrElse callback and apply dual --- docs/modules/Either.ts.md | 93 ++++++++++++----------- docs/modules/Option.ts.md | 86 +++++++++++----------- guides/Either.md | 66 ++++++++++++++++- guides/Option.md | 11 +++ src/Either.ts | 150 ++++++++++++++++++++++---------------- src/Option.ts | 21 ++++-- 6 files changed, 268 insertions(+), 159 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index f9a15aab0..ff9eaa7c5 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -30,7 +30,6 @@ Added in v1.0.0 - [right](#right) - [conversions](#conversions) - [fromIterable](#fromiterable) - - [fromNullable](#fromnullable) - [fromOption](#fromoption) - [toRefinement](#torefinement) - [debugging](#debugging) @@ -83,11 +82,12 @@ Added in v1.0.0 - [Traversable](#traversable) - [getOptionalSemigroup](#getoptionalsemigroup) - [interop](#interop) + - [fromNullable](#fromnullable) - [getOrThrow](#getorthrow) + - [liftNullable](#liftnullable) - [liftThrowable](#liftthrowable) - [lifting](#lifting) - [lift2](#lift2) - - [liftNullable](#liftnullable) - [liftOption](#liftoption) - [liftPredicate](#liftpredicate) - [mapping](#mapping) @@ -322,30 +322,6 @@ export declare const fromIterable: (onEmpty: LazyArg) => (collection: I Added in v1.0.0 -## fromNullable - -Takes a lazy default and a nullable value, if the value is not nully, turn it into a `Right`, if the value is nully use -the provided default as a `Left`. - -**Signature** - -```ts -export declare const fromNullable: (onNullable: LazyArg) => (a: A) => Either> -``` - -**Example** - -```ts -import * as E from '@fp-ts/core/Either' - -const parse = E.fromNullable(() => 'nullable') - -assert.deepStrictEqual(parse(1), E.right(1)) -assert.deepStrictEqual(parse(null), E.left('nullable')) -``` - -Added in v1.0.0 - ## fromOption **Signature** @@ -639,7 +615,10 @@ Returns the wrapped value if it's a `Right` or a default value if is a `Left`. **Signature** ```ts -export declare const getOrElse: (onLeft: LazyArg) => (self: Either) => B | A +export declare const getOrElse: { + (self: Either, onLeft: (e: E) => B): A | B + (onLeft: (e: E) => B): (self: Either) => B | A +} ``` **Example** @@ -649,17 +628,11 @@ import * as E from '@fp-ts/core/Either' import { pipe } from '@fp-ts/core/Function' assert.deepStrictEqual( - pipe( - E.right(1), - E.getOrElse(() => 0) - ), + E.getOrElse(E.right(1), () => 0), 1 ) assert.deepStrictEqual( - pipe( - E.left('error'), - E.getOrElse(() => 0) - ), + E.getOrElse(E.left('error'), () => 0), 0 ) ``` @@ -934,6 +907,30 @@ Added in v1.0.0 # interop +## fromNullable + +Takes a lazy default and a nullable value, if the value is not nully, turn it into a `Right`, if the value is nully use +the provided default as a `Left`. + +**Signature** + +```ts +export declare const fromNullable: (onNullable: LazyArg) => (a: A) => Either> +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' + +const parse = E.fromNullable(() => 'nullable') + +assert.deepStrictEqual(parse(1), E.right(1)) +assert.deepStrictEqual(parse(null), E.left('nullable')) +``` + +Added in v1.0.0 + ## getOrThrow **Signature** @@ -944,6 +941,19 @@ export declare const getOrThrow: (onLeft?: (e: E) => Error) => (self: Eith Added in v1.0.0 +## liftNullable + +**Signature** + +```ts +export declare const liftNullable: ( + f: (...a: A) => B | null | undefined, + onNullable: (...a: A) => E +) => (...a: A) => Either> +``` + +Added in v1.0.0 + ## liftThrowable Lifts a function that may throw to one returning a `Either`. @@ -975,19 +985,6 @@ export declare const lift2: ( Added in v1.0.0 -## liftNullable - -**Signature** - -```ts -export declare const liftNullable: ( - f: (...a: A) => B | null | undefined, - onNullable: (...a: A) => E -) => (...a: A) => Either> -``` - -Added in v1.0.0 - ## liftOption **Signature** diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index c6c8429c3..98b423e41 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -26,6 +26,7 @@ Added in v1.0.0 - [tap](#tap) - [constructors](#constructors) - [none](#none) + - [of](#of) - [some](#some) - [conversions](#conversions) - [fromEither](#fromeither) @@ -82,12 +83,12 @@ Added in v1.0.0 - [getOrNull](#getornull) - [getOrThrow](#getorthrow) - [getOrUndefined](#getorundefined) + - [liftNullable](#liftnullable) - [liftThrowable](#liftthrowable) - [lifting](#lifting) - [getOptionalMonoid](#getoptionalmonoid) - [lift2](#lift2) - [liftEither](#lifteither) - - [liftNullable](#liftnullable) - [liftPredicate](#liftpredicate) - [mapping](#mapping) - [as](#as) @@ -123,7 +124,6 @@ Added in v1.0.0 - [contains](#contains) - [exists](#exists) - [flatten](#flatten) - - [of](#of) - [reduceAll](#reduceall) - [struct](#struct) - [toArray](#toarray) @@ -281,6 +281,18 @@ export declare const none: () => Option Added in v1.0.0 +## of + +Alias of `some`. + +**Signature** + +```ts +export declare const of: (a: A) => Option +``` + +Added in v1.0.0 + ## some Creates a new `Option` that wraps the given value. @@ -1017,6 +1029,36 @@ assert.deepStrictEqual(pipe(none(), getOrUndefined), undefined) Added in v1.0.0 +## liftNullable + +This API is useful for lifting a function that returns `null` or `undefined` into the `Option` context. + +**Signature** + +```ts +export declare const liftNullable: ( + f: (...a: A) => B | null | undefined +) => (...a: A) => Option> +``` + +**Example** + +```ts +import { liftNullable, none, some } from '@fp-ts/core/Option' + +const parse = (s: string): number | undefined => { + const n = parseFloat(s) + return isNaN(n) ? undefined : n +} + +const parseOption = liftNullable(parse) + +assert.deepStrictEqual(parseOption('1'), some(1)) +assert.deepStrictEqual(parseOption('not a number'), none()) +``` + +Added in v1.0.0 + ## liftThrowable A utility function that lifts a function that throws exceptions into a function that returns an `Option`. @@ -1113,36 +1155,6 @@ assert.deepEqual(parseNumber('not a number'), O.none()) Added in v1.0.0 -## liftNullable - -This API is useful for lifting a function that returns `null` or `undefined` into the `Option` context. - -**Signature** - -```ts -export declare const liftNullable: ( - f: (...a: A) => B | null | undefined -) => (...a: A) => Option> -``` - -**Example** - -```ts -import { liftNullable, none, some } from '@fp-ts/core/Option' - -const parse = (s: string): number | undefined => { - const n = parseFloat(s) - return isNaN(n) ? undefined : n -} - -const parseOption = liftNullable(parse) - -assert.deepStrictEqual(parseOption('1'), some(1)) -assert.deepStrictEqual(parseOption('not a number'), none()) -``` - -Added in v1.0.0 - ## liftPredicate Returns a _smart constructor_ based on the given predicate. @@ -1610,16 +1622,6 @@ export declare const flatten: (self: Option>) => Option Added in v1.0.0 -## of - -**Signature** - -```ts -export declare const of: (a: A) => Option -``` - -Added in v1.0.0 - ## reduceAll Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. diff --git a/guides/Either.md b/guides/Either.md index 26c6ea543..235cb26a0 100644 --- a/guides/Either.md +++ b/guides/Either.md @@ -40,6 +40,15 @@ const success: Either = right(1); const failure: Either = left("error message"); ``` +**Cheat sheet** (constructors) + +| Name | Given | To | +| ------- | ----- | ------------------ | +| `right` | `A` | `Either` | +| `left` | `E` | `Either` | + +# Conversions + You can also use the `fromOption` function to convert an `Option` to an `Either`. ```ts @@ -59,6 +68,14 @@ const failure: Either = pipe( The `fromOption` function requires an argument because it needs to know what value to use for the `Left` variant of the `Either` type when given a `None`. In the example, the argument "error message" is used as the value for the `Left` variant when `None` is encountered. This allows `Either` to provide more information about why a failure occurred. +**Cheat sheet** (conversions) + +| Name | Given | To | +| -------------- | ------------------------------------ | ------------------ | +| `toRefinement` | `A => Either` | `Refinement` | +| `fromIterable` | `Iterable`, `onEmpty: LazyArg` | `Either` | +| `fromOption` | `Option`, `onNone: LazyArg` | `Either` | + # Working with `Either` Once you have an instance of `Either`, you can use the various functions provided in the `@fp-ts/core/Either` module to work with it. @@ -113,7 +130,25 @@ console.log(parseNumber("2")); // right(2) console.log(parseNumber("Not a number")); // left("Cannot parse 'Not a number' as a number") ``` -# Pattern matching +**Cheat sheet** (sequencing) + +| Name | Given | To | +| --------- | -------------------------------------- | --------------------- | +| `map` | `Either`, `A => B` | `Either` | +| `flatMap` | `Either`, `E1 => Either` | `Either` | + +# Debugging + +At any time, it is possible to inspect what is happening in your pipeline using two utility functions: + +**Cheat sheet** (debugging) + +| Name | Given | To | Description | +| -------------- | --------------------------- | -------------- | ------------------------------------- | +| `inspectRight` | `Either`, `A => void` | `Either` | callback called if it is a `Right` | +| `inspectLeft` | `Either`, `E => void` | `Either` | callback called if it is a `Left` | + +# Pattern matching and error handling The `match` function allows us to match on the `Left` and `Right` cases of an `Either` value and provide different actions for each. @@ -139,3 +174,32 @@ const output = pipe( console.log(output); // Output: Error: Cannot parse 'Not a number' as a number ``` + +**Cheat sheet** (error handling) + +| Name | Given | To | +| ---------------- | --------------------------------------------------- | ---------------- | +| `match` | `Either`, `onLeft: E => B`, `onRight: A => C` | `B \| C` | +| `getOrThrow` | `Either`, `onLeft?: E => Error` | `A` | +| `getOrNull` | `Either` | `A \| null` | +| `getOrUndefined` | `Either` | `A \| undefined` | +| `getOrElse` | `Either`, `onLeft: E => B` | `A \| B` | + +# Interop + +**Cheat sheet** (interop - nullable) + +| Name | Given | To | +| ----------------- | ----------------------------------------------------- | ------------------------------------ | +| `fromNullable` | `A` | `Option>` | +| `liftNullable` | `(...a: A) => B \| null \| undefined` | `(...a: A) => Option` | +| `flatMapNullable` | `Either`, `(...a: A) => B \| null \| undefined` | `Option>` | +| `getOrNull` | `Either` | `A \| null` | +| `getOrUndefined` | `Either` | `A \| undefined` | + +**Cheat sheet** (interop - throwing) + +| Name | Given | To | +| --------------- | ----------------------------------------- | ------------------------ | +| `liftThrowable` | `(...a: A) => B` (may throw) | `(...a: A) => Option` | +| `getOrThrow` | `Either`, `onNone?: LazyArg` | `A` | diff --git a/guides/Option.md b/guides/Option.md index 456d1fdec..63de6eac9 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -84,6 +84,17 @@ const optionBoolean = none(); In this way you don't need to specify the type of the variables `optionNumber`, `optionString`, `optionBoolean` because TypeScript infers the type from the call site. +# Conversions + +**Cheat sheet** (conversions) + +| Name | Given | To | +| -------------- | --------------------------------- | ------------------ | +| `toRefinement` | `A => Option` | `Refinement` | +| `fromIterable` | `Iterable` | `Option` | +| `fromEither` | `Either` | `Option` | +| `toEither` | `Option`, `onNone: LazyArg` | `Either` | + # Modeling optional properties with `Option` Here is an example of a `User` model where the `email` field is of type `Option`. This means that the value of the `email` field may or may not be present and will be of type `string` when it is present. diff --git a/src/Either.ts b/src/Either.ts index 660e67bf0..703f485ac 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -4,7 +4,7 @@ import * as BI from "@fp-ts/core/Bigint" import type { LazyArg } from "@fp-ts/core/Function" -import { constNull, constUndefined, identity, pipe } from "@fp-ts/core/Function" +import { constNull, constUndefined, dual, identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { structural } from "@fp-ts/core/internal/effect" import * as either from "@fp-ts/core/internal/Either" @@ -33,6 +33,10 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" +// ------------------------------------------------------------------------------------- +// models +// ------------------------------------------------------------------------------------- + /** * @category models * @since 1.0.0 @@ -65,6 +69,10 @@ export interface EitherTypeLambda extends TypeLambda { readonly type: Either } +// ------------------------------------------------------------------------------------- +// constructors +// ------------------------------------------------------------------------------------- + /** * Constructs a new `Either` holding a `Right` value. This usually represents a successful value due to the right bias * of this structure. @@ -91,6 +99,10 @@ export const left: (e: E) => Either = either.left */ export const of: (a: A) => Either = right +// ------------------------------------------------------------------------------------- +// guards +// ------------------------------------------------------------------------------------- + /** * Returns `true` if the specified value is an instance of `Either`, `false` * otherwise. @@ -118,6 +130,47 @@ export const isLeft: (self: Either) => self is Left = either.isLe */ export const isRight: (self: Either) => self is Right = either.isRight +// ------------------------------------------------------------------------------------- +// conversions +// ------------------------------------------------------------------------------------- + +/** + * Returns a `Refinement` from a `Either` returning function. + * This function ensures that a `Refinement` definition is type-safe. + * + * @category conversions + * @since 1.0.0 + */ +export const toRefinement = (f: (a: A) => Either): Refinement => + (a: A): a is B => isRight(f(a)) + +/** + * @category conversions + * @since 1.0.0 + */ +export const fromIterable = (onEmpty: LazyArg) => + (collection: Iterable): Either => { + for (const a of collection) { + return right(a) + } + return left(onEmpty()) + } + +/** + * @example + * import * as E from '@fp-ts/core/Either' + * import { pipe } from '@fp-ts/core/Function' + * import * as O from '@fp-ts/core/Option' + * + * assert.deepStrictEqual(pipe(O.some(1), E.fromOption(() => 'error')), E.right(1)) + * assert.deepStrictEqual(pipe(O.none(), E.fromOption(() => 'error')), E.left('error')) + * + * @category conversions + * @since 1.0.0 + */ +export const fromOption: (onNone: LazyArg) => (self: Option) => Either = + either.fromOption + /** * Returns an effect whose Right is mapped by the specified `f` function. * @@ -602,25 +655,29 @@ export const getFirstRightSemigroup: () => Semigroup> = semiC * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual( - * pipe( - * E.right(1), - * E.getOrElse(() => 0) - * ), + * E.getOrElse(E.right(1), () => 0), * 1 * ) * assert.deepStrictEqual( - * pipe( - * E.left('error'), - * E.getOrElse(() => 0) - * ), + * E.getOrElse(E.left('error'), () => 0), * 0 * ) * + * @dual * @category getters * @since 1.0.0 */ -export const getOrElse = (onLeft: LazyArg) => - (self: Either): A | B => isLeft(self) ? onLeft() : self.right +export const getOrElse: { + (self: Either, onLeft: (e: E) => B): A | B + (onLeft: (e: E) => B): (self: Either) => B | A +} = dual< + (self: Either, onLeft: (e: E) => B) => A | B, + (onLeft: (e: E) => B) => (self: Either) => A | B +>( + 2, + (self: Either, onLeft: (e: E) => B): A | B => + isLeft(self) ? onLeft(self.left) : self.right +) /** * Executes this effect and returns its value, if it succeeds, but otherwise @@ -721,6 +778,10 @@ export const Foldable: foldable.Foldable = { export const match = (onLeft: (e: E) => B, onRight: (a: A) => C) => (self: Either): B | C => isLeft(self) ? onLeft(self.left) : onRight(self.right) +// ------------------------------------------------------------------------------------- +// interop +// ------------------------------------------------------------------------------------- + /** * Takes a lazy default and a nullable value, if the value is not nully, turn it into a `Right`, if the value is nully use * the provided default as a `Left`. @@ -733,7 +794,7 @@ export const match = (onLeft: (e: E) => B, onRight: (a: A) => C) * assert.deepStrictEqual(parse(1), E.right(1)) * assert.deepStrictEqual(parse(null), E.left('nullable')) * - * @category conversions + * @category interop * @since 1.0.0 */ export const fromNullable = (onNullable: LazyArg) => @@ -741,7 +802,7 @@ export const fromNullable = (onNullable: LazyArg) => a == null ? left(onNullable()) : right(a as NonNullable) /** - * @category lifting + * @category interop * @since 1.0.0 */ export const liftNullable = , B, E>( @@ -759,16 +820,6 @@ export const flatMapNullable = ( ): ((self: Either) => Either>) => flatMap(liftNullable(f, onNullable)) -/** - * Returns a `Refinement` from a `Either` returning function. - * This function ensures that a `Refinement` definition is type-safe. - * - * @category conversions - * @since 1.0.0 - */ -export const toRefinement = (f: (a: A) => Either): Refinement => - (a: A): a is B => isRight(f(a)) - /** * @category interop * @since 1.0.0 @@ -909,6 +960,10 @@ export const tap: ( Chainable ) +// ------------------------------------------------------------------------------------- +// debugging +// ------------------------------------------------------------------------------------- + /** * @category debugging * @since 1.0.0 @@ -923,23 +978,6 @@ export const inspectRight = ( return self } -/** - * Returns an effect that effectfully "peeks" at the failure of this effect. - * - * @category error handling - * @since 1.0.0 - */ -export const tapError = ( - onLeft: (e: E1) => Either -) => - (self: Either): Either => { - if (isRight(self)) { - return self - } - const out = onLeft(self.left) - return isLeft(out) ? out : self - } - /** * @category debugging * @since 1.0.0 @@ -955,32 +993,22 @@ export const inspectLeft = ( } /** - * @category conversions + * Returns an effect that effectfully "peeks" at the failure of this effect. + * + * @category error handling * @since 1.0.0 */ -export const fromIterable = (onEmpty: LazyArg) => - (collection: Iterable): Either => { - for (const a of collection) { - return right(a) +export const tapError = ( + onLeft: (e: E1) => Either +) => + (self: Either): Either => { + if (isRight(self)) { + return self } - return left(onEmpty()) + const out = onLeft(self.left) + return isLeft(out) ? out : self } -/** - * @example - * import * as E from '@fp-ts/core/Either' - * import { pipe } from '@fp-ts/core/Function' - * import * as O from '@fp-ts/core/Option' - * - * assert.deepStrictEqual(pipe(O.some(1), E.fromOption(() => 'error')), E.right(1)) - * assert.deepStrictEqual(pipe(O.none(), E.fromOption(() => 'error')), E.left('error')) - * - * @category conversions - * @since 1.0.0 - */ -export const fromOption: (onNone: LazyArg) => (self: Option) => Either = - either.fromOption - /** * Converts a `Either` to an `Option` discarding the Right. * diff --git a/src/Option.ts b/src/Option.ts index 2e07ed083..20026d6d6 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -39,7 +39,7 @@ import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" // ------------------------------------------------------------------------------------- -// model +// models // ------------------------------------------------------------------------------------- /** @@ -100,6 +100,14 @@ export const none = (): Option => option.none */ export const some: (value: A) => Option = option.some +/** + * Alias of `some`. + * + * @category constructors + * @since 1.0.0 + */ +export const of: (a: A) => Option = some + // ------------------------------------------------------------------------------------- // guards // ------------------------------------------------------------------------------------- @@ -378,7 +386,7 @@ export const fromNullable = ( * assert.deepStrictEqual(parseOption('1'), some(1)) * assert.deepStrictEqual(parseOption('not a number'), none()) * - * @category lifting + * @category interop * @since 1.0.0 */ export const liftNullable = , B>( @@ -606,11 +614,6 @@ export const as: (b: B) => <_>(self: Option<_>) => Option = covariant.as(C */ export const asUnit: <_>(self: Option<_>) => Option = covariant.asUnit(Covariant) -/** - * @since 1.0.0 - */ -export const of: (a: A) => Option = some - /** * @category instances * @since 1.0.0 @@ -727,6 +730,10 @@ export const tap: (f: (a: A) => Option<_>) => (self: Option) => Option< Chainable ) +// ------------------------------------------------------------------------------------- +// debugging +// ------------------------------------------------------------------------------------- + /** * Useful for debugging purposes, the `onSome` callback is called with the value of `self` if it is a `Some`. * From 2be156fb2cfd7a45d3a7ccf32b7716c7e0d45976 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 12:09:24 +0100 Subject: [PATCH 132/255] Either: add toOption --- docs/modules/Either.ts.md | 23 +++++++++++++++++++++++ guides/Either.md | 1 + src/Either.ts | 17 +++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index ff9eaa7c5..bde9e4531 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -31,6 +31,7 @@ Added in v1.0.0 - [conversions](#conversions) - [fromIterable](#fromiterable) - [fromOption](#fromoption) + - [toOption](#tooption) - [toRefinement](#torefinement) - [debugging](#debugging) - [inspectLeft](#inspectleft) @@ -355,6 +356,28 @@ assert.deepStrictEqual( Added in v1.0.0 +## toOption + +Converts a `Either` to an `Option` discarding the error. + +**Signature** + +```ts +export declare const toOption: (self: Either) => Option +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(E.toOption(E.right(1)), O.some(1)) +assert.deepStrictEqual(E.toOption(E.left('a')), O.none()) +``` + +Added in v1.0.0 + ## toRefinement Returns a `Refinement` from a `Either` returning function. diff --git a/guides/Either.md b/guides/Either.md index 235cb26a0..77bf58bff 100644 --- a/guides/Either.md +++ b/guides/Either.md @@ -75,6 +75,7 @@ The `fromOption` function requires an argument because it needs to know what val | `toRefinement` | `A => Either` | `Refinement` | | `fromIterable` | `Iterable`, `onEmpty: LazyArg` | `Either` | | `fromOption` | `Option`, `onNone: LazyArg` | `Either` | +| `toOption` | `Either` | `Option` | # Working with `Either` diff --git a/src/Either.ts b/src/Either.ts index 703f485ac..a7b8f0784 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -156,6 +156,23 @@ export const fromIterable = (onEmpty: LazyArg) => return left(onEmpty()) } +/** + * Converts a `Either` to an `Option` discarding the error. + * + * @param self - The `Either` to convert to an `Option`. + * + * @example + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(E.toOption(E.right(1)), O.some(1)) + * assert.deepStrictEqual(E.toOption(E.left('a')), O.none()) + * + * @category conversions + * @since 1.0.0 + */ +export const toOption: (self: Either) => Option = either.getRight + /** * @example * import * as E from '@fp-ts/core/Either' From 83a1899ae7d23133e017c94981805e2ed4b936fe Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 12:41:06 +0100 Subject: [PATCH 133/255] Option: add getLeft, getRight --- docs/modules/Either.ts.md | 94 ++++++++++++++++++++------------------- docs/modules/Option.ts.md | 48 ++++++++++++++++++++ docs/modules/These.ts.md | 8 +++- guides/Either.md | 14 +++--- guides/Option.md | 14 +++--- src/Either.ts | 62 +++++++++++++------------- src/Option.ts | 32 +++++++++++++ src/These.ts | 8 +++- test/Either.ts | 6 ++- test/Option.ts | 6 ++- 10 files changed, 198 insertions(+), 94 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index bde9e4531..3f1cd21f7 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -31,6 +31,8 @@ Added in v1.0.0 - [conversions](#conversions) - [fromIterable](#fromiterable) - [fromOption](#fromoption) + - [getLeft](#getleft) + - [getRight](#getright) - [toOption](#tooption) - [toRefinement](#torefinement) - [debugging](#debugging) @@ -54,11 +56,9 @@ Added in v1.0.0 - [filter](#filter) - [filterMap](#filtermap) - [getters](#getters) - - [getLeft](#getleft) - [getOrElse](#getorelse) - [getOrNull](#getornull) - [getOrUndefined](#getorundefined) - - [getRight](#getright) - [merge](#merge) - [guards](#guards) - [isEither](#iseither) @@ -356,6 +356,52 @@ assert.deepStrictEqual( Added in v1.0.0 +## getLeft + +Converts a `Either` to an `Option` discarding the value. + +**Signature** + +```ts +export declare const getLeft: (self: Either) => Option +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(E.getLeft(E.right('ok')), O.none()) +assert.deepStrictEqual(E.getLeft(E.left('err')), O.some('err')) +``` + +Added in v1.0.0 + +## getRight + +Converts a `Either` to an `Option` discarding the error. + +Alias of `toOption`. + +**Signature** + +```ts +export declare const getRight: (self: Either) => Option +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(E.getRight(E.right('ok')), O.some('ok')) +assert.deepStrictEqual(E.getRight(E.left('err')), O.none()) +``` + +Added in v1.0.0 + ## toOption Converts a `Either` to an `Option` discarding the error. @@ -609,28 +655,6 @@ Added in v1.0.0 # getters -## getLeft - -Converts a `Either` to an `Option` discarding the Right. - -**Signature** - -```ts -export declare const getLeft: (self: Either) => Option -``` - -**Example** - -```ts -import * as O from '@fp-ts/core/Option' -import * as E from '@fp-ts/core/Either' - -assert.deepStrictEqual(E.getLeft(E.right('ok')), O.none()) -assert.deepStrictEqual(E.getLeft(E.left('err')), O.some('err')) -``` - -Added in v1.0.0 - ## getOrElse Returns the wrapped value if it's a `Right` or a default value if is a `Left`. @@ -682,28 +706,6 @@ export declare const getOrUndefined: (self: Either) => A | undefined Added in v1.0.0 -## getRight - -Converts a `Either` to an `Option` discarding the error. - -**Signature** - -```ts -export declare const getRight: (self: Either) => Option -``` - -**Example** - -```ts -import * as O from '@fp-ts/core/Option' -import * as E from '@fp-ts/core/Either' - -assert.deepStrictEqual(E.getRight(E.right('ok')), O.some('ok')) -assert.deepStrictEqual(E.getRight(E.left('err')), O.none()) -``` - -Added in v1.0.0 - ## merge **Signature** diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 98b423e41..a4f92afe1 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -31,6 +31,8 @@ Added in v1.0.0 - [conversions](#conversions) - [fromEither](#fromeither) - [fromIterable](#fromiterable) + - [getLeft](#getleft) + - [getRight](#getright) - [toEither](#toeither) - [toRefinement](#torefinement) - [debugging](#debugging) @@ -354,6 +356,52 @@ assert.deepStrictEqual(fromIterable([]), none()) Added in v1.0.0 +## getLeft + +Converts a `Either` to an `Option` discarding the value. + +**Signature** + +```ts +export declare const getLeft: (self: Either) => Option +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(O.getLeft(E.right('ok')), O.none()) +assert.deepStrictEqual(O.getLeft(E.left('err')), O.some('err')) +``` + +Added in v1.0.0 + +## getRight + +Converts a `Either` to an `Option` discarding the error. + +Alias of `fromEither`. + +**Signature** + +```ts +export declare const getRight: (self: Either) => Option +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(O.getRight(E.right('ok')), O.some('ok')) +assert.deepStrictEqual(O.getRight(E.left('err')), O.none()) +``` + +Added in v1.0.0 + ## toEither Converts an `Option` to an `Either`, allowing you to provide a value to be used in the case of a `None`. diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 8736fc5aa..48a22cea7 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -779,6 +779,8 @@ Added in v1.0.0 ## getLeft +Converts a `These` to an `Option` discarding the value (`Both` included). + **Signature** ```ts @@ -789,7 +791,7 @@ Added in v1.0.0 ## getLeftOnly -Returns the `E` value if and only if the value is constructed with `Left` +Returns the error if and only if the value is a `Left` (i.e. `Both` is excluded). **Signature** @@ -831,6 +833,8 @@ Added in v1.0.0 ## getRight +Converts a `These` to an `Option` discarding the error (`Both` included). + **Signature** ```ts @@ -841,7 +845,7 @@ Added in v1.0.0 ## getRightOnly -Returns the `A` value if and only if the value is constructed with `Right` +Returns the value if and only if the value is a `Right` (i.e. `Both` is excluded). **Signature** diff --git a/guides/Either.md b/guides/Either.md index 77bf58bff..0c8657451 100644 --- a/guides/Either.md +++ b/guides/Either.md @@ -70,12 +70,14 @@ The `fromOption` function requires an argument because it needs to know what val **Cheat sheet** (conversions) -| Name | Given | To | -| -------------- | ------------------------------------ | ------------------ | -| `toRefinement` | `A => Either` | `Refinement` | -| `fromIterable` | `Iterable`, `onEmpty: LazyArg` | `Either` | -| `fromOption` | `Option`, `onNone: LazyArg` | `Either` | -| `toOption` | `Either` | `Option` | +| Name | Given | To | Note | +| -------------- | ------------------------------------ | ------------------ | ------------------- | +| `toRefinement` | `A => Either` | `Refinement` | | +| `fromIterable` | `Iterable`, `onEmpty: LazyArg` | `Either` | | +| `fromOption` | `Option`, `onNone: LazyArg` | `Either` | | +| `toOption` | `Either` | `Option` | | +| `getRight` | `Either` | `Option` | alias of `toOption` | +| `getLeft` | `Either` | `Option` | | # Working with `Either` diff --git a/guides/Option.md b/guides/Option.md index 63de6eac9..79c0c739a 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -88,12 +88,14 @@ In this way you don't need to specify the type of the variables `optionNumber`, **Cheat sheet** (conversions) -| Name | Given | To | -| -------------- | --------------------------------- | ------------------ | -| `toRefinement` | `A => Option` | `Refinement` | -| `fromIterable` | `Iterable` | `Option` | -| `fromEither` | `Either` | `Option` | -| `toEither` | `Option`, `onNone: LazyArg` | `Either` | +| Name | Given | To | Note | +| -------------- | --------------------------------- | ------------------ | --------------------- | +| `toRefinement` | `A => Option` | `Refinement` | | +| `fromIterable` | `Iterable` | `Option` | | +| `fromEither` | `Either` | `Option` | | +| `getRight` | `Either` | `Option` | alias of `fromEither` | +| `getLeft` | `Either` | `Option` | | +| `toEither` | `Option`, `onNone: LazyArg` | `Either` | | # Modeling optional properties with `Option` diff --git a/src/Either.ts b/src/Either.ts index a7b8f0784..39e2fe2be 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -173,6 +173,38 @@ export const fromIterable = (onEmpty: LazyArg) => */ export const toOption: (self: Either) => Option = either.getRight +/** + * Converts a `Either` to an `Option` discarding the error. + * + * Alias of `toOption`. + * + * @example + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(E.getRight(E.right('ok')), O.some('ok')) + * assert.deepStrictEqual(E.getRight(E.left('err')), O.none()) + * + * @category conversions + * @since 1.0.0 + */ +export const getRight: (self: Either) => Option = toOption + +/** + * Converts a `Either` to an `Option` discarding the value. + * + * @example + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(E.getLeft(E.right('ok')), O.none()) + * assert.deepStrictEqual(E.getLeft(E.left('err')), O.some('err')) + * + * @category conversions + * @since 1.0.0 + */ +export const getLeft: (self: Either) => Option = either.getLeft + /** * @example * import * as E from '@fp-ts/core/Either' @@ -1026,36 +1058,6 @@ export const tapError = ( return isLeft(out) ? out : self } -/** - * Converts a `Either` to an `Option` discarding the Right. - * - * @example - * import * as O from '@fp-ts/core/Option' - * import * as E from '@fp-ts/core/Either' - * - * assert.deepStrictEqual(E.getLeft(E.right('ok')), O.none()) - * assert.deepStrictEqual(E.getLeft(E.left('err')), O.some('err')) - * - * @category getters - * @since 1.0.0 - */ -export const getLeft: (self: Either) => Option = either.getLeft - -/** - * Converts a `Either` to an `Option` discarding the error. - * - * @example - * import * as O from '@fp-ts/core/Option' - * import * as E from '@fp-ts/core/Either' - * - * assert.deepStrictEqual(E.getRight(E.right('ok')), O.some('ok')) - * assert.deepStrictEqual(E.getRight(E.left('err')), O.none()) - * - * @category getters - * @since 1.0.0 - */ -export const getRight: (self: Either) => Option = either.getRight - /** * @category getters * @since 1.0.0 diff --git a/src/Option.ts b/src/Option.ts index 20026d6d6..5ec4d22ed 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -217,6 +217,38 @@ export const fromIterable = (collection: Iterable): Option => { */ export const fromEither: (self: Either) => Option = either.getRight +/** + * Converts a `Either` to an `Option` discarding the error. + * + * Alias of `fromEither`. + * + * @example + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(O.getRight(E.right('ok')), O.some('ok')) + * assert.deepStrictEqual(O.getRight(E.left('err')), O.none()) + * + * @category conversions + * @since 1.0.0 + */ +export const getRight: (self: Either) => Option = fromEither + +/** + * Converts a `Either` to an `Option` discarding the value. + * + * @example + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(O.getLeft(E.right('ok')), O.none()) + * assert.deepStrictEqual(O.getLeft(E.left('err')), O.some('err')) + * + * @category conversions + * @since 1.0.0 + */ +export const getLeft: (self: Either) => Option = either.getLeft + /** * Converts an `Option` to an `Either`, allowing you to provide a value to be used in the case of a `None`. * diff --git a/src/These.ts b/src/These.ts index cabac74d2..05fb254b0 100644 --- a/src/These.ts +++ b/src/These.ts @@ -416,6 +416,8 @@ export const flatMapThese = ( ) => (self: Validated): Validated => pipe(self, flatMap(liftThese(f))) /** + * Converts a `These` to an `Option` discarding the error (`Both` included). + * * @category getters * @since 1.0.0 */ @@ -424,7 +426,7 @@ export const getRight = ( ): Option => isLeft(self) ? O.none() : O.some(self.right) /** - * Returns the `A` value if and only if the value is constructed with `Right` + * Returns the value if and only if the value is a `Right` (i.e. `Both` is excluded). * * @category getters * @since 1.0.0 @@ -434,6 +436,8 @@ export const getRightOnly = ( ): Option => isRight(self) ? O.some(self.right) : O.none() /** + * Converts a `These` to an `Option` discarding the value (`Both` included). + * * @category getters * @since 1.0.0 */ @@ -442,7 +446,7 @@ export const getLeft = ( ): Option => isRight(self) ? O.none() : O.some(self.left) /** - * Returns the `E` value if and only if the value is constructed with `Left` + * Returns the error if and only if the value is a `Left` (i.e. `Both` is excluded). * * @category getters * @since 1.0.0 diff --git a/test/Either.ts b/test/Either.ts index 79f3bf137..505b15a7f 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -7,7 +7,11 @@ import * as String from "@fp-ts/core/String" import * as Util from "@fp-ts/core/test/util" describe.concurrent("Either", () => { - it("instances and derived exports", () => { + it("exports", () => { + expect(_.toOption).exist + expect(_.getRight).exist + expect(_.getLeft).exist + expect(_.Invariant).exist expect(_.tupled).exist expect(_.bindTo).exist diff --git a/test/Option.ts b/test/Option.ts index 6db17069f..97e1073db 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -11,7 +11,11 @@ import * as Util from "@fp-ts/core/test/util" const p = (n: number): boolean => n > 2 describe.concurrent("Option", () => { - it("instances and derived exports", () => { + it("exports", () => { + expect(_.toEither).exist + expect(_.getRight).exist + expect(_.getLeft).exist + expect(_.Invariant).exist expect(_.tupled).exist expect(_.bindTo).exist From a79ea75ced6ac9bf9eea471dd45f2d6b787ec521 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 13:55:47 +0100 Subject: [PATCH 134/255] Order: apply dual --- docs/modules/typeclass/Order.ts.md | 33 +++++-- src/typeclass/Order.ts | 142 +++++++++++++++++++++++------ test/typeclass/Order.ts | 64 +++++++------ 3 files changed, 173 insertions(+), 66 deletions(-) diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index 10e98253e..686f4f9be 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -249,7 +249,10 @@ Test whether a value is between a minimum and a maximum (inclusive). **Signature** ```ts -export declare const between: (O: Order) => (minimum: A, maximum: A) => (a: A) => boolean +export declare const between: (O: Order) => { + (a: A, minimum: A, maximum: A): boolean + (minimum: A, maximum: A): (a: A) => boolean +} ``` Added in v1.0.0 @@ -261,7 +264,10 @@ Clamp a value between a minimum and a maximum. **Signature** ```ts -export declare const clamp: (O: Order) => (minimum: A, maximum: A) => (a: A) => A +export declare const clamp: (O: Order) => { + (a: A, minimum: A, maximum: A): A + (minimum: A, maximum: A): (a: A) => A +} ``` Added in v1.0.0 @@ -271,7 +277,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const contramap: (f: (b: B) => A) => (self: Order) => Order +export declare const contramap: { + (self: Order, f: (b: B) => A): Order + (f: (b: B) => A): (self: Order) => Order +} ``` Added in v1.0.0 @@ -283,7 +292,7 @@ Test whether one value is _strictly greater than_ another. **Signature** ```ts -export declare const greaterThan: (O: Order) => (that: A) => (self: A) => boolean +export declare const greaterThan: (O: Order) => { (self: A, that: A): boolean; (that: A): (self: A) => boolean } ``` Added in v1.0.0 @@ -295,7 +304,10 @@ Test whether one value is _non-strictly greater than_ another. **Signature** ```ts -export declare const greaterThanOrEqualTo: (O: Order) => (that: A) => (self: A) => boolean +export declare const greaterThanOrEqualTo: (O: Order) => { + (self: A, that: A): boolean + (that: A): (self: A) => boolean +} ``` Added in v1.0.0 @@ -307,7 +319,7 @@ Test whether one value is _strictly less than_ another. **Signature** ```ts -export declare const lessThan: (O: Order) => (that: A) => (self: A) => boolean +export declare const lessThan: (O: Order) => { (self: A, that: A): boolean; (that: A): (self: A) => boolean } ``` Added in v1.0.0 @@ -319,7 +331,10 @@ Test whether one value is _non-strictly less than_ another. **Signature** ```ts -export declare const lessThanOrEqualTo: (O: Order) => (that: A) => (self: A) => boolean +export declare const lessThanOrEqualTo: (O: Order) => { + (self: A, that: A): boolean + (that: A): (self: A) => boolean +} ``` Added in v1.0.0 @@ -331,7 +346,7 @@ Take the maximum of two values. If they are considered equal, the first argument **Signature** ```ts -export declare const max: (O: Order) => (that: A) => (self: A) => A +export declare const max: (O: Order) => { (self: A, that: A): A; (that: A): (self: A) => A } ``` Added in v1.0.0 @@ -343,7 +358,7 @@ Take the minimum of two values. If they are considered equal, the first argument **Signature** ```ts -export declare const min: (O: Order) => (that: A) => (self: A) => A +export declare const min: (O: Order) => { (self: A, that: A): A; (that: A): (self: A) => A } ``` Added in v1.0.0 diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 8229d0a4b..03c318152 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -1,6 +1,7 @@ /** * @since 1.0.0 */ +import { dual } from "@fp-ts/core/Function" import type { TypeLambda } from "@fp-ts/core/HKT" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import type * as invariant from "@fp-ts/core/typeclass/Invariant" @@ -142,10 +143,20 @@ export const reverse = (O: Order): Order => fromCompare((self, that) => O.compare(that, self)) /** + * @dual * @since 1.0.0 */ -export const contramap = (f: (b: B) => A) => - (self: Order): Order => fromCompare((b1, b2) => self.compare(f(b1), f(b2))) +export const contramap: { + (self: Order, f: (b: B) => A): Order + (f: (b: B) => A): (self: Order) => Order +} = dual< + (self: Order, f: (b: B) => A) => Order, + (f: (b: B) => A) => (self: Order) => Order +>( + 2, + (self: Order, f: (b: B) => A): Order => + fromCompare((b1, b2) => self.compare(f(b1), f(b2))) +) /** * @category instances @@ -184,103 +195,180 @@ const empty: Order = fromCompare(() => 0) */ export const getMonoid = (): Monoid> => monoid.fromSemigroup(getSemigroup(), empty) +const imap = contravariant.imap(contramap) + /** * @category instances * @since 1.0.0 */ -export const Contravariant: contravariant.Contravariant = contravariant.make( +export const Contravariant: contravariant.Contravariant = { + imap, contramap -) +} /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap: Contravariant.imap + imap } +const productMany = ( + self: Order, + collection: Iterable> +): Order<[A, ...Array]> => tuple(self, ...collection) + /** * @category instances * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { - imap: Contravariant.imap, + imap, product: tuple, - productMany: (self, collection) => tuple(self, ...collection) + productMany } +const productAll = (collection: Iterable>): Order> => + tuple>(...collection) + +const of: (a: A) => Order = () => empty + /** * @category instances * @since 1.0.0 */ export const Product: product.Product = { - of: () => empty, - imap: Invariant.imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, - productAll: (collection: Iterable>) => tuple>(...collection) + of, + imap, + product: tuple, + productMany, + productAll } /** * Test whether one value is _strictly less than_ another. * + * @dual * @since 1.0.0 */ -export const lessThan = (O: Order) => (that: A) => (self: A) => O.compare(self, that) === -1 +export const lessThan = (O: Order): { + (self: A, that: A): boolean + (that: A): (self: A) => boolean +} => + dual< + (self: A, that: A) => boolean, + (that: A) => (self: A) => boolean + >(2, (self: A, that: A) => O.compare(self, that) === -1) /** * Test whether one value is _strictly greater than_ another. * + * @dual * @since 1.0.0 */ -export const greaterThan = (O: Order) => (that: A) => (self: A) => O.compare(self, that) === 1 +export const greaterThan = (O: Order): { + (self: A, that: A): boolean + (that: A): (self: A) => boolean +} => + dual< + (self: A, that: A) => boolean, + (that: A) => (self: A) => boolean + >(2, (self: A, that: A) => O.compare(self, that) === 1) /** * Test whether one value is _non-strictly less than_ another. * + * @dual * @since 1.0.0 */ -export const lessThanOrEqualTo = (O: Order) => - (that: A) => (self: A) => O.compare(self, that) !== 1 +export const lessThanOrEqualTo = (O: Order): { + (self: A, that: A): boolean + (that: A): (self: A) => boolean +} => + dual< + (self: A, that: A) => boolean, + (that: A) => (self: A) => boolean + >(2, (self: A, that: A) => O.compare(self, that) !== 1) /** * Test whether one value is _non-strictly greater than_ another. * + * @dual * @since 1.0.0 */ -export const greaterThanOrEqualTo = (O: Order) => - (that: A) => (self: A) => O.compare(self, that) !== -1 +export const greaterThanOrEqualTo = (O: Order): { + (self: A, that: A): boolean + (that: A): (self: A) => boolean +} => + dual< + (self: A, that: A) => boolean, + (that: A) => (self: A) => boolean + >(2, (self: A, that: A) => O.compare(self, that) !== -1) /** * Take the minimum of two values. If they are considered equal, the first argument is chosen. * + * @dual * @since 1.0.0 */ -export const min = (O: Order) => - (that: A) => (self: A): A => self === that || O.compare(self, that) < 1 ? self : that +export const min = (O: Order): { + (self: A, that: A): A + (that: A): (self: A) => A +} => + dual< + (self: A, that: A) => A, + (that: A) => (self: A) => A + >(2, (self: A, that: A) => self === that || O.compare(self, that) < 1 ? self : that) /** * Take the maximum of two values. If they are considered equal, the first argument is chosen. * + * @dual * @since 1.0.0 */ -export const max = (O: Order) => - (that: A) => (self: A): A => self === that || O.compare(self, that) > -1 ? self : that +export const max = (O: Order): { + (self: A, that: A): A + (that: A): (self: A) => A +} => + dual< + (self: A, that: A) => A, + (that: A) => (self: A) => A + >(2, (self: A, that: A) => self === that || O.compare(self, that) > -1 ? self : that) /** * Clamp a value between a minimum and a maximum. * + * @dual * @since 1.0.0 */ -export const clamp = (O: Order) => - (minimum: A, maximum: A) => (a: A) => min(O)(max(O)(a)(minimum))(maximum) +export const clamp = (O: Order): { + (a: A, minimum: A, maximum: A): A + (minimum: A, maximum: A): (a: A) => A +} => + dual< + (a: A, minimum: A, maximum: A) => A, + (minimum: A, maximum: A) => (a: A) => A + >( + 3, + (a: A, minimum: A, maximum: A): A => min(O)(maximum, max(O)(minimum, a)) + ) /** * Test whether a value is between a minimum and a maximum (inclusive). * + * @dual * @since 1.0.0 */ -export const between = (O: Order) => - (minimum: A, maximum: A) => - (a: A): boolean => !lessThan(O)(minimum)(a) && !greaterThan(O)(maximum)(a) +export const between = (O: Order): { + (a: A, minimum: A, maximum: A): boolean + (minimum: A, maximum: A): (a: A) => boolean +} => + dual< + (a: A, minimum: A, maximum: A) => boolean, + (minimum: A, maximum: A) => (a: A) => boolean + >( + 3, + (a: A, minimum: A, maximum: A): boolean => + !lessThan(O)(a, minimum) && !greaterThan(O)(a, maximum) + ) diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index 9e59bcfb1..b0379e29a 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -4,6 +4,10 @@ import * as _ from "@fp-ts/core/typeclass/Order" import * as U from "../util" describe("Order", () => { + it("exports", () => { + expect(_.Contravariant).exist + }) + it("bigint", () => { const O = _.bigint expect(pipe(1n, _.lessThanOrEqualTo(O)(2n))).toBe(true) @@ -27,8 +31,8 @@ describe("Order", () => { U.deepStrictEqual(O.compare({ a: "a", b: 1, c: true }, { a: "a", b: 1, c: true }), 0) }) - it("Contravariant", () => { - const O = pipe(_.number, _.Contravariant.contramap((s: string) => s.length)) + it("contramap", () => { + const O = _.contramap(_.number, (s: string) => s.length) U.deepStrictEqual(O.compare("a", "b"), 0) U.deepStrictEqual(O.compare("a", "bb"), -1) U.deepStrictEqual(O.compare("aa", "b"), 1) @@ -119,20 +123,20 @@ describe("Order", () => { it("clamp", () => { const clamp = _.clamp(_.number) - U.deepStrictEqual(clamp(1, 10)(2), 2) - U.deepStrictEqual(clamp(1, 10)(10), 10) - U.deepStrictEqual(clamp(1, 10)(20), 10) - U.deepStrictEqual(clamp(1, 10)(1), 1) - U.deepStrictEqual(clamp(1, 10)(-10), 1) + U.deepStrictEqual(clamp(2, 1, 10), 2) + U.deepStrictEqual(clamp(10, 1, 10), 10) + U.deepStrictEqual(clamp(20, 1, 10), 10) + U.deepStrictEqual(clamp(1, 1, 10), 1) + U.deepStrictEqual(clamp(-10, 1, 10), 1) }) it("between", () => { const between = _.between(_.number) - U.deepStrictEqual(between(1, 10)(2), true) - U.deepStrictEqual(between(1, 10)(10), true) - U.deepStrictEqual(between(1, 10)(20), false) - U.deepStrictEqual(between(1, 10)(1), true) - U.deepStrictEqual(between(1, 10)(-10), false) + U.deepStrictEqual(between(2, 1, 10), true) + U.deepStrictEqual(between(10, 1, 10), true) + U.deepStrictEqual(between(20, 1, 10), false) + U.deepStrictEqual(between(1, 1, 10), true) + U.deepStrictEqual(between(-10, 1, 10), false) }) it("reverse", () => { @@ -144,30 +148,30 @@ describe("Order", () => { it("lessThan", () => { const lessThan = _.lessThan(_.number) - U.deepStrictEqual(pipe(0, lessThan(1)), true) - U.deepStrictEqual(pipe(1, lessThan(1)), false) - U.deepStrictEqual(pipe(2, lessThan(1)), false) + U.deepStrictEqual(lessThan(0, 1), true) + U.deepStrictEqual(lessThan(1, 1), false) + U.deepStrictEqual(lessThan(2, 1), false) }) it("lessThanOrEqualTo", () => { const lessThanOrEqualTo = _.lessThanOrEqualTo(_.number) - U.deepStrictEqual(pipe(0, lessThanOrEqualTo(1)), true) - U.deepStrictEqual(pipe(1, lessThanOrEqualTo(1)), true) - U.deepStrictEqual(pipe(2, lessThanOrEqualTo(1)), false) + U.deepStrictEqual(lessThanOrEqualTo(0, 1), true) + U.deepStrictEqual(lessThanOrEqualTo(1, 1), true) + U.deepStrictEqual(lessThanOrEqualTo(2, 1), false) }) it("greaterThan", () => { const greaterThan = _.greaterThan(_.number) - U.deepStrictEqual(pipe(0, greaterThan(1)), false) - U.deepStrictEqual(pipe(1, greaterThan(1)), false) - U.deepStrictEqual(pipe(2, greaterThan(1)), true) + U.deepStrictEqual(greaterThan(0, 1), false) + U.deepStrictEqual(greaterThan(1, 1), false) + U.deepStrictEqual(greaterThan(2, 1), true) }) it("greaterThanOrEqualTo", () => { const greaterThanOrEqualTo = _.greaterThanOrEqualTo(_.number) - U.deepStrictEqual(pipe(0, greaterThanOrEqualTo(1)), false) - U.deepStrictEqual(pipe(1, greaterThanOrEqualTo(1)), true) - U.deepStrictEqual(pipe(2, greaterThanOrEqualTo(1)), true) + U.deepStrictEqual(greaterThanOrEqualTo(0, 1), false) + U.deepStrictEqual(greaterThanOrEqualTo(1, 1), true) + U.deepStrictEqual(greaterThanOrEqualTo(2, 1), true) }) it("min", () => { @@ -178,11 +182,11 @@ describe("Order", () => { _.contramap((a: A) => a.a) ) ) - U.deepStrictEqual(pipe({ a: 1 }, min({ a: 2 })), { a: 1 }) - U.deepStrictEqual(pipe({ a: 2 }, min({ a: 1 })), { a: 1 }) + U.deepStrictEqual(min({ a: 1 }, { a: 2 }), { a: 1 }) + U.deepStrictEqual(min({ a: 2 }, { a: 1 }), { a: 1 }) const first = { a: 1 } const second = { a: 1 } - U.strictEqual(pipe(first, min(second)), first) + U.strictEqual(min(first, second), first) }) it("max", () => { @@ -193,11 +197,11 @@ describe("Order", () => { _.contramap((a: A) => a.a) ) ) - U.deepStrictEqual(pipe({ a: 1 }, max({ a: 2 })), { a: 2 }) - U.deepStrictEqual(pipe({ a: 2 }, max({ a: 1 })), { a: 2 }) + U.deepStrictEqual(max({ a: 1 }, { a: 2 }), { a: 2 }) + U.deepStrictEqual(max({ a: 2 }, { a: 1 }), { a: 2 }) const first = { a: 1 } const second = { a: 1 } - U.strictEqual(pipe(first, max(second)), first) + U.strictEqual(max(first, second), first) }) describe("SemiProduct", () => { From 38d2db2f7e410c4726bb067c2bf48e7c084cc4e4 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 14:30:51 +0100 Subject: [PATCH 135/255] simplify getOrThrow --- docs/modules/Either.ts.md | 7 ++- docs/modules/Option.ts.md | 38 ++++++++++---- docs/modules/These.ts.md | 4 +- guides/Either.md | 10 ++-- guides/Option.md | 18 +++---- src/Either.ts | 19 ++++--- src/Option.ts | 102 +++++++++++++++++++++++++++----------- src/These.ts | 24 ++++----- src/internal/Either.ts | 11 +++- test/Either.ts | 7 +-- test/Option.ts | 7 +-- test/These.ts | 19 +++---- 12 files changed, 160 insertions(+), 106 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 3f1cd21f7..6e035ff2b 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -328,7 +328,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromOption: (onNone: LazyArg) => (self: Option) => Either +export declare const fromOption: { + (fa: Option, onNone: () => E): Either + (onNone: () => E): (fa: Option) => Either +} ``` **Example** @@ -961,7 +964,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getOrThrow: (onLeft?: (e: E) => Error) => (self: Either) => A +export declare const getOrThrow: (self: Either) => A ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index a4f92afe1..396ce8414 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -409,7 +409,10 @@ Converts an `Option` to an `Either`, allowing you to provide a value to be used **Signature** ```ts -export declare const toEither: (onNone: LazyArg) => (self: Option) => Either +export declare const toEither: { + (fa: Option, onNone: () => E): Either + (onNone: () => E): (fa: Option) => Either +} ``` **Example** @@ -549,7 +552,10 @@ Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` **Signature** ```ts -export declare const getOrElse: (onNone: LazyArg) => (self: Option) => B | A +export declare const getOrElse: { + (self: Option, onNone: LazyArg): A | B + (onNone: LazyArg): (self: Option) => B | A +} ``` **Example** @@ -583,7 +589,10 @@ Returns the provided `Option` `that` if `self` is `None`, otherwise returns `sel **Signature** ```ts -export declare const orElse: (that: LazyArg>) => (self: Option) => Option +export declare const orElse: { + (self: Option, that: LazyArg>): Option + (that: LazyArg>): (self: Option) => Option +} ``` **Example** @@ -634,7 +643,10 @@ This is useful when it's important to know whether the value was retrieved from **Signature** ```ts -export declare const orElseEither: (that: LazyArg>) => (self: Option) => Option> +export declare const orElseEither: { + (self: Option, that: LazyArg>): Option> + (that: LazyArg>): (self: Option) => Option> +} ``` Added in v1.0.0 @@ -1040,7 +1052,7 @@ Returns the contained value if the `Option` is `Some`, otherwise throws an error **Signature** ```ts -export declare const getOrThrow: (onNone?: LazyArg) => (self: Option) => A +export declare const getOrThrow: (self: Option) => A ``` **Example** @@ -1049,8 +1061,8 @@ export declare const getOrThrow: (onNone?: LazyArg) => (self: Option pipe(O.none(), O.getOrThrow())) +assert.deepStrictEqual(pipe(O.some(1), O.getOrThrow), 1) +assert.throws(() => pipe(O.none(), O.getOrThrow)) ``` Added in v1.0.0 @@ -1274,7 +1286,10 @@ Maps the given function to the value of the `Option` if it is a `Some`, otherwis **Signature** ```ts -export declare const map: (f: (a: A) => B) => (self: Option) => Option +export declare const map: { + (self: Option, f: (a: A) => B): Option + (f: (a: A) => B): (self: Option) => Option +} ``` Added in v1.0.0 @@ -1434,9 +1449,10 @@ This is `flatMap` + `fromNullable`, useful when working with optional values. **Signature** ```ts -export declare const flatMapNullable: ( - f: (a: A) => B | null | undefined -) => (self: Option) => Option> +export declare const flatMapNullable: { + (self: Option, f: (a: A) => B | null | undefined): Option> + (f: (a: A) => B | null | undefined): (self: Option) => Option> +} ``` **Example** diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 48a22cea7..f3f8b8fa8 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1107,7 +1107,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getOrThrow: (onLeft?: (e: E) => Error) => (self: These) => A +export declare const getOrThrow: (self: These) => A ``` Added in v1.0.0 @@ -1117,7 +1117,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getRightOnlyOrThrow: (onLeft: (e: E) => unknown) => (self: These) => A +export declare const getRightOnlyOrThrow: (self: These) => A ``` Added in v1.0.0 diff --git a/guides/Either.md b/guides/Either.md index 0c8657451..9592b6333 100644 --- a/guides/Either.md +++ b/guides/Either.md @@ -183,7 +183,7 @@ console.log(output); // Output: Error: Cannot parse 'Not a number' as a number | Name | Given | To | | ---------------- | --------------------------------------------------- | ---------------- | | `match` | `Either`, `onLeft: E => B`, `onRight: A => C` | `B \| C` | -| `getOrThrow` | `Either`, `onLeft?: E => Error` | `A` | +| `getOrThrow` | `Either` | `A` | | `getOrNull` | `Either` | `A \| null` | | `getOrUndefined` | `Either` | `A \| undefined` | | `getOrElse` | `Either`, `onLeft: E => B` | `A \| B` | @@ -202,7 +202,7 @@ console.log(output); // Output: Error: Cannot parse 'Not a number' as a number **Cheat sheet** (interop - throwing) -| Name | Given | To | -| --------------- | ----------------------------------------- | ------------------------ | -| `liftThrowable` | `(...a: A) => B` (may throw) | `(...a: A) => Option` | -| `getOrThrow` | `Either`, `onNone?: LazyArg` | `A` | +| Name | Given | To | +| --------------- | ---------------------------- | ------------------------ | +| `liftThrowable` | `(...a: A) => B` (may throw) | `(...a: A) => Option` | +| `getOrThrow` | `Either` | `A` | diff --git a/guides/Option.md b/guides/Option.md index 79c0c739a..286dac873 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -315,8 +315,8 @@ The fastest way to get the value wrapped in an option is to call the `getOrThrow ```ts import { getOrThrow } from "@fp-ts/core/Option"; -console.log(pipe(some(10), getOrThrow()); // 10 -console.log(pipe(none(), getOrThrow()); // throws new Error("getOrThrow called on a None") +console.log(pipe(some(10), getOrThrow); // 10 +console.log(pipe(none(), getOrThrow); // throws new Error("getOrThrow called on a None") ``` A more safe alternative is [pattern matching](https://github.com/gvergnaud/ts-pattern#what-is-pattern-matching) on the `Option`. @@ -374,7 +374,7 @@ pipe( | Name | Given | To | | ---------------- | --------------------------------------------------- | ---------------- | | `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | -| `getOrThrow` | `Option`, `onNone?: LazyArg` | `A` | +| `getOrThrow` | `Option` | `A` | | `getOrNull` | `Option` | `A \| null` | | `getOrUndefined` | `Option` | `A \| undefined` | | `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | @@ -478,16 +478,16 @@ On the other hand, if we have a value of type `Option` and want to get the wrapp ```ts import { getOrThrow } from "@fp-ts/core/Option"; -console.log(pipe(some(10), getOrThrow()); // 10 -console.log(pipe(none(), getOrThrow()); // throws new Error("getOrThrow called on a None") +console.log(pipe(some(10), getOrThrow); // 10 +console.log(pipe(none(), getOrThrow); // throws new Error("getOrThrow called on a None") ``` **Cheat sheet** (interop - throwing) -| Name | Given | To | -| --------------- | -------------------------------------- | ------------------------ | -| `liftThrowable` | `(...a: A) => B` (may throw) | `(...a: A) => Option` | -| `getOrThrow` | `Option`, `onNone?: LazyArg` | `A` | +| Name | Given | To | +| --------------- | ---------------------------- | ------------------------ | +| `liftThrowable` | `(...a: A) => B` (may throw) | `(...a: A) => Option` | +| `getOrThrow` | `Option` | `A` | # Combining two or more `Option`s diff --git a/src/Either.ts b/src/Either.ts index 39e2fe2be..b59af438b 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -217,8 +217,10 @@ export const getLeft: (self: Either) => Option = either.getLeft * @category conversions * @since 1.0.0 */ -export const fromOption: (onNone: LazyArg) => (self: Option) => Either = - either.fromOption +export const fromOption: { + (fa: Option, onNone: () => E): Either + (onNone: () => E): (fa: Option) => Either +} = either.fromOption /** * Returns an effect whose Right is mapped by the specified `f` function. @@ -873,15 +875,12 @@ export const flatMapNullable = ( * @category interop * @since 1.0.0 */ -export const getOrThrow = ( - onLeft: (e: E) => Error = () => new Error("getOrThrow called on a Left") -) => - (self: Either): A => { - if (isRight(self)) { - return self.right - } - throw onLeft(self.left) +export const getOrThrow = (self: Either): A => { + if (isRight(self)) { + return self.right } + throw new Error("getOrThrow called on a Left") +} /** * Lifts a function that may throw to one returning a `Either`. diff --git a/src/Option.ts b/src/Option.ts index 5ec4d22ed..8d08742dd 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -4,7 +4,7 @@ import * as BI from "@fp-ts/core/Bigint" import type { Either } from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" -import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" +import { constNull, constUndefined, dual, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { structural } from "@fp-ts/core/internal/effect" import * as either from "@fp-ts/core/internal/Either" @@ -267,8 +267,10 @@ export const getLeft: (self: Either) => Option = either.getLeft * @category conversions * @since 1.0.0 */ -export const toEither: (onNone: LazyArg) => (self: Option) => Either = - either.fromOption +export const toEither: { + (fa: Option, onNone: () => E): Either + (onNone: () => E): (fa: Option) => Either +} = either.fromOption // ------------------------------------------------------------------------------------- // error handling @@ -287,11 +289,20 @@ export const toEither: (onNone: LazyArg) => (self: Option) => Either * assert.deepStrictEqual(pipe(some(1), getOrElse(() => 0)), 1) * assert.deepStrictEqual(pipe(none(), getOrElse(() => 0)), 0) * + * @dual * @category error handling * @since 1.0.0 */ -export const getOrElse = (onNone: LazyArg) => - (self: Option): A | B => isNone(self) ? onNone() : self.value +export const getOrElse: { + (self: Option, onNone: LazyArg): A | B + (onNone: LazyArg): (self: Option) => B | A +} = dual< + (self: Option, onNone: LazyArg) => A | B, + (onNone: LazyArg) => (self: Option) => A | B +>( + 2, + (self: Option, onNone: LazyArg): A | B => isNone(self) ? onNone() : self.value +) /** * Returns the provided `Option` `that` if `self` is `None`, otherwise returns `self`. @@ -332,11 +343,20 @@ export const getOrElse = (onNone: LazyArg) => * O.some('a') * ) * + * @dual * @category error handling * @since 1.0.0 */ -export const orElse = (that: LazyArg>) => - (self: Option): Option => isNone(self) ? that() : self +export const orElse: { + (self: Option, that: LazyArg>): Option + (that: LazyArg>): (self: Option) => Option +} = dual< + (self: Option, that: LazyArg>) => Option, + (that: LazyArg>) => (self: Option) => Option +>( + 2, + (self: Option, that: LazyArg>): Option => isNone(self) ? that() : self +) /** * Similar to `orElse`, but instead of returning a simple union, it returns an `Either` object, @@ -347,16 +367,23 @@ export const orElse = (that: LazyArg>) => * @param that - The second `Option` to be considered if the first `Option` is `None`. * @param self - The first `Option` to be checked. * + * @dual * @category error handling * @since 1.0.0 */ -export const orElseEither = ( - that: LazyArg> -) => - (self: Option): Option> => - isNone(self) ? - pipe(that(), map(either.right)) : - pipe(self, map(either.left)) +export const orElseEither: { + (self: Option, that: LazyArg>): Option> + (that: LazyArg>): (self: Option) => Option> +} = dual< + (self: Option, that: LazyArg>) => Option>, + ( + that: LazyArg> + ) => (self: Option) => Option> +>( + 2, + (self: Option, that: LazyArg>): Option> => + isNone(self) ? map(that(), either.right) : map(self, either.left) +) /** * Given an Iterable collection of `Option`s, the function returns the first `Some` found in the collection. @@ -496,11 +523,21 @@ export const getOrUndefined: (self: Option) => A | undefined = getOrElse(c * none() * ) * + * @dual * @category sequencing * @since 1.0.0 */ -export const flatMapNullable = (f: (a: A) => B | null | undefined) => - (self: Option): Option> => isNone(self) ? none() : fromNullable(f(self.value)) +export const flatMapNullable: { + (self: Option, f: (a: A) => B | null | undefined): Option> + (f: (a: A) => B | null | undefined): (self: Option) => Option> +} = dual< + (self: Option, f: (a: A) => B | null | undefined) => Option>, + (f: (a: A) => B | null | undefined) => (self: Option) => Option> +>( + 2, + (self: Option, f: (a: A) => B | null | undefined): Option> => + isNone(self) ? none() : fromNullable(f(self.value)) +) /** * A utility function that lifts a function that throws exceptions into a function that returns an `Option`. @@ -535,29 +572,25 @@ export const liftThrowable = , B>( /** * Returns the contained value if the `Option` is `Some`, otherwise throws an error. * - * @param onNone - An optional function that returns the error to be thrown when the `Option` is `None`. * @param self - The `Option` to extract the value from. - * @throws The error returned by `onNone` if the `Option` is `None`. + * @throws `Error("getOrThrow called on a None")` * * @example * import { pipe } from '@fp-ts/core/Function' * import * as O from '@fp-ts/core/Option' * - * assert.deepStrictEqual(pipe(O.some(1), O.getOrThrow()), 1) - * assert.throws(() => pipe(O.none(), O.getOrThrow())) + * assert.deepStrictEqual(pipe(O.some(1), O.getOrThrow), 1) + * assert.throws(() => pipe(O.none(), O.getOrThrow)) * * @category interop * @since 1.0.0 */ -export const getOrThrow = ( - onNone: LazyArg = () => new Error("getOrThrow called on a None") -) => - (self: Option): A => { - if (isSome(self)) { - return self.value - } - throw onNone() +export const getOrThrow = (self: Option): A => { + if (isSome(self)) { + return self.value } + throw new Error("getOrThrow called on a None") +} // ------------------------------------------------------------------------------------- // instances @@ -569,11 +602,20 @@ export const getOrThrow = ( * @param f - The function to map over the value of the `Option` * @param self - An `Option` to map * + * @dual * @category mapping * @since 1.0.0 */ -export const map = (f: (a: A) => B) => - (self: Option): Option => isNone(self) ? none() : some(f(self.value)) +export const map: { + (self: Option, f: (a: A) => B): Option + (f: (a: A) => B): (self: Option) => Option +} = dual< + (self: Option, f: (a: A) => B) => Option, + (f: (a: A) => B) => (self: Option) => Option +>( + 2, + (self: Option, f: (a: A) => B): Option => isNone(self) ? none() : some(f(self.value)) +) const imap = covariant.imap(map) diff --git a/src/These.ts b/src/These.ts index 05fb254b0..406908d1e 100644 --- a/src/These.ts +++ b/src/These.ts @@ -244,27 +244,23 @@ export const liftThrowable = , B, E>( * @category interop * @since 1.0.0 */ -export const getOrThrow = ( - onLeft: (e: E) => Error = () => new Error("getOrThrow called on a Left") -) => - (self: These): A => { - if (isRightOrBoth(self)) { - return self.right - } - throw onLeft(self.left) +export const getOrThrow = (self: These): A => { + if (isRightOrBoth(self)) { + return self.right } + throw new Error("getOrThrow called on a Left") +} /** * @category interop * @since 1.0.0 */ -export const getRightOnlyOrThrow = (onLeft: (e: E) => unknown) => - (self: These): A => { - if (isRight(self)) { - return self.right - } - throw onLeft(self.left) +export const getRightOnlyOrThrow = (self: These): A => { + if (isRight(self)) { + return self.right } + throw new Error("getRightOnlyOrThrow called on Left or Both") +} /** * @category conversions diff --git a/src/internal/Either.ts b/src/internal/Either.ts index e0cce556b..44cd8713f 100644 --- a/src/internal/Either.ts +++ b/src/internal/Either.ts @@ -3,6 +3,7 @@ */ import type { Either, Left, Right } from "@fp-ts/core/Either" +import { dual } from "@fp-ts/core/Function" import { proto } from "@fp-ts/core/internal/effect" import * as option from "@fp-ts/core/internal/Option" import type { Option } from "@fp-ts/core/Option" @@ -32,5 +33,11 @@ export const getRight = ( ): Option => (isLeft(self) ? option.none : option.some(self.right)) /** @internal */ -export const fromOption = (onNone: () => E) => - (fa: Option): Either => option.isNone(fa) ? left(onNone()) : right(fa.value) +export const fromOption = dual< + (fa: Option, onNone: () => E) => Either, + (onNone: () => E) => (fa: Option) => Either +>( + 2, + (fa: Option, onNone: () => E): Either => + option.isNone(fa) ? left(onNone()) : right(fa.value) +) diff --git a/test/Either.ts b/test/Either.ts index 505b15a7f..c54c4d316 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -166,11 +166,8 @@ describe.concurrent("Either", () => { }) it("getOrThrow", () => { - expect(pipe(_.right(1), _.getOrThrow((e: string) => new Error(e)))).toEqual(1) - expect(() => pipe(_.left("e"), _.getOrThrow((e: string) => new Error(e)))).toThrowError( - new Error("e") - ) - expect(() => pipe(_.left("e"), _.getOrThrow())).toThrowError( + expect(pipe(_.right(1), _.getOrThrow)).toEqual(1) + expect(() => pipe(_.left("e"), _.getOrThrow)).toThrowError( new Error("getOrThrow called on a Left") ) }) diff --git a/test/Option.ts b/test/Option.ts index 97e1073db..6915b8483 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -188,11 +188,8 @@ describe.concurrent("Option", () => { }) it("getOrThrow", () => { - expect(pipe(_.some(1), _.getOrThrow(() => new Error("e")))).toEqual(1) - expect(() => pipe(_.none(), _.getOrThrow(() => new Error("e")))).toThrowError( - new Error("e") - ) - expect(() => pipe(_.none(), _.getOrThrow())).toThrowError( + expect(pipe(_.some(1), _.getOrThrow)).toEqual(1) + expect(() => pipe(_.none(), _.getOrThrow)).toThrowError( new Error("getOrThrow called on a None") ) }) diff --git a/test/These.ts b/test/These.ts index 69e025535..5e8593785 100644 --- a/test/These.ts +++ b/test/These.ts @@ -568,23 +568,20 @@ describe("These", () => { }) it("getOrThrow", () => { - expect(pipe(_.right(1), _.getOrThrow((e: string) => new Error(e)))).toEqual(1) - expect(pipe(_.both("e", 1), _.getOrThrow((e: string) => new Error(e)))).toEqual(1) - expect(() => pipe(_.left("e"), _.getOrThrow((e: string) => new Error(e)))).toThrowError( - new Error("e") - ) - expect(() => pipe(_.left("e"), _.getOrThrow())).toThrowError( + expect(pipe(_.right(1), _.getOrThrow)).toEqual(1) + expect(pipe(_.both("e", 1), _.getOrThrow)).toEqual(1) + expect(() => pipe(_.left("e"), _.getOrThrow)).toThrowError( new Error("getOrThrow called on a Left") ) }) it("getRightOnlyOrThrow", () => { - expect(pipe(_.right(1), _.getRightOnlyOrThrow((e: string) => new Error(e)))).toEqual(1) - expect(() => pipe(_.left("e"), _.getRightOnlyOrThrow((e: string) => new Error(e)))).toThrow( - new Error("e") + expect(pipe(_.right(1), _.getRightOnlyOrThrow)).toEqual(1) + expect(() => pipe(_.left("e"), _.getRightOnlyOrThrow)).toThrow( + new Error("getRightOnlyOrThrow called on Left or Both") ) - expect(() => pipe(_.both("e", 1), _.getRightOnlyOrThrow((e: string) => new Error(e)))).toThrow( - new Error("e") + expect(() => pipe(_.both("e", 1), _.getRightOnlyOrThrow)).toThrow( + new Error("getRightOnlyOrThrow called on Left or Both") ) }) From 76f2b4c12cd8c731b81fc86b54f312900a7d03a8 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 17:39:10 +0100 Subject: [PATCH 136/255] Option: apply dual --- docs/modules/Bigint.ts.md | 8 +- docs/modules/Either.ts.md | 49 ++-- docs/modules/Number.ts.md | 8 +- docs/modules/Option.ts.md | 92 +++++-- docs/modules/These.ts.md | 93 +++++-- docs/modules/typeclass/SemiApplicative.ts.md | 9 +- src/Bigint.ts | 39 ++- src/Either.ts | 60 ++++- src/Number.ts | 39 ++- src/Option.ts | 253 ++++++++++++++----- src/These.ts | 83 +++++- src/typeclass/SemiApplicative.ts | 10 +- 12 files changed, 570 insertions(+), 173 deletions(-) diff --git a/docs/modules/Bigint.ts.md b/docs/modules/Bigint.ts.md index c3c444e65..4308ff4dc 100644 --- a/docs/modules/Bigint.ts.md +++ b/docs/modules/Bigint.ts.md @@ -43,7 +43,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const divide: (that: bigint) => (self: bigint) => bigint +export declare const divide: { (self: bigint, that: bigint): bigint; (that: bigint): (self: bigint) => bigint } ``` Added in v1.0.0 @@ -53,7 +53,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiply: (that: bigint) => (self: bigint) => bigint +export declare const multiply: { (self: bigint, that: bigint): bigint; (that: bigint): (self: bigint) => bigint } ``` Added in v1.0.0 @@ -63,7 +63,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtract: (that: bigint) => (self: bigint) => bigint +export declare const subtract: { (self: bigint, that: bigint): bigint; (that: bigint): (self: bigint) => bigint } ``` Added in v1.0.0 @@ -73,7 +73,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const sum: (that: bigint) => (self: bigint) => bigint +export declare const sum: { (self: bigint, that: bigint): bigint; (that: bigint): (self: bigint) => bigint } ``` Added in v1.0.0 diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 6e035ff2b..ba8779c8f 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -140,7 +140,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const divide: (that: Either) => (self: Either) => Either +export declare const divide: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} ``` Added in v1.0.0 @@ -150,9 +153,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiply: ( - that: Either -) => (self: Either) => Either +export declare const multiply: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} ``` Added in v1.0.0 @@ -162,9 +166,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiplyBigint: ( - that: Either -) => (self: Either) => Either +export declare const multiplyBigint: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} ``` Added in v1.0.0 @@ -174,9 +179,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtract: ( - that: Either -) => (self: Either) => Either +export declare const subtract: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} ``` Added in v1.0.0 @@ -186,9 +192,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtractBigint: ( - that: Either -) => (self: Either) => Either +export declare const subtractBigint: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} ``` Added in v1.0.0 @@ -198,7 +205,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const sum: (that: Either) => (self: Either) => Either +export declare const sum: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} ``` Added in v1.0.0 @@ -208,9 +218,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const sumBigint: ( - that: Either -) => (self: Either) => Either +export declare const sumBigint: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} ``` Added in v1.0.0 @@ -1007,8 +1018,8 @@ Lifts a binary function into `Either`. ```ts export declare const lift2: ( - f: (a: A) => (b: B) => C -) => (that: Either) => (self: Either) => Either + f: (a: A, b: B) => C +) => (self: Either, that: Either) => Either ``` Added in v1.0.0 diff --git a/docs/modules/Number.ts.md b/docs/modules/Number.ts.md index 5a9f7c5ee..5438f625d 100644 --- a/docs/modules/Number.ts.md +++ b/docs/modules/Number.ts.md @@ -51,7 +51,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const divide: (that: number) => (self: number) => number +export declare const divide: { (self: number, that: number): number; (that: number): (self: number) => number } ``` **Example** @@ -70,7 +70,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiply: (that: number) => (self: number) => number +export declare const multiply: { (self: number, that: number): number; (that: number): (self: number) => number } ``` **Example** @@ -99,7 +99,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtract: (that: number) => (self: number) => number +export declare const subtract: { (self: number, that: number): number; (that: number): (self: number) => number } ``` **Example** @@ -118,7 +118,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const sum: (that: number) => (self: number) => number +export declare const sum: { (self: number, that: number): number; (that: number): (self: number) => number } ``` **Example** diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 396ce8414..3c1e67096 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -142,7 +142,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const divide: (that: Option) => (self: Option) => Option +export declare const divide: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} ``` Added in v1.0.0 @@ -152,7 +155,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiply: (that: Option) => (self: Option) => Option +export declare const multiply: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} ``` Added in v1.0.0 @@ -183,7 +189,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiplyBigint: (that: Option) => (self: Option) => Option +export declare const multiplyBigint: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} ``` Added in v1.0.0 @@ -193,7 +202,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtract: (that: Option) => (self: Option) => Option +export declare const subtract: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} ``` Added in v1.0.0 @@ -203,7 +215,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtractBigint: (that: Option) => (self: Option) => Option +export declare const subtractBigint: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} ``` Added in v1.0.0 @@ -213,7 +228,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const sum: (that: Option) => (self: Option) => Option +export declare const sum: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} ``` Added in v1.0.0 @@ -244,7 +262,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const sumBigint: (that: Option) => (self: Option) => Option +export declare const sumBigint: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} ``` Added in v1.0.0 @@ -451,7 +472,10 @@ Useful for debugging purposes, the `onNone` callback is is called if `self` is a **Signature** ```ts -export declare const inspectNone: (onNone: () => void) => (self: Option) => Option +export declare const inspectNone: { + (self: Option, onNone: () => void): Option + (onNone: () => void): (self: Option) => Option +} ``` Added in v1.0.0 @@ -463,7 +487,10 @@ Useful for debugging purposes, the `onSome` callback is called with the value of **Signature** ```ts -export declare const inspectSome: (onSome: (a: A) => void) => (self: Option) => Option +export declare const inspectSome: { + (self: Option, onSome: (a: A) => void): Option + (onSome: (a: A) => void): (self: Option) => Option +} ``` Added in v1.0.0 @@ -679,7 +706,10 @@ Useful when in addition to filtering you also want to change the type of the `Op **Signature** ```ts -export declare const filterMap: (f: (a: A) => Option) => (self: Option) => Option +export declare const filterMap: { + (self: Option, f: (a: A) => Option): Option + (f: (a: A) => Option): (self: Option) => Option +} ``` Added in v1.0.0 @@ -1182,7 +1212,7 @@ If either of the `Option`s is `None`, the result will be `None`. **Signature** ```ts -export declare const lift2: (f: (a: A) => (b: B) => C) => (that: Option) => (self: Option) => Option +export declare const lift2: (f: (a: A, b: B) => C) => (self: Option, that: Option) => Option ``` Added in v1.0.0 @@ -1217,7 +1247,8 @@ Added in v1.0.0 ## liftPredicate -Returns a _smart constructor_ based on the given predicate. +Transforms a `Predicate` function into a `Some` of the input value if the predicate returns `true` or `None` +if the predicate returns `false`. **Signature** @@ -1341,7 +1372,10 @@ function when passed the `Option`'s value. **Signature** ```ts -export declare const match: (onNone: LazyArg, onSome: (a: A) => C) => (self: Option) => B | C +export declare const match: { + (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C + (onNone: LazyArg, onSome: (a: A) => C): (self: Option) => B | C +} ``` **Example** @@ -1412,7 +1446,10 @@ Applies a function to the value of an `Option` and flattens the result, if the i **Signature** ```ts -export declare const flatMap: (f: (a: A) => Option) => (self: Option) => Option +export declare const flatMap: { + (self: Option, f: (a: A) => Option): Option + (f: (a: A) => Option): (self: Option) => Option +} ``` Added in v1.0.0 @@ -1424,7 +1461,10 @@ Applies a provided function that returns an `Either` to the contents of an `Opti **Signature** ```ts -export declare const flatMapEither: (f: (a: A) => Either) => (self: Option) => Option +export declare const flatMapEither: { + (self: Option, f: (a: A) => Either): Option + (f: (a: A) => Either): (self: Option) => Option +} ``` **Example** @@ -1536,7 +1576,7 @@ Added in v1.0.0 ```ts export declare const sequence: ( F: applicative.Applicative -) => (fas: Option>) => Kind> +) => (self: Option>) => Kind> ``` Added in v1.0.0 @@ -1548,7 +1588,10 @@ Added in v1.0.0 ```ts export declare const traverse: ( F: applicative.Applicative -) => (f: (a: A) => Kind) => (self: Option) => Kind> +) => { + (self: Option, f: (a: A) => Kind): Kind> + (f: (a: A) => Kind): (self: Option) => Kind> +} ``` Added in v1.0.0 @@ -1634,7 +1677,10 @@ Returns a function that checks if an `Option` contains a given value using a pro **Signature** ```ts -export declare const contains: (equivalence: Equivalence) => (a: A) => (self: Option) => boolean +export declare const contains: (equivalence: Equivalence) => { + (self: Option, a: A): boolean + (a: A): (self: Option) => boolean +} ``` **Example** @@ -1658,7 +1704,10 @@ Check if a value in an `Option` type meets a certain predicate. **Signature** ```ts -export declare const exists: (predicate: Predicate) => (self: Option) => boolean +export declare const exists: { + (self: Option, predicate: Predicate): boolean + (predicate: Predicate): (self: Option) => boolean +} ``` **Example** @@ -1693,7 +1742,10 @@ Reduces an `Iterable` of `Option` to a single value of type `B`, elements tha **Signature** ```ts -export declare const reduceAll: (b: B, f: (b: B, a: A) => B) => (self: Iterable>) => B +export declare const reduceAll: { + (self: Iterable>, b: B, f: (b: B, a: A) => B): B + (b: B, f: (b: B, a: A) => B): (self: Iterable>) => B +} ``` **Example** diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index f3f8b8fa8..d2be85a00 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -169,9 +169,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const divide: ( - that: These -) => (self: These) => These +export declare const divide: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + number + > + (that: These): ( + self: These + ) => These +} ``` Added in v1.0.0 @@ -181,9 +187,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiply: ( - that: These -) => (self: These) => These +export declare const multiply: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + number + > + (that: These): ( + self: These + ) => These +} ``` Added in v1.0.0 @@ -193,9 +205,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiplyBigint: ( - that: These -) => (self: These) => These +export declare const multiplyBigint: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + bigint + > + (that: These): ( + self: These + ) => These +} ``` Added in v1.0.0 @@ -205,9 +223,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtract: ( - that: These -) => (self: These) => These +export declare const subtract: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + number + > + (that: These): ( + self: These + ) => These +} ``` Added in v1.0.0 @@ -217,9 +241,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtractBigint: ( - that: These -) => (self: These) => These +export declare const subtractBigint: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + bigint + > + (that: These): ( + self: These + ) => These +} ``` Added in v1.0.0 @@ -229,9 +259,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const sum: ( - that: These -) => (self: These) => These +export declare const sum: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + number + > + (that: These): ( + self: These + ) => These +} ``` Added in v1.0.0 @@ -241,9 +277,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const sumBigint: ( - that: These -) => (self: These) => These +export declare const sumBigint: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + bigint + > + (that: These): ( + self: These + ) => These +} ``` Added in v1.0.0 @@ -1145,10 +1187,11 @@ Added in v1.0.0 ```ts export declare const lift2: ( - f: (a: A) => (b: B) => C -) => ( - that: These -) => (self: These) => These + f: (a: A, b: B) => C +) => ( + self: These, + that: These +) => These ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index 407409d22..5aabd6f7d 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -37,10 +37,11 @@ Lifts a binary function into `F`. export declare const lift2: ( F: SemiApplicative ) => ( - f: (a: A) => (b: B) => C -) => ( - that: Kind -) => (self: Kind) => Kind + f: (a: A, b: B) => C +) => ( + self: Kind, + that: Kind +) => Kind ``` Added in v1.0.0 diff --git a/src/Bigint.ts b/src/Bigint.ts index 50e27e4e9..4b198d86f 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -6,6 +6,7 @@ * @since 1.0.0 */ +import { dual } from "@fp-ts/core/Function" import * as predicate from "@fp-ts/core/Predicate" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" @@ -19,30 +20,56 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" export const isBigint: (u: unknown) => u is bigint = predicate.isBigInt /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const sum = (that: bigint) => - (self: bigint): bigint => semigroup.bigintSum.combine(self, that) +export const sum: { + (self: bigint, that: bigint): bigint + (that: bigint): (self: bigint) => bigint +} = dual< + (self: bigint, that: bigint) => bigint, + (that: bigint) => (self: bigint) => bigint +>(2, semigroup.bigintSum.combine) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiply = (that: bigint) => - (self: bigint): bigint => semigroup.bigintMultiply.combine(self, that) +export const multiply: { + (self: bigint, that: bigint): bigint + (that: bigint): (self: bigint) => bigint +} = dual< + (self: bigint, that: bigint) => bigint, + (that: bigint) => (self: bigint) => bigint +>(2, semigroup.bigintMultiply.combine) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtract = (that: bigint) => (self: bigint): bigint => self - that +export const subtract: { + (self: bigint, that: bigint): bigint + (that: bigint): (self: bigint) => bigint +} = dual< + (self: bigint, that: bigint) => bigint, + (that: bigint) => (self: bigint) => bigint +>(2, (self: bigint, that: bigint): bigint => self - that) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const divide = (that: bigint) => (self: bigint): bigint => self / that +export const divide: { + (self: bigint, that: bigint): bigint + (that: bigint): (self: bigint) => bigint +} = dual< + (self: bigint, that: bigint) => bigint, + (that: bigint) => (self: bigint) => bigint +>(2, (self: bigint, that: bigint): bigint => self / that) /** * @since 1.0.0 diff --git a/src/Either.ts b/src/Either.ts index b59af438b..a39ba31b0 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -595,8 +595,8 @@ export const getFirstLeftSemigroup: (S: Semigroup) => Semigroup( - f: (a: A) => (b: B) => C -) => (that: Either) => (self: Either) => Either = semiApplicative + f: (a: A, b: B) => C +) => (self: Either, that: Either) => Either = semiApplicative .lift2(SemiApplicative) /** @@ -1165,40 +1165,82 @@ export const getOptionalSemigroup = (S: Semigroup): Semigroup(self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = dual< + (self: Either, that: Either) => Either, + (that: Either) => (self: Either) => Either +>(2, lift2(N.sum)) /** * @category algebraic operations * @since 1.0.0 */ -export const multiply = lift2(N.multiply) +export const multiply: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = dual< + (self: Either, that: Either) => Either, + (that: Either) => (self: Either) => Either +>(2, lift2(N.multiply)) /** * @category algebraic operations * @since 1.0.0 */ -export const subtract = lift2(N.subtract) +export const subtract: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = dual< + (self: Either, that: Either) => Either, + (that: Either) => (self: Either) => Either +>(2, lift2(N.subtract)) /** * @category algebraic operations * @since 1.0.0 */ -export const divide = lift2(N.divide) +export const divide: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = dual< + (self: Either, that: Either) => Either, + (that: Either) => (self: Either) => Either +>(2, lift2(N.divide)) /** * @category algebraic operations * @since 1.0.0 */ -export const sumBigint = lift2(BI.sum) +export const sumBigint: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = dual< + (self: Either, that: Either) => Either, + (that: Either) => (self: Either) => Either +>(2, lift2(BI.sum)) /** * @category algebraic operations * @since 1.0.0 */ -export const multiplyBigint = lift2(BI.multiply) +export const multiplyBigint: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = dual< + (self: Either, that: Either) => Either, + (that: Either) => (self: Either) => Either +>(2, lift2(BI.multiply)) /** * @category algebraic operations * @since 1.0.0 */ -export const subtractBigint = lift2(BI.subtract) +export const subtractBigint: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = dual< + (self: Either, that: Either) => Either, + (that: Either) => (self: Either) => Either +>(2, lift2(BI.subtract)) diff --git a/src/Number.ts b/src/Number.ts index 2b24ae566..631141de7 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -5,6 +5,7 @@ * * @since 1.0.0 */ +import { dual } from "@fp-ts/core/Function" import type { Ordering } from "@fp-ts/core/Ordering" import * as predicate from "@fp-ts/core/Predicate" import * as bounded from "@fp-ts/core/typeclass/Bounded" @@ -26,11 +27,17 @@ export const isNumber = predicate.isNumber * * assert.deepStrictEqual(pipe(2, sum(3)), 5) * + * @dual * @category algebraic operations * @since 1.0.0 */ -export const sum = (that: number) => - (self: number): number => semigroup.numberSum.combine(self, that) +export const sum: { + (self: number, that: number): number + (that: number): (self: number) => number +} = dual< + (self: number, that: number) => number, + (that: number) => (self: number) => number +>(2, semigroup.numberSum.combine) /** * @example @@ -39,11 +46,17 @@ export const sum = (that: number) => * * assert.deepStrictEqual(pipe(2, multiply(3)), 6) * + * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiply = (that: number) => - (self: number): number => semigroup.numberMultiply.combine(self, that) +export const multiply: { + (self: number, that: number): number + (that: number): (self: number) => number +} = dual< + (self: number, that: number) => number, + (that: number) => (self: number) => number +>(2, semigroup.numberMultiply.combine) /** * @example @@ -52,10 +65,17 @@ export const multiply = (that: number) => * * assert.deepStrictEqual(pipe(2, subtract(3)), -1) * + * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtract = (that: number) => (self: number): number => self - that +export const subtract: { + (self: number, that: number): number + (that: number): (self: number) => number +} = dual< + (self: number, that: number) => number, + (that: number) => (self: number) => number +>(2, (self: number, that: number): number => self - that) /** * @example @@ -64,10 +84,17 @@ export const subtract = (that: number) => (self: number): number => self - that * * assert.deepStrictEqual(pipe(6, divide(3)), 2) * + * @dual * @category algebraic operations * @since 1.0.0 */ -export const divide = (that: number) => (self: number): number => self / that +export const divide: { + (self: number, that: number): number + (that: number): (self: number) => number +} = dual< + (self: number, that: number) => number, + (that: number) => (self: number) => number +>(2, (self: number, that: number): number => self / that) /** * @example diff --git a/src/Option.ts b/src/Option.ts index 8d08742dd..d9337bcab 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -279,8 +279,8 @@ export const toEither: { /** * Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` * - * @param onNone - Function that returns the default value to return if the `Option` is `None`. * @param self - The `Option` to get the value of. + * @param onNone - Function that returns the default value to return if the `Option` is `None`. * * @example * import { some, none, getOrElse } from '@fp-ts/core/Option' @@ -307,8 +307,8 @@ export const getOrElse: { /** * Returns the provided `Option` `that` if `self` is `None`, otherwise returns `self`. * - * @param that - The `Option` to return if `self` is `None`. * @param self - The first `Option` to be checked. + * @param that - The `Option` to return if `self` is `None`. * * @example * import * as O from '@fp-ts/core/Option' @@ -364,8 +364,8 @@ export const orElse: { * * This is useful when it's important to know whether the value was retrieved from the first `Option` or the second option. * - * @param that - The second `Option` to be considered if the first `Option` is `None`. * @param self - The first `Option` to be checked. + * @param that - The second `Option` to be considered if the first `Option` is `None`. * * @dual * @category error handling @@ -599,8 +599,8 @@ export const getOrThrow = (self: Option): A => { /** * Maps the given function to the value of the `Option` if it is a `Some`, otherwise it returns `None`. * - * @param f - The function to map over the value of the `Option` * @param self - An `Option` to map + * @param f - The function to map over the value of the `Option` * * @dual * @category mapping @@ -720,11 +720,21 @@ export const Pointed: pointed.Pointed = { /** * Applies a function to the value of an `Option` and flattens the result, if the input is `Some`. * + * @dual * @category sequencing * @since 1.0.0 */ -export const flatMap = (f: (a: A) => Option) => - (self: Option): Option => isNone(self) ? none() : f(self.value) +export const flatMap: { + (self: Option, f: (a: A) => Option): Option + (f: (a: A) => Option): (self: Option) => Option +} = dual< + (self: Option, f: (a: A) => Option) => Option, + (f: (a: A) => Option) => (self: Option) => Option +>( + 2, + (self: Option, f: (a: A) => Option): Option => + isNone(self) ? none() : f(self.value) +) /** * @category instances @@ -811,40 +821,50 @@ export const tap: (f: (a: A) => Option<_>) => (self: Option) => Option< /** * Useful for debugging purposes, the `onSome` callback is called with the value of `self` if it is a `Some`. * - * @param onSome - callback function that is called with the value of `self` if it is a `Some` * @param self - the `Option` to inspect + * @param onSome - callback function that is called with the value of `self` if it is a `Some` * + * @dual * @category debugging * @since 1.0.0 */ -export const inspectSome = ( - onSome: (a: A) => void -) => - (self: Option): Option => { - if (isSome(self)) { - onSome(self.value) - } - return self +export const inspectSome: { + (self: Option, onSome: (a: A) => void): Option + (onSome: (a: A) => void): (self: Option) => Option +} = dual< + (self: Option, onSome: (a: A) => void) => Option, + ( + onSome: (a: A) => void + ) => (self: Option) => Option +>(2, (self: Option, onSome: (a: A) => void): Option => { + if (isSome(self)) { + onSome(self.value) } + return self +}) /** * Useful for debugging purposes, the `onNone` callback is is called if `self` is a `None`. * - * @param onNone - callback function that is is called if `self` is a `None` * @param self - the `Option` to inspect + * @param onNone - callback function that is is called if `self` is a `None` * + * @dual * @category debugging * @since 1.0.0 */ -export const inspectNone = ( - onNone: () => void -) => - (self: Option): Option => { - if (isNone(self)) { - onNone() - } - return self +export const inspectNone: { + (self: Option, onNone: () => void): Option + (onNone: () => void): (self: Option) => Option +} = dual< + (self: Option, onNone: () => void) => Option, + (onNone: () => void) => (self: Option) => Option +>(2, (self: Option, onNone: () => void): Option => { + if (isNone(self)) { + onNone() } + return self +}) /** * @category instances @@ -1000,8 +1020,8 @@ export const getOptionalMonoid = ( * @since 1.0.0 */ export const lift2: ( - f: (a: A) => (b: B) => C -) => (that: Option) => (self: Option) => Option = semiApplicative + f: (a: A, b: B) => C +) => (self: Option, that: Option) => Option = semiApplicative .lift2(SemiApplicative) /** @@ -1189,14 +1209,24 @@ export const separate: (self: Option>) => [Option, Option< * * Useful when in addition to filtering you also want to change the type of the `Option`. * - * @param f - A function to apply to the value of the `Option`. * @param self - The `Option` to map over. + * @param f - A function to apply to the value of the `Option`. * + * @dual * @category filtering * @since 1.0.0 */ -export const filterMap = (f: (a: A) => Option) => - (self: Option): Option => isNone(self) ? none() : f(self.value) +export const filterMap: { + (self: Option, f: (a: A) => Option): Option + (f: (a: A) => Option): (self: Option) => Option +} = dual< + (self: Option, f: (a: A) => Option) => Option, + (f: (a: A) => Option) => (self: Option) => Option +>( + 2, + (self: Option, f: (a: A) => Option): Option => + isNone(self) ? none() : f(self.value) +) /** * @category instances @@ -1223,17 +1253,34 @@ export const filter: { } = filterable.filter(Filterable) /** + * @dual * @category traversing * @since 1.0.0 */ export const traverse = ( F: applicative.Applicative -) => +): { + (self: Option, f: (a: A) => Kind): Kind> ( f: (a: A) => Kind - ) => - (self: Option): Kind> => + ): (self: Option) => Kind> +} => + dual< + ( + self: Option, + f: (a: A) => Kind + ) => Kind>, + ( + f: (a: A) => Kind + ) => (self: Option) => Kind> + >( + 2, + ( + self: Option, + f: (a: A) => Kind + ): Kind> => isNone(self) ? F.of>(none()) : pipe(f(self.value), F.map(some)) + ) /** * @category traversing @@ -1241,7 +1288,7 @@ export const traverse = ( */ export const sequence: ( F: applicative.Applicative -) => (fas: Option>) => Kind> = traversable +) => (self: Option>) => Kind> = traversable .sequence(traverse) /** @@ -1268,9 +1315,9 @@ export const traverseTap: ( * Matches the given `Option` and returns either the provided `onNone` value or the result of the provided `onSome` * function when passed the `Option`'s value. * + * @param self - The `Option` to match * @param onNone - The value to be returned if the `Option` is `None` * @param onSome - The function to be called if the `Option` is `Some`, it will be passed the `Option`'s value and its result will be returned - * @param self - The `Option` to match * * @example * import { some, none, match } from '@fp-ts/core/Option' @@ -1292,11 +1339,21 @@ export const traverseTap: ( * 'a none' * ) * + * @dual * @category pattern matching * @since 1.0.0 */ -export const match = (onNone: LazyArg, onSome: (a: A) => C) => - (self: Option): B | C => isNone(self) ? onNone() : onSome(self.value) +export const match: { + (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C + (onNone: LazyArg, onSome: (a: A) => C): (self: Option) => B | C +} = dual< + (self: Option, onNone: LazyArg, onSome: (a: A) => C) => B | C, + (onNone: LazyArg, onSome: (a: A) => C) => (self: Option) => B | C +>( + 3, + (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C => + isNone(self) ? onNone() : onSome(self.value) +) /** * The `Order` instance allows `Option` values to be compared with @@ -1326,7 +1383,10 @@ export const liftOrder = (O: Order): Order> => ) /** - * Returns a *smart constructor* based on the given predicate. + * Transforms a `Predicate` function into a `Some` of the input value if the predicate returns `true` or `None` + * if the predicate returns `false`. + * + * @param predicate - A `Predicate` function that takes in a value of type `A` and returns a boolean. * * @example * import * as O from '@fp-ts/core/Option' @@ -1371,8 +1431,8 @@ export const liftEither = , E, B>( /** * Applies a provided function that returns an `Either` to the contents of an `Option`, flattening the result into another `Option`. * - * @param f - The function to be applied to the contents of the `Option`. * @param self - The `Option` to apply the function to. + * @param f - The function to be applied to the contents of the `Option`. * * @example * import * as O from '@fp-ts/core/Option' @@ -1384,16 +1444,27 @@ export const liftEither = , E, B>( * assert.deepStrictEqual(pipe(O.some(1), O.flatMapEither(f)), O.some(2)) * assert.deepStrictEqual(pipe(O.some(3), O.flatMapEither(f)), O.none()) * + * @dual * @category sequencing * @since 1.0.0 */ -export const flatMapEither = (f: (a: A) => Either) => - (self: Option): Option => pipe(self, flatMap(liftEither(f))) +export const flatMapEither: { + (self: Option, f: (a: A) => Either): Option + (f: (a: A) => Either): (self: Option) => Option +} = dual< + (self: Option, f: (a: A) => Either) => Option, + (f: (a: A) => Either) => (self: Option) => Option +>( + 2, + (self: Option, f: (a: A) => Either): Option => + pipe(self, flatMap(liftEither(f))) +) /** * Returns a function that checks if an `Option` contains a given value using a provided `Equivalence` instance. * * @param equivalence - An `Equivalence` instance to compare values of the `Option`. + * @param self - The `Option` to apply the comparison to. * @param a - The value to compare against the `Option`. * * @example @@ -1405,16 +1476,23 @@ export const flatMapEither = (f: (a: A) => Either) => * assert.deepStrictEqual(pipe(some(1), contains(Equivalence)(2)), false) * assert.deepStrictEqual(pipe(none(), contains(Equivalence)(2)), false) * + * @dual * @since 1.0.0 */ -export const contains = (equivalence: Equivalence) => - (a: A) => (self: Option): boolean => isNone(self) ? false : equivalence(self.value, a) +export const contains = (equivalence: Equivalence): { + (self: Option, a: A): boolean + (a: A): (self: Option) => boolean +} => + dual< + (self: Option, a: A) => boolean, + (a: A) => (self: Option) => boolean + >(2, (self: Option, a: A): boolean => isNone(self) ? false : equivalence(self.value, a)) /** * Check if a value in an `Option` type meets a certain predicate. * - * @param predicate - The condition to check. * @param self - The `Option` to check. + * @param predicate - The condition to check. * * @example * import { some, none, exists } from '@fp-ts/core/Option' @@ -1426,19 +1504,27 @@ export const contains = (equivalence: Equivalence) => * assert.deepStrictEqual(pipe(some(1), exists(isEven)), false) * assert.deepStrictEqual(pipe(none(), exists(isEven)), false) * + * @dual * @since 1.0.0 */ -export const exists = (predicate: Predicate) => - (self: Option): boolean => isNone(self) ? false : predicate(self.value) +export const exists: { + (self: Option, predicate: Predicate): boolean + (predicate: Predicate): (self: Option) => boolean +} = dual< + (self: Option, predicate: Predicate) => boolean, + (predicate: Predicate) => (self: Option) => boolean +>( + 2, + (self: Option, predicate: Predicate): boolean => + isNone(self) ? false : predicate(self.value) +) /** * Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. * - * @since 1.0.0 - * + * @param self - The Iterable of `Option` to be reduced. * @param b - The initial value of the accumulator. * @param f - The reducing function that takes the current accumulator value and the unwrapped value of an `Option`. - * @param self - The Iterable of `Option` to be reduced. * * @example * import { some, none, reduceAll } from '@fp-ts/core/Option' @@ -1446,9 +1532,19 @@ export const exists = (predicate: Predicate) => * * const iterable = [some(1), none(), some(2), none()] * assert.deepStrictEqual(pipe(iterable, reduceAll(0, (b, a) => b + a)), 3) + * + * @dual + * @since 1.0.0 */ -export const reduceAll = (b: B, f: (b: B, a: A) => B) => - (self: Iterable>): B => { +export const reduceAll: { + (self: Iterable>, b: B, f: (b: B, a: A) => B): B + (b: B, f: (b: B, a: A) => B): (self: Iterable>) => B +} = dual< + (self: Iterable>, b: B, f: (b: B, a: A) => B) => B, + (b: B, f: (b: B, a: A) => B) => (self: Iterable>) => B +>( + 3, + (self: Iterable>, b: B, f: (b: B, a: A) => B): B => { let out: B = b for (const oa of self) { if (isSome(oa)) { @@ -1457,6 +1553,7 @@ export const reduceAll = (b: B, f: (b: B, a: A) => B) => } return out } +) // ------------------------------------------------------------------------------------- // algebraic operations @@ -1466,43 +1563,85 @@ export const reduceAll = (b: B, f: (b: B, a: A) => B) => * @category algebraic operations * @since 1.0.0 */ -export const sum = lift2(N.sum) +export const sum: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = dual< + (self: Option, that: Option) => Option, + (that: Option) => (self: Option) => Option +>(2, lift2(N.sum)) /** * @category algebraic operations * @since 1.0.0 */ -export const multiply = lift2(N.multiply) +export const multiply: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = dual< + (self: Option, that: Option) => Option, + (that: Option) => (self: Option) => Option +>(2, lift2(N.multiply)) /** * @category algebraic operations * @since 1.0.0 */ -export const subtract = lift2(N.subtract) +export const subtract: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = dual< + (self: Option, that: Option) => Option, + (that: Option) => (self: Option) => Option +>(2, lift2(N.subtract)) /** * @category algebraic operations * @since 1.0.0 */ -export const divide = lift2(N.divide) +export const divide: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = dual< + (self: Option, that: Option) => Option, + (that: Option) => (self: Option) => Option +>(2, lift2(N.divide)) /** * @category algebraic operations * @since 1.0.0 */ -export const sumBigint = lift2(BI.sum) +export const sumBigint: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = dual< + (self: Option, that: Option) => Option, + (that: Option) => (self: Option) => Option +>(2, lift2(BI.sum)) /** * @category algebraic operations * @since 1.0.0 */ -export const multiplyBigint = lift2(BI.multiply) +export const multiplyBigint: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = dual< + (self: Option, that: Option) => Option, + (that: Option) => (self: Option) => Option +>(2, lift2(BI.multiply)) /** * @category algebraic operations * @since 1.0.0 */ -export const subtractBigint = lift2(BI.subtract) +export const subtractBigint: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = dual< + (self: Option, that: Option) => Option, + (that: Option) => (self: Option) => Option +>(2, lift2(BI.subtract)) /** * Sum all numbers in an iterable of `Option` ignoring the `None` values. diff --git a/src/These.ts b/src/These.ts index 406908d1e..d5cad818c 100644 --- a/src/These.ts +++ b/src/These.ts @@ -6,7 +6,7 @@ import * as BI from "@fp-ts/core/Bigint" import type { Either, Left, Right } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" -import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" +import { constNull, constUndefined, dual, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { proto, structural } from "@fp-ts/core/internal/effect" import * as N from "@fp-ts/core/Number" @@ -995,12 +995,11 @@ export const SemiApplicative: semiApplicative.SemiApplicative( - f: (a: A) => (b: B) => C -) => ( - that: Validated -) => (self: Validated) => Validated = semiApplicative.lift2( - SemiApplicative -) + f: (a: A, b: B) => C +) => (self: Validated, that: Validated) => Validated = + semiApplicative.lift2( + SemiApplicative + ) /** * @category products @@ -1304,40 +1303,96 @@ export const Monad: monad.Monad = { * @category algebraic operations * @since 1.0.0 */ -export const sum = lift2(N.sum) +export const sum: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = dual< + (self: Validated, that: Validated) => Validated, + ( + that: Validated + ) => (self: Validated) => Validated +>(2, lift2(N.sum)) /** * @category algebraic operations * @since 1.0.0 */ -export const multiply = lift2(N.multiply) +export const multiply: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = dual< + (self: Validated, that: Validated) => Validated, + ( + that: Validated + ) => (self: Validated) => Validated +>(2, lift2(N.multiply)) /** * @category algebraic operations * @since 1.0.0 */ -export const subtract = lift2(N.subtract) +export const subtract: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = dual< + (self: Validated, that: Validated) => Validated, + ( + that: Validated + ) => (self: Validated) => Validated +>(2, lift2(N.subtract)) /** * @category algebraic operations * @since 1.0.0 */ -export const divide = lift2(N.divide) +export const divide: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = dual< + (self: Validated, that: Validated) => Validated, + ( + that: Validated + ) => (self: Validated) => Validated +>(2, lift2(N.divide)) /** * @category algebraic operations * @since 1.0.0 */ -export const sumBigint = lift2(BI.sum) +export const sumBigint: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = dual< + (self: Validated, that: Validated) => Validated, + ( + that: Validated + ) => (self: Validated) => Validated +>(2, lift2(BI.sum)) /** * @category algebraic operations * @since 1.0.0 */ -export const multiplyBigint = lift2(BI.multiply) +export const multiplyBigint: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = dual< + (self: Validated, that: Validated) => Validated, + ( + that: Validated + ) => (self: Validated) => Validated +>(2, lift2(BI.multiply)) /** * @category algebraic operations * @since 1.0.0 */ -export const subtractBigint = lift2(BI.subtract) +export const subtractBigint: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = dual< + (self: Validated, that: Validated) => Validated, + ( + that: Validated + ) => (self: Validated) => Validated +>(2, lift2(BI.subtract)) diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 554630a1d..7bf725dcc 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -80,8 +80,8 @@ export const andThen = (F: SemiApplicative) => * @since 1.0.0 */ export const lift2 = (F: SemiApplicative) => - (f: (a: A) => (b: B) => C) => - ( - that: Kind - ): (self: Kind) => Kind => - zipWith(F)(that, (a, b) => f(b)(a)) + (f: (a: A, b: B) => C) => + ( + self: Kind, + that: Kind + ): Kind => pipe(self, zipWith(F)(that, f)) From ebcbe0e3e580d0341395049a95d05f5776af51bb Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 18:56:18 +0100 Subject: [PATCH 137/255] These: align to Either --- docs/modules/Either.ts.md | 7 -- docs/modules/Option.ts.md | 8 +- docs/modules/These.ts.md | 87 ++---------------- src/Either.ts | 124 ++++++++++++------------- src/Option.ts | 115 ++++++++++++----------- src/These.ts | 188 ++++++++++++++------------------------ src/internal/Either.ts | 8 +- test/These.ts | 181 +++++++++--------------------------- 8 files changed, 249 insertions(+), 469 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index ba8779c8f..a4b86c45f 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -566,13 +566,6 @@ Added in v1.0.0 Executes this effect and returns its value, if it succeeds, but otherwise executes the specified effect. -| x | y | x | > orElse(y) | -| -------- | -------- | -------- | ----------- | -| left(a) | left(b) | left(b) | -| left(a) | right(2) | right(2) | -| right(1) | left(b) | right(1) | -| right(1) | right(2) | right(1) | - **Signature** ```ts diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 3c1e67096..e9fcc82ab 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -311,7 +311,7 @@ Alias of `some`. **Signature** ```ts -export declare const of: (a: A) => Option +export declare const of: (value: A) => Option ``` Added in v1.0.0 @@ -431,8 +431,8 @@ Converts an `Option` to an `Either`, allowing you to provide a value to be used ```ts export declare const toEither: { - (fa: Option, onNone: () => E): Either - (onNone: () => E): (fa: Option) => Either + (self: Option, onNone: () => E): Either + (onNone: () => E): (self: Option) => Either } ``` @@ -562,7 +562,7 @@ Added in v1.0.0 ## firstSomeOf -Given an Iterable collection of `Option`s, the function returns the first `Some` found in the collection. +Given an `Iterable` collection of `Option`s, the function returns the first `Some` found in the collection. **Signature** diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index d2be85a00..86c7500e7 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -32,7 +32,6 @@ Added in v1.0.0 - [of](#of) - [right](#right) - [rightOrBoth](#rightorboth) - - [succeed](#succeed) - [warn](#warn) - [conversions](#conversions) - [absolve](#absolve) @@ -52,15 +51,12 @@ Added in v1.0.0 - [do notation](#do-notation) - [Do](#do) - [andThenBind](#andthenbind) - - [andThenBindEither](#andthenbindeither) - - [andThenBindThese](#andthenbindthese) - [bind](#bind) - [bindEither](#bindeither) - [bindThese](#bindthese) - [bindTo](#bindto) - [let](#let) - [error handling](#error-handling) - - [catchAll](#catchall) - [firstRightOrBothOf](#firstrightorbothof) - [mapLeft](#mapleft) - [orElse](#orelse) @@ -105,7 +101,6 @@ Added in v1.0.0 - [SemiProduct](#semiproduct) - [Traversable](#traversable) - [interop](#interop) - - [fromThrowable](#fromthrowable) - [getOrThrow](#getorthrow) - [getRightOnlyOrThrow](#getrightonlyorthrow) - [liftThrowable](#liftthrowable) @@ -359,7 +354,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const leftOrBoth: (e: LazyArg) => (self: O.Option) => These +export declare const leftOrBoth: (onSome: LazyArg) => (self: O.Option) => These ``` Added in v1.0.0 @@ -391,19 +386,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const rightOrBoth: (a: () => A) => (self: O.Option) => These -``` - -Added in v1.0.0 - -## succeed - -Alias of `right`. - -**Signature** - -```ts -export declare const succeed: (a: A) => These +export declare const rightOrBoth: (onNone: LazyArg) => (self: O.Option) => These ``` Added in v1.0.0 @@ -579,36 +562,6 @@ export declare const andThenBind: ( Added in v1.0.0 -## andThenBindEither - -**Signature** - -```ts -export declare const andThenBindEither: ( - name: Exclude, - that: Either -) => ( - self: These -) => These -``` - -Added in v1.0.0 - -## andThenBindThese - -**Signature** - -```ts -export declare const andThenBindThese: ( - name: Exclude, - that: These -) => ( - self: These -) => These -``` - -Added in v1.0.0 - ## bind **Signature** @@ -679,20 +632,6 @@ Added in v1.0.0 # error handling -## catchAll - -Recovers from all errors. - -**Signature** - -```ts -export declare const catchAll: ( - onLeft: (e: E1) => These -) => (self: These) => These -``` - -Added in v1.0.0 - ## firstRightOrBothOf **Signature** @@ -724,7 +663,9 @@ executes the specified effect. **Signature** ```ts -export declare const orElse: (that: These) => (self: These) => These +export declare const orElse: ( + that: (e1: E1) => These +) => (self: These) => These ``` Added in v1.0.0 @@ -737,9 +678,9 @@ fails, in which case, it will produce the value of the specified effect. **Signature** ```ts -export declare const orElseEither: ( - that: These -) => (self: These) => These> +export declare const orElseEither: ( + that: (e1: E1) => These +) => (self: These) => These> ``` Added in v1.0.0 @@ -1132,18 +1073,6 @@ Added in v1.0.0 # interop -## fromThrowable - -Constructs a new `These` from a function that might throw. - -**Signature** - -```ts -export declare const fromThrowable: (f: () => A, onThrow: (error: unknown) => E) => These -``` - -Added in v1.0.0 - ## getOrThrow **Signature** diff --git a/src/Either.ts b/src/Either.ts index a39ba31b0..6196d2483 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -258,14 +258,6 @@ export const tupled: (self: Either) => Either = invariant.tu Invariant ) -/** - * @category do notation - * @since 1.0.0 - */ -export const bindTo: ( - name: N -) => (self: Either) => Either = invariant.bindTo(Invariant) - /** * @category mapping * @since 1.0.0 @@ -293,23 +285,6 @@ export const asUnit: (self: Either) => Either = covariant.a Covariant ) -const let_: ( - name: Exclude, - f: (a: A) => B -) => ( - self: Either -) => Either = covariant.let( - Covariant -) - -export { - /** - * @category do notation - * @since 1.0.0 - */ - let_ as let -} - /** * Returns an effect whose Left and Right channels have been mapped by * the specified pair of functions, `f` and `g`. @@ -354,12 +329,6 @@ export const Of: of_.Of = { */ export const unit: Either = of_.unit(Of) -/** - * @category do notation - * @since 1.0.0 - */ -export const Do: Either = of_.Do(Of) - /** * @category instances * @since 1.0.0 @@ -418,18 +387,6 @@ export const Chainable: chainable.Chainable = { flatMap } -/** - * @category do notation - * @since 1.0.0 - */ -export const bind: ( - name: Exclude, - f: (a: A) => Either -) => ( - self: Either -) => Either = chainable - .bind(Chainable) - /** * Sequences the specified effect after this effect, but ignores the value * produced by the effect. @@ -486,20 +443,6 @@ export const SemiProduct: semiProduct.SemiProduct = { productMany } -/** - * A variant of `bind` that sequentially ignores the scope. - * - * @category do notation - * @since 1.0.0 - */ -export const andThenBind: ( - name: Exclude, - that: Either -) => ( - self: Either -) => Either = semiProduct - .andThenBind(SemiProduct) - /** * Appends an element to the end of a tuple. * @@ -734,13 +677,6 @@ export const getOrElse: { * Executes this effect and returns its value, if it succeeds, but otherwise * executes the specified effect. * - * | x | y | x |> orElse(y) | - * | ---------- | ---------- | ---------------| - * | left(a) | left(b) | left(b) | - * | left(a) | right(2) | right(2) | - * | right(1) | left(b) | right(1) | - * | right(1) | right(2) | right(1) | - * * @category error handling * @since 1.0.0 */ @@ -1244,3 +1180,63 @@ export const subtractBigint: { (self: Either, that: Either) => Either, (that: Either) => (self: Either) => Either >(2, lift2(BI.subtract)) + +// ------------------------------------------------------------------------------------- +// do notation +// ------------------------------------------------------------------------------------- + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindTo: ( + name: N +) => (self: Either) => Either = invariant.bindTo(Invariant) + +const let_: ( + name: Exclude, + f: (a: A) => B +) => ( + self: Either +) => Either = covariant.let( + Covariant +) + +export { + /** + * @category do notation + * @since 1.0.0 + */ + let_ as let +} +/** + * @category do notation + * @since 1.0.0 + */ +export const Do: Either = of_.Do(Of) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bind: ( + name: Exclude, + f: (a: A) => Either +) => ( + self: Either +) => Either = chainable + .bind(Chainable) + +/** + * A variant of `bind` that sequentially ignores the scope. + * + * @category do notation + * @since 1.0.0 + */ +export const andThenBind: ( + name: Exclude, + that: Either +) => ( + self: Either +) => Either = semiProduct + .andThenBind(SemiProduct) diff --git a/src/Option.ts b/src/Option.ts index d9337bcab..65ebb05ff 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -106,7 +106,7 @@ export const some: (value: A) => Option = option.some * @category constructors * @since 1.0.0 */ -export const of: (a: A) => Option = some +export const of: (value: A) => Option = some // ------------------------------------------------------------------------------------- // guards @@ -252,8 +252,8 @@ export const getLeft: (self: Either) => Option = either.getLeft /** * Converts an `Option` to an `Either`, allowing you to provide a value to be used in the case of a `None`. * - * @param onNone - a function that produces an error value when the `Option` is `None`. * @param self - the `Option` to convert. + * @param onNone - a function that produces an error value when the `Option` is `None`. * * @example * import { pipe } from '@fp-ts/core/Function' @@ -264,12 +264,13 @@ export const getLeft: (self: Either) => Option = either.getLeft * assert.deepStrictEqual(pipe(O.some(1), O.toEither(onNone)), E.right(1)) * assert.deepStrictEqual(pipe(O.none(), O.toEither(onNone)), E.left('error')) * + * @dual * @category conversions * @since 1.0.0 */ export const toEither: { - (fa: Option, onNone: () => E): Either - (onNone: () => E): (fa: Option) => Either + (self: Option, onNone: () => E): Either + (onNone: () => E): (self: Option) => Either } = either.fromOption // ------------------------------------------------------------------------------------- @@ -386,7 +387,7 @@ export const orElseEither: { ) /** - * Given an Iterable collection of `Option`s, the function returns the first `Some` found in the collection. + * Given an `Iterable` collection of `Option`s, the function returns the first `Some` found in the collection. * * @param collection - An iterable collection of `Option` to be searched. * @@ -641,28 +642,6 @@ export const Invariant: invariant.Invariant = { */ export const tupled: (self: Option) => Option<[A]> = invariant.tupled(Invariant) -/** - * @category do notation - * @since 1.0.0 - */ -export const bindTo: ( - name: N -) => (self: Option) => Option<{ [K in N]: A }> = invariant.bindTo(Invariant) - -const let_: ( - name: Exclude, - f: (a: A) => B -) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant - .let(Covariant) - -export { - /** - * @category do notation - * @since 1.0.0 - */ - let_ as let -} - /** * @category mapping * @since 1.0.0 @@ -701,12 +680,6 @@ export const Of: of_.Of = { */ export const unit: Option = of_.unit(Of) -/** - * @category do notation - * @since 1.0.0 - */ -export const Do: Option<{}> = of_.Do(Of) - /** * @category instances * @since 1.0.0 @@ -774,16 +747,6 @@ export const Chainable: chainable.Chainable = { flatMap } -/** - * @category do notation - * @since 1.0.0 - */ -export const bind: ( - name: Exclude, - f: (a: A) => Option -) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable - .bind(Chainable) - /** * Sequences the specified `that` `Option` but ignores its value. * @@ -907,18 +870,6 @@ export const SemiProduct: semiProduct.SemiProduct = { productMany } -/** - * A variant of `bind` that sequentially ignores the scope. - * - * @category do notation - * @since 1.0.0 - */ -export const andThenBind: ( - name: Exclude, - that: Option -) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct - .andThenBind(SemiProduct) - /** * Appends an element to the end of a tuple. * @@ -1694,3 +1645,57 @@ export const multiplyAll = (self: Iterable>): number => { } return out } + +// ------------------------------------------------------------------------------------- +// do notation +// ------------------------------------------------------------------------------------- + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindTo: ( + name: N +) => (self: Option) => Option<{ [K in N]: A }> = invariant.bindTo(Invariant) + +const let_: ( + name: Exclude, + f: (a: A) => B +) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant + .let(Covariant) + +export { + /** + * @category do notation + * @since 1.0.0 + */ + let_ as let +} + +/** + * @category do notation + * @since 1.0.0 + */ +export const bind: ( + name: Exclude, + f: (a: A) => Option +) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable + .bind(Chainable) + +/** + * @category do notation + * @since 1.0.0 + */ +export const Do: Option<{}> = of_.Do(Of) + +/** + * A variant of `bind` that sequentially ignores the scope. + * + * @category do notation + * @since 1.0.0 + */ +export const andThenBind: ( + name: Exclude, + that: Option +) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct + .andThenBind(SemiProduct) diff --git a/src/These.ts b/src/These.ts index d5cad818c..99c7d64d0 100644 --- a/src/These.ts +++ b/src/These.ts @@ -91,7 +91,7 @@ export const right: (right: A) => These = E.right * @category constructors * @since 1.0.0 */ -export const of = right +export const of: (right: A) => These = right /** * @category constructors @@ -104,35 +104,27 @@ export const both = (left: E, right: A): These => * @category constructors * @since 1.0.0 */ -export const fail = (e: E): Validated => left([e]) +export const leftOrBoth = (onSome: LazyArg) => + (self: Option): These => O.isNone(self) ? left(onSome()) : both(onSome(), self.value) /** - * Alias of `right`. - * * @category constructors * @since 1.0.0 */ -export const succeed: (a: A) => Validated = right - -/** - * @category constructors - * @since 1.0.0 - */ -export const warn = (e: E, a: A): Validated => both([e], a) +export const rightOrBoth = (onNone: LazyArg) => + (self: Option): These => O.isNone(self) ? right(onNone()) : both(self.value, onNone()) /** * @category constructors * @since 1.0.0 */ -export const leftOrBoth = (e: LazyArg) => - (self: Option): These => O.isNone(self) ? left(e()) : both(e(), self.value) +export const fail = (e: E): Validated => left([e]) /** * @category constructors * @since 1.0.0 */ -export const rightOrBoth = (a: () => A) => - (self: Option): These => O.isNone(self) ? right(a()) : both(self.value, a()) +export const warn = (e: E, a: A): Validated => both([e], a) /** * @category pattern matching @@ -212,23 +204,6 @@ export const isThese = (u: unknown): u is These => typeof u === "object" && u != null && structural in u && "_tag" in u && (u["_tag"] === "Left" || u["_tag"] === "Right" || u["_tag"] === "Both") -/** - * Constructs a new `These` from a function that might throw. - * - * @category interop - * @since 1.0.0 - */ -export const fromThrowable = ( - f: () => A, - onThrow: (error: unknown) => E -): These => { - try { - return right(f()) - } catch (e) { - return left(onThrow(e)) - } -} - /** * Lifts a function that may throw to one returning a `These`. * @@ -238,7 +213,14 @@ export const fromThrowable = ( export const liftThrowable = , B, E>( f: (...a: A) => B, onThrow: (error: unknown) => E -): ((...a: A) => These) => (...a) => fromThrowable(() => f(...a), onThrow) +): ((...a: A) => These) => + (...a) => { + try { + return right(f(...a)) + } catch (e) { + return left(onThrow(e)) + } + } /** * @category interop @@ -627,14 +609,6 @@ export const tupled: (self: These) => These = invariant.tupl Invariant ) -/** - * @category do notation - * @since 1.0.0 - */ -export const bindTo: ( - name: N -) => (self: These) => These = invariant.bindTo(Invariant) - /** * @category mapping * @since 1.0.0 @@ -660,23 +634,6 @@ export const as: (b: B) => (self: These) => These = covaria */ export const asUnit: (self: These) => These = covariant.asUnit(Covariant) -const let_: ( - name: Exclude, - f: (a: A) => B -) => ( - self: These -) => These = covariant.let( - Covariant -) - -export { - /** - * @category do notation - * @since 1.0.0 - */ - let_ as let -} - /** * @category instances * @since 1.0.0 @@ -690,12 +647,6 @@ export const Of: of_.Of = { */ export const unit: These = of_.unit(Of) -/** - * @category do notation - * @since 1.0.0 - */ -export const Do: These = of_.Do(Of) - /** * @category instances * @since 1.0.0 @@ -782,16 +733,6 @@ export const Foldable: foldable.Foldable = { reduce } -/** - * Recovers from all errors. - * - * @category error handling - * @since 1.0.0 - */ -export const catchAll = ( - onLeft: (e: E1) => These -) => (self: These): These => isLeft(self) ? onLeft(self.left) : self - /** * Executes this effect and returns its value, if it succeeds, but otherwise * executes the specified effect. @@ -799,9 +740,9 @@ export const catchAll = ( * @category error handling * @since 1.0.0 */ -export const orElse = ( - that: These -) => (self: These): These => isLeft(self) ? that : self +export const orElse = ( + that: (e1: E1) => These +) => (self: These): These => isLeft(self) ? that(self.left) : self /** * Returns an effect that will produce the value of this effect, unless it @@ -810,12 +751,12 @@ export const orElse = ( * @category error handling * @since 1.0.0 */ -export const orElseEither = ( - that: These +export const orElseEither = ( + that: (e1: E1) => These ) => - (self: These): These> => + (self: These): These> => isLeft(self) ? - pipe(that, map(E.right)) : + pipe(that(self.left), map(E.right)) : pipe(self, map(E.left)) /** @@ -827,7 +768,7 @@ export const orElseEither = ( */ export const orElseFail = ( onLeft: LazyArg -): (self: These) => These => catchAll(() => left(onLeft())) +): (self: These) => These => orElse(() => left(onLeft())) /** * @category error handling @@ -1054,42 +995,6 @@ const productAll = ( return right(rights) } -/** - * @category do notation - * @since 1.0.0 - */ -export const andThenBind: ( - name: Exclude, - that: Validated -) => ( - self: Validated -) => Validated = semiProduct - .andThenBind(SemiProduct) - -/** - * @category do notation - * @since 1.0.0 - */ -export const andThenBindEither = ( - name: Exclude, - that: Either -): ( - self: Validated -) => Validated => - andThenBind(name, fromEither(that)) - -/** - * @category do notation - * @since 1.0.0 - */ -export const andThenBindThese = ( - name: Exclude, - that: These -): ( - self: Validated -) => Validated => - andThenBind(name, fromThese(that)) - /** * Appends an element to the end of a tuple. * @@ -1396,3 +1301,50 @@ export const subtractBigint: { that: Validated ) => (self: Validated) => Validated >(2, lift2(BI.subtract)) + +// ------------------------------------------------------------------------------------- +// do notation +// ------------------------------------------------------------------------------------- + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindTo: ( + name: N +) => (self: These) => These = invariant.bindTo(Invariant) + +const let_: ( + name: Exclude, + f: (a: A) => B +) => ( + self: These +) => These = covariant.let( + Covariant +) + +export { + /** + * @category do notation + * @since 1.0.0 + */ + let_ as let +} + +/** + * @category do notation + * @since 1.0.0 + */ +export const Do: These = of_.Do(Of) + +/** + * @category do notation + * @since 1.0.0 + */ +export const andThenBind: ( + name: Exclude, + that: Validated +) => ( + self: Validated +) => Validated = semiProduct + .andThenBind(SemiProduct) diff --git a/src/internal/Either.ts b/src/internal/Either.ts index 44cd8713f..4d3fd0d62 100644 --- a/src/internal/Either.ts +++ b/src/internal/Either.ts @@ -34,10 +34,10 @@ export const getRight = ( /** @internal */ export const fromOption = dual< - (fa: Option, onNone: () => E) => Either, - (onNone: () => E) => (fa: Option) => Either + (self: Option, onNone: () => E) => Either, + (onNone: () => E) => (self: Option) => Either >( 2, - (fa: Option, onNone: () => E): Either => - option.isNone(fa) ? left(onNone()) : right(fa.value) + (self: Option, onNone: () => E): Either => + option.isNone(self) ? left(onNone()) : right(self.value) ) diff --git a/test/These.ts b/test/These.ts index 5e8593785..ca29b7e6a 100644 --- a/test/These.ts +++ b/test/These.ts @@ -132,82 +132,13 @@ describe("These", () => { ) }) - it("andThenBindEither", () => { - Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindEither("b", E.right(2))), - _.succeed({ a: 1, b: 2 }) - ) - Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindEither("b", E.left("e2"))), - _.fail("e2") - ) - Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindEither("b", E.right(2))), - _.fail("e1") - ) - Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindEither("b", E.left("e2"))), - _.fail("e1") - ) - Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.andThenBindEither("b", E.right(2))), - _.warn("e1", { a: 1, b: 2 }) - ) - expect( - pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.andThenBindEither("b", E.left("e2"))) - ).toEqual( - _.left(["e1", "e2"]) - ) - }) - - it("andThenBindThese", () => { - Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindThese("b", _.right(2))), - _.succeed({ a: 1, b: 2 }) - ) - Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindThese("b", _.left("e2"))), - _.fail("e2") - ) - Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.succeed(1)), _.andThenBindThese("b", _.both("e2", 2))), - _.warn("e2", { a: 1, b: 2 }) - ) - Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindThese("b", _.right(2))), - _.fail("e1") - ) - Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindThese("b", _.left("e2"))), - _.fail("e1") - ) - Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.fail("e1")), _.andThenBindThese("b", _.both("e2", 2))), - _.fail("e1") - ) - Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.andThenBindThese("b", _.right(2))), - _.warn("e1", { a: 1, b: 2 }) - ) - expect( - pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.andThenBindThese("b", _.left("e2"))) - ).toEqual( - _.left(["e1", "e2"]) - ) - expect( - pipe(_.Do, _.bind("a", () => _.warn("e1", 1)), _.andThenBindThese("b", _.both("e2", 2))) - ).toEqual( - _.both(["e1", "e2"], { a: 1, b: 2 }) - ) - }) - it("andThenBind", () => { Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindEither("b", () => E.right(2))), - _.succeed({ a: 1, b: 2 }) + pipe(_.Do, _.bind("a", () => _.right(1)), _.bindEither("b", () => E.right(2))), + _.right({ a: 1, b: 2 }) ) Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindEither("b", () => E.left("e2"))), + pipe(_.Do, _.bind("a", () => _.right(1)), _.bindEither("b", () => E.left("e2"))), _.fail("e2") ) Util.deepStrictEqual( @@ -231,15 +162,15 @@ describe("These", () => { it("andThenBind", () => { Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindThese("b", () => _.right(2))), - _.succeed({ a: 1, b: 2 }) + pipe(_.Do, _.bind("a", () => _.right(1)), _.bindThese("b", () => _.right(2))), + _.right({ a: 1, b: 2 }) ) Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindThese("b", () => _.left("e2"))), + pipe(_.Do, _.bind("a", () => _.right(1)), _.bindThese("b", () => _.left("e2"))), _.fail("e2") ) Util.deepStrictEqual( - pipe(_.Do, _.bind("a", () => _.succeed(1)), _.bindThese("b", () => _.both("e2", 2))), + pipe(_.Do, _.bind("a", () => _.right(1)), _.bindThese("b", () => _.both("e2", 2))), _.warn("e2", { a: 1, b: 2 }) ) Util.deepStrictEqual( @@ -356,15 +287,15 @@ describe("These", () => { const f = ( n: number ) => (n >= 2 ? - (n <= 5 ? _.succeed(n * 2) : _.warn("e2", n)) : + (n <= 5 ? _.right(n * 2) : _.warn("e2", n)) : _.fail("e3")) Util.deepStrictEqual( pipe(_.fail("e1"), _.flatMap(f)), _.fail("e1") ) - Util.deepStrictEqual(pipe(_.succeed(2), _.flatMap(f)), _.succeed(4)) - Util.deepStrictEqual(pipe(_.succeed(1), _.flatMap(f)), _.fail("e3")) - Util.deepStrictEqual(pipe(_.succeed(6), _.flatMap(f)), _.warn("e2", 6)) + Util.deepStrictEqual(pipe(_.right(2), _.flatMap(f)), _.right(4)) + Util.deepStrictEqual(pipe(_.right(1), _.flatMap(f)), _.fail("e3")) + Util.deepStrictEqual(pipe(_.right(6), _.flatMap(f)), _.warn("e2", 6)) Util.deepStrictEqual( pipe(_.warn("e1", 2), _.flatMap(f)), _.warn("e1", 4) @@ -375,8 +306,8 @@ describe("These", () => { it("flatMapNullable", () => { const f = _.flatMapNullable((n: number) => (n > 0 ? n : null), () => "e2") - Util.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) - Util.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) + Util.deepStrictEqual(f(_.right(1)), _.right(1)) + Util.deepStrictEqual(f(_.right(-1)), _.fail("e2")) Util.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) Util.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) expect(f(_.warn("e1", -1))).toEqual(_.left(["e1", "e2"])) @@ -384,8 +315,8 @@ describe("These", () => { it("flatMapOption", () => { const f = _.flatMapOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "e2") - Util.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) - Util.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) + Util.deepStrictEqual(f(_.right(1)), _.right(1)) + Util.deepStrictEqual(f(_.right(-1)), _.fail("e2")) Util.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) Util.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) expect(f(_.warn("e1", -1))).toEqual(_.left(["e1", "e2"])) @@ -393,8 +324,8 @@ describe("These", () => { it("flatMapEither", () => { const f = _.flatMapEither((n: number) => (n > 0 ? E.right(n) : E.left("e2"))) - Util.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) - Util.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) + Util.deepStrictEqual(f(_.right(1)), _.right(1)) + Util.deepStrictEqual(f(_.right(-1)), _.fail("e2")) Util.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) Util.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) expect(f(_.warn("e1", -1))).toEqual(_.left(["e1", "e2"])) @@ -404,9 +335,9 @@ describe("These", () => { const f = _.flatMapThese(( n: number ) => (n > 10 ? _.both("e3", n) : n > 0 ? _.right(n) : _.left("e2"))) - Util.deepStrictEqual(f(_.succeed(1)), _.succeed(1)) - Util.deepStrictEqual(f(_.succeed(-1)), _.fail("e2")) - Util.deepStrictEqual(f(_.succeed(11)), _.warn("e3", 11)) + Util.deepStrictEqual(f(_.right(1)), _.right(1)) + Util.deepStrictEqual(f(_.right(-1)), _.fail("e2")) + Util.deepStrictEqual(f(_.right(11)), _.warn("e3", 11)) Util.deepStrictEqual(f(_.fail("e1")), _.fail("e1")) Util.deepStrictEqual(f(_.warn("e1", 1)), _.warn("e1", 1)) expect(f(_.warn("e1", -1))).toEqual(_.left(["e1", "e2"])) @@ -507,22 +438,6 @@ describe("These", () => { Util.deepStrictEqual(_.isBoth(_.both("e", 1)), true) }) - it("fromThrowable", () => { - Util.deepStrictEqual( - _.fromThrowable(() => { - return 1 - }, identity), - _.right(1) - ) - - Util.deepStrictEqual( - _.fromThrowable(() => { - throw "string error" - }, identity), - _.left("string error") - ) - }) - it("liftThrowable", () => { const f = _.liftThrowable((s: string) => { const len = s.length @@ -637,7 +552,7 @@ describe("These", () => { }) it("fromThese", () => { - Util.deepStrictEqual(_.fromThese(_.right(1)), _.succeed(1)) + Util.deepStrictEqual(_.fromThese(_.right(1)), _.right(1)) Util.deepStrictEqual(_.fromThese(_.left("e")), _.fail("e")) Util.deepStrictEqual(_.fromThese(_.both("e", 1)), _.warn("e", 1)) }) @@ -666,13 +581,13 @@ describe("These", () => { it("liftEither", () => { const f = _.liftEither((n: number) => (n > 0 ? E.right(n) : E.left("e"))) - Util.deepStrictEqual(f(1), _.succeed(1)) + Util.deepStrictEqual(f(1), _.right(1)) Util.deepStrictEqual(f(-1), _.fail("e")) }) it("liftThese", () => { const f = _.liftThese((n: number) => (n > 0 ? _.right(n) : _.left("e"))) - Util.deepStrictEqual(f(1), _.succeed(1)) + Util.deepStrictEqual(f(1), _.right(1)) Util.deepStrictEqual(f(-1), _.fail("e")) }) @@ -708,40 +623,30 @@ describe("These", () => { Util.deepStrictEqual(_.of(1), _.right(1)) }) - it("catchAll", () => { - Util.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.right(2))), _.right(1)) - Util.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.left("b"))), _.right(1)) - Util.deepStrictEqual(pipe(_.right(1), _.catchAll(() => _.both("b", 2))), _.right(1)) - Util.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.right(2))), _.right(2)) - Util.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.left("b"))), _.left("b")) - Util.deepStrictEqual(pipe(_.left("a"), _.catchAll(() => _.both("b", 2))), _.both("b", 2)) - Util.deepStrictEqual(pipe(_.both("a", 1), _.catchAll(() => _.right(2))), _.both("a", 1)) - Util.deepStrictEqual(pipe(_.both("a", 1), _.catchAll(() => _.left("b"))), _.both("a", 1)) - Util.deepStrictEqual(pipe(_.both("a", 1), _.catchAll(() => _.both("b", 2))), _.both("a", 1)) - }) - it("orElse", () => { - Util.deepStrictEqual(pipe(_.right(1), _.orElse(_.right(2))), _.right(1)) - Util.deepStrictEqual(pipe(_.right(1), _.orElse(_.left("b"))), _.right(1)) - Util.deepStrictEqual(pipe(_.right(1), _.orElse(_.both("b", 2))), _.right(1)) - Util.deepStrictEqual(pipe(_.left("a"), _.orElse(_.right(2))), _.right(2)) - Util.deepStrictEqual(pipe(_.left("a"), _.orElse(_.left("b"))), _.left("b")) - Util.deepStrictEqual(pipe(_.left("a"), _.orElse(_.both("b", 2))), _.both("b", 2)) - Util.deepStrictEqual(pipe(_.both("a", 1), _.orElse(_.right(2))), _.both("a", 1)) - Util.deepStrictEqual(pipe(_.both("a", 1), _.orElse(_.left("b"))), _.both("a", 1)) - Util.deepStrictEqual(pipe(_.both("a", 1), _.orElse(_.both("b", 2))), _.both("a", 1)) + Util.deepStrictEqual(pipe(_.right(1), _.orElse(() => _.right(2))), _.right(1)) + Util.deepStrictEqual(pipe(_.right(1), _.orElse(() => _.left("b"))), _.right(1)) + Util.deepStrictEqual(pipe(_.right(1), _.orElse(() => _.both("b", 2))), _.right(1)) + Util.deepStrictEqual(pipe(_.left("a"), _.orElse(() => _.right(2))), _.right(2)) + Util.deepStrictEqual(pipe(_.left("a"), _.orElse(() => _.left("b"))), _.left("b")) + Util.deepStrictEqual(pipe(_.left("a"), _.orElse(() => _.both("b", 2))), _.both("b", 2)) + Util.deepStrictEqual(pipe(_.both("a", 1), _.orElse(() => _.right(2))), _.both("a", 1)) + Util.deepStrictEqual(pipe(_.both("a", 1), _.orElse(() => _.left("b"))), _.both("a", 1)) + Util.deepStrictEqual(pipe(_.both("a", 1), _.orElse(() => _.both("b", 2))), _.both("a", 1)) }) it("orElseEither", () => { - expect(pipe(_.right(1), _.orElseEither(_.right(2)))).toEqual(_.right(E.left(1))) - expect(pipe(_.right(1), _.orElseEither(_.left("b")))).toEqual(_.right(E.left(1))) - expect(pipe(_.right(1), _.orElseEither(_.both("b", 2)))).toEqual(_.right(E.left(1))) - expect(pipe(_.left("a"), _.orElseEither(_.right(2)))).toEqual(_.right(E.right(2))) - expect(pipe(_.left("a"), _.orElseEither(_.left("b")))).toEqual(_.left("b")) - expect(pipe(_.left("a"), _.orElseEither(_.both("b", 2)))).toEqual(_.both("b", E.right(2))) - expect(pipe(_.both("a", 1), _.orElseEither(_.right(2)))).toEqual(_.both("a", E.left(1))) - expect(pipe(_.both("a", 1), _.orElseEither(_.left("b")))).toEqual(_.both("a", E.left(1))) - expect(pipe(_.both("a", 1), _.orElseEither(_.both("b", 2)))).toEqual(_.both("a", E.left(1))) + expect(pipe(_.right(1), _.orElseEither(() => _.right(2)))).toEqual(_.right(E.left(1))) + expect(pipe(_.right(1), _.orElseEither(() => _.left("b")))).toEqual(_.right(E.left(1))) + expect(pipe(_.right(1), _.orElseEither(() => _.both("b", 2)))).toEqual(_.right(E.left(1))) + expect(pipe(_.left("a"), _.orElseEither(() => _.right(2)))).toEqual(_.right(E.right(2))) + expect(pipe(_.left("a"), _.orElseEither(() => _.left("b")))).toEqual(_.left("b")) + expect(pipe(_.left("a"), _.orElseEither(() => _.both("b", 2)))).toEqual(_.both("b", E.right(2))) + expect(pipe(_.both("a", 1), _.orElseEither(() => _.right(2)))).toEqual(_.both("a", E.left(1))) + expect(pipe(_.both("a", 1), _.orElseEither(() => _.left("b")))).toEqual(_.both("a", E.left(1))) + expect(pipe(_.both("a", 1), _.orElseEither(() => _.both("b", 2)))).toEqual( + _.both("a", E.left(1)) + ) }) it("orElseFail", () => { From 3db048d065bccd5aa975ae680cff6fed90af6c55 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 19:21:48 +0100 Subject: [PATCH 138/255] Covariant: apply dual --- docs/modules/Either.ts.md | 10 ++++-- docs/modules/Option.ts.md | 7 ++-- docs/modules/ReadonlyArray.ts.md | 7 ++-- docs/modules/These.ts.md | 10 ++++-- docs/modules/typeclass/Covariant.ts.md | 45 +++++++++++++++----------- src/Either.ts | 12 ++++--- src/Option.ts | 11 +++++-- src/ReadonlyArray.ts | 14 ++++---- src/These.ts | 13 +++++--- src/typeclass/Covariant.ts | 32 ++++++++++++++---- 10 files changed, 111 insertions(+), 50 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index a4b86c45f..249d472d0 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -1080,7 +1080,10 @@ Maps the Right value of this effect to the specified constant value. **Signature** ```ts -export declare const as: (b: B) => (self: Either) => Either +export declare const as: { + (self: Either, b: B): Either + (b: B): (self: Either) => Either +} ``` Added in v1.0.0 @@ -1115,7 +1118,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const flap: (self: Either B>) => (a: A) => Either +export declare const flap: { + (a: A, self: Either B>): Either + (self: Either B>): (a: A) => Either +} ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index e9fcc82ab..358175e5c 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -1281,7 +1281,7 @@ Maps the `Some` value of this `Option` to the specified constant value. **Signature** ```ts -export declare const as: (b: B) => <_>(self: Option<_>) => Option +export declare const as: { <_, B>(self: Option<_>, b: B): Option; (b: B): <_>(self: Option<_>) => Option } ``` Added in v1.0.0 @@ -1305,7 +1305,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const flap: (self: Option<(a: A) => B>) => (a: A) => Option +export declare const flap: { + (a: A, self: Option<(a: A) => B>): Option + (self: Option<(a: A) => B>): (a: A) => Option +} ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index c2af2e172..e72ed1b58 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -1439,7 +1439,7 @@ Maps the success value of this effect to the specified constant value. **Signature** ```ts -export declare const as: (b: B) => (self: ReadonlyArray) => B[] +export declare const as: { <_, B>(self: readonly _[], b: B): B[]; (b: B): <_>(self: readonly _[]) => B[] } ``` Added in v1.0.0 @@ -1449,7 +1449,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const flap: (self: readonly ((a: A) => B)[]) => (a: A) => B[] +export declare const flap: { + (a: A, self: readonly ((a: A) => B)[]): B[] + (self: readonly ((a: A) => B)[]): (a: A) => B[] +} ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 86c7500e7..8ea10ab2c 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1197,7 +1197,10 @@ Maps the right value of this effect to the specified constant value. **Signature** ```ts -export declare const as: (b: B) => (self: These) => These +export declare const as: { + (self: These, b: B): These + (b: B): (self: These) => These +} ``` Added in v1.0.0 @@ -1232,7 +1235,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const flap: (self: These B>) => (a: A) => These +export declare const flap: { + (a: A, self: These B>): These + (self: These B>): (a: A) => These +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index badb18d3e..f883b4f35 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -14,6 +14,8 @@ Added in v1.0.0 - [constructors](#constructors) - [make](#make) +- [do notation](#do-notation) + - [let](#let) - [mapping](#mapping) - [as](#as) - [asUnit](#asunit) @@ -22,7 +24,6 @@ Added in v1.0.0 - [Covariant (interface)](#covariant-interface) - [utils](#utils) - [imap](#imap) - - [let](#let) - [mapComposition](#mapcomposition) --- @@ -41,6 +42,23 @@ export declare const make: ( Added in v1.0.0 +# do notation + +## let + +**Signature** + +```ts +export declare const let: ( + F: Covariant +) => ( + name: Exclude, + f: (a: A) => B +) => (self: Kind) => Kind +``` + +Added in v1.0.0 + # mapping ## as @@ -50,7 +68,10 @@ Added in v1.0.0 ```ts export declare const as: ( F: Covariant -) => (b: B) => (self: Kind) => Kind +) => { + (self: Kind, b: B): Kind + (b: B): (self: Kind) => Kind +} ``` Added in v1.0.0 @@ -74,7 +95,10 @@ Added in v1.0.0 ```ts export declare const flap: ( F: Covariant -) => (self: Kind B>) => (a: A) => Kind +) => { + (a: A, self: Kind B>): Kind + (self: Kind B>): (a: A) => Kind +} ``` Added in v1.0.0 @@ -109,21 +133,6 @@ export declare const imap: ( Added in v1.0.0 -## let - -**Signature** - -```ts -export declare const let: ( - F: Covariant -) => ( - name: Exclude, - f: (a: A) => B -) => (self: Kind) => Kind -``` - -Added in v1.0.0 - ## mapComposition Returns a default `map` composition. diff --git a/src/Either.ts b/src/Either.ts index 6196d2483..51b5bd925 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -262,7 +262,10 @@ export const tupled: (self: Either) => Either = invariant.tu * @category mapping * @since 1.0.0 */ -export const flap: (self: Either B>) => (a: A) => Either = covariant +export const flap: { + (a: A, self: Either B>): Either + (self: Either B>): (a: A) => Either +} = covariant .flap(Covariant) /** @@ -271,9 +274,10 @@ export const flap: (self: Either B>) => (a: A) => Either(b: B) => (self: Either) => Either = covariant.as( - Covariant -) +export const as: { + (self: Either, b: B): Either + (b: B): (self: Either) => Either +} = covariant.as(Covariant) /** * Returns the effect Eithering from mapping the Right of this effect to unit. diff --git a/src/Option.ts b/src/Option.ts index 65ebb05ff..3112a7e10 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -646,8 +646,10 @@ export const tupled: (self: Option) => Option<[A]> = invariant.tupled(Inva * @category mapping * @since 1.0.0 */ -export const flap: (self: Option<(a: A) => B>) => (a: A) => Option = covariant - .flap(Covariant) +export const flap: { + (a: A, self: Option<(a: A) => B>): Option + (self: Option<(a: A) => B>): (a: A) => Option +} = covariant.flap(Covariant) /** * Maps the `Some` value of this `Option` to the specified constant value. @@ -655,7 +657,10 @@ export const flap: (self: Option<(a: A) => B>) => (a: A) => Option = co * @category mapping * @since 1.0.0 */ -export const as: (b: B) => <_>(self: Option<_>) => Option = covariant.as(Covariant) +export const as: { + <_, B>(self: Option<_>, b: B): Option + (b: B): <_>(self: Option<_>) => Option +} = covariant.as(Covariant) /** * Returns the `Option` resulting from mapping the `Some` value to `void`. diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 064d1275d..4d333edda 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1319,9 +1319,10 @@ export { * @category mapping * @since 1.0.0 */ -export const flap: (self: ReadonlyArray<(a: A) => B>) => (a: A) => Array = covariant.flap( - Covariant -) as any +export const flap: { + (a: A, self: ReadonlyArray<(a: A) => B>): Array + (self: ReadonlyArray<(a: A) => B>): (a: A) => Array +} = covariant.flap(Covariant) as any /** * Maps the success value of this effect to the specified constant value. @@ -1329,9 +1330,10 @@ export const flap: (self: ReadonlyArray<(a: A) => B>) => (a: A) => Array(b: B) => (self: ReadonlyArray) => Array = covariant.as( - Covariant -) as any +export const as: { + <_, B>(self: ReadonlyArray<_>, b: B): Array + (b: B): <_>(self: ReadonlyArray<_>) => Array +} = covariant.as(Covariant) as any /** * @category instances diff --git a/src/These.ts b/src/These.ts index 99c7d64d0..e41c5bbff 100644 --- a/src/These.ts +++ b/src/These.ts @@ -613,8 +613,10 @@ export const tupled: (self: These) => These = invariant.tupl * @category mapping * @since 1.0.0 */ -export const flap: (self: These B>) => (a: A) => These = covariant - .flap(Covariant) +export const flap: { + (a: A, self: These B>): These + (self: These B>): (a: A) => These +} = covariant.flap(Covariant) /** * Maps the right value of this effect to the specified constant value. @@ -622,9 +624,10 @@ export const flap: (self: These B>) => (a: A) => These(b: B) => (self: These) => These = covariant.as( - Covariant -) +export const as: { + (self: These, b: B): These + (b: B): (self: These) => These +} = covariant.as(Covariant) /** * Returns the effect resulting from mapping the right of this effect to unit. diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index 972540128..664e0f533 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { pipe } from "@fp-ts/core/Function" +import { dual, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" @@ -50,16 +50,35 @@ export const make = (map: Covariant["map"]): Covariant< * @category mapping * @since 1.0.0 */ -export const flap = (F: Covariant) => - (self: Kind B>) => - (a: A): Kind => pipe(self, F.map(f => f(a))) +export const flap = (F: Covariant): { + (a: A, self: Kind B>): Kind + (self: Kind B>): (a: A) => Kind +} => + dual< + (a: A, self: Kind B>) => Kind, + (self: Kind B>) => (a: A) => Kind + >( + 2, + (a: A, self: Kind B>): Kind => + pipe(self, F.map(f => f(a))) + ) /** * @category mapping * @since 1.0.0 */ -export const as = (F: Covariant) => - (b: B): ((self: Kind) => Kind) => F.map(() => b) +export const as = (F: Covariant): { + (self: Kind, b: B): Kind + (b: B): (self: Kind) => Kind +} => + dual< + (self: Kind, b: B) => Kind, + (b: B) => (self: Kind) => Kind + >( + 2, + (self: Kind, b: B): Kind => + pipe(self, F.map(() => b)) + ) /** * @category mapping @@ -81,6 +100,7 @@ const let_ = ( export { /** + * @category do notation * @since 1.0.0 */ let_ as let From 97879984aaea288f8996910fed15917682cf33d2 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 19:33:31 +0100 Subject: [PATCH 139/255] FlatMap: apply dual --- docs/modules/Either.ts.md | 12 ++++-- docs/modules/Option.ts.md | 12 ++++-- docs/modules/ReadonlyArray.ts.md | 7 ++-- docs/modules/These.ts.md | 23 ++++++++--- docs/modules/typeclass/FlatMap.ts.md | 26 +++++++++--- src/Either.ts | 21 ++++++---- src/Option.ts | 14 ++++--- src/ReadonlyArray.ts | 13 ++++-- src/These.ts | 25 ++++++------ src/typeclass/FlatMap.ts | 60 +++++++++++++++++++++++----- 10 files changed, 150 insertions(+), 63 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 249d472d0..ea88a65be 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -1342,7 +1342,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const andThen: (that: Either) => (self: Either) => Either +export declare const andThen: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} ``` Added in v1.0.0 @@ -1376,9 +1379,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const composeKleisliArrow: ( - bfc: (b: B) => Either -) => (afb: (a: A) => Either) => (a: A) => Either +export declare const composeKleisliArrow: { + (afb: (a: A) => Either, bfc: (b: B) => Either): (a: A) => Either + (bfc: (b: B) => Either): (afb: (a: A) => Either) => (a: A) => Either +} ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 358175e5c..32cd93fb3 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -1632,7 +1632,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const andThen: (that: Option) => <_>(self: Option<_>) => Option +export declare const andThen: { + <_, B>(self: Option<_>, that: Option): Option + (that: Option): <_>(self: Option<_>) => Option +} ``` Added in v1.0.0 @@ -1666,9 +1669,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const composeKleisliArrow: ( - bfc: (b: B) => Option -) => (afb: (a: A) => Option) => (a: A) => Option +export declare const composeKleisliArrow: { + (afb: (a: A) => Option, bfc: (b: B) => Option): (a: A) => Option + (bfc: (b: B) => Option): (afb: (a: A) => Option) => (a: A) => Option +} ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index e72ed1b58..3b96ff7b1 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -1942,9 +1942,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const composeKleisliArrow: ( - bfc: (b: B) => readonly C[] -) => (afb: (a: A) => readonly B[]) => (a: A) => readonly C[] +export declare const composeKleisliArrow: { + (afb: (a: A) => readonly B[], bfc: (b: B) => readonly C[]): (a: A) => readonly C[] + (bfc: (b: B) => readonly C[]): (afb: (a: A) => readonly B[]) => (a: A) => readonly C[] +} ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 8ea10ab2c..939b58e63 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1494,9 +1494,15 @@ Added in v3.0.0 **Signature** ```ts -export declare const andThen: ( - that: These -) => (self: These) => These +export declare const andThen: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + B + > + (that: These): ( + self: These + ) => These +} ``` Added in v1.0.0 @@ -1534,9 +1540,14 @@ Added in v1.0.0 **Signature** ```ts -export declare const composeKleisliArrow: ( - bfc: (b: B) => These -) => (afb: (a: A) => These) => (a: A) => These +export declare const composeKleisliArrow: { + (afb: (a: A) => These, bfc: (b: B) => These): ( + a: A + ) => These + (bfc: (b: B) => These): ( + afb: (a: A) => These + ) => (a: A) => These +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/FlatMap.ts.md b/docs/modules/typeclass/FlatMap.ts.md index 1a03f3310..11cfb66d5 100644 --- a/docs/modules/typeclass/FlatMap.ts.md +++ b/docs/modules/typeclass/FlatMap.ts.md @@ -48,9 +48,18 @@ A variant of `flatMap` that ignores the value produced by this effect. ```ts export declare const andThen: ( F: FlatMap -) => ( - that: Kind -) => (self: Kind) => Kind +) => { + (self: Kind, that: Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + B + > + (that: Kind): ( + self: Kind + ) => Kind +} ``` Added in v1.0.0 @@ -62,9 +71,14 @@ Added in v1.0.0 ```ts export declare const composeKleisliArrow: ( F: FlatMap -) => ( - bfc: (b: B) => Kind -) => (afb: (a: A) => Kind) => (a: A) => Kind +) => { + (afb: (a: A) => Kind, bfc: (b: B) => Kind): ( + a: A + ) => Kind + (bfc: (b: B) => Kind): ( + afb: (a: A) => Kind + ) => (a: A) => Kind +} ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index 51b5bd925..ebed59fe2 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -368,18 +368,23 @@ export const flatten: (self: Either>) => Either( - that: Either -) => (self: Either) => Either = flatMap_ - .andThen(FlatMap) +export const andThen: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = flatMap_.andThen(FlatMap) /** * @since 1.0.0 */ -export const composeKleisliArrow: ( - bfc: (b: B) => Either -) => (afb: (a: A) => Either) => (a: A) => Either = flatMap_ - .composeKleisliArrow(FlatMap) +export const composeKleisliArrow: { + ( + afb: (a: A) => Either, + bfc: (b: B) => Either + ): (a: A) => Either + ( + bfc: (b: B) => Either + ): (afb: (a: A) => Either) => (a: A) => Either +} = flatMap_.composeKleisliArrow(FlatMap) /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index 3112a7e10..4e7d645cc 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -731,16 +731,18 @@ export const flatten: (self: Option>) => Option = flatMap_ /** * @since 1.0.0 */ -export const andThen: (that: Option) => <_>(self: Option<_>) => Option = flatMap_ - .andThen(FlatMap) +export const andThen: { + <_, B>(self: Option<_>, that: Option): Option + (that: Option): <_>(self: Option<_>) => Option +} = flatMap_.andThen(FlatMap) /** * @since 1.0.0 */ -export const composeKleisliArrow: ( - bfc: (b: B) => Option -) => (afb: (a: A) => Option) => (a: A) => Option = flatMap_ - .composeKleisliArrow(FlatMap) +export const composeKleisliArrow: { + (afb: (a: A) => Option, bfc: (b: B) => Option): (a: A) => Option + (bfc: (b: B) => Option): (afb: (a: A) => Option) => (a: A) => Option +} = flatMap_.composeKleisliArrow(FlatMap) /** * @category instances diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 4d333edda..238cdd67a 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1416,10 +1416,15 @@ export const flattenNonEmpty: ( /** * @since 1.0.0 */ -export const composeKleisliArrow: ( - bfc: (b: B) => ReadonlyArray -) => (afb: (a: A) => ReadonlyArray) => (a: A) => ReadonlyArray = flatMap_ - .composeKleisliArrow(FlatMap) +export const composeKleisliArrow: { + ( + afb: (a: A) => ReadonlyArray, + bfc: (b: B) => ReadonlyArray + ): (a: A) => ReadonlyArray + ( + bfc: (b: B) => ReadonlyArray + ): (afb: (a: A) => ReadonlyArray) => (a: A) => ReadonlyArray +} = flatMap_.composeKleisliArrow(FlatMap) /** * @category instances diff --git a/src/These.ts b/src/These.ts index e41c5bbff..46e1297c2 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1106,22 +1106,23 @@ export const flatten: ( /** * @since 1.0.0 */ -export const andThen: ( - that: Validated -) => ( - self: Validated -) => Validated = flatMap_ - .andThen(FlatMap) +export const andThen: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = flatMap_.andThen(FlatMap) /** * @since 1.0.0 */ -export const composeKleisliArrow: ( - bfc: (b: B) => Validated -) => ( - afb: (a: A) => Validated -) => (a: A) => Validated = flatMap_ - .composeKleisliArrow(FlatMap) +export const composeKleisliArrow: { + ( + afb: (a: A) => Validated, + bfc: (b: B) => Validated + ): (a: A) => Validated + ( + bfc: (b: B) => Validated + ): (afb: (a: A) => Validated) => (a: A) => Validated +} = flatMap_.composeKleisliArrow(FlatMap) /** * @category instances diff --git a/src/typeclass/FlatMap.ts b/src/typeclass/FlatMap.ts index 13bb5809f..c3fbe81d4 100644 --- a/src/typeclass/FlatMap.ts +++ b/src/typeclass/FlatMap.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { identity, pipe } from "@fp-ts/core/Function" +import { dual, identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" /** @@ -27,20 +27,60 @@ export const flatten = (F: FlatMap) => * * @since 1.0.0 */ -export const andThen = (F: FlatMap) => +export const andThen = (F: FlatMap): { + ( + self: Kind, + that: Kind + ): Kind ( that: Kind - ): (( - self: Kind - ) => Kind) => F.flatMap(() => that) + ): (self: Kind) => Kind +} => + dual< + ( + self: Kind, + that: Kind + ) => Kind, + ( + that: Kind + ) => ( + self: Kind + ) => Kind + >(2, ( + self: Kind, + that: Kind + ): Kind => pipe(self, F.flatMap(() => that))) /** * @since 1.0.0 */ export const composeKleisliArrow = ( F: FlatMap -): ( - bfc: (b: B) => Kind -) => ( - afb: (a: A) => Kind -) => (a: A) => Kind => bc => ab => a => pipe(ab(a), F.flatMap(bc)) +): { + ( + afb: (a: A) => Kind, + bfc: (b: B) => Kind + ): (a: A) => Kind + ( + bfc: (b: B) => Kind + ): ( + afb: (a: A) => Kind + ) => (a: A) => Kind +} => + dual< + ( + afb: (a: A) => Kind, + bfc: (b: B) => Kind + ) => (a: A) => Kind, + ( + bfc: (b: B) => Kind + ) => ( + afb: (a: A) => Kind + ) => (a: A) => Kind + >( + 2, + ( + afb: (a: A) => Kind, + bfc: (b: B) => Kind + ): ((a: A) => Kind) => a => pipe(afb(a), F.flatMap(bfc)) + ) From f46f5c18d1021117fbc0faa414f59fca0dd50ccd Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 31 Jan 2023 19:55:17 +0100 Subject: [PATCH 140/255] Chainable: apply dual --- docs/modules/Either.ts.md | 37 +++++++----- docs/modules/Option.ts.md | 10 ++- docs/modules/These.ts.md | 51 ++++++++++------ docs/modules/typeclass/Chainable.ts.md | 30 +++++++-- src/Either.ts | 33 ++++++---- src/Option.ts | 19 ++++-- src/ReadonlyArray.ts | 3 + src/These.ts | 33 ++++++---- src/typeclass/Chainable.ts | 84 +++++++++++++++++++------- src/typeclass/Covariant.ts | 2 + src/typeclass/FlatMap.ts | 2 + 11 files changed, 216 insertions(+), 88 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index ea88a65be..4acc95f7d 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -20,6 +20,8 @@ Added in v1.0.0 - [subtractBigint](#subtractbigint) - [sum](#sum) - [sumBigint](#sumbigint) +- [combinators](#combinators) + - [tap](#tap) - [combining](#combining) - [getFirstLeftMonoid](#getfirstleftmonoid) - [getFirstLeftSemigroup](#getfirstleftsemigroup) @@ -127,7 +129,6 @@ Added in v1.0.0 - [flatten](#flatten) - [reverse](#reverse) - [struct](#struct) - - [tap](#tap) - [tuple](#tuple) - [unit](#unit) @@ -226,6 +227,23 @@ export declare const sumBigint: { Added in v1.0.0 +# combinators + +## tap + +Returns an effect that effectfully "peeks" at the success of this effect. + +**Signature** + +```ts +export declare const tap: { + (self: Either, f: (a: A) => Either): Either + (f: (a: A) => Either): (self: Either) => Either +} +``` + +Added in v1.0.0 + # combining ## getFirstLeftMonoid @@ -1240,7 +1258,10 @@ produced by the effect. **Signature** ```ts -export declare const andThenDiscard: (that: Either) => (self: Either) => Either +export declare const andThenDiscard: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} ``` Added in v1.0.0 @@ -1458,18 +1479,6 @@ export declare const struct: >>( Added in v1.0.0 -## tap - -Returns an effect that effectfully "peeks" at the success of this effect. - -**Signature** - -```ts -export declare const tap: (f: (a: A) => Either) => (self: Either) => Either -``` - -Added in v1.0.0 - ## tuple **Signature** diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 32cd93fb3..2e21c2e2e 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -282,7 +282,10 @@ This function is useful for performing additional computations on the value of t **Signature** ```ts -export declare const tap: (f: (a: A) => Option<_>) => (self: Option) => Option +export declare const tap: { + (self: Option, f: (a: A) => Option<_>): Option + (f: (a: A) => Option<_>): (self: Option) => Option +} ``` Added in v1.0.0 @@ -1437,7 +1440,10 @@ It is useful when we want to chain multiple operations, but only care about the **Signature** ```ts -export declare const andThenDiscard: <_>(that: Option<_>) => (self: Option) => Option +export declare const andThenDiscard: { + (self: Option, that: Option<_>): Option + <_>(that: Option<_>): (self: Option) => Option +} ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 939b58e63..a5912a272 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -20,6 +20,8 @@ Added in v1.0.0 - [subtractBigint](#subtractbigint) - [sum](#sum) - [sumBigint](#sumbigint) +- [combinators](#combinators) + - [tap](#tap) - [combining](#combining) - [getFirstLeftMonoid](#getfirstleftmonoid) - [getFirstLeftSemigroup](#getfirstleftsemigroup) @@ -151,7 +153,6 @@ Added in v1.0.0 - [flatten](#flatten) - [reverse](#reverse) - [struct](#struct) - - [tap](#tap) - [tuple](#tuple) - [unit](#unit) @@ -285,6 +286,28 @@ export declare const sumBigint: { Added in v1.0.0 +# combinators + +## tap + +Returns an effect that effectfully "peeks" at the success of this effect. + +**Signature** + +```ts +export declare const tap: { + (self: These, f: (a: A) => These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + A + > + (f: (a: A) => These): ( + self: These + ) => These +} +``` + +Added in v1.0.0 + # combining ## getFirstLeftMonoid @@ -1354,9 +1377,15 @@ produced by the effect. **Signature** ```ts -export declare const andThenDiscard: ( - that: These -) => (self: These) => These +export declare const andThenDiscard: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + A + > + (that: These): ( + self: These + ) => These +} ``` Added in v1.0.0 @@ -1604,20 +1633,6 @@ export declare const struct: ( - f: (a: A) => These -) => (self: These) => These -``` - -Added in v1.0.0 - ## tuple **Signature** diff --git a/docs/modules/typeclass/Chainable.ts.md b/docs/modules/typeclass/Chainable.ts.md index 615e82864..0f8aa804d 100644 --- a/docs/modules/typeclass/Chainable.ts.md +++ b/docs/modules/typeclass/Chainable.ts.md @@ -34,9 +34,18 @@ produced by the effect. ```ts export declare const andThenDiscard: ( F: Chainable -) => ( - that: Kind -) => (self: Kind) => Kind +) => { + (self: Kind, that: Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + A + > + (that: Kind): ( + self: Kind + ) => Kind +} ``` Added in v1.0.0 @@ -81,9 +90,18 @@ Returns an effect that effectfully "peeks" at the success of this effect. ```ts export declare const tap: ( F: Chainable -) => ( - f: (a: A) => Kind -) => (self: Kind) => Kind +) => { + (self: Kind, f: (a: A) => Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + A + > + (f: (a: A) => Kind): ( + self: Kind + ) => Kind +} ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index ebed59fe2..8f2af6d20 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -259,6 +259,7 @@ export const tupled: (self: Either) => Either = invariant.tu ) /** + * @dual * @category mapping * @since 1.0.0 */ @@ -271,6 +272,7 @@ export const flap: { /** * Maps the Right value of this effect to the specified constant value. * + * @dual * @category mapping * @since 1.0.0 */ @@ -366,6 +368,7 @@ export const flatten: (self: Either>) => Either = { * Sequences the specified effect after this effect, but ignores the value * produced by the effect. * + * @dual * @category sequencing * @since 1.0.0 */ -export const andThenDiscard: ( - that: Either -) => (self: Either) => Either = chainable - .andThenDiscard(Chainable) +export const andThenDiscard: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = chainable.andThenDiscard(Chainable) /** * @category instances @@ -945,13 +950,19 @@ export const traverseTap: ( /** * Returns an effect that effectfully "peeks" at the success of this effect. * - * @since 1.0.0 - */ -export const tap: ( - f: (a: A) => Either -) => (self: Either) => Either = chainable.tap( - Chainable -) + * @dual + * @category combinators + * @since 1.0.0 + */ +export const tap: { + ( + self: Either, + f: (a: A) => Either + ): Either + ( + f: (a: A) => Either + ): (self: Either) => Either +} = chainable.tap(Chainable) // ------------------------------------------------------------------------------------- // debugging diff --git a/src/Option.ts b/src/Option.ts index 4e7d645cc..c5159e3a2 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -643,6 +643,7 @@ export const Invariant: invariant.Invariant = { export const tupled: (self: Option) => Option<[A]> = invariant.tupled(Invariant) /** + * @dual * @category mapping * @since 1.0.0 */ @@ -654,6 +655,7 @@ export const flap: { /** * Maps the `Some` value of this `Option` to the specified constant value. * + * @dual * @category mapping * @since 1.0.0 */ @@ -729,6 +731,7 @@ export const flatten: (self: Option>) => Option = flatMap_ .flatten(FlatMap) /** + * @dual * @since 1.0.0 */ export const andThen: { @@ -737,6 +740,7 @@ export const andThen: { } = flatMap_.andThen(FlatMap) /** + * @dual * @since 1.0.0 */ export const composeKleisliArrow: { @@ -762,11 +766,14 @@ export const Chainable: chainable.Chainable = { * @param that - The `Option` that will be ignored in the chain and discarded * @param self - The `Option` we care about * + * @dual * @category sequencing * @since 1.0.0 */ -export const andThenDiscard: <_>(that: Option<_>) => (self: Option) => Option = chainable - .andThenDiscard(Chainable) +export const andThenDiscard: { + (self: Option, that: Option<_>): Option + <_>(that: Option<_>): (self: Option) => Option +} = chainable.andThenDiscard(Chainable) /** * Applies the provided function `f` to the value of the `Option` if it is `Some` and returns the original `Option` @@ -777,12 +784,14 @@ export const andThenDiscard: <_>(that: Option<_>) => (self: Option) => Opt * @param f - Function to apply to the value of the `Option` if it is `Some` * @param self - The `Option` to apply the function to * + * @dual * @category combinators * @since 1.0.0 */ -export const tap: (f: (a: A) => Option<_>) => (self: Option) => Option = chainable.tap( - Chainable -) +export const tap: { + (self: Option, f: (a: A) => Option<_>): Option + (f: (a: A) => Option<_>): (self: Option) => Option +} = chainable.tap(Chainable) // ------------------------------------------------------------------------------------- // debugging diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 238cdd67a..edb5d4547 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1316,6 +1316,7 @@ export { } /** + * @dual * @category mapping * @since 1.0.0 */ @@ -1327,6 +1328,7 @@ export const flap: { /** * Maps the success value of this effect to the specified constant value. * + * @dual * @category mapping * @since 1.0.0 */ @@ -1414,6 +1416,7 @@ export const flattenNonEmpty: ( ) => NonEmptyArray = flatMapNonEmpty(identity) /** + * @dual * @since 1.0.0 */ export const composeKleisliArrow: { diff --git a/src/These.ts b/src/These.ts index 46e1297c2..3f938f9ce 100644 --- a/src/These.ts +++ b/src/These.ts @@ -610,6 +610,7 @@ export const tupled: (self: These) => These = invariant.tupl ) /** + * @dual * @category mapping * @since 1.0.0 */ @@ -621,6 +622,7 @@ export const flap: { /** * Maps the right value of this effect to the specified constant value. * + * @dual * @category mapping * @since 1.0.0 */ @@ -1104,6 +1106,7 @@ export const flatten: ( .flatten(FlatMap) /** + * @dual * @since 1.0.0 */ export const andThen: { @@ -1112,6 +1115,7 @@ export const andThen: { } = flatMap_.andThen(FlatMap) /** + * @dual * @since 1.0.0 */ export const composeKleisliArrow: { @@ -1174,24 +1178,31 @@ export const bindThese = ( * Sequences the specified effect after this effect, but ignores the value * produced by the effect. * + * @dual * @category sequencing * @since 1.0.0 */ -export const andThenDiscard: ( - that: Validated -) => (self: Validated) => Validated = chainable - .andThenDiscard(Chainable) +export const andThenDiscard: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = chainable.andThenDiscard(Chainable) /** * Returns an effect that effectfully "peeks" at the success of this effect. * - * @since 1.0.0 - */ -export const tap: ( - f: (a: A) => Validated -) => (self: Validated) => Validated = chainable.tap( - Chainable -) + * @dual + * @category combinators + * @since 1.0.0 + */ +export const tap: { + ( + self: Validated, + f: (a: A) => Validated + ): Validated + ( + f: (a: A) => Validated + ): (self: Validated) => Validated +} = chainable.tap(Chainable) /** * @category instances diff --git a/src/typeclass/Chainable.ts b/src/typeclass/Chainable.ts index 86ce4df76..80a83ce74 100644 --- a/src/typeclass/Chainable.ts +++ b/src/typeclass/Chainable.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { pipe } from "@fp-ts/core/Function" +import { dual, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" import type { FlatMap } from "@fp-ts/core/typeclass/FlatMap" @@ -12,35 +12,77 @@ import type { FlatMap } from "@fp-ts/core/typeclass/FlatMap" */ export interface Chainable extends FlatMap, Covariant {} -/** - * Returns an effect that effectfully "peeks" at the success of this effect. - * - * @since 1.0.0 - */ -export const tap = (F: Chainable) => - ( - f: (a: A) => Kind - ): ((self: Kind) => Kind) => - F.flatMap(a => - pipe( - f(a), - F.map(() => a) - ) - ) - /** * Sequences the specified effect after this effect, but ignores the value * produced by the effect. * + * @dual * @category sequencing * @since 1.0.0 */ -export const andThenDiscard = (F: Chainable) => +export const andThenDiscard = (F: Chainable): { + ( + self: Kind, + that: Kind + ): Kind ( that: Kind - ): (( - self: Kind - ) => Kind) => tap(F)(() => that) + ): (self: Kind) => Kind +} => + dual< + ( + self: Kind, + that: Kind + ) => Kind, + ( + that: Kind + ) => ( + self: Kind + ) => Kind + >(2, ( + self: Kind, + that: Kind + ): Kind => tap(F)(self, () => that)) + +/** + * Returns an effect that effectfully "peeks" at the success of this effect. + * + * @dual + * @since 1.0.0 + */ +export const tap = (F: Chainable): { + ( + self: Kind, + f: (a: A) => Kind + ): Kind + ( + f: (a: A) => Kind + ): (self: Kind) => Kind +} => + dual< + ( + self: Kind, + f: (a: A) => Kind + ) => Kind, + ( + f: (a: A) => Kind + ) => (self: Kind) => Kind + >( + 2, + ( + self: Kind, + f: (a: A) => Kind + ): Kind => + pipe( + self, + F.flatMap(a => + pipe( + f(a), + F.map(() => a) + ) + ) + ) + ) /** * @since 1.0.0 diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index 664e0f533..ad62fe4f6 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -47,6 +47,7 @@ export const make = (map: Covariant["map"]): Covariant< }) /** + * @dual * @category mapping * @since 1.0.0 */ @@ -64,6 +65,7 @@ export const flap = (F: Covariant): { ) /** + * @dual * @category mapping * @since 1.0.0 */ diff --git a/src/typeclass/FlatMap.ts b/src/typeclass/FlatMap.ts index c3fbe81d4..4c0de8f43 100644 --- a/src/typeclass/FlatMap.ts +++ b/src/typeclass/FlatMap.ts @@ -25,6 +25,7 @@ export const flatten = (F: FlatMap) => /** * A variant of `flatMap` that ignores the value produced by this effect. * + * @dual * @since 1.0.0 */ export const andThen = (F: FlatMap): { @@ -52,6 +53,7 @@ export const andThen = (F: FlatMap): { ): Kind => pipe(self, F.flatMap(() => that))) /** + * @dual * @since 1.0.0 */ export const composeKleisliArrow = ( From d24af57b1f9e46e5696ea6f2f7f551d95a6ffde9 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 1 Feb 2023 06:31:47 +0100 Subject: [PATCH 141/255] SemiApplicative: refactor lift2 to return a dual function --- docs/modules/Either.ts.md | 5 +- docs/modules/Option.ts.md | 7 +- docs/modules/ReadonlyArray.ts.md | 4 +- docs/modules/These.ts.md | 15 +++- docs/modules/typeclass/SemiApplicative.ts.md | 7 +- src/Either.ts | 85 +++++------------- src/Option.ts | 79 +++++----------- src/ReadonlyArray.ts | 11 +-- src/These.ts | 95 ++++---------------- src/typeclass/Chainable.ts | 2 - src/typeclass/Covariant.ts | 2 - src/typeclass/FlatMap.ts | 2 - src/typeclass/Order.ts | 8 -- src/typeclass/SemiApplicative.ts | 16 +++- 14 files changed, 107 insertions(+), 231 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 4acc95f7d..4175a92d4 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -1030,7 +1030,10 @@ Lifts a binary function into `Either`. ```ts export declare const lift2: ( f: (a: A, b: B) => C -) => (self: Either, that: Either) => Either +) => { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 2e21c2e2e..57e353704 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -1209,13 +1209,14 @@ Added in v1.0.0 ## lift2 -Applies a function to the contained value of two `Option`s, returning a new `Option` of the result. -If either of the `Option`s is `None`, the result will be `None`. +Lifts a binary function into `Option`. **Signature** ```ts -export declare const lift2: (f: (a: A, b: B) => C) => (self: Option, that: Option) => Option +export declare const lift2: ( + f: (a: A, b: B) => C +) => { (self: Option, that: Option): Option; (that: Option): (self: Option) => Option } ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 3b96ff7b1..6f1d36058 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -1345,7 +1345,9 @@ Lifts a binary function into `ReadonlyArray`. **Signature** ```ts -export declare const lift2: (f: (a: A, b: B) => C) => (fa: readonly A[], fb: readonly B[]) => C[] +export declare const lift2: ( + f: (a: A, b: B) => C +) => { (self: readonly A[], that: readonly B[]): C[]; (that: readonly B[]): (self: readonly A[]) => C[] } ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index a5912a272..d5f7d3ade 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1135,15 +1135,22 @@ Added in v1.0.0 ## lift2 +Lifts a binary function into `These`. + **Signature** ```ts export declare const lift2: ( f: (a: A, b: B) => C -) => ( - self: These, - that: These -) => These +) => { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + C + > + (that: These): ( + self: These + ) => These +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index 5aabd6f7d..0038f35ab 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -38,10 +38,13 @@ export declare const lift2: ( F: SemiApplicative ) => ( f: (a: A, b: B) => C -) => ( +) => (( self: Kind, that: Kind -) => Kind +) => Kind) & + (( + that: Kind + ) => (self: Kind) => Kind) ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index 8f2af6d20..eb9aa2539 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -266,8 +266,7 @@ export const tupled: (self: Either) => Either = invariant.tu export const flap: { (a: A, self: Either B>): Either (self: Either B>): (a: A) => Either -} = covariant - .flap(Covariant) +} = covariant.flap(Covariant) /** * Maps the Right value of this effect to the specified constant value. @@ -548,13 +547,15 @@ export const getFirstLeftSemigroup: (S: Semigroup) => Semigroup( - f: (a: A, b: B) => C -) => (self: Either, that: Either) => Either = semiApplicative - .lift2(SemiApplicative) +export const lift2: (f: (a: A, b: B) => C) => { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = semiApplicative.lift2(SemiApplicative) /** * @category products @@ -955,13 +956,8 @@ export const traverseTap: ( * @since 1.0.0 */ export const tap: { - ( - self: Either, - f: (a: A) => Either - ): Either - ( - f: (a: A) => Either - ): (self: Either) => Either + (self: Either, f: (a: A) => Either): Either + (f: (a: A) => Either): (self: Either) => Either } = chainable.tap(Chainable) // ------------------------------------------------------------------------------------- @@ -1118,88 +1114,53 @@ export const getOptionalSemigroup = (S: Semigroup): Semigroup(self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} = dual< - (self: Either, that: Either) => Either, - (that: Either) => (self: Either) => Either ->(2, lift2(N.sum)) +export const sum = lift2(N.sum) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiply: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} = dual< - (self: Either, that: Either) => Either, - (that: Either) => (self: Either) => Either ->(2, lift2(N.multiply)) +export const multiply = lift2(N.multiply) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtract: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} = dual< - (self: Either, that: Either) => Either, - (that: Either) => (self: Either) => Either ->(2, lift2(N.subtract)) +export const subtract = lift2(N.subtract) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const divide: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} = dual< - (self: Either, that: Either) => Either, - (that: Either) => (self: Either) => Either ->(2, lift2(N.divide)) +export const divide = lift2(N.divide) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const sumBigint: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} = dual< - (self: Either, that: Either) => Either, - (that: Either) => (self: Either) => Either ->(2, lift2(BI.sum)) +export const sumBigint = lift2(BI.sum) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiplyBigint: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} = dual< - (self: Either, that: Either) => Either, - (that: Either) => (self: Either) => Either ->(2, lift2(BI.multiply)) +export const multiplyBigint = lift2(BI.multiply) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtractBigint: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} = dual< - (self: Either, that: Either) => Either, - (that: Either) => (self: Either) => Either ->(2, lift2(BI.subtract)) +export const subtractBigint = lift2(BI.subtract) // ------------------------------------------------------------------------------------- // do notation diff --git a/src/Option.ts b/src/Option.ts index c5159e3a2..e1e9302f3 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -976,20 +976,17 @@ export const getOptionalMonoid = ( ) /** - * Applies a function to the contained value of two `Option`s, returning a new `Option` of the result. - * If either of the `Option`s is `None`, the result will be `None`. + * Lifts a binary function into `Option`. * - * @param f - A function to apply to the contained values of the `Option`s - * @param that - An `Option` to lift the function over - * @param self - An `Option` to lift the function over + * @param f - The function to lift. * * @category lifting * @since 1.0.0 */ -export const lift2: ( - f: (a: A, b: B) => C -) => (self: Option, that: Option) => Option = semiApplicative - .lift2(SemiApplicative) +export const lift2: (f: (a: A, b: B) => C) => { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = semiApplicative.lift2(SemiApplicative) /** * Zips two `Option` values together using a provided function, returning a new `Option` of the result. @@ -1220,7 +1217,6 @@ export const filter: { } = filterable.filter(Filterable) /** - * @dual * @category traversing * @since 1.0.0 */ @@ -1527,88 +1523,53 @@ export const reduceAll: { // ------------------------------------------------------------------------------------- /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const sum: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} = dual< - (self: Option, that: Option) => Option, - (that: Option) => (self: Option) => Option ->(2, lift2(N.sum)) +export const sum = lift2(N.sum) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiply: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} = dual< - (self: Option, that: Option) => Option, - (that: Option) => (self: Option) => Option ->(2, lift2(N.multiply)) +export const multiply = lift2(N.multiply) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtract: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} = dual< - (self: Option, that: Option) => Option, - (that: Option) => (self: Option) => Option ->(2, lift2(N.subtract)) +export const subtract = lift2(N.subtract) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const divide: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} = dual< - (self: Option, that: Option) => Option, - (that: Option) => (self: Option) => Option ->(2, lift2(N.divide)) +export const divide = lift2(N.divide) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const sumBigint: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} = dual< - (self: Option, that: Option) => Option, - (that: Option) => (self: Option) => Option ->(2, lift2(BI.sum)) +export const sumBigint = lift2(BI.sum) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiplyBigint: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} = dual< - (self: Option, that: Option) => Option, - (that: Option) => (self: Option) => Option ->(2, lift2(BI.multiply)) +export const multiplyBigint = lift2(BI.multiply) /** + * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtractBigint: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} = dual< - (self: Option, that: Option) => Option, - (that: Option) => (self: Option) => Option ->(2, lift2(BI.subtract)) +export const subtractBigint = lift2(BI.subtract) /** * Sum all numbers in an iterable of `Option` ignoring the `None` values. diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index edb5d4547..5813d3d75 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1762,14 +1762,15 @@ export const ap: ( /** * Lifts a binary function into `ReadonlyArray`. * + * @param f - The function to lift. + * * @category lifting * @since 1.0.0 */ -export const lift2: ( - f: (a: A, b: B) => C -) => (fa: ReadonlyArray, fb: ReadonlyArray) => Array = semiApplicative.lift2( - SemiApplicative -) as any +export const lift2: (f: (a: A, b: B) => C) => { + (self: ReadonlyArray, that: ReadonlyArray): Array + (that: ReadonlyArray): (self: ReadonlyArray) => Array +} = semiApplicative.lift2(SemiApplicative) as any /** * @category lifting diff --git a/src/These.ts b/src/These.ts index 3f938f9ce..9334772b4 100644 --- a/src/These.ts +++ b/src/These.ts @@ -6,7 +6,7 @@ import * as BI from "@fp-ts/core/Bigint" import type { Either, Left, Right } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" -import { constNull, constUndefined, dual, pipe } from "@fp-ts/core/Function" +import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { proto, structural } from "@fp-ts/core/internal/effect" import * as N from "@fp-ts/core/Number" @@ -937,15 +937,17 @@ export const SemiApplicative: semiApplicative.SemiApplicative( - f: (a: A, b: B) => C -) => (self: Validated, that: Validated) => Validated = - semiApplicative.lift2( - SemiApplicative - ) +export const lift2: (f: (a: A, b: B) => C) => { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = semiApplicative.lift2(SemiApplicative) /** * @category products @@ -1195,13 +1197,8 @@ export const andThenDiscard: { * @since 1.0.0 */ export const tap: { - ( - self: Validated, - f: (a: A) => Validated - ): Validated - ( - f: (a: A) => Validated - ): (self: Validated) => Validated + (self: Validated, f: (a: A) => Validated): Validated + (f: (a: A) => Validated): (self: Validated) => Validated } = chainable.tap(Chainable) /** @@ -1223,99 +1220,43 @@ export const Monad: monad.Monad = { * @category algebraic operations * @since 1.0.0 */ -export const sum: { - (self: Validated, that: Validated): Validated - (that: Validated): (self: Validated) => Validated -} = dual< - (self: Validated, that: Validated) => Validated, - ( - that: Validated - ) => (self: Validated) => Validated ->(2, lift2(N.sum)) +export const sum = lift2(N.sum) /** * @category algebraic operations * @since 1.0.0 */ -export const multiply: { - (self: Validated, that: Validated): Validated - (that: Validated): (self: Validated) => Validated -} = dual< - (self: Validated, that: Validated) => Validated, - ( - that: Validated - ) => (self: Validated) => Validated ->(2, lift2(N.multiply)) +export const multiply = lift2(N.multiply) /** * @category algebraic operations * @since 1.0.0 */ -export const subtract: { - (self: Validated, that: Validated): Validated - (that: Validated): (self: Validated) => Validated -} = dual< - (self: Validated, that: Validated) => Validated, - ( - that: Validated - ) => (self: Validated) => Validated ->(2, lift2(N.subtract)) +export const subtract = lift2(N.subtract) /** * @category algebraic operations * @since 1.0.0 */ -export const divide: { - (self: Validated, that: Validated): Validated - (that: Validated): (self: Validated) => Validated -} = dual< - (self: Validated, that: Validated) => Validated, - ( - that: Validated - ) => (self: Validated) => Validated ->(2, lift2(N.divide)) +export const divide = lift2(N.divide) /** * @category algebraic operations * @since 1.0.0 */ -export const sumBigint: { - (self: Validated, that: Validated): Validated - (that: Validated): (self: Validated) => Validated -} = dual< - (self: Validated, that: Validated) => Validated, - ( - that: Validated - ) => (self: Validated) => Validated ->(2, lift2(BI.sum)) +export const sumBigint = lift2(BI.sum) /** * @category algebraic operations * @since 1.0.0 */ -export const multiplyBigint: { - (self: Validated, that: Validated): Validated - (that: Validated): (self: Validated) => Validated -} = dual< - (self: Validated, that: Validated) => Validated, - ( - that: Validated - ) => (self: Validated) => Validated ->(2, lift2(BI.multiply)) +export const multiplyBigint = lift2(BI.multiply) /** * @category algebraic operations * @since 1.0.0 */ -export const subtractBigint: { - (self: Validated, that: Validated): Validated - (that: Validated): (self: Validated) => Validated -} = dual< - (self: Validated, that: Validated) => Validated, - ( - that: Validated - ) => (self: Validated) => Validated ->(2, lift2(BI.subtract)) +export const subtractBigint = lift2(BI.subtract) // ------------------------------------------------------------------------------------- // do notation diff --git a/src/typeclass/Chainable.ts b/src/typeclass/Chainable.ts index 80a83ce74..b0ee983ad 100644 --- a/src/typeclass/Chainable.ts +++ b/src/typeclass/Chainable.ts @@ -16,7 +16,6 @@ export interface Chainable extends FlatMap, Covariant(F: Chainable): { /** * Returns an effect that effectfully "peeks" at the success of this effect. * - * @dual * @since 1.0.0 */ export const tap = (F: Chainable): { diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index ad62fe4f6..664e0f533 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -47,7 +47,6 @@ export const make = (map: Covariant["map"]): Covariant< }) /** - * @dual * @category mapping * @since 1.0.0 */ @@ -65,7 +64,6 @@ export const flap = (F: Covariant): { ) /** - * @dual * @category mapping * @since 1.0.0 */ diff --git a/src/typeclass/FlatMap.ts b/src/typeclass/FlatMap.ts index 4c0de8f43..c3fbe81d4 100644 --- a/src/typeclass/FlatMap.ts +++ b/src/typeclass/FlatMap.ts @@ -25,7 +25,6 @@ export const flatten = (F: FlatMap) => /** * A variant of `flatMap` that ignores the value produced by this effect. * - * @dual * @since 1.0.0 */ export const andThen = (F: FlatMap): { @@ -53,7 +52,6 @@ export const andThen = (F: FlatMap): { ): Kind => pipe(self, F.flatMap(() => that))) /** - * @dual * @since 1.0.0 */ export const composeKleisliArrow = ( diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 03c318152..66a928be6 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -249,7 +249,6 @@ export const Product: product.Product = { /** * Test whether one value is _strictly less than_ another. * - * @dual * @since 1.0.0 */ export const lessThan = (O: Order): { @@ -264,7 +263,6 @@ export const lessThan = (O: Order): { /** * Test whether one value is _strictly greater than_ another. * - * @dual * @since 1.0.0 */ export const greaterThan = (O: Order): { @@ -279,7 +277,6 @@ export const greaterThan = (O: Order): { /** * Test whether one value is _non-strictly less than_ another. * - * @dual * @since 1.0.0 */ export const lessThanOrEqualTo = (O: Order): { @@ -294,7 +291,6 @@ export const lessThanOrEqualTo = (O: Order): { /** * Test whether one value is _non-strictly greater than_ another. * - * @dual * @since 1.0.0 */ export const greaterThanOrEqualTo = (O: Order): { @@ -309,7 +305,6 @@ export const greaterThanOrEqualTo = (O: Order): { /** * Take the minimum of two values. If they are considered equal, the first argument is chosen. * - * @dual * @since 1.0.0 */ export const min = (O: Order): { @@ -324,7 +319,6 @@ export const min = (O: Order): { /** * Take the maximum of two values. If they are considered equal, the first argument is chosen. * - * @dual * @since 1.0.0 */ export const max = (O: Order): { @@ -339,7 +333,6 @@ export const max = (O: Order): { /** * Clamp a value between a minimum and a maximum. * - * @dual * @since 1.0.0 */ export const clamp = (O: Order): { @@ -357,7 +350,6 @@ export const clamp = (O: Order): { /** * Test whether a value is between a minimum and a maximum (inclusive). * - * @dual * @since 1.0.0 */ export const between = (O: Order): { diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 7bf725dcc..7d62a5046 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { identity, pipe, SK } from "@fp-ts/core/Function" +import { dual, identity, pipe, SK } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" @@ -76,12 +76,22 @@ export const andThen = (F: SemiApplicative) => /** * Lifts a binary function into `F`. * + * @param f - The function to lift. + * * @category lifting * @since 1.0.0 */ export const lift2 = (F: SemiApplicative) => (f: (a: A, b: B) => C) => - ( + dual< + ( + self: Kind, + that: Kind + ) => Kind, + ( + that: Kind + ) => (self: Kind) => Kind + >(2, ( self: Kind, that: Kind - ): Kind => pipe(self, zipWith(F)(that, f)) + ): Kind => pipe(self, zipWith(F)(that, f))) From 222d749a375ff59acd5226c444bda7d00502609e Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 1 Feb 2023 06:50:02 +0100 Subject: [PATCH 142/255] fix algebraic operations overloadings order --- docs/modules/Bigint.ts.md | 8 ++-- docs/modules/Number.ts.md | 8 ++-- docs/modules/Option.ts.md | 82 +++++++++++++++++++-------------------- src/Bigint.ts | 8 ++-- src/Either.ts | 14 +++---- src/Number.ts | 8 ++-- src/Option.ts | 32 +++++++-------- src/These.ts | 14 +++---- test/Option.ts | 30 +++++++------- 9 files changed, 102 insertions(+), 102 deletions(-) diff --git a/docs/modules/Bigint.ts.md b/docs/modules/Bigint.ts.md index 4308ff4dc..097868766 100644 --- a/docs/modules/Bigint.ts.md +++ b/docs/modules/Bigint.ts.md @@ -43,7 +43,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const divide: { (self: bigint, that: bigint): bigint; (that: bigint): (self: bigint) => bigint } +export declare const divide: { (that: bigint): (self: bigint) => bigint; (self: bigint, that: bigint): bigint } ``` Added in v1.0.0 @@ -53,7 +53,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiply: { (self: bigint, that: bigint): bigint; (that: bigint): (self: bigint) => bigint } +export declare const multiply: { (that: bigint): (self: bigint) => bigint; (self: bigint, that: bigint): bigint } ``` Added in v1.0.0 @@ -63,7 +63,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtract: { (self: bigint, that: bigint): bigint; (that: bigint): (self: bigint) => bigint } +export declare const subtract: { (that: bigint): (self: bigint) => bigint; (self: bigint, that: bigint): bigint } ``` Added in v1.0.0 @@ -73,7 +73,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const sum: { (self: bigint, that: bigint): bigint; (that: bigint): (self: bigint) => bigint } +export declare const sum: { (that: bigint): (self: bigint) => bigint; (self: bigint, that: bigint): bigint } ``` Added in v1.0.0 diff --git a/docs/modules/Number.ts.md b/docs/modules/Number.ts.md index 5438f625d..dbdba912b 100644 --- a/docs/modules/Number.ts.md +++ b/docs/modules/Number.ts.md @@ -51,7 +51,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const divide: { (self: number, that: number): number; (that: number): (self: number) => number } +export declare const divide: { (that: number): (self: number) => number; (self: number, that: number): number } ``` **Example** @@ -70,7 +70,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const multiply: { (self: number, that: number): number; (that: number): (self: number) => number } +export declare const multiply: { (that: number): (self: number) => number; (self: number, that: number): number } ``` **Example** @@ -99,7 +99,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const subtract: { (self: number, that: number): number; (that: number): (self: number) => number } +export declare const subtract: { (that: number): (self: number) => number; (self: number, that: number): number } ``` **Example** @@ -118,7 +118,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const sum: { (self: number, that: number): number; (that: number): (self: number) => number } +export declare const sum: { (that: number): (self: number) => number; (self: number, that: number): number } ``` **Example** diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 57e353704..4eebf257e 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -15,13 +15,13 @@ Added in v1.0.0 - [algebraic operations](#algebraic-operations) - [divide](#divide) - [multiply](#multiply) - - [multiplyAll](#multiplyall) - [multiplyBigint](#multiplybigint) + - [multiplyCompact](#multiplycompact) - [subtract](#subtract) - [subtractBigint](#subtractbigint) - [sum](#sum) - - [sumAll](#sumall) - [sumBigint](#sumbigint) + - [sumCompact](#sumcompact) - [combinators](#combinators) - [tap](#tap) - [constructors](#constructors) @@ -126,7 +126,7 @@ Added in v1.0.0 - [contains](#contains) - [exists](#exists) - [flatten](#flatten) - - [reduceAll](#reduceall) + - [reduceCompact](#reducecompact) - [struct](#struct) - [toArray](#toarray) - [tuple](#tuple) @@ -163,36 +163,36 @@ export declare const multiply: { Added in v1.0.0 -## multiplyAll - -Multiply all numbers in an iterable of `Option` ignoring the `None` values. +## multiplyBigint **Signature** ```ts -export declare const multiplyAll: (self: Iterable>) => number +export declare const multiplyBigint: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} ``` -**Example** +Added in v1.0.0 -```ts -import { multiplyAll, some, none } from '@fp-ts/core/Option' +## multiplyCompact -const iterable = [some(2), none(), some(3), none()] -assert.deepStrictEqual(multiplyAll(iterable), 6) -``` +Multiply all numbers in an iterable of `Option` ignoring the `None` values. -Added in v1.0.0 +**Signature** -## multiplyBigint +```ts +export declare const multiplyCompact: (self: Iterable>) => number +``` -**Signature** +**Example** ```ts -export declare const multiplyBigint: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} +import { multiplyCompact, some, none } from '@fp-ts/core/Option' + +const iterable = [some(2), none(), some(3), none()] +assert.deepStrictEqual(multiplyCompact(iterable), 6) ``` Added in v1.0.0 @@ -236,36 +236,36 @@ export declare const sum: { Added in v1.0.0 -## sumAll - -Sum all numbers in an iterable of `Option` ignoring the `None` values. +## sumBigint **Signature** ```ts -export declare const sumAll: (self: Iterable>) => number +export declare const sumBigint: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} ``` -**Example** +Added in v1.0.0 -```ts -import { sumAll, some, none } from '@fp-ts/core/Option' +## sumCompact -const iterable = [some(2), none(), some(3), none()] -assert.deepStrictEqual(sumAll(iterable), 5) -``` +Sum all numbers in an iterable of `Option` ignoring the `None` values. -Added in v1.0.0 +**Signature** -## sumBigint +```ts +export declare const sumCompact: (self: Iterable>) => number +``` -**Signature** +**Example** ```ts -export declare const sumBigint: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} +import { sumCompact, some, none } from '@fp-ts/core/Option' + +const iterable = [some(2), none(), some(3), none()] +assert.deepStrictEqual(sumCompact(iterable), 5) ``` Added in v1.0.0 @@ -1749,14 +1749,14 @@ export declare const flatten: (self: Option>) => Option Added in v1.0.0 -## reduceAll +## reduceCompact Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. **Signature** ```ts -export declare const reduceAll: { +export declare const reduceCompact: { (self: Iterable>, b: B, f: (b: B, a: A) => B): B (b: B, f: (b: B, a: A) => B): (self: Iterable>) => B } @@ -1765,14 +1765,14 @@ export declare const reduceAll: { **Example** ```ts -import { some, none, reduceAll } from '@fp-ts/core/Option' +import { some, none, reduceCompact } from '@fp-ts/core/Option' import { pipe } from '@fp-ts/core/Function' const iterable = [some(1), none(), some(2), none()] assert.deepStrictEqual( pipe( iterable, - reduceAll(0, (b, a) => b + a) + reduceCompact(0, (b, a) => b + a) ), 3 ) diff --git a/src/Bigint.ts b/src/Bigint.ts index 4b198d86f..12c2de1bd 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -25,8 +25,8 @@ export const isBigint: (u: unknown) => u is bigint = predicate.isBigInt * @since 1.0.0 */ export const sum: { - (self: bigint, that: bigint): bigint (that: bigint): (self: bigint) => bigint + (self: bigint, that: bigint): bigint } = dual< (self: bigint, that: bigint) => bigint, (that: bigint) => (self: bigint) => bigint @@ -38,8 +38,8 @@ export const sum: { * @since 1.0.0 */ export const multiply: { - (self: bigint, that: bigint): bigint (that: bigint): (self: bigint) => bigint + (self: bigint, that: bigint): bigint } = dual< (self: bigint, that: bigint) => bigint, (that: bigint) => (self: bigint) => bigint @@ -51,8 +51,8 @@ export const multiply: { * @since 1.0.0 */ export const subtract: { - (self: bigint, that: bigint): bigint (that: bigint): (self: bigint) => bigint + (self: bigint, that: bigint): bigint } = dual< (self: bigint, that: bigint) => bigint, (that: bigint) => (self: bigint) => bigint @@ -64,8 +64,8 @@ export const subtract: { * @since 1.0.0 */ export const divide: { - (self: bigint, that: bigint): bigint (that: bigint): (self: bigint) => bigint + (self: bigint, that: bigint): bigint } = dual< (self: bigint, that: bigint) => bigint, (that: bigint) => (self: bigint) => bigint diff --git a/src/Either.ts b/src/Either.ts index eb9aa2539..07fc64d2e 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1118,49 +1118,49 @@ export const getOptionalSemigroup = (S: Semigroup): Semigroup(N.sum) +export const sum = lift2(N.sum) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiply = lift2(N.multiply) +export const multiply = lift2(N.multiply) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtract = lift2(N.subtract) +export const subtract = lift2(N.subtract) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const divide = lift2(N.divide) +export const divide = lift2(N.divide) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const sumBigint = lift2(BI.sum) +export const sumBigint = lift2(BI.sum) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiplyBigint = lift2(BI.multiply) +export const multiplyBigint = lift2(BI.multiply) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtractBigint = lift2(BI.subtract) +export const subtractBigint = lift2(BI.subtract) // ------------------------------------------------------------------------------------- // do notation diff --git a/src/Number.ts b/src/Number.ts index 631141de7..7a30af4d7 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -32,8 +32,8 @@ export const isNumber = predicate.isNumber * @since 1.0.0 */ export const sum: { - (self: number, that: number): number (that: number): (self: number) => number + (self: number, that: number): number } = dual< (self: number, that: number) => number, (that: number) => (self: number) => number @@ -51,8 +51,8 @@ export const sum: { * @since 1.0.0 */ export const multiply: { - (self: number, that: number): number (that: number): (self: number) => number + (self: number, that: number): number } = dual< (self: number, that: number) => number, (that: number) => (self: number) => number @@ -70,8 +70,8 @@ export const multiply: { * @since 1.0.0 */ export const subtract: { - (self: number, that: number): number (that: number): (self: number) => number + (self: number, that: number): number } = dual< (self: number, that: number) => number, (that: number) => (self: number) => number @@ -89,8 +89,8 @@ export const subtract: { * @since 1.0.0 */ export const divide: { - (self: number, that: number): number (that: number): (self: number) => number + (self: number, that: number): number } = dual< (self: number, that: number) => number, (that: number) => (self: number) => number diff --git a/src/Option.ts b/src/Option.ts index e1e9302f3..51e436f0c 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1490,16 +1490,16 @@ export const exists: { * @param f - The reducing function that takes the current accumulator value and the unwrapped value of an `Option`. * * @example - * import { some, none, reduceAll } from '@fp-ts/core/Option' + * import { some, none, reduceCompact } from '@fp-ts/core/Option' * import { pipe } from '@fp-ts/core/Function' * * const iterable = [some(1), none(), some(2), none()] - * assert.deepStrictEqual(pipe(iterable, reduceAll(0, (b, a) => b + a)), 3) + * assert.deepStrictEqual(pipe(iterable, reduceCompact(0, (b, a) => b + a)), 3) * * @dual * @since 1.0.0 */ -export const reduceAll: { +export const reduceCompact: { (self: Iterable>, b: B, f: (b: B, a: A) => B): B (b: B, f: (b: B, a: A) => B): (self: Iterable>) => B } = dual< @@ -1527,49 +1527,49 @@ export const reduceAll: { * @category algebraic operations * @since 1.0.0 */ -export const sum = lift2(N.sum) +export const sum = lift2(N.sum) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiply = lift2(N.multiply) +export const multiply = lift2(N.multiply) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtract = lift2(N.subtract) +export const subtract = lift2(N.subtract) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const divide = lift2(N.divide) +export const divide = lift2(N.divide) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const sumBigint = lift2(BI.sum) +export const sumBigint = lift2(BI.sum) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiplyBigint = lift2(BI.multiply) +export const multiplyBigint = lift2(BI.multiply) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtractBigint = lift2(BI.subtract) +export const subtractBigint = lift2(BI.subtract) /** * Sum all numbers in an iterable of `Option` ignoring the `None` values. @@ -1577,15 +1577,15 @@ export const subtractBigint = lift2(BI.subtract) * @param self - The iterable of `Option` to be summed. * * @example - * import { sumAll, some, none } from '@fp-ts/core/Option' + * import { sumCompact, some, none } from '@fp-ts/core/Option' * * const iterable = [some(2), none(), some(3), none()] - * assert.deepStrictEqual(sumAll(iterable), 5) + * assert.deepStrictEqual(sumCompact(iterable), 5) * * @category algebraic operations * @since 1.0.0 */ -export const sumAll = (self: Iterable>): number => { +export const sumCompact = (self: Iterable>): number => { let out = 0 for (const oa of self) { if (isSome(oa)) { @@ -1601,15 +1601,15 @@ export const sumAll = (self: Iterable>): number => { * @param self - The iterable of `Option` to be multiplied. * * @example - * import { multiplyAll, some, none } from '@fp-ts/core/Option' + * import { multiplyCompact, some, none } from '@fp-ts/core/Option' * * const iterable = [some(2), none(), some(3), none()] - * assert.deepStrictEqual(multiplyAll(iterable), 6) + * assert.deepStrictEqual(multiplyCompact(iterable), 6) * * @category algebraic operations * @since 1.0.0 */ -export const multiplyAll = (self: Iterable>): number => { +export const multiplyCompact = (self: Iterable>): number => { let out = 1 for (const oa of self) { if (isSome(oa)) { diff --git a/src/These.ts b/src/These.ts index 9334772b4..8b700588a 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1220,43 +1220,43 @@ export const Monad: monad.Monad = { * @category algebraic operations * @since 1.0.0 */ -export const sum = lift2(N.sum) +export const sum = lift2(N.sum) /** * @category algebraic operations * @since 1.0.0 */ -export const multiply = lift2(N.multiply) +export const multiply = lift2(N.multiply) /** * @category algebraic operations * @since 1.0.0 */ -export const subtract = lift2(N.subtract) +export const subtract = lift2(N.subtract) /** * @category algebraic operations * @since 1.0.0 */ -export const divide = lift2(N.divide) +export const divide = lift2(N.divide) /** * @category algebraic operations * @since 1.0.0 */ -export const sumBigint = lift2(BI.sum) +export const sumBigint = lift2(BI.sum) /** * @category algebraic operations * @since 1.0.0 */ -export const multiplyBigint = lift2(BI.multiply) +export const multiplyBigint = lift2(BI.multiply) /** * @category algebraic operations * @since 1.0.0 */ -export const subtractBigint = lift2(BI.subtract) +export const subtractBigint = lift2(BI.subtract) // ------------------------------------------------------------------------------------- // do notation diff --git a/test/Option.ts b/test/Option.ts index 6915b8483..38b7ab90e 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -72,7 +72,7 @@ describe.concurrent("Option", () => { expect(_.Alternative).exist expect(_.Foldable).exist - expect(_.reduceAll).exist + expect(_.reduceCompact).exist expect(_.toArray).exist expect(_.Traversable).exist @@ -546,11 +546,11 @@ describe.concurrent("Option", () => { expect(pipe(_.some(1), _.zipWith(_.some(2), (a, b) => a + b))).toEqual(_.some(3)) }) - it("reduceAll", () => { - const sumAll = _.reduceAll(0, N.SemigroupSum.combine) - expect(sumAll([])).toEqual(0) - expect(sumAll([_.some(2), _.some(3)])).toEqual(5) - expect(sumAll([_.some(2), _.none(), _.some(3)])).toEqual(5) + it("reduceCompact", () => { + const sumCompact = _.reduceCompact(0, N.sum) + expect(sumCompact([])).toEqual(0) + expect(sumCompact([_.some(2), _.some(3)])).toEqual(5) + expect(sumCompact([_.some(2), _.none(), _.some(3)])).toEqual(5) }) it("sum", () => { @@ -600,16 +600,16 @@ describe.concurrent("Option", () => { expect(pipe(_.some(1), _.Foldable.reduce(0, (b, a) => b + a))).toEqual(1) }) - it("sumAll", () => { - expect(_.sumAll([])).toEqual(0) - expect(_.sumAll([_.some(2), _.some(3)])).toEqual(5) - expect(_.sumAll([_.some(2), _.none(), _.some(3)])).toEqual(5) + it("sumCompact", () => { + expect(_.sumCompact([])).toEqual(0) + expect(_.sumCompact([_.some(2), _.some(3)])).toEqual(5) + expect(_.sumCompact([_.some(2), _.none(), _.some(3)])).toEqual(5) }) - it("multiplyAll", () => { - expect(_.multiplyAll([])).toEqual(1) - expect(_.multiplyAll([_.some(2), _.some(3)])).toEqual(6) - expect(_.multiplyAll([_.some(2), _.none(), _.some(3)])).toEqual(6) - expect(_.multiplyAll([_.some(2), _.some(0), _.some(3)])).toEqual(0) + it("multiplyCompact", () => { + expect(_.multiplyCompact([])).toEqual(1) + expect(_.multiplyCompact([_.some(2), _.some(3)])).toEqual(6) + expect(_.multiplyCompact([_.some(2), _.none(), _.some(3)])).toEqual(6) + expect(_.multiplyCompact([_.some(2), _.some(0), _.some(3)])).toEqual(0) }) }) From 906fe918826832f37004807c27b04ceccbeefb14 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 1 Feb 2023 07:42:10 +0100 Subject: [PATCH 143/255] SemiApplicative: apply dual --- docs/modules/Either.ts.md | 36 +++++----- docs/modules/Option.ts.md | 40 ++++++----- docs/modules/ReadonlyArray.ts.md | 5 +- docs/modules/These.ts.md | 49 +++++++------ docs/modules/typeclass/Chainable.ts.md | 38 ++++------ docs/modules/typeclass/Covariant.ts.md | 12 ++-- docs/modules/typeclass/FlatMap.ts.md | 34 ++++----- docs/modules/typeclass/SemiApplicative.ts.md | 35 ++++++--- src/Either.ts | 28 +++++--- src/Option.ts | 21 +++--- src/ReadonlyArray.ts | 10 +-- src/These.ts | 30 +++++--- src/typeclass/Chainable.ts | 20 +----- src/typeclass/Covariant.ts | 10 +-- src/typeclass/FlatMap.ts | 22 +----- src/typeclass/SemiApplicative.ts | 75 +++++++++++++++----- 16 files changed, 251 insertions(+), 214 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 4175a92d4..5053b90d2 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -26,6 +26,7 @@ Added in v1.0.0 - [getFirstLeftMonoid](#getfirstleftmonoid) - [getFirstLeftSemigroup](#getfirstleftsemigroup) - [getFirstRightSemigroup](#getfirstrightsemigroup) + - [zipWith](#zipwith) - [constructors](#constructors) - [left](#left) - [of](#of) @@ -106,8 +107,6 @@ Added in v1.0.0 - [Right (interface)](#right-interface) - [pattern matching](#pattern-matching) - [match](#match) -- [products](#products) - - [zipWith](#zipwith) - [sequencing](#sequencing) - [andThenDiscard](#andthendiscard) - [flatMap](#flatmap) @@ -300,6 +299,19 @@ export declare const getFirstRightSemigroup: () => Semigroup> Added in v1.0.0 +## zipWith + +**Signature** + +```ts +export declare const zipWith: { + (self: Either, that: Either, f: (a: A, b: B) => C): Either + (that: Either, f: (a: A, b: B) => C): (self: Either) => Either +} +``` + +Added in v1.0.0 + # constructors ## left @@ -1236,21 +1248,6 @@ assert.deepStrictEqual(pipe(E.left(['error 1', 'error 2']), E.match(onLeft, onRi Added in v1.0.0 -# products - -## zipWith - -**Signature** - -```ts -export declare const zipWith: ( - fb: Either, - f: (a: A, b: B) => C -) => (fa: Either) => Either -``` - -Added in v1.0.0 - # sequencing ## andThenDiscard @@ -1379,7 +1376,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const ap: (fa: Either) => (self: Either B>) => Either +export declare const ap: { + (self: Either B>, that: Either): Either + (that: Either): (self: Either B>) => Either +} ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 4eebf257e..a06cf6211 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -24,6 +24,8 @@ Added in v1.0.0 - [sumCompact](#sumcompact) - [combinators](#combinators) - [tap](#tap) +- [combining](#combining) + - [zipWith](#zipwith) - [constructors](#constructors) - [none](#none) - [of](#of) @@ -103,8 +105,6 @@ Added in v1.0.0 - [Some (interface)](#some-interface) - [pattern matching](#pattern-matching) - [match](#match) -- [products](#products) - - [zipWith](#zipwith) - [sequencing](#sequencing) - [andThenDiscard](#andthendiscard) - [flatMap](#flatmap) @@ -290,6 +290,23 @@ export declare const tap: { Added in v1.0.0 +# combining + +## zipWith + +Zips two `Option` values together using a provided function, returning a new `Option` of the result. + +**Signature** + +```ts +export declare const zipWith: { + (self: Option, that: Option, f: (a: A, b: B) => C): Option + (that: Option, f: (a: A, b: B) => C): (self: Option) => Option +} +``` + +Added in v1.0.0 + # constructors ## none @@ -1416,20 +1433,6 @@ assert.deepStrictEqual( Added in v1.0.0 -# products - -## zipWith - -Zips two `Option` values together using a provided function, returning a new `Option` of the result. - -**Signature** - -```ts -export declare const zipWith: (fb: Option, f: (a: A, b: B) => C) => (fa: Option) => Option -``` - -Added in v1.0.0 - # sequencing ## andThenDiscard @@ -1652,7 +1655,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const ap: (fa: Option) => (self: Option<(a: A) => B>) => Option +export declare const ap: { + (self: Option<(a: A) => B>, that: Option): Option + (that: Option): (self: Option<(a: A) => B>) => Option +} ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 6f1d36058..1949315d1 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -1865,7 +1865,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const ap: (fa: readonly A[]) => (self: readonly ((a: A) => B)[]) => B[] +export declare const ap: { + (self: readonly ((a: A) => B)[], that: readonly A[]): B[] + (that: readonly A[]): (self: readonly ((a: A) => B)[]) => B[] +} ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index d5f7d3ade..1583b2289 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -26,6 +26,7 @@ Added in v1.0.0 - [getFirstLeftMonoid](#getfirstleftmonoid) - [getFirstLeftSemigroup](#getfirstleftsemigroup) - [getFirstRightOrBothSemigroup](#getfirstrightorbothsemigroup) + - [zipWith](#zipwith) - [constructors](#constructors) - [both](#both) - [fail](#fail) @@ -128,8 +129,6 @@ Added in v1.0.0 - [match](#match) - [predicates](#predicates) - [exists](#exists) -- [products](#products) - - [zipWith](#zipwith) - [sequencing](#sequencing) - [andThenDiscard](#andthendiscard) - [flatMap](#flatmap) @@ -340,6 +339,25 @@ export declare const getFirstRightOrBothSemigroup: () => Semigroup( + self: These, + that: These, + f: (a: A, b: B) => C + ): These + (that: These, f: (a: A, b: B) => C): ( + self: These + ) => These +} +``` + +Added in v1.0.0 + # constructors ## both @@ -1359,21 +1377,6 @@ export declare const exists: (predicate: Predicate) => (self: These( - fb: These, - f: (a: A, b: B) => C -) => (fa: These) => These -``` - -Added in v1.0.0 - # sequencing ## andThenDiscard @@ -1548,9 +1551,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const ap: ( - fa: These -) => (self: These B>) => These +export declare const ap: { + (self: These B>, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + B + > + (that: These): ( + self: These B> + ) => These +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Chainable.ts.md b/docs/modules/typeclass/Chainable.ts.md index 0f8aa804d..bb2a686fb 100644 --- a/docs/modules/typeclass/Chainable.ts.md +++ b/docs/modules/typeclass/Chainable.ts.md @@ -34,18 +34,13 @@ produced by the effect. ```ts export declare const andThenDiscard: ( F: Chainable -) => { - (self: Kind, that: Kind): Kind< - F, - R1 & R2, - O1 | O2, - E1 | E2, - A - > - (that: Kind): ( - self: Kind - ) => Kind -} +) => (( + self: Kind, + that: Kind +) => Kind) & + (( + that: Kind + ) => (self: Kind) => Kind) ``` Added in v1.0.0 @@ -90,18 +85,13 @@ Returns an effect that effectfully "peeks" at the success of this effect. ```ts export declare const tap: ( F: Chainable -) => { - (self: Kind, f: (a: A) => Kind): Kind< - F, - R1 & R2, - O1 | O2, - E1 | E2, - A - > - (f: (a: A) => Kind): ( - self: Kind - ) => Kind -} +) => (( + self: Kind, + f: (a: A) => Kind +) => Kind) & + (( + f: (a: A) => Kind + ) => (self: Kind) => Kind) ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index f883b4f35..a3349216f 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -68,10 +68,8 @@ Added in v1.0.0 ```ts export declare const as: ( F: Covariant -) => { - (self: Kind, b: B): Kind - (b: B): (self: Kind) => Kind -} +) => ((self: Kind, b: B) => Kind) & + ((b: B) => (self: Kind) => Kind) ``` Added in v1.0.0 @@ -95,10 +93,8 @@ Added in v1.0.0 ```ts export declare const flap: ( F: Covariant -) => { - (a: A, self: Kind B>): Kind - (self: Kind B>): (a: A) => Kind -} +) => ((a: A, self: Kind B>) => Kind) & + ((self: Kind B>) => (a: A) => Kind) ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/FlatMap.ts.md b/docs/modules/typeclass/FlatMap.ts.md index 11cfb66d5..ab8c8695e 100644 --- a/docs/modules/typeclass/FlatMap.ts.md +++ b/docs/modules/typeclass/FlatMap.ts.md @@ -48,18 +48,13 @@ A variant of `flatMap` that ignores the value produced by this effect. ```ts export declare const andThen: ( F: FlatMap -) => { - (self: Kind, that: Kind): Kind< - F, - R1 & R2, - O1 | O2, - E1 | E2, - B - > - (that: Kind): ( - self: Kind - ) => Kind -} +) => (( + self: Kind, + that: Kind +) => Kind) & + (( + that: Kind + ) => (self: Kind) => Kind) ``` Added in v1.0.0 @@ -71,14 +66,13 @@ Added in v1.0.0 ```ts export declare const composeKleisliArrow: ( F: FlatMap -) => { - (afb: (a: A) => Kind, bfc: (b: B) => Kind): ( - a: A - ) => Kind - (bfc: (b: B) => Kind): ( - afb: (a: A) => Kind - ) => (a: A) => Kind -} +) => (( + afb: (a: A) => Kind, + bfc: (b: B) => Kind +) => (a: A) => Kind) & + (( + bfc: (b: B) => Kind + ) => (afb: (a: A) => Kind) => (a: A) => Kind) ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index 0038f35ab..c8263e4c7 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -84,9 +84,13 @@ Added in v1.0.0 ```ts export declare const andThen: ( F: SemiApplicative -) => ( +) => (( + self: Kind, that: Kind -) => (self: Kind) => Kind +) => Kind) & + (( + that: Kind + ) => (self: Kind) => Kind) ``` Added in v1.0.0 @@ -98,9 +102,13 @@ Added in v1.0.0 ```ts export declare const andThenDiscard: ( F: SemiApplicative -) => ( +) => (( + self: Kind, that: Kind -) => (self: Kind) => Kind +) => Kind) & + (( + that: Kind + ) => (self: Kind) => Kind) ``` Added in v1.0.0 @@ -112,9 +120,13 @@ Added in v1.0.0 ```ts export declare const ap: ( F: SemiApplicative -) => ( +) => (( + self: Kind B>, that: Kind -) => (self: Kind B>) => Kind +) => Kind) & + (( + that: Kind + ) => (self: Kind B>) => Kind) ``` Added in v1.0.0 @@ -128,10 +140,15 @@ Zips two `F` values together using a provided function, returning a new `F` of t ```ts export declare const zipWith: ( F: SemiApplicative -) => ( - fb: Kind, +) => (( + self: Kind, + that: Kind, f: (a: A, b: B) => C -) => (fa: Kind) => Kind +) => Kind) & + (( + that: Kind, + f: (a: A, b: B) => C + ) => (self: Kind) => Kind) ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index 07fc64d2e..af1cbba68 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -558,22 +558,30 @@ export const lift2: (f: (a: A, b: B) => C) => { } = semiApplicative.lift2(SemiApplicative) /** - * @category products + * @dual + * @category combining * @since 1.0.0 */ -export const zipWith: ( - fb: Either, - f: (a: A, b: B) => C -) => (fa: Either) => Either = semiApplicative.zipWith(SemiApplicative) +export const zipWith: { + ( + self: Either, + that: Either, + f: (a: A, b: B) => C + ): Either + ( + that: Either, + f: (a: A, b: B) => C + ): (self: Either) => Either +} = semiApplicative.zipWith(SemiApplicative) /** + * @dual * @since 1.0.0 */ -export const ap: ( - fa: Either -) => (self: Either B>) => Either = semiApplicative.ap( - SemiApplicative -) +export const ap: { + (self: Either B>, that: Either): Either + (that: Either): (self: Either B>) => Either +} = semiApplicative.ap(SemiApplicative) /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index 51e436f0c..4b2bd2472 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -995,22 +995,23 @@ export const lift2: (f: (a: A, b: B) => C) => { * @param fb - The right-hand side of the zip operation * @param f - The function used to combine the values of the two `Option`s * - * @category products + * @dual + * @category combining * @since 1.0.0 */ -export const zipWith: ( - fb: Option, - f: (a: A, b: B) => C -) => (fa: Option) => Option = semiApplicative.zipWith(SemiApplicative) +export const zipWith: { + (self: Option, that: Option, f: (a: A, b: B) => C): Option + (that: Option, f: (a: A, b: B) => C): (self: Option) => Option +} = semiApplicative.zipWith(SemiApplicative) /** + * @dual * @since 1.0.0 */ -export const ap: ( - fa: Option -) => (self: Option<(a: A) => B>) => Option = semiApplicative.ap( - SemiApplicative -) +export const ap: { + (self: Option<(a: A) => B>, that: Option): Option + (that: Option): (self: Option<(a: A) => B>) => Option +} = semiApplicative.ap(SemiApplicative) /** * Semigroup that models the combination of computations that can fail, if at least one element is `None` diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 5813d3d75..8fa2a8e42 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1751,13 +1751,13 @@ export const SemiApplicative: semiApplicative.SemiApplicative( - fa: ReadonlyArray -) => (self: ReadonlyArray<(a: A) => B>) => Array = semiApplicative.ap( - SemiApplicative -) as any +export const ap: { + (self: ReadonlyArray<(a: A) => B>, that: ReadonlyArray): Array + (that: ReadonlyArray): (self: ReadonlyArray<(a: A) => B>) => Array +} = semiApplicative.ap(SemiApplicative) as any /** * Lifts a binary function into `ReadonlyArray`. diff --git a/src/These.ts b/src/These.ts index 8b700588a..26ce78de2 100644 --- a/src/These.ts +++ b/src/These.ts @@ -950,24 +950,34 @@ export const lift2: (f: (a: A, b: B) => C) => { } = semiApplicative.lift2(SemiApplicative) /** - * @category products + * @dual + * @category combining * @since 1.0.0 */ -export const zipWith: ( - fb: Validated, - f: (a: A, b: B) => C -) => (fa: Validated) => Validated = semiApplicative.zipWith( +export const zipWith: { + ( + self: Validated, + that: Validated, + f: (a: A, b: B) => C + ): Validated + ( + that: Validated, + f: (a: A, b: B) => C + ): (self: Validated) => Validated +} = semiApplicative.zipWith( SemiApplicative ) /** + * @dual * @since 1.0.0 */ -export const ap: ( - fa: Validated -) => (self: Validated B>) => Validated = semiApplicative.ap( - SemiApplicative -) +export const ap: { + (self: Validated B>, that: Validated): Validated + ( + that: Validated + ): (self: Validated B>) => Validated +} = semiApplicative.ap(SemiApplicative) /** * @category combining diff --git a/src/typeclass/Chainable.ts b/src/typeclass/Chainable.ts index b0ee983ad..fdd0a7bf5 100644 --- a/src/typeclass/Chainable.ts +++ b/src/typeclass/Chainable.ts @@ -19,15 +19,7 @@ export interface Chainable extends FlatMap, Covariant(F: Chainable): { - ( - self: Kind, - that: Kind - ): Kind - ( - that: Kind - ): (self: Kind) => Kind -} => +export const andThenDiscard = (F: Chainable) => dual< ( self: Kind, @@ -48,15 +40,7 @@ export const andThenDiscard = (F: Chainable): { * * @since 1.0.0 */ -export const tap = (F: Chainable): { - ( - self: Kind, - f: (a: A) => Kind - ): Kind - ( - f: (a: A) => Kind - ): (self: Kind) => Kind -} => +export const tap = (F: Chainable) => dual< ( self: Kind, diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index 664e0f533..2c94b8712 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -50,10 +50,7 @@ export const make = (map: Covariant["map"]): Covariant< * @category mapping * @since 1.0.0 */ -export const flap = (F: Covariant): { - (a: A, self: Kind B>): Kind - (self: Kind B>): (a: A) => Kind -} => +export const flap = (F: Covariant) => dual< (a: A, self: Kind B>) => Kind, (self: Kind B>) => (a: A) => Kind @@ -67,10 +64,7 @@ export const flap = (F: Covariant): { * @category mapping * @since 1.0.0 */ -export const as = (F: Covariant): { - (self: Kind, b: B): Kind - (b: B): (self: Kind) => Kind -} => +export const as = (F: Covariant) => dual< (self: Kind, b: B) => Kind, (b: B) => (self: Kind) => Kind diff --git a/src/typeclass/FlatMap.ts b/src/typeclass/FlatMap.ts index c3fbe81d4..5bfc49206 100644 --- a/src/typeclass/FlatMap.ts +++ b/src/typeclass/FlatMap.ts @@ -27,15 +27,7 @@ export const flatten = (F: FlatMap) => * * @since 1.0.0 */ -export const andThen = (F: FlatMap): { - ( - self: Kind, - that: Kind - ): Kind - ( - that: Kind - ): (self: Kind) => Kind -} => +export const andThen = (F: FlatMap) => dual< ( self: Kind, @@ -56,17 +48,7 @@ export const andThen = (F: FlatMap): { */ export const composeKleisliArrow = ( F: FlatMap -): { - ( - afb: (a: A) => Kind, - bfc: (b: B) => Kind - ): (a: A) => Kind - ( - bfc: (b: B) => Kind - ): ( - afb: (a: A) => Kind - ) => (a: A) => Kind -} => +) => dual< ( afb: (a: A) => Kind, diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 7d62a5046..79c414a21 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -39,39 +39,82 @@ export const liftSemigroup = (F: SemiApplicative) => * @since 1.0.0 */ export const zipWith = (F: SemiApplicative) => - (fb: Kind, f: (a: A, b: B) => C) => - (fa: Kind): Kind => - pipe(F.product(fa, fb), F.map(([a, b]) => f(a, b))) + dual< + ( + self: Kind, + that: Kind, + f: (a: A, b: B) => C + ) => Kind, + ( + that: Kind, + f: (a: A, b: B) => C + ) => (self: Kind) => Kind + >( + 3, + ( + self: Kind, + that: Kind, + f: (a: A, b: B) => C + ): Kind => + pipe(F.product(self, that), F.map(([a, b]) => f(a, b))) + ) /** * @since 1.0.0 */ export const ap = (F: SemiApplicative) => - ( + dual< + ( + self: Kind B>, + that: Kind + ) => Kind, + ( + that: Kind + ) => ( + self: Kind B> + ) => Kind + >(2, ( + self: Kind B>, that: Kind - ): ( - self: Kind B> - ) => Kind => zipWith(F)(that, (f, a) => f(a)) + ): Kind => zipWith(F)(self, that, (f, a) => f(a))) /** * @since 1.0.0 */ export const andThenDiscard = (F: SemiApplicative) => - ( + dual< + ( + self: Kind, + that: Kind + ) => Kind, + ( + that: Kind + ) => ( + self: Kind + ) => Kind + >(2, ( + self: Kind, that: Kind - ): ( - self: Kind - ) => Kind => zipWith(F)(that, identity) + ): Kind => zipWith(F)(self, that, identity)) /** * @since 1.0.0 */ export const andThen = (F: SemiApplicative) => - ( + dual< + ( + self: Kind, + that: Kind + ) => Kind, + ( + that: Kind + ) => ( + self: Kind + ) => Kind + >(2, ( + self: Kind, that: Kind - ): ( - self: Kind - ) => Kind => zipWith(F)(that, SK) + ): Kind => zipWith(F)(self, that, SK)) /** * Lifts a binary function into `F`. @@ -94,4 +137,4 @@ export const lift2 = (F: SemiApplicative) => >(2, ( self: Kind, that: Kind - ): Kind => pipe(self, zipWith(F)(that, f))) + ): Kind => zipWith(F)(self, that, f)) From 946109113a75befb88d56bf7600319f70bded7b8 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 1 Feb 2023 08:24:10 +0100 Subject: [PATCH 144/255] Option, Either, These: add getEquivalence --- docs/modules/Either.ts.md | 14 ++ docs/modules/Function.ts.md | 4 +- docs/modules/Option.ts.md | 161 +++++++++++-------- docs/modules/ReadonlyArray.ts.md | 43 ++--- docs/modules/These.ts.md | 14 ++ docs/modules/typeclass/Applicative.ts.md | 6 +- docs/modules/typeclass/SemiApplicative.ts.md | 30 ++-- src/Either.ts | 22 ++- src/Function.ts | 11 +- src/Option.ts | 89 +++++++--- src/ReadonlyArray.ts | 13 +- src/These.ts | 23 ++- src/typeclass/Applicative.ts | 4 +- src/typeclass/SemiApplicative.ts | 6 +- test/Either.ts | 40 +++-- test/Option.ts | 14 +- test/ReadonlyArray.ts | 5 +- test/These.ts | 16 ++ test/typeclass/Applicative.ts | 2 +- test/typeclass/SemiApplicative.ts | 2 +- 20 files changed, 341 insertions(+), 178 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 5053b90d2..bf916c1c5 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -47,6 +47,8 @@ Added in v1.0.0 - [bind](#bind) - [bindTo](#bindto) - [let](#let) +- [equivalence](#equivalence) + - [getEquivalence](#getequivalence) - [error handling](#error-handling) - [firstRightOf](#firstrightof) - [mapLeft](#mapleft) @@ -566,6 +568,18 @@ export declare const let: ( Added in v1.0.0 +# equivalence + +## getEquivalence + +**Signature** + +```ts +export declare const getEquivalence: (EE: Equivalence, EA: Equivalence) => Equivalence> +``` + +Added in v1.0.0 + # error handling ## firstRightOf diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 3dab46745..f38be7df4 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -51,7 +51,7 @@ Unary functions form a monoid as long as you can provide a monoid for the codoma **Signature** ```ts -export declare const getMonoid: (Monoid: monoid.Monoid) => () => monoid.Monoid<(a: A) => M> +export declare const getMonoid: (Monoid: Monoid) => () => Monoid<(a: A) => M> ``` **Example** @@ -84,7 +84,7 @@ Unary functions form a semigroup as long as you can provide a semigroup for the **Signature** ```ts -export declare const getSemigroup: (Semigroup: semigroup.Semigroup) => () => semigroup.Semigroup<(a: A) => S> +export declare const getSemigroup: (Semigroup: Semigroup) => () => Semigroup<(a: A) => S> ``` **Example** diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index a06cf6211..ddc7bb7e9 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -46,6 +46,8 @@ Added in v1.0.0 - [bind](#bind) - [bindTo](#bindto) - [let](#let) +- [equivalence](#equivalence) + - [getEquivalence](#getequivalence) - [error handling](#error-handling) - [firstSomeOf](#firstsomeof) - [getOrElse](#getorelse) @@ -55,6 +57,8 @@ Added in v1.0.0 - [filter](#filter) - [filterMap](#filtermap) - [separate](#separate) +- [folding](#folding) + - [reduceCompact](#reducecompact) - [guards](#guards) - [isNone](#isnone) - [isOption](#isoption) @@ -82,6 +86,7 @@ Added in v1.0.0 - [getFailureMonoid](#getfailuremonoid) - [getFailureSemigroup](#getfailuresemigroup) - [getFirstSomeSemigroup](#getfirstsomesemigroup) + - [getOptionalMonoid](#getoptionalmonoid) - [interop](#interop) - [fromNullable](#fromnullable) - [getOrNull](#getornull) @@ -90,7 +95,6 @@ Added in v1.0.0 - [liftNullable](#liftnullable) - [liftThrowable](#liftthrowable) - [lifting](#lifting) - - [getOptionalMonoid](#getoptionalmonoid) - [lift2](#lift2) - [liftEither](#lifteither) - [liftPredicate](#liftpredicate) @@ -111,7 +115,7 @@ Added in v1.0.0 - [flatMapEither](#flatmapeither) - [flatMapNullable](#flatmapnullable) - [sorting](#sorting) - - [liftOrder](#liftorder) + - [getOrder](#getorder) - [traversing](#traversing) - [sequence](#sequence) - [traverse](#traverse) @@ -126,7 +130,6 @@ Added in v1.0.0 - [contains](#contains) - [exists](#exists) - [flatten](#flatten) - - [reduceCompact](#reducecompact) - [struct](#struct) - [toArray](#toarray) - [tuple](#tuple) @@ -578,6 +581,32 @@ export declare const let: ( Added in v1.0.0 +# equivalence + +## getEquivalence + +**Signature** + +```ts +export declare const getEquivalence: (E: Equivalence) => Equivalence> +``` + +**Example** + +```ts +import { none, some, getEquivalence } from '@fp-ts/core/Option' +import * as N from '@fp-ts/core/number' + +const isEquivalent = getEquivalence(N.Equivalence) +assert.deepStrictEqual(isEquivalent(none(), none()), true) +assert.deepStrictEqual(isEquivalent(none(), some(1)), false) +assert.deepStrictEqual(isEquivalent(some(1), none()), false) +assert.deepStrictEqual(isEquivalent(some(1), some(2)), false) +assert.deepStrictEqual(isEquivalent(some(1), some(1)), true) +``` + +Added in v1.0.0 + # error handling ## firstSomeOf @@ -744,6 +773,39 @@ export declare const separate: (self: Option>) => [Option, Added in v1.0.0 +# folding + +## reduceCompact + +Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. + +**Signature** + +```ts +export declare const reduceCompact: { + (self: Iterable>, b: B, f: (b: B, a: A) => B): B + (b: B, f: (b: B, a: A) => B): (self: Iterable>) => B +} +``` + +**Example** + +```ts +import { some, none, reduceCompact } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +const iterable = [some(1), none(), some(2), none()] +assert.deepStrictEqual( + pipe( + iterable, + reduceCompact(0, (b, a) => b + a) + ), + 3 +) +``` + +Added in v1.0.0 + # guards ## isNone @@ -1048,6 +1110,33 @@ export declare const getFirstSomeSemigroup: () => Semigroup> Added in v1.0.0 +## getOptionalMonoid + +Monoid that models the combination of values that may be absent, elements that are `None` are ignored +while elements that are `Some` are combined using the provided `Semigroup`. + +**Signature** + +```ts +export declare const getOptionalMonoid: (Semigroup: Semigroup) => Monoid> +``` + +**Example** + +```ts +import { getOptionalMonoid, some, none } from '@fp-ts/core/Option' +import * as N from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +const M = getOptionalMonoid(N.SemigroupSum) +assert.deepStrictEqual(M.combine(none(), none()), none()) +assert.deepStrictEqual(M.combine(some(1), none()), some(1)) +assert.deepStrictEqual(M.combine(none(), some(1)), some(1)) +assert.deepStrictEqual(M.combine(some(1), some(2)), some(3)) +``` + +Added in v1.0.0 + # interop ## fromNullable @@ -1197,33 +1286,6 @@ Added in v1.0.0 # lifting -## getOptionalMonoid - -Monoid that models the combination of values that may be absent, elements that are `None` are ignored -while elements that are `Some` are combined using the provided `Semigroup`. - -**Signature** - -```ts -export declare const getOptionalMonoid: (Semigroup: Semigroup) => Monoid> -``` - -**Example** - -```ts -import { getOptionalMonoid, some, none } from '@fp-ts/core/Option' -import * as N from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' - -const M = getOptionalMonoid(N.SemigroupSum) -assert.deepStrictEqual(M.combine(none(), none()), none()) -assert.deepStrictEqual(M.combine(some(1), none()), some(1)) -assert.deepStrictEqual(M.combine(none(), some(1)), some(1)) -assert.deepStrictEqual(M.combine(some(1), some(2)), some(3)) -``` - -Added in v1.0.0 - ## lift2 Lifts a binary function into `Option`. @@ -1549,7 +1611,7 @@ Added in v1.0.0 # sorting -## liftOrder +## getOrder The `Order` instance allows `Option` values to be compared with `compare`, whenever there is an `Order` instance for @@ -1560,17 +1622,17 @@ the type the `Option` contains. **Signature** ```ts -export declare const liftOrder: (O: Order) => Order> +export declare const getOrder: (O: Order) => Order> ``` **Example** ```ts -import { none, some, liftOrder } from '@fp-ts/core/Option' +import { none, some, getOrder } from '@fp-ts/core/Option' import * as N from '@fp-ts/core/Number' import { pipe } from '@fp-ts/core/Function' -const O = liftOrder(N.Order) +const O = getOrder(N.Order) assert.deepStrictEqual(O.compare(none(), none()), 0) assert.deepStrictEqual(O.compare(none(), some(1)), -1) assert.deepStrictEqual(O.compare(some(1), none()), 1) @@ -1755,37 +1817,6 @@ export declare const flatten: (self: Option>) => Option Added in v1.0.0 -## reduceCompact - -Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. - -**Signature** - -```ts -export declare const reduceCompact: { - (self: Iterable>, b: B, f: (b: B, a: A) => B): B - (b: B, f: (b: B, a: A) => B): (self: Iterable>) => B -} -``` - -**Example** - -```ts -import { some, none, reduceCompact } from '@fp-ts/core/Option' -import { pipe } from '@fp-ts/core/Function' - -const iterable = [some(1), none(), some(2), none()] -assert.deepStrictEqual( - pipe( - iterable, - reduceCompact(0, (b, a) => b + a) - ), - 3 -) -``` - -Added in v1.0.0 - ## struct **Signature** diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 1949315d1..085319d0e 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -117,14 +117,13 @@ Added in v1.0.0 - [getUnionSemigroup](#getunionsemigroup) - [lifting](#lifting) - [every](#every) + - [getOrder](#getorder) - [lift2](#lift2) - [liftEither](#lifteither) - [liftMonoid](#liftmonoid) - [liftNullable](#liftnullable) - [liftOption](#liftoption) - - [liftOrder](#liftorder) - [liftPredicate](#liftpredicate) - - [liftSemigroup](#liftsemigroup) - [mapping](#mapping) - [as](#as) - [flap](#flap) @@ -1338,6 +1337,21 @@ export declare function every(predicate: Predicate): Predicate(O: order.Order) => order.Order +``` + +Added in v1.0.0 + ## lift2 Lifts a binary function into `ReadonlyArray`. @@ -1394,21 +1408,6 @@ export declare const liftOption: (f: (...a: A) => Option Added in v1.0.0 -## liftOrder - -This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. -The returned `Order` compares two arrays by applying the given `Order` to each element in the arrays. -If all elements are equal, the arrays are then compared based on their length. -It is useful when you need to compare two arrays of the same type and you have a specific way of comparing each element of the array. - -**Signature** - -```ts -export declare const liftOrder: (O: order.Order) => order.Order -``` - -Added in v1.0.0 - ## liftPredicate **Signature** @@ -1422,16 +1421,6 @@ export declare const liftPredicate: { Added in v1.0.0 -## liftSemigroup - -**Signature** - -```ts -export declare const liftSemigroup: (S: Semigroup) => Semigroup -``` - -Added in v1.0.0 - # mapping ## as diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 1583b2289..bba4756e2 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -59,6 +59,8 @@ Added in v1.0.0 - [bindThese](#bindthese) - [bindTo](#bindto) - [let](#let) +- [equivalence](#equivalence) + - [getEquivalence](#getequivalence) - [error handling](#error-handling) - [firstRightOrBothOf](#firstrightorbothof) - [mapLeft](#mapleft) @@ -671,6 +673,18 @@ export declare const let: ( Added in v1.0.0 +# equivalence + +## getEquivalence + +**Signature** + +```ts +export declare const getEquivalence: (EE: Equivalence, EA: Equivalence) => Equivalence> +``` + +Added in v1.0.0 + # error handling ## firstRightOrBothOf diff --git a/docs/modules/typeclass/Applicative.ts.md b/docs/modules/typeclass/Applicative.ts.md index 7dca794b4..72fc5328d 100644 --- a/docs/modules/typeclass/Applicative.ts.md +++ b/docs/modules/typeclass/Applicative.ts.md @@ -15,7 +15,7 @@ Added in v1.0.0 - [type class](#type-class) - [Applicative (interface)](#applicative-interface) - [utils](#utils) - - [liftMonoid](#liftmonoid) + - [getMonoid](#getmonoid) --- @@ -33,14 +33,14 @@ Added in v1.0.0 # utils -## liftMonoid +## getMonoid Lift a monoid into 'F', the inner values are combined using the provided `Monoid`. **Signature** ```ts -export declare const liftMonoid: ( +export declare const getMonoid: ( F: Applicative ) => (M: Monoid) => Monoid> ``` diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index c8263e4c7..6fbbdb5bf 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -13,8 +13,8 @@ Added in v1.0.0

Table of contents

- [lifting](#lifting) + - [getSemigroup](#getsemigroup) - [lift2](#lift2) - - [liftSemigroup](#liftsemigroup) - [type class](#type-class) - [SemiApplicative (interface)](#semiapplicative-interface) - [utils](#utils) @@ -27,6 +27,20 @@ Added in v1.0.0 # lifting +## getSemigroup + +Lift a `Semigroup` into 'F', the inner values are combined using the provided `Semigroup`. + +**Signature** + +```ts +export declare const getSemigroup: ( + F: SemiApplicative +) => (S: Semigroup
) => Semigroup> +``` + +Added in v1.0.0 + ## lift2 Lifts a binary function into `F`. @@ -49,20 +63,6 @@ export declare const lift2: ( Added in v1.0.0 -## liftSemigroup - -Lift a `Semigroup` into 'F', the inner values are combined using the provided `Semigroup`. - -**Signature** - -```ts -export declare const liftSemigroup: ( - F: SemiApplicative -) => (S: Semigroup) => Semigroup> -``` - -Added in v1.0.0 - # type class ## SemiApplicative (interface) diff --git a/src/Either.ts b/src/Either.ts index af1cbba68..aa2ba09d3 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -222,6 +222,24 @@ export const fromOption: { (onNone: () => E): (fa: Option) => Either } = either.fromOption +// ------------------------------------------------------------------------------------- +// equivalence +// ------------------------------------------------------------------------------------- + +/** + * @category equivalence + * @since 1.0.0 + */ +export const getEquivalence = ( + EE: Equivalence, + EA: Equivalence +): Equivalence> => + (x, y) => + x === y || + (isLeft(x) ? + isLeft(y) && EE(x.left, y.left) : + isRight(y) && EA(x.right, y.right)) + /** * Returns an effect whose Right is mapped by the specified `f` function. * @@ -542,7 +560,7 @@ export const SemiApplicative: semiApplicative.SemiApplicative */ export const getFirstLeftSemigroup: (S: Semigroup) => Semigroup> = semiApplicative - .liftSemigroup(SemiApplicative) + .getSemigroup(SemiApplicative) /** * Lifts a binary function into `Either`. @@ -606,7 +624,7 @@ export const Applicative: applicative.Applicative = { * @since 1.0.0 */ export const getFirstLeftMonoid: (M: Monoid) => Monoid> = applicative - .liftMonoid( + .getMonoid( Applicative ) diff --git a/src/Function.ts b/src/Function.ts index 0266cbea2..e743651f6 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -2,7 +2,8 @@ * @since 1.0.0 */ import type { TypeLambda } from "@fp-ts/core/HKT" -import type * as monoid from "@fp-ts/core/typeclass/Monoid" +import type { Monoid } from "@fp-ts/core/typeclass/Monoid" +import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" // ------------------------------------------------------------------------------------- @@ -47,8 +48,8 @@ export const compose: (bc: (b: B) => C) => (ab: (a: A) => B) => (a: A) * @category instances * @since 1.0.0 */ -export const getSemigroup = (Semigroup: semigroup.Semigroup) => - (): semigroup.Semigroup<(a: A) => S> => +export const getSemigroup = (Semigroup: Semigroup) => + (): Semigroup<(a: A) => S> => semigroup.fromCombine((self, that) => (a) => Semigroup.combine(self(a), that(a))) /** @@ -75,8 +76,8 @@ export const getSemigroup = (Semigroup: semigroup.Semigroup) => * @category instances * @since 1.0.0 */ -export const getMonoid = (Monoid: monoid.Monoid) => - (): monoid.Monoid<(a: A) => M> => { +export const getMonoid = (Monoid: Monoid) => + (): Monoid<(a: A) => M> => { const S = getSemigroup(Monoid)() const empty = () => Monoid.empty return ({ ...S, combineAll: (collection) => S.combineMany(empty, collection), empty }) diff --git a/src/Option.ts b/src/Option.ts index 4b2bd2472..7c7c20e8e 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -962,7 +962,7 @@ export const SemiApplicative: semiApplicative.SemiApplicative * assert.deepStrictEqual(M.combine(none(), some(1)), some(1)) * assert.deepStrictEqual(M.combine(some(1), some(2)), some(3)) * - * @category lifting + * @category instances * @since 1.0.0 */ export const getOptionalMonoid = ( @@ -975,19 +975,6 @@ export const getOptionalMonoid = ( none() ) -/** - * Lifts a binary function into `Option`. - * - * @param f - The function to lift. - * - * @category lifting - * @since 1.0.0 - */ -export const lift2: (f: (a: A, b: B) => C) => { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} = semiApplicative.lift2(SemiApplicative) - /** * Zips two `Option` values together using a provided function, returning a new `Option` of the result. * @@ -1024,7 +1011,7 @@ export const ap: { * @since 1.0.0 */ export const getFailureSemigroup: (S: Semigroup) => Semigroup> = semiApplicative - .liftSemigroup(SemiApplicative) + .getSemigroup(SemiApplicative) /** * @category instances @@ -1051,7 +1038,7 @@ export const Applicative: applicative.Applicative = { * @category instances * @since 1.0.0 */ -export const getFailureMonoid: (M: Monoid) => Monoid> = applicative.liftMonoid( +export const getFailureMonoid: (M: Monoid) => Monoid> = applicative.getMonoid( Applicative ) @@ -1169,6 +1156,10 @@ export const Compactable: compactable.Compactable = { export const separate: (self: Option>) => [Option, Option] = compactable .separate({ ...Covariant, ...Compactable }) +// ------------------------------------------------------------------------------------- +// filtering +// ------------------------------------------------------------------------------------- + /** * Maps over the value of an `Option` and filters out `None`s. * @@ -1217,6 +1208,10 @@ export const filter: { (predicate: Predicate): (fb: Option) => Option } = filterable.filter(Filterable) +// ------------------------------------------------------------------------------------- +// traversing +// ------------------------------------------------------------------------------------- + /** * @category traversing * @since 1.0.0 @@ -1275,6 +1270,10 @@ export const traverseTap: ( ) => (self: Option) => Kind> = traversable .traverseTap(Traversable) +// ------------------------------------------------------------------------------------- +// pattern matching +// ------------------------------------------------------------------------------------- + /** * Matches the given `Option` and returns either the provided `onNone` value or the result of the provided `onSome` * function when passed the `Option`'s value. @@ -1319,6 +1318,32 @@ export const match: { isNone(self) ? onNone() : onSome(self.value) ) +// ------------------------------------------------------------------------------------- +// equivalence +// ------------------------------------------------------------------------------------- + +/** + * @example + * import { none, some, getEquivalence } from '@fp-ts/core/Option' + * import * as N from '@fp-ts/core/number' + * + * const isEquivalent = getEquivalence(N.Equivalence) + * assert.deepStrictEqual(isEquivalent(none(), none()), true) + * assert.deepStrictEqual(isEquivalent(none(), some(1)), false) + * assert.deepStrictEqual(isEquivalent(some(1), none()), false) + * assert.deepStrictEqual(isEquivalent(some(1), some(2)), false) + * assert.deepStrictEqual(isEquivalent(some(1), some(1)), true) + * + * @category equivalence + * @since 1.0.0 + */ +export const getEquivalence = (E: Equivalence): Equivalence> => + (x, y) => x === y || (isNone(x) ? isNone(y) : isNone(y) ? false : E(x.value, y.value)) + +// ------------------------------------------------------------------------------------- +// sorting +// ------------------------------------------------------------------------------------- + /** * The `Order` instance allows `Option` values to be compared with * `compare`, whenever there is an `Order` instance for @@ -1327,11 +1352,11 @@ export const match: { * `None` is considered to be less than any `Some` value. * * @example - * import { none, some, liftOrder } from '@fp-ts/core/Option' + * import { none, some, getOrder } from '@fp-ts/core/Option' * import * as N from '@fp-ts/core/Number' * import { pipe } from '@fp-ts/core/Function' * - * const O = liftOrder(N.Order) + * const O = getOrder(N.Order) * assert.deepStrictEqual(O.compare(none(), none()), 0) * assert.deepStrictEqual(O.compare(none(), some(1)), -1) * assert.deepStrictEqual(O.compare(some(1), none()), 1) @@ -1341,11 +1366,28 @@ export const match: { * @category sorting * @since 1.0.0 */ -export const liftOrder = (O: Order): Order> => +export const getOrder = (O: Order): Order> => order.fromCompare((self, that) => isSome(self) ? (isSome(that) ? O.compare(self.value, that.value) : 1) : -1 ) +// ------------------------------------------------------------------------------------- +// lifting +// ------------------------------------------------------------------------------------- + +/** + * Lifts a binary function into `Option`. + * + * @param f - The function to lift. + * + * @category lifting + * @since 1.0.0 + */ +export const lift2: (f: (a: A, b: B) => C) => { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = semiApplicative.lift2(SemiApplicative) + /** * Transforms a `Predicate` function into a `Some` of the input value if the predicate returns `true` or `None` * if the predicate returns `false`. @@ -1392,6 +1434,10 @@ export const liftEither = , E, B>( f: (...a: A) => Either ) => (...a: A): Option => fromEither(f(...a)) +// ------------------------------------------------------------------------------------- +// sequencing +// ------------------------------------------------------------------------------------- + /** * Applies a provided function that returns an `Either` to the contents of an `Option`, flattening the result into another `Option`. * @@ -1424,6 +1470,10 @@ export const flatMapEither: { pipe(self, flatMap(liftEither(f))) ) +// ------------------------------------------------------------------------------------- +// utils +// ------------------------------------------------------------------------------------- + /** * Returns a function that checks if an `Option` contains a given value using a provided `Equivalence` instance. * @@ -1498,6 +1548,7 @@ export const exists: { * assert.deepStrictEqual(pipe(iterable, reduceCompact(0, (b, a) => b + a)), 3) * * @dual + * @category folding * @since 1.0.0 */ export const reduceCompact: { diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 8fa2a8e42..2da9da554 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1772,15 +1772,6 @@ export const lift2: (f: (a: A, b: B) => C) => { (that: ReadonlyArray): (self: ReadonlyArray) => Array } = semiApplicative.lift2(SemiApplicative) as any -/** - * @category lifting - * @since 1.0.0 - */ -export const liftSemigroup: (S: Semigroup) => Semigroup> = semiApplicative - .liftSemigroup( - SemiApplicative - ) - /** * @category instances * @since 1.0.0 @@ -1811,7 +1802,7 @@ export const Applicative: applicative.Applicative = { * @since 1.0.0 */ export const liftMonoid: (M: Monoid) => Monoid> = applicative - .liftMonoid( + .getMonoid( Applicative ) @@ -2180,4 +2171,4 @@ export const getMonoid: () => Monoid> = monoid.readonlyArray * @category lifting * @since 1.0.0 */ -export const liftOrder: (O: Order) => Order> = order.array +export const getOrder: (O: Order) => Order> = order.array diff --git a/src/These.ts b/src/These.ts index 26ce78de2..767b04101 100644 --- a/src/These.ts +++ b/src/These.ts @@ -126,6 +126,25 @@ export const fail = (e: E): Validated => left([e]) */ export const warn = (e: E, a: A): Validated => both([e], a) +// ------------------------------------------------------------------------------------- +// equivalence +// ------------------------------------------------------------------------------------- + +/** + * @category equivalence + * @since 1.0.0 + */ +export const getEquivalence = ( + EE: Equivalence, + EA: Equivalence +): Equivalence> => + (x, y) => + isLeft(x) + ? isLeft(y) && EE(x.left, y.left) + : isRight(x) + ? isRight(y) && EA(x.right, y.right) + : isBoth(y) && EE(x.left, y.left) && EA(x.right, y.right) + /** * @category pattern matching * @since 1.0.0 @@ -986,7 +1005,7 @@ export const ap: { export const getFirstLeftSemigroup: ( S: Semigroup ) => Semigroup> = semiApplicative - .liftSemigroup(SemiApplicative) + .getSemigroup(SemiApplicative) const productAll = ( collection: Iterable> @@ -1097,7 +1116,7 @@ export const Applicative: applicative.Applicative = { * @since 1.0.0 */ export const getFirstLeftMonoid: (M: Monoid) => Monoid> = applicative - .liftMonoid( + .getMonoid( Applicative ) diff --git a/src/typeclass/Applicative.ts b/src/typeclass/Applicative.ts index 626835845..84deeb68a 100644 --- a/src/typeclass/Applicative.ts +++ b/src/typeclass/Applicative.ts @@ -19,9 +19,9 @@ export interface Applicative extends SemiApplicative, P * * @since 1.0.0 */ -export const liftMonoid = (F: Applicative) => +export const getMonoid = (F: Applicative) => (M: Monoid): Monoid> => monoid.fromSemigroup( - semiApplicative.liftSemigroup(F)(M), + semiApplicative.getSemigroup(F)(M), F.of(M.empty) ) diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 79c414a21..4e6948479 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -19,7 +19,7 @@ export interface SemiApplicative extends SemiProduct, C * @category lifting * @since 1.0.0 */ -export const liftSemigroup = (F: SemiApplicative) => +export const getSemigroup = (F: SemiApplicative) => (S: Semigroup): Semigroup> => ({ combine: (self, that) => pipe(F.product(self, that), F.map(([a1, a2]) => S.combine(a1, a2))), combineMany: (self, collection) => @@ -32,8 +32,8 @@ export const liftSemigroup = (F: SemiApplicative) => /** * Zips two `F` values together using a provided function, returning a new `F` of the result. * - * @param fa - The left-hand side of the zip operation - * @param fb - The right-hand side of the zip operation + * @param self - The left-hand side of the zip operation + * @param that - The right-hand side of the zip operation * @param f - The function used to combine the values of the two `Option`s * * @since 1.0.0 diff --git a/test/Either.ts b/test/Either.ts index c54c4d316..a0076c53b 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -3,7 +3,7 @@ import { flow, identity, pipe } from "@fp-ts/core/Function" import { structural } from "@fp-ts/core/internal/effect" import * as N from "@fp-ts/core/Number" import * as O from "@fp-ts/core/Option" -import * as String from "@fp-ts/core/String" +import * as S from "@fp-ts/core/String" import * as Util from "@fp-ts/core/test/util" describe.concurrent("Either", () => { @@ -201,19 +201,19 @@ describe.concurrent("Either", () => { }) it("map", () => { - const f = _.map(String.length) + const f = _.map(S.length) Util.deepStrictEqual(pipe(_.right("abc"), f), _.right(3)) Util.deepStrictEqual(pipe(_.left("s"), f), _.left("s")) }) it("flatMap", () => { - const f = _.flatMap(flow(String.length, _.right)) + const f = _.flatMap(flow(S.length, _.right)) Util.deepStrictEqual(pipe(_.right("abc"), f), _.right(3)) Util.deepStrictEqual(pipe(_.left("maError"), f), _.left("maError")) }) it("bimap", () => { - const f = _.bimap(String.length, (n: number) => n > 2) + const f = _.bimap(S.length, (n: number) => n > 2) Util.deepStrictEqual(pipe(_.right(1), f), _.right(false)) }) @@ -297,7 +297,7 @@ describe.concurrent("Either", () => { const p = (n: number) => n > 2 const f = (n: number) => (p(n) ? O.some(n + 1) : O.none()) Util.deepStrictEqual(pipe(_.left("123"), _.filterMap(f, () => "")), _.left("123")) - Util.deepStrictEqual(pipe(_.right(1), _.filterMap(f, () => "")), _.left(String.Monoid.empty)) + Util.deepStrictEqual(pipe(_.right(1), _.filterMap(f, () => "")), _.left(S.Monoid.empty)) Util.deepStrictEqual(pipe(_.right(3), _.filterMap(f, () => "")), _.right(4)) }) @@ -508,15 +508,25 @@ describe.concurrent("Either", () => { }) it("getOptionalSemigroup", () => { - const S = _.getOptionalSemigroup(String.Semigroup) - Util.deepStrictEqual(S.combine(_.left("e"), _.left("e")), _.left("e")) - Util.deepStrictEqual(S.combine(_.left("e"), _.right("a")), _.right("a")) - Util.deepStrictEqual(S.combine(_.right("a"), _.left("e")), _.right("a")) - Util.deepStrictEqual(S.combine(_.right("b"), _.right("a")), _.right("ba")) - Util.deepStrictEqual(S.combine(_.right("a"), _.right("b")), _.right("ab")) - - Util.deepStrictEqual(S.combineMany(_.right("a"), [_.right("b")]), _.right("ab")) - Util.deepStrictEqual(S.combineMany(_.left("e"), [_.right("b")]), _.right("b")) - Util.deepStrictEqual(S.combineMany(_.right("a"), [_.left("e")]), _.right("a")) + const OS = _.getOptionalSemigroup(S.Semigroup) + Util.deepStrictEqual(OS.combine(_.left("e"), _.left("e")), _.left("e")) + Util.deepStrictEqual(OS.combine(_.left("e"), _.right("a")), _.right("a")) + Util.deepStrictEqual(OS.combine(_.right("a"), _.left("e")), _.right("a")) + Util.deepStrictEqual(OS.combine(_.right("b"), _.right("a")), _.right("ba")) + Util.deepStrictEqual(OS.combine(_.right("a"), _.right("b")), _.right("ab")) + + Util.deepStrictEqual(OS.combineMany(_.right("a"), [_.right("b")]), _.right("ab")) + Util.deepStrictEqual(OS.combineMany(_.left("e"), [_.right("b")]), _.right("b")) + Util.deepStrictEqual(OS.combineMany(_.right("a"), [_.left("e")]), _.right("a")) + }) + + it("getEquivalence", () => { + const isEquivalent = _.getEquivalence(S.Equivalence, N.Equivalence) + Util.deepStrictEqual(isEquivalent(_.right(1), _.right(1)), true) + Util.deepStrictEqual(isEquivalent(_.right(1), _.right(2)), false) + Util.deepStrictEqual(isEquivalent(_.right(1), _.left("foo")), false) + Util.deepStrictEqual(isEquivalent(_.left("foo"), _.left("foo")), true) + Util.deepStrictEqual(isEquivalent(_.left("foo"), _.left("bar")), false) + Util.deepStrictEqual(isEquivalent(_.left("foo"), _.right(1)), false) }) }) diff --git a/test/Option.ts b/test/Option.ts index 38b7ab90e..203fcbc7d 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -352,8 +352,8 @@ describe.concurrent("Option", () => { Util.deepStrictEqual(_.getOrUndefined(_.some(1)), 1) }) - it("liftOrder", () => { - const OS = _.liftOrder(S.Order) + it("getOrder", () => { + const OS = _.getOrder(S.Order) Util.deepStrictEqual(OS.compare(_.none(), _.none()), 0) Util.deepStrictEqual(OS.compare(_.some("a"), _.none()), 1) Util.deepStrictEqual(OS.compare(_.none(), _.some("a")), -1) @@ -612,4 +612,14 @@ describe.concurrent("Option", () => { expect(_.multiplyCompact([_.some(2), _.none(), _.some(3)])).toEqual(6) expect(_.multiplyCompact([_.some(2), _.some(0), _.some(3)])).toEqual(0) }) + + it("getEquivalence", () => { + const isEquivalent = _.getEquivalence(N.Equivalence) + expect(isEquivalent(_.none(), _.none())).toEqual(true) + expect(isEquivalent(_.none(), _.some(1))).toEqual(false) + expect(isEquivalent(_.some(1), _.none())).toEqual(false) + expect(isEquivalent(_.some(2), _.some(1))).toEqual(false) + expect(isEquivalent(_.some(1), _.some(2))).toEqual(false) + expect(isEquivalent(_.some(2), _.some(2))).toEqual(true) + }) }) diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 8f2e3672a..3840f87b2 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -44,7 +44,6 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.Product).exist expect(RA.SemiApplicative).exist - expect(RA.liftSemigroup).exist expect(RA.lift2).exist expect(RA.ap).exist @@ -1044,8 +1043,8 @@ describe.concurrent("ReadonlyArray", () => { deepStrictEqual(M.combineAll([[1, 2], [3, 4, 5], [5, 6, 7, 1]]), [1, 2, 3, 4, 5, 5, 6, 7, 1]) }) - it("liftOrder", () => { - const O = RA.liftOrder(String.Order) + it("getOrder", () => { + const O = RA.getOrder(String.Order) deepStrictEqual(O.compare([], []), 0) deepStrictEqual(O.compare(["a"], ["a"]), 0) diff --git a/test/These.ts b/test/These.ts index ca29b7e6a..7e98e2827 100644 --- a/test/These.ts +++ b/test/These.ts @@ -1,6 +1,7 @@ import * as E from "@fp-ts/core/Either" import { identity, pipe } from "@fp-ts/core/Function" import { structural } from "@fp-ts/core/internal/effect" +import * as N from "@fp-ts/core/Number" import * as O from "@fp-ts/core/Option" import * as S from "@fp-ts/core/String" import * as _ from "@fp-ts/core/These" @@ -779,4 +780,19 @@ describe("These", () => { expect(pipe(_.right(1n), _.subtractBigint(e))).toEqual(e) expect(pipe(_.right(2n), _.subtractBigint(_.right(3n)))).toEqual(_.right(-1n)) }) + + it("getEquivalence", () => { + const isEquivalent = _.getEquivalence(N.Equivalence, N.Equivalence) + Util.deepStrictEqual(isEquivalent(_.left(2), _.left(2)), true) + Util.deepStrictEqual(isEquivalent(_.left(2), _.left(3)), false) + Util.deepStrictEqual(isEquivalent(_.left(3), _.left(2)), false) + Util.deepStrictEqual(isEquivalent(_.left(2), _.right(2)), false) + Util.deepStrictEqual(isEquivalent(_.left(2), _.both(2, 2)), false) + Util.deepStrictEqual(isEquivalent(_.right(2), _.right(2)), true) + Util.deepStrictEqual(isEquivalent(_.right(2), _.right(3)), false) + Util.deepStrictEqual(isEquivalent(_.right(3), _.right(2)), false) + Util.deepStrictEqual(isEquivalent(_.right(2), _.both(2, 2)), false) + Util.deepStrictEqual(isEquivalent(_.both(2, 2), _.both(2, 2)), true) + Util.deepStrictEqual(isEquivalent(_.both(2, 3), _.both(3, 2)), false) + }) }) diff --git a/test/typeclass/Applicative.ts b/test/typeclass/Applicative.ts index fb426b75d..cdf5b8d6a 100644 --- a/test/typeclass/Applicative.ts +++ b/test/typeclass/Applicative.ts @@ -5,7 +5,7 @@ import * as U from "../util" describe("Applicative", () => { it("liftMonoid", () => { - const liftMonoid = _.liftMonoid(O.Applicative) + const liftMonoid = _.getMonoid(O.Applicative) const M = liftMonoid(N.MonoidSum) U.deepStrictEqual(M.combine(O.none(), O.none()), O.none()) U.deepStrictEqual(M.combine(O.some(1), O.none()), O.none()) diff --git a/test/typeclass/SemiApplicative.ts b/test/typeclass/SemiApplicative.ts index 2c9e8ee12..9b0832eb1 100644 --- a/test/typeclass/SemiApplicative.ts +++ b/test/typeclass/SemiApplicative.ts @@ -31,7 +31,7 @@ describe("SemiApplicative", () => { }) it("liftSemigroup", () => { - const liftSemigroup = _.liftSemigroup(O.SemiApplicative) + const liftSemigroup = _.getSemigroup(O.SemiApplicative) const S = liftSemigroup(String.Semigroup) U.deepStrictEqual(S.combine(O.none(), O.none()), O.none()) U.deepStrictEqual(S.combine(O.none(), O.some("b")), O.none()) From 5e090ffb40d23309ecf12bc3561bb7ebe18020ba Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 1 Feb 2023 09:35:11 +0100 Subject: [PATCH 145/255] Filterable: make filter dual --- docs/modules/Option.ts.md | 6 +- docs/modules/ReadonlyArray.ts.md | 6 +- docs/modules/typeclass/Filterable.ts.md | 8 ++ dtslint/ts4.7/Option.ts | 92 +++++++++++++++++++++ guides/Option.md | 69 +++++++++------- src/Option.ts | 103 ++++++++++++------------ src/ReadonlyArray.ts | 10 ++- src/typeclass/Filterable.ts | 24 ++++-- 8 files changed, 229 insertions(+), 89 deletions(-) create mode 100644 dtslint/ts4.7/Option.ts diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index ddc7bb7e9..24d8e6663 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -739,8 +739,10 @@ If you need to change the type of the `Option` in addition to filtering, see `fi ```ts export declare const filter: { - (refinement: Refinement): (fc: Option) => Option - (predicate: Predicate): (fb: Option) => Option + (self: Option, refinement: (a: A) => a is B): Option + (self: Option, predicate: (a: A) => boolean): Option + (refinement: (a: A) => a is B): (self: Option) => Option + (predicate: (a: A) => boolean): (self: Option) => Option } ``` diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 085319d0e..e72edb2e1 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -428,8 +428,10 @@ Added in v1.0.0 ```ts export declare const filter: { - (refinement: Refinement): (self: readonly C[]) => B[] - (predicate: Predicate): (self: readonly B[]) => B[] + (self: readonly C[], refinement: (a: A) => a is B): B[] + (self: readonly B[], predicate: (a: A) => boolean): B[] + (refinement: (a: A) => a is B): (self: readonly C[]) => B[] + (predicate: (a: A) => boolean): (self: readonly B[]) => B[] } ``` diff --git a/docs/modules/typeclass/Filterable.ts.md b/docs/modules/typeclass/Filterable.ts.md index a0af17ee5..8a330719b 100644 --- a/docs/modules/typeclass/Filterable.ts.md +++ b/docs/modules/typeclass/Filterable.ts.md @@ -48,6 +48,14 @@ Added in v1.0.0 export declare const filter: ( F: Filterable ) => { + (self: Kind, refinement: (a: A) => a is B): Kind< + F, + R, + O, + E, + B + > + (self: Kind, predicate: (a: A) => boolean): Kind (refinement: (a: A) => a is B): ( self: Kind ) => Kind diff --git a/dtslint/ts4.7/Option.ts b/dtslint/ts4.7/Option.ts new file mode 100644 index 000000000..7caa49ebc --- /dev/null +++ b/dtslint/ts4.7/Option.ts @@ -0,0 +1,92 @@ +import { pipe } from '@fp-ts/core/Function' +import * as _ from '@fp-ts/core/Option' + +declare const n: number +declare const sn: string | number +declare const isString: (u: unknown) => u is string +declare const predicate: (sn: string | number) => boolean +declare const on: _.Option +declare const osn: _.Option + +// ------------------------------------------------------------------------------------- +// liftPredicate +// ------------------------------------------------------------------------------------- + +// $ExpectType Option +pipe(sn, _.liftPredicate(isString)) +pipe( + sn, + _.liftPredicate( + ( + n // $ExpectType string | number + ): n is number => typeof n === 'number' + ) +) + +// $ExpectType Option +pipe(sn, _.liftPredicate(predicate)) +// $ExpectType Option +pipe(n, _.liftPredicate(predicate)) +// $ExpectType Option +pipe( + n, + _.liftPredicate( + ( + _n // $ExpectType number + ) => true + ) +) + +// ------------------------------------------------------------------------------------- +// getOrElse +// ------------------------------------------------------------------------------------- + +// $ExpectType string | null +pipe(_.some('a'), _.getOrElse(() => null)) + +// ------------------------------------------------------------------------------------- +// do notation +// ------------------------------------------------------------------------------------- + +// $ExpectType Option<{ a1: number; a2: string; }> +pipe( + _.Do, + _.bind('a1', () => _.some(1)), + _.bind('a2', () => _.some('b')) +) + +// ------------------------------------------------------------------------------------- +// filter +// ------------------------------------------------------------------------------------- + +// $ExpectType Option +pipe(on, _.filter(predicate)) + +// $ExpectType Option +_.filter(on, predicate) + +// $ExpectType Option +pipe(osn, _.filter(isString)) + +// $ExpectType Option +_.filter(osn, isString) + +// $ExpectType Option +pipe( + on, + _.filter( + ( + x // $ExpectType number + ): x is number => true + ) +) + +// $ExpectType Option +pipe( + on, + _.filter( + ( + _x // $ExpectType number + ) => true + ) +) diff --git a/guides/Option.md b/guides/Option.md index 286dac873..7312435d5 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -315,43 +315,62 @@ The fastest way to get the value wrapped in an option is to call the `getOrThrow ```ts import { getOrThrow } from "@fp-ts/core/Option"; -console.log(pipe(some(10), getOrThrow); // 10 -console.log(pipe(none(), getOrThrow); // throws new Error("getOrThrow called on a None") +console.log(getOrThrow(some(10)); // 10 +console.log(getOrThrow(none()); // throws new Error("getOrThrow called on a None") ``` -A more safe alternative is [pattern matching](https://github.com/gvergnaud/ts-pattern#what-is-pattern-matching) on the `Option`. +A more safe alternative is using the `isSome` and `isNone` guards: -The `match` function allows you to match on the `None` and `Some` cases of an `Option` value and provide different actions for each. +```ts +import { some, isSome } from "@fp-ts/core/Option"; -For example we can use the `match` function to handle the `Option` value returned by `parseNumber` and decide what to do based on whether it's a `None` or a `Some`. +const option = some(1); + +// Use the `isSome` function to check if the `option` is an instance of `Some` +if (isSome(option)) { + console.log(`Option has a value: ${option.value}`); +} else { + console.log(`Option is empty.`); +} +// Option has a value: 1 +``` + +Another alternative is [pattern matching](https://github.com/gvergnaud/ts-pattern#what-is-pattern-matching) on the `Option`. + +The `match` function allows you to match on the `None` and `Some` cases of an `Option` value and provide different actions for each. ```ts +import { some, match } from "@fp-ts/core/Option"; import { pipe } from "@fp-ts/core/Function"; -import { match } from "@fp-ts/core/Option"; - -const output = pipe( - parseNumber("Not a number"), - match( - // If the result is a None, return an error string - () => `Error: ${error}`, - // If the result is a Some, return a string with the number - (n) => `The number is ${n}` - ) + +const option = some(1); + +/** + * Use the `match` function to conditionally return a string based on whether the `Option` is `None` or `Some`. + * If the `Option` is `None`, the first function will be called with no arguments. + * If the `Option` is `Some`, the `value` will be passed to the second function. + */ +const output = match( + option, + () => `Option is empty.`, + (value) => `Option has a value: ${value}` ); -console.log(output); // Output: Error: Cannot parse 'Not a number' as a number +console.log(output); // Option has a value: 1 ``` +One reason to use `match` instead of `isSome` is that `match` is more expressive and provides a clear way to handle both cases of an `Option`. With `match`, you can directly provide two functions to handle the case of the `Option` being `None` or `Some`, respectively. On the other hand, with `isSome`, you would need to manually check the value and take separate actions based on whether it's `Some` or `None`. With `match`, the code can be more concise and easy to understand. Additionally, if you have complex logic to handle both cases, using `match` can make the code easier to read and maintain. + There are specializations of `match` to make working with code that does not use `Option` more convenient and faster, particularly `getOrNull` and `getOrUndefined`. ```ts import { getOrNull, getOrUndefined } from "@fp-ts/core/Option"; -pipe(some(5), getOrNull); // 5 -pipe(none(), getOrNull); // null +getOrNull(some(5)); // 5 +getOrNull(none()); // null -pipe(some(5), getOrUndefined); // 5 -pipe(none(), getOrUndefined); // undefined +getOrUndefined(some(5)); // 5 +getOrUndefined(none()); // undefined ``` For greater flexibility, there is also the `getOrElse` function which allows you to set what value corresponds to the `None` case: @@ -359,14 +378,8 @@ For greater flexibility, there is also the `getOrElse` function which allows you ```ts import { getOrElse } from "@fp-ts/core/Option"; -pipe( - some(5), - getOrElse(() => 0) -); // 5 -pipe( - none(), - getOrElse(() => 0) -); // 0 +getOrElse(some(5), () => 0); // 5 +getOrElse(none(), () => 0); // 0 ``` **Cheat sheet** (error handling) diff --git a/src/Option.ts b/src/Option.ts index 7c7c20e8e..978f46c41 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -163,6 +163,54 @@ export const isNone: (self: Option) => self is None = option.isNone */ export const isSome: (self: Option) => self is Some = option.isSome +// ------------------------------------------------------------------------------------- +// pattern matching +// ------------------------------------------------------------------------------------- + +/** + * Matches the given `Option` and returns either the provided `onNone` value or the result of the provided `onSome` + * function when passed the `Option`'s value. + * + * @param self - The `Option` to match + * @param onNone - The value to be returned if the `Option` is `None` + * @param onSome - The function to be called if the `Option` is `Some`, it will be passed the `Option`'s value and its result will be returned + * + * @example + * import { some, none, match } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * assert.deepStrictEqual( + * pipe( + * some(1), + * match(() => 'a none', a => `a some containing ${a}`) + * ), + * 'a some containing 1' + * ) + * + * assert.deepStrictEqual( + * pipe( + * none(), + * match(() => 'a none', a => `a some containing ${a}`) + * ), + * 'a none' + * ) + * + * @dual + * @category pattern matching + * @since 1.0.0 + */ +export const match: { + (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C + (onNone: LazyArg, onSome: (a: A) => C): (self: Option) => B | C +} = dual< + (self: Option, onNone: LazyArg, onSome: (a: A) => C) => B | C, + (onNone: LazyArg, onSome: (a: A) => C) => (self: Option) => B | C +>( + 3, + (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C => + isNone(self) ? onNone() : onSome(self.value) +) + // ------------------------------------------------------------------------------------- // conversions // ------------------------------------------------------------------------------------- @@ -1200,12 +1248,15 @@ export const Filterable: filterable.Filterable = { * @param predicate - A predicate function to apply to the `Option` value. * @param fb - The `Option` to filter. * + * @dual * @category filtering * @since 1.0.0 */ export const filter: { - (refinement: Refinement): (fc: Option) => Option - (predicate: Predicate): (fb: Option) => Option + (self: Option, refinement: (a: A) => a is B): Option + (self: Option, predicate: (a: A) => boolean): Option + (refinement: (a: A) => a is B): (self: Option) => Option + (predicate: (a: A) => boolean): (self: Option) => Option } = filterable.filter(Filterable) // ------------------------------------------------------------------------------------- @@ -1270,54 +1321,6 @@ export const traverseTap: ( ) => (self: Option) => Kind> = traversable .traverseTap(Traversable) -// ------------------------------------------------------------------------------------- -// pattern matching -// ------------------------------------------------------------------------------------- - -/** - * Matches the given `Option` and returns either the provided `onNone` value or the result of the provided `onSome` - * function when passed the `Option`'s value. - * - * @param self - The `Option` to match - * @param onNone - The value to be returned if the `Option` is `None` - * @param onSome - The function to be called if the `Option` is `Some`, it will be passed the `Option`'s value and its result will be returned - * - * @example - * import { some, none, match } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' - * - * assert.deepStrictEqual( - * pipe( - * some(1), - * match(() => 'a none', a => `a some containing ${a}`) - * ), - * 'a some containing 1' - * ) - * - * assert.deepStrictEqual( - * pipe( - * none(), - * match(() => 'a none', a => `a some containing ${a}`) - * ), - * 'a none' - * ) - * - * @dual - * @category pattern matching - * @since 1.0.0 - */ -export const match: { - (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C - (onNone: LazyArg, onSome: (a: A) => C): (self: Option) => B | C -} = dual< - (self: Option, onNone: LazyArg, onSome: (a: A) => C) => B | C, - (onNone: LazyArg, onSome: (a: A) => C) => (self: Option) => B | C ->( - 3, - (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C => - isNone(self) ? onNone() : onSome(self.value) -) - // ------------------------------------------------------------------------------------- // equivalence // ------------------------------------------------------------------------------------- diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 2da9da554..6062c6a6c 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1516,14 +1516,20 @@ export const Filterable: filterable.Filterable = { } /** + * @dual * @category filtering * @since 1.0.0 */ export const filter: { ( - refinement: Refinement + self: ReadonlyArray, + refinement: (a: A) => a is B + ): Array + (self: ReadonlyArray, predicate: (a: A) => boolean): Array + ( + refinement: (a: A) => a is B ): (self: ReadonlyArray) => Array - (predicate: Predicate): (self: ReadonlyArray) => Array + (predicate: (a: A) => boolean): (self: ReadonlyArray) => Array } = filterable.filter(Filterable) as any /** diff --git a/src/typeclass/Filterable.ts b/src/typeclass/Filterable.ts index 61f209229..58a08ca35 100644 --- a/src/typeclass/Filterable.ts +++ b/src/typeclass/Filterable.ts @@ -4,7 +4,7 @@ * @since 1.0.0 */ import type { Either } from "@fp-ts/core/Either" -import { pipe } from "@fp-ts/core/Function" +import { dual, pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" @@ -42,6 +42,14 @@ export const filterMapComposition = export const filter: ( F: Filterable ) => { + ( + self: Kind, + refinement: (a: A) => a is B + ): Kind + ( + self: Kind, + predicate: (a: A) => boolean + ): Kind (refinement: (a: A) => a is B): ( self: Kind ) => Kind @@ -49,10 +57,16 @@ export const filter: ( predicate: (a: A) => boolean ): (self: Kind) => Kind } = (Filterable: Filterable) => - ( - predicate: (a: A) => boolean - ): ((self: Kind) => Kind) => - Filterable.filterMap((b) => (predicate(b) ? option.some(b) : option.none)) + dual< + (self: Kind, predicate: (a: A) => boolean) => Kind, + ( + predicate: (a: A) => boolean + ) => (self: Kind) => Kind + >( + 2, + (self: Kind, predicate: (a: A) => boolean): Kind => + pipe(self, Filterable.filterMap((b) => (predicate(b) ? option.some(b) : option.none))) + ) /** * @since 1.0.0 From 621ccf902c9dc7f42bf9aa6fae9a818fdaac014b Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 1 Feb 2023 16:20:58 +0100 Subject: [PATCH 146/255] SemiProduct: make appendElement dual --- docs/modules/Either.ts.md | 7 ++-- docs/modules/Option.ts.md | 7 ++-- docs/modules/Predicate.ts.md | 7 ++-- docs/modules/These.ts.md | 14 ++++--- docs/modules/typeclass/SemiProduct.ts.md | 51 ++++++++++++++---------- src/Either.ts | 50 +++++++++++++++++------ src/Option.ts | 43 +++++++++++++++----- src/Predicate.ts | 12 ++++-- src/These.ts | 50 +++++++++++++++++------ src/typeclass/SemiProduct.ts | 29 +++++++++----- 10 files changed, 184 insertions(+), 86 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index bf916c1c5..df4bc05eb 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -1405,9 +1405,10 @@ Appends an element to the end of a tuple. **Signature** ```ts -export declare const appendElement: ( - that: Either -) => (self: Either) => Either +export declare const appendElement: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 24d8e6663..39d422c22 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -1734,9 +1734,10 @@ Appends an element to the end of a tuple. **Signature** ```ts -export declare const appendElement: ( - fb: Option -) => (self: Option) => Option<[...A, B]> +export declare const appendElement: { + (self: Option, that: Option): Option<[...A, B]> + (that: Option): (self: Option) => Option<[...A, B]> +} ``` Added in v1.0.0 diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index 8e31ffbb1..e6acbc0ba 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -328,9 +328,10 @@ Appends an element to the end of a tuple. **Signature** ```ts -export declare const appendElement: ( - that: Predicate -) => (self: Predicate) => Predicate +export declare const appendElement: { + (self: Predicate, that: Predicate): Predicate + (that: Predicate): (self: Predicate) => Predicate +} ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index bba4756e2..088c8cbc1 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1585,11 +1585,15 @@ Appends an element to the end of a tuple. **Signature** ```ts -export declare const appendElement: ( - that: These -) => ( - self: These -) => These +export declare const appendElement: { + ( + self: These, + that: These + ): These + (that: These): ( + self: These + ) => These +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index a2d2c883d..dc69b4048 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -14,10 +14,11 @@ Added in v1.0.0 - [constructors](#constructors) - [productMany](#productmany) +- [do notation](#do-notation) + - [andThenBind](#andthenbind) - [type class](#type-class) - [SemiProduct (interface)](#semiproduct-interface) - [utils](#utils) - - [andThenBind](#andthenbind) - [appendElement](#appendelement) - [nonEmptyStruct](#nonemptystruct) - [nonEmptyTuple](#nonemptytuple) @@ -46,6 +47,25 @@ export declare const productMany: ( Added in v1.0.0 +# do notation + +## andThenBind + +**Signature** + +```ts +export declare const andThenBind: ( + F: SemiProduct +) => ( + name: Exclude, + that: Kind +) => ( + self: Kind +) => Kind +``` + +Added in v1.0.0 + # type class ## SemiProduct (interface) @@ -70,23 +90,6 @@ Added in v1.0.0 # utils -## andThenBind - -**Signature** - -```ts -export declare const andThenBind: ( - F: SemiProduct -) => ( - name: Exclude, - that: Kind -) => ( - self: Kind -) => Kind -``` - -Added in v1.0.0 - ## appendElement Appends an element to the end of a tuple. @@ -96,11 +99,15 @@ Appends an element to the end of a tuple. ```ts export declare const appendElement: ( F: SemiProduct -) => ( +) => (( + self: Kind, that: Kind -) => ( - self: Kind -) => Kind +) => Kind) & + (( + that: Kind + ) => ( + self: Kind + ) => Kind) ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index aa2ba09d3..f2c76562f 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -479,12 +479,15 @@ export const SemiProduct: semiProduct.SemiProduct = { * * @since 1.0.0 */ -export const appendElement: ( - that: Either -) => >( - self: Either -) => Either = semiProduct - .appendElement(SemiProduct) +export const appendElement: { + , E2, B>( + self: Either, + that: Either + ): Either + ( + that: Either + ): >(self: Either) => Either +} = semiProduct.appendElement(SemiProduct) const productAll = ( collection: Iterable> @@ -1144,49 +1147,70 @@ export const getOptionalSemigroup = (S: Semigroup): Semigroup(self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = lift2(N.sum) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiply = lift2(N.multiply) +export const multiply: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = lift2(N.multiply) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtract = lift2(N.subtract) +export const subtract: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = lift2(N.subtract) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const divide = lift2(N.divide) +export const divide: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = lift2(N.divide) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const sumBigint = lift2(BI.sum) +export const sumBigint: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = lift2(BI.sum) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiplyBigint = lift2(BI.multiply) +export const multiplyBigint: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = lift2(BI.multiply) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtractBigint = lift2(BI.subtract) +export const subtractBigint: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} = lift2(BI.subtract) // ------------------------------------------------------------------------------------- // do notation diff --git a/src/Option.ts b/src/Option.ts index 978f46c41..5d7962c31 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -939,10 +939,10 @@ export const SemiProduct: semiProduct.SemiProduct = { * * @since 1.0.0 */ -export const appendElement: ( - fb: Option -) => >(self: Option) => Option<[...A, B]> = semiProduct - .appendElement(SemiProduct) +export const appendElement: { + , B>(self: Option, that: Option): Option<[...A, B]> + (that: Option): >(self: Option) => Option<[...A, B]> +} = semiProduct.appendElement(SemiProduct) const productAll = (collection: Iterable>): Option> => { const out: Array = [] @@ -1582,49 +1582,70 @@ export const reduceCompact: { * @category algebraic operations * @since 1.0.0 */ -export const sum = lift2(N.sum) +export const sum: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = lift2(N.sum) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiply = lift2(N.multiply) +export const multiply: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = lift2(N.multiply) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtract = lift2(N.subtract) +export const subtract: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = lift2(N.subtract) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const divide = lift2(N.divide) +export const divide: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = lift2(N.divide) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const sumBigint = lift2(BI.sum) +export const sumBigint: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = lift2(BI.sum) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const multiplyBigint = lift2(BI.multiply) +export const multiplyBigint: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = lift2(BI.multiply) /** * @dual * @category algebraic operations * @since 1.0.0 */ -export const subtractBigint = lift2(BI.subtract) +export const subtractBigint: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} = lift2(BI.subtract) /** * Sum all numbers in an iterable of `Option` ignoring the `None` values. diff --git a/src/Predicate.ts b/src/Predicate.ts index 25fb04981..146b2a27a 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -222,9 +222,15 @@ export const andThenBind: ( * * @since 1.0.0 */ -export const appendElement: (that: Predicate) => >( - self: Predicate -) => Predicate = semiProduct.appendElement(SemiProduct) as any +export const appendElement: { + , B>( + self: Predicate, + that: Predicate + ): Predicate + ( + that: Predicate + ): >(self: Predicate) => Predicate +} = semiProduct.appendElement(SemiProduct) as any /** * @since 1.0.0 diff --git a/src/These.ts b/src/These.ts index 767b04101..78322ae87 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1036,12 +1036,15 @@ const productAll = ( * * @since 1.0.0 */ -export const appendElement: ( - that: Validated -) => >( - self: Validated -) => Validated = semiProduct - .appendElement(SemiProduct) +export const appendElement: { + , E2, B>( + self: Validated, + that: Validated + ): Validated + ( + that: Validated + ): >(self: Validated) => Validated +} = semiProduct.appendElement(SemiProduct) /** * @category instances @@ -1249,43 +1252,64 @@ export const Monad: monad.Monad = { * @category algebraic operations * @since 1.0.0 */ -export const sum = lift2(N.sum) +export const sum: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = lift2(N.sum) /** * @category algebraic operations * @since 1.0.0 */ -export const multiply = lift2(N.multiply) +export const multiply: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = lift2(N.multiply) /** * @category algebraic operations * @since 1.0.0 */ -export const subtract = lift2(N.subtract) +export const subtract: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = lift2(N.subtract) /** * @category algebraic operations * @since 1.0.0 */ -export const divide = lift2(N.divide) +export const divide: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = lift2(N.divide) /** * @category algebraic operations * @since 1.0.0 */ -export const sumBigint = lift2(BI.sum) +export const sumBigint: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = lift2(BI.sum) /** * @category algebraic operations * @since 1.0.0 */ -export const multiplyBigint = lift2(BI.multiply) +export const multiplyBigint: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = lift2(BI.multiply) /** * @category algebraic operations * @since 1.0.0 */ -export const subtractBigint = lift2(BI.subtract) +export const subtractBigint: { + (self: Validated, that: Validated): Validated + (that: Validated): (self: Validated) => Validated +} = lift2(BI.subtract) // ------------------------------------------------------------------------------------- // do notation diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index c41b10aee..ad8a522e4 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { pipe } from "@fp-ts/core/Function" +import { dual, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" @@ -89,6 +89,7 @@ export const productMany = ( } /** + * @category do notation * @since 1.0.0 */ export const andThenBind = (F: SemiProduct) => @@ -119,16 +120,24 @@ export const andThenBind = (F: SemiProduct) => * @since 1.0.0 */ export const appendElement = (F: SemiProduct) => - ( - that: Kind - ) => - >( + dual< + , R2, O2, E2, B>( + self: Kind, + that: Kind + ) => Kind, + ( + that: Kind + ) => >( self: Kind - ): Kind => - pipe( - F.product(self, that), - F.imap(([a, b]) => [...a, b], ab => [ab.slice(0, -1), ab[ab.length - 1]] as any) - ) + ) => Kind + >(2, , R2, O2, E2, B>( + self: Kind, + that: Kind + ): Kind => + pipe( + F.product(self, that), + F.imap(([a, b]) => [...a, b], ab => [ab.slice(0, -1), ab[ab.length - 1]] as any) + )) /** * @since 1.0.0 From 2e5e849aeadbdf27106b03d6debdf2560648ddf2 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 1 Feb 2023 16:30:05 +0100 Subject: [PATCH 147/255] Traversable: make traverseTap dual --- docs/modules/Either.ts.md | 5 ++++- docs/modules/Option.ts.md | 5 ++++- docs/modules/ReadonlyArray.ts.md | 5 ++++- docs/modules/These.ts.md | 5 ++++- docs/modules/typeclass/Traversable.ts.md | 15 ++++++++++--- src/Either.ts | 13 +++++++---- src/Option.ts | 13 +++++++---- src/ReadonlyArray.ts | 13 +++++++---- src/These.ts | 13 +++++++---- src/typeclass/Traversable.ts | 28 +++++++++++++++++++----- 10 files changed, 87 insertions(+), 28 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index df4bc05eb..fd2e50f6c 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -1351,7 +1351,10 @@ Added in v1.0.0 ```ts export declare const traverseTap: ( F: applicative.Applicative -) => (f: (a: A) => Kind) => (self: Either) => Kind> +) => { + (self: Either, f: (a: A) => Kind): Kind> + (f: (a: A) => Kind): (self: Either) => Kind> +} ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 39d422c22..6ded28024 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -1680,7 +1680,10 @@ Added in v1.0.0 ```ts export declare const traverseTap: ( F: applicative.Applicative -) => (f: (a: A) => Kind) => (self: Option) => Kind> +) => { + (self: Option, f: (a: A) => Kind): Kind> + (f: (a: A) => Kind): (self: Option) => Kind> +} ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index e72edb2e1..35936b750 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -1804,7 +1804,10 @@ Added in v1.0.0 ```ts export declare const traverseTap: ( F: applicative.Applicative -) => (f: (a: A) => Kind) => (self: readonly A[]) => Kind +) => { + (self: readonly A[], f: (a: A) => Kind): Kind + (f: (a: A) => Kind): (self: readonly A[]) => Kind +} ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 088c8cbc1..7aba28ee5 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1509,7 +1509,10 @@ Added in v1.0.0 ```ts export declare const traverseTap: ( F: applicative.Applicative -) => (f: (a: A) => Kind) => (self: These) => Kind> +) => { + (self: These, f: (a: A) => Kind): Kind> + (f: (a: A) => Kind): (self: These) => Kind> +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Traversable.ts.md b/docs/modules/typeclass/Traversable.ts.md index ce63e5216..d21b93ca5 100644 --- a/docs/modules/typeclass/Traversable.ts.md +++ b/docs/modules/typeclass/Traversable.ts.md @@ -124,9 +124,18 @@ export declare const traverseTap: ( T: Traversable ) => ( F: Applicative -) => ( - f: (a: A) => Kind -) => (self: Kind) => Kind> +) => { + (self: Kind, f: (a: A) => Kind): Kind< + F, + R, + O, + E, + Kind + > + (f: (a: A) => Kind): ( + self: Kind + ) => Kind> +} ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index f2c76562f..0a4808a55 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -972,10 +972,15 @@ export const Traversable: traversable.Traversable = { */ export const traverseTap: ( F: applicative.Applicative -) => ( - f: (a: A) => Kind -) => (self: Either) => Kind> = traversable - .traverseTap(Traversable) +) => { + ( + self: Either, + f: (a: A) => Kind + ): Kind> + ( + f: (a: A) => Kind + ): (self: Either) => Kind> +} = traversable.traverseTap(Traversable) /** * Returns an effect that effectfully "peeks" at the success of this effect. diff --git a/src/Option.ts b/src/Option.ts index 5d7962c31..c31cb08bf 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1316,10 +1316,15 @@ export const Traversable: traversable.Traversable = { */ export const traverseTap: ( F: applicative.Applicative -) => ( - f: (a: A) => Kind -) => (self: Option) => Kind> = traversable - .traverseTap(Traversable) +) => { + ( + self: Option, + f: (a: A) => Kind + ): Kind> + ( + f: (a: A) => Kind + ): (self: Option) => Kind> +} = traversable.traverseTap(Traversable) // ------------------------------------------------------------------------------------- // equivalence diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 6062c6a6c..1c2b43ac0 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1675,10 +1675,15 @@ export const Traversable: traversable.Traversable = { */ export const traverseTap: ( F: applicative.Applicative -) => ( - f: (a: A) => Kind -) => (self: ReadonlyArray) => Kind> = traversable - .traverseTap(Traversable) as any +) => { + ( + self: ReadonlyArray, + f: (a: A) => Kind + ): Kind> + ( + f: (a: A) => Kind + ): (self: ReadonlyArray) => Kind> +} = traversable.traverseTap(Traversable) as any /** * @category traversing diff --git a/src/These.ts b/src/These.ts index 78322ae87..ca5892cd6 100644 --- a/src/These.ts +++ b/src/These.ts @@ -726,10 +726,15 @@ export const Traversable: traversable.Traversable = { */ export const traverseTap: ( F: applicative.Applicative -) => ( - f: (a: A) => Kind -) => (self: These) => Kind> = traversable - .traverseTap(Traversable) +) => { + ( + self: These, + f: (a: A) => Kind + ): Kind> + ( + f: (a: A) => Kind + ): (self: These) => Kind> +} = traversable.traverseTap(Traversable) /** * Returns a function that checks if a `These` contains a given value using a provided `equivalence` function. diff --git a/src/typeclass/Traversable.ts b/src/typeclass/Traversable.ts index f99b23096..00257be14 100644 --- a/src/typeclass/Traversable.ts +++ b/src/typeclass/Traversable.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { identity, pipe } from "@fp-ts/core/Function" +import { dual, identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" import type { Applicative } from "@fp-ts/core/typeclass/Applicative" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" @@ -75,7 +75,25 @@ export const sequence = ( * @since 1.0.0 */ export const traverseTap = (T: Traversable) => - (F: Applicative) => - (f: (a: A) => Kind): ( - self: Kind - ) => Kind> => T.traverse(F)(a => pipe(f(a), F.map(() => a))) + (F: Applicative): { + ( + self: Kind, + f: (a: A) => Kind + ): Kind> + ( + f: (a: A) => Kind + ): (self: Kind) => Kind> + } => + dual< + ( + self: Kind, + f: (a: A) => Kind + ) => Kind>, + (f: (a: A) => Kind) => ( + self: Kind + ) => Kind> + >(2, ( + self: Kind, + f: (a: A) => Kind + ): Kind> => + pipe(self, T.traverse(F)(a => pipe(f(a), F.map(() => a))))) From 47f9fa86c7f40c6987aff25eebb5b624bb9f15d9 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 1 Feb 2023 17:04:18 +0100 Subject: [PATCH 148/255] remove bigint APIs --- docs/modules/Either.ts.md | 42 ---- docs/modules/Option.ts.md | 455 +++++++++++++++++--------------------- docs/modules/These.ts.md | 57 ----- guides/Option.md | 48 ++-- src/Either.ts | 31 --- src/Option.ts | 337 +++++++++++++--------------- src/These.ts | 28 --- test/Either.ts | 18 -- test/Option.ts | 18 -- test/These.ts | 21 -- 10 files changed, 399 insertions(+), 656 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index fd2e50f6c..7f55ad86f 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -15,11 +15,8 @@ Added in v1.0.0 - [algebraic operations](#algebraic-operations) - [divide](#divide) - [multiply](#multiply) - - [multiplyBigint](#multiplybigint) - [subtract](#subtract) - - [subtractBigint](#subtractbigint) - [sum](#sum) - - [sumBigint](#sumbigint) - [combinators](#combinators) - [tap](#tap) - [combining](#combining) @@ -163,19 +160,6 @@ export declare const multiply: { Added in v1.0.0 -## multiplyBigint - -**Signature** - -```ts -export declare const multiplyBigint: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} -``` - -Added in v1.0.0 - ## subtract **Signature** @@ -189,19 +173,6 @@ export declare const subtract: { Added in v1.0.0 -## subtractBigint - -**Signature** - -```ts -export declare const subtractBigint: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} -``` - -Added in v1.0.0 - ## sum **Signature** @@ -215,19 +186,6 @@ export declare const sum: { Added in v1.0.0 -## sumBigint - -**Signature** - -```ts -export declare const sumBigint: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} -``` - -Added in v1.0.0 - # combinators ## tap diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 6ded28024..8fb4ad7aa 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -15,16 +15,15 @@ Added in v1.0.0 - [algebraic operations](#algebraic-operations) - [divide](#divide) - [multiply](#multiply) - - [multiplyBigint](#multiplybigint) - [multiplyCompact](#multiplycompact) - [subtract](#subtract) - - [subtractBigint](#subtractbigint) - [sum](#sum) - - [sumBigint](#sumbigint) - [sumCompact](#sumcompact) -- [combinators](#combinators) - - [tap](#tap) - [combining](#combining) + - [ap](#ap) + - [getFailureMonoid](#getfailuremonoid) + - [getFailureSemigroup](#getfailuresemigroup) + - [getFirstSomeSemigroup](#getfirstsomesemigroup) - [zipWith](#zipwith) - [constructors](#constructors) - [none](#none) @@ -58,7 +57,9 @@ Added in v1.0.0 - [filterMap](#filtermap) - [separate](#separate) - [folding](#folding) + - [Foldable](#foldable) - [reduceCompact](#reducecompact) + - [toArray](#toarray) - [guards](#guards) - [isNone](#isnone) - [isOption](#isoption) @@ -66,26 +67,16 @@ Added in v1.0.0 - [instances](#instances) - [Alternative](#alternative) - [Applicative](#applicative) - - [Chainable](#chainable) - [Compactable](#compactable) - [Coproduct](#coproduct) - - [Covariant](#covariant) - [Filterable](#filterable) - - [FlatMap](#flatmap) - - [Foldable](#foldable) - - [Invariant](#invariant) - [Monad](#monad) - - [Of](#of) - - [Pointed](#pointed) - [Product](#product) - [SemiAlternative](#semialternative) - [SemiApplicative](#semiapplicative) - [SemiCoproduct](#semicoproduct) - [SemiProduct](#semiproduct) - [Traversable](#traversable) - - [getFailureMonoid](#getfailuremonoid) - - [getFailureSemigroup](#getfailuresemigroup) - - [getFirstSomeSemigroup](#getfirstsomesemigroup) - [getOptionalMonoid](#getoptionalmonoid) - [interop](#interop) - [fromNullable](#fromnullable) @@ -99,10 +90,13 @@ Added in v1.0.0 - [liftEither](#lifteither) - [liftPredicate](#liftpredicate) - [mapping](#mapping) + - [Covariant](#covariant) + - [Invariant](#invariant) - [as](#as) - [asUnit](#asunit) - [flap](#flap) - [map](#map) + - [tupled](#tupled) - [models](#models) - [None (interface)](#none-interface) - [Option (type alias)](#option-type-alias) @@ -110,10 +104,16 @@ Added in v1.0.0 - [pattern matching](#pattern-matching) - [match](#match) - [sequencing](#sequencing) + - [Chainable](#chainable) + - [FlatMap](#flatmap) + - [andThen](#andthen) - [andThenDiscard](#andthendiscard) + - [composeKleisliArrow](#composekleisliarrow) - [flatMap](#flatmap) - [flatMapEither](#flatmapeither) - [flatMapNullable](#flatmapnullable) + - [flatten](#flatten) + - [tap](#tap) - [sorting](#sorting) - [getOrder](#getorder) - [traversing](#traversing) @@ -123,17 +123,13 @@ Added in v1.0.0 - [type lambdas](#type-lambdas) - [OptionTypeLambda (interface)](#optiontypelambda-interface) - [utils](#utils) - - [andThen](#andthen) - - [ap](#ap) + - [Of](#of) + - [Pointed](#pointed) - [appendElement](#appendelement) - - [composeKleisliArrow](#composekleisliarrow) - [contains](#contains) - [exists](#exists) - - [flatten](#flatten) - [struct](#struct) - - [toArray](#toarray) - [tuple](#tuple) - - [tupled](#tupled) - [unit](#unit) --- @@ -166,19 +162,6 @@ export declare const multiply: { Added in v1.0.0 -## multiplyBigint - -**Signature** - -```ts -export declare const multiplyBigint: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} -``` - -Added in v1.0.0 - ## multiplyCompact Multiply all numbers in an iterable of `Option` ignoring the `None` values. @@ -213,88 +196,101 @@ export declare const subtract: { Added in v1.0.0 -## subtractBigint +## sum **Signature** ```ts -export declare const subtractBigint: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option +export declare const sum: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option } ``` Added in v1.0.0 -## sum +## sumCompact + +Sum all numbers in an iterable of `Option` ignoring the `None` values. **Signature** ```ts -export declare const sum: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} +export declare const sumCompact: (self: Iterable>) => number +``` + +**Example** + +```ts +import { sumCompact, some, none } from '@fp-ts/core/Option' + +const iterable = [some(2), none(), some(3), none()] +assert.deepStrictEqual(sumCompact(iterable), 5) ``` Added in v1.0.0 -## sumBigint +# combining + +## ap **Signature** ```ts -export declare const sumBigint: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option +export declare const ap: { + (self: Option<(a: A) => B>, that: Option): Option + (that: Option): (self: Option<(a: A) => B>) => Option } ``` Added in v1.0.0 -## sumCompact +## getFailureMonoid -Sum all numbers in an iterable of `Option` ignoring the `None` values. +Monoid that models the combination of computations that can fail, if at least one element is `None` +then the resulting combination is `None`, otherwise if all elements are `Some` then the resulting combination +is the combination of the wrapped elements using the provided `Monoid`. + +The `empty` value is `some(M.empty)`. + +See also `getFailureSemigroup` if you need a `Semigroup` instead of a `Monoid`. **Signature** ```ts -export declare const sumCompact: (self: Iterable>) => number +export declare const getFailureMonoid: (M: Monoid) => Monoid> ``` -**Example** +Added in v1.0.0 -```ts -import { sumCompact, some, none } from '@fp-ts/core/Option' +## getFailureSemigroup -const iterable = [some(2), none(), some(3), none()] -assert.deepStrictEqual(sumCompact(iterable), 5) -``` +Semigroup that models the combination of computations that can fail, if at least one element is `None` +then the resulting combination is `None`, otherwise if all elements are `Some` then the resulting combination +is the combination of the wrapped elements using the provided `Semigroup`. -Added in v1.0.0 +See also `getFailureMonoid` if you need a `Monoid` instead of a `Semigroup`. -# combinators +**Signature** -## tap +```ts +export declare const getFailureSemigroup: (S: Semigroup) => Semigroup> +``` -Applies the provided function `f` to the value of the `Option` if it is `Some` and returns the original `Option` -unless `f` returns `None`, in which case it returns `None`. +Added in v1.0.0 -This function is useful for performing additional computations on the value of the input `Option` without affecting its value. +## getFirstSomeSemigroup + +Semigroup returning the first `Some` value encountered. **Signature** ```ts -export declare const tap: { - (self: Option, f: (a: A) => Option<_>): Option - (f: (a: A) => Option<_>): (self: Option) => Option -} +export declare const getFirstSomeSemigroup: () => Semigroup> ``` Added in v1.0.0 -# combining - ## zipWith Zips two `Option` values together using a provided function, returning a new `Option` of the result. @@ -777,6 +773,16 @@ Added in v1.0.0 # folding +## Foldable + +**Signature** + +```ts +export declare const Foldable: foldable.Foldable +``` + +Added in v1.0.0 + ## reduceCompact Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. @@ -808,6 +814,29 @@ assert.deepStrictEqual( Added in v1.0.0 +## toArray + +Transforms an `Option` into an `Array`. +If the input is `None`, an empty array is returned. +If the input is `Some`, the value is wrapped in an array. + +**Signature** + +```ts +export declare const toArray: (self: Option) => A[] +``` + +**Example** + +```ts +import { some, none, toArray } from '@fp-ts/core/Option' + +assert.deepStrictEqual(toArray(some(1)), [1]) +assert.deepStrictEqual(toArray(none()), []) +``` + +Added in v1.0.0 + # guards ## isNone @@ -896,16 +925,6 @@ export declare const Applicative: applicative.Applicative Added in v1.0.0 -## Chainable - -**Signature** - -```ts -export declare const Chainable: chainable.Chainable -``` - -Added in v1.0.0 - ## Compactable **Signature** @@ -926,16 +945,6 @@ export declare const Coproduct: coproduct_.Coproduct Added in v1.0.0 -## Covariant - -**Signature** - -```ts -export declare const Covariant: covariant.Covariant -``` - -Added in v1.0.0 - ## Filterable **Signature** @@ -946,36 +955,6 @@ export declare const Filterable: filterable.Filterable Added in v1.0.0 -## FlatMap - -**Signature** - -```ts -export declare const FlatMap: flatMap_.FlatMap -``` - -Added in v1.0.0 - -## Foldable - -**Signature** - -```ts -export declare const Foldable: foldable.Foldable -``` - -Added in v1.0.0 - -## Invariant - -**Signature** - -```ts -export declare const Invariant: invariant.Invariant -``` - -Added in v1.0.0 - ## Monad **Signature** @@ -986,26 +965,6 @@ export declare const Monad: monad.Monad Added in v1.0.0 -## Of - -**Signature** - -```ts -export declare const Of: of_.Of -``` - -Added in v1.0.0 - -## Pointed - -**Signature** - -```ts -export declare const Pointed: pointed.Pointed -``` - -Added in v1.0.0 - ## Product **Signature** @@ -1066,52 +1025,6 @@ export declare const Traversable: traversable.Traversable Added in v1.0.0 -## getFailureMonoid - -Monoid that models the combination of computations that can fail, if at least one element is `None` -then the resulting combination is `None`, otherwise if all elements are `Some` then the resulting combination -is the combination of the wrapped elements using the provided `Monoid`. - -The `empty` value is `some(M.empty)`. - -See also `getFailureSemigroup` if you need a `Semigroup` instead of a `Monoid`. - -**Signature** - -```ts -export declare const getFailureMonoid: (M: Monoid) => Monoid> -``` - -Added in v1.0.0 - -## getFailureSemigroup - -Semigroup that models the combination of computations that can fail, if at least one element is `None` -then the resulting combination is `None`, otherwise if all elements are `Some` then the resulting combination -is the combination of the wrapped elements using the provided `Semigroup`. - -See also `getFailureMonoid` if you need a `Monoid` instead of a `Semigroup`. - -**Signature** - -```ts -export declare const getFailureSemigroup: (S: Semigroup) => Semigroup> -``` - -Added in v1.0.0 - -## getFirstSomeSemigroup - -Semigroup returning the first `Some` value encountered. - -**Signature** - -```ts -export declare const getFirstSomeSemigroup: () => Semigroup> -``` - -Added in v1.0.0 - ## getOptionalMonoid Monoid that models the combination of values that may be absent, elements that are `None` are ignored @@ -1359,6 +1272,26 @@ Added in v1.0.0 # mapping +## Covariant + +**Signature** + +```ts +export declare const Covariant: covariant.Covariant +``` + +Added in v1.0.0 + +## Invariant + +**Signature** + +```ts +export declare const Invariant: invariant.Invariant +``` + +Added in v1.0.0 + ## as Maps the `Some` value of this `Option` to the specified constant value. @@ -1413,6 +1346,16 @@ export declare const map: { Added in v1.0.0 +## tupled + +**Signature** + +```ts +export declare const tupled: (self: Option) => Option<[A]> +``` + +Added in v1.0.0 + # models ## None (interface) @@ -1499,6 +1442,39 @@ Added in v1.0.0 # sequencing +## Chainable + +**Signature** + +```ts +export declare const Chainable: chainable.Chainable +``` + +Added in v1.0.0 + +## FlatMap + +**Signature** + +```ts +export declare const FlatMap: flatMap_.FlatMap +``` + +Added in v1.0.0 + +## andThen + +**Signature** + +```ts +export declare const andThen: { + <_, B>(self: Option<_>, that: Option): Option + (that: Option): <_>(self: Option<_>) => Option +} +``` + +Added in v1.0.0 + ## andThenDiscard Sequences the specified `that` `Option` but ignores its value. @@ -1516,6 +1492,19 @@ export declare const andThenDiscard: { Added in v1.0.0 +## composeKleisliArrow + +**Signature** + +```ts +export declare const composeKleisliArrow: { + (afb: (a: A) => Option, bfc: (b: B) => Option): (a: A) => Option + (bfc: (b: B) => Option): (afb: (a: A) => Option) => (a: A) => Option +} +``` + +Added in v1.0.0 + ## flatMap Applies a function to the value of an `Option` and flattens the result, if the input is `Some`. @@ -1611,6 +1600,34 @@ assert.deepStrictEqual( Added in v1.0.0 +## flatten + +**Signature** + +```ts +export declare const flatten: (self: Option>) => Option +``` + +Added in v1.0.0 + +## tap + +Applies the provided function `f` to the value of the `Option` if it is `Some` and returns the original `Option` +unless `f` returns `None`, in which case it returns `None`. + +This function is useful for performing additional computations on the value of the input `Option` without affecting its value. + +**Signature** + +```ts +export declare const tap: { + (self: Option, f: (a: A) => Option<_>): Option + (f: (a: A) => Option<_>): (self: Option) => Option +} +``` + +Added in v1.0.0 + # sorting ## getOrder @@ -1704,28 +1721,22 @@ Added in v1.0.0 # utils -## andThen +## Of **Signature** ```ts -export declare const andThen: { - <_, B>(self: Option<_>, that: Option): Option - (that: Option): <_>(self: Option<_>) => Option -} +export declare const Of: of_.Of ``` Added in v1.0.0 -## ap +## Pointed **Signature** ```ts -export declare const ap: { - (self: Option<(a: A) => B>, that: Option): Option - (that: Option): (self: Option<(a: A) => B>) => Option -} +export declare const Pointed: pointed.Pointed ``` Added in v1.0.0 @@ -1745,19 +1756,6 @@ export declare const appendElement: { Added in v1.0.0 -## composeKleisliArrow - -**Signature** - -```ts -export declare const composeKleisliArrow: { - (afb: (a: A) => Option, bfc: (b: B) => Option): (a: A) => Option - (bfc: (b: B) => Option): (afb: (a: A) => Option) => (a: A) => Option -} -``` - -Added in v1.0.0 - ## contains Returns a function that checks if an `Option` contains a given value using a provided `Equivalence` instance. @@ -1813,16 +1811,6 @@ assert.deepStrictEqual(pipe(none(), exists(isEven)), false) Added in v1.0.0 -## flatten - -**Signature** - -```ts -export declare const flatten: (self: Option>) => Option -``` - -Added in v1.0.0 - ## struct **Signature** @@ -1835,29 +1823,6 @@ export declare const struct: >>( Added in v1.0.0 -## toArray - -Transforms an `Option` into an `Array`. -If the input is `None`, an empty array is returned. -If the input is `Some`, the value is wrapped in an array. - -**Signature** - -```ts -export declare const toArray: (self: Option) => A[] -``` - -**Example** - -```ts -import { some, none, toArray } from '@fp-ts/core/Option' - -assert.deepStrictEqual(toArray(some(1)), [1]) -assert.deepStrictEqual(toArray(none()), []) -``` - -Added in v1.0.0 - ## tuple **Signature** @@ -1870,16 +1835,6 @@ export declare const tuple: []>( Added in v1.0.0 -## tupled - -**Signature** - -```ts -export declare const tupled: (self: Option) => Option<[A]> -``` - -Added in v1.0.0 - ## unit **Signature** diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 7aba28ee5..83f68b0cb 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -15,11 +15,8 @@ Added in v1.0.0 - [algebraic operations](#algebraic-operations) - [divide](#divide) - [multiply](#multiply) - - [multiplyBigint](#multiplybigint) - [subtract](#subtract) - - [subtractBigint](#subtractbigint) - [sum](#sum) - - [sumBigint](#sumbigint) - [combinators](#combinators) - [tap](#tap) - [combining](#combining) @@ -197,24 +194,6 @@ export declare const multiply: { Added in v1.0.0 -## multiplyBigint - -**Signature** - -```ts -export declare const multiplyBigint: { - (self: These, that: These): These< - readonly [E1 | E2, ...(E1 | E2)[]], - bigint - > - (that: These): ( - self: These - ) => These -} -``` - -Added in v1.0.0 - ## subtract **Signature** @@ -233,24 +212,6 @@ export declare const subtract: { Added in v1.0.0 -## subtractBigint - -**Signature** - -```ts -export declare const subtractBigint: { - (self: These, that: These): These< - readonly [E1 | E2, ...(E1 | E2)[]], - bigint - > - (that: These): ( - self: These - ) => These -} -``` - -Added in v1.0.0 - ## sum **Signature** @@ -269,24 +230,6 @@ export declare const sum: { Added in v1.0.0 -## sumBigint - -**Signature** - -```ts -export declare const sumBigint: { - (self: These, that: These): These< - readonly [E1 | E2, ...(E1 | E2)[]], - bigint - > - (that: These): ( - self: These - ) => These -} -``` - -Added in v1.0.0 - # combinators ## tap diff --git a/guides/Option.md b/guides/Option.md index 7312435d5..f46a3c686 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -384,13 +384,16 @@ getOrElse(none(), () => 0); // 0 **Cheat sheet** (error handling) -| Name | Given | To | -| ---------------- | --------------------------------------------------- | ---------------- | -| `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | -| `getOrThrow` | `Option` | `A` | -| `getOrNull` | `Option` | `A \| null` | -| `getOrUndefined` | `Option` | `A \| undefined` | -| `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | +| Name | Given | To | +| ---------------- | --------------------------------------------------- | ---------------------- | +| `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | +| `getOrThrow` | `Option` | `A` | +| `getOrNull` | `Option` | `A \| null` | +| `getOrUndefined` | `Option` | `A \| undefined` | +| `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | +| `orElse` | `Option`, `LazyArg>` | `Option` | +| `orElseEither` | `Option`, `LazyArg>` | `Option>` | +| `firstSomeOf` | `Iterable>` | `Option` | # Interop @@ -506,9 +509,28 @@ console.log(pipe(none(), getOrThrow); // throws new Error("getOrThrow called on **Cheat sheet** (combining) -| Name | Given | To | -| -------------- | ----------------------------------------- | ---------------------- | -| `orElse` | `Option`, `LazyArg>` | `Option` | -| `orElseEither` | `Option`, `LazyArg>` | `Option>` | -| `firstSomeOf` | `Iterable>` | `Option` | -| `reduceAll` | `Iterable>`, `B`, `(B, A) => B` | `B` | +| Name | Given | To | +| ----------------------- | --------------------------------------- | ---------------------- | +| `zipWith` | `Option`, `Option`, `(A, B) => C` | `C` | +| `ap` | `Option<(a: A) => B>`, `Option` | `Option` | +| `getFailureSemigroup` | `Semigroup` | `Semigroup>` | +| `getFailureMonoid` | `Monoid` | `Monoid>` | +| `getFirstSomeSemigroup` | | `Semigroup>` | + +**Cheat sheet** (folding) + +| Name | Given | To | +| --------------- | ----------------------------------------- | ---------- | +| `reduceCompact` | `Iterable>`, `B`, `(B, A) => B` | `B` | +| `toArray` | `Option` | `Array` | + +**Cheat sheet** (algebraic operations) + +| Name | Given | To | +| ----------------- | ---------------------------------- | ---------------- | +| `sum` | `Option`, `Option` | `Option` | +| `multiply` | `Option`, `Option` | `Option` | +| `subtract` | `Option`, `Option` | `Option` | +| `divide` | `Option`, `Option` | `Option` | +| `sumCompact` | `Iterable>` | `number` | +| `multiplyCompact` | `Iterable>` | `number` | diff --git a/src/Either.ts b/src/Either.ts index 0a4808a55..2982743f0 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -2,7 +2,6 @@ * @since 1.0.0 */ -import * as BI from "@fp-ts/core/Bigint" import type { LazyArg } from "@fp-ts/core/Function" import { constNull, constUndefined, dual, identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" @@ -1187,36 +1186,6 @@ export const divide: { (that: Either): (self: Either) => Either } = lift2(N.divide) -/** - * @dual - * @category algebraic operations - * @since 1.0.0 - */ -export const sumBigint: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} = lift2(BI.sum) - -/** - * @dual - * @category algebraic operations - * @since 1.0.0 - */ -export const multiplyBigint: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} = lift2(BI.multiply) - -/** - * @dual - * @category algebraic operations - * @since 1.0.0 - */ -export const subtractBigint: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} = lift2(BI.subtract) - // ------------------------------------------------------------------------------------- // do notation // ------------------------------------------------------------------------------------- diff --git a/src/Option.ts b/src/Option.ts index c31cb08bf..84b1f6fad 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1,7 +1,6 @@ /** * @since 1.0.0 */ -import * as BI from "@fp-ts/core/Bigint" import type { Either } from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" import { constNull, constUndefined, dual, pipe } from "@fp-ts/core/Function" @@ -535,59 +534,6 @@ export const getOrNull: (self: Option) => A | null = getOrElse(constNull) */ export const getOrUndefined: (self: Option) => A | undefined = getOrElse(constUndefined) -/** - * This is `flatMap` + `fromNullable`, useful when working with optional values. - * - * @example - * import { some, none, flatMapNullable } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' - * - * interface Employee { - * company?: { - * address?: { - * street?: { - * name?: string - * } - * } - * } - * } - * - * const employee1: Employee = { company: { address: { street: { name: 'high street' } } } } - * - * assert.deepStrictEqual( - * pipe( - * some(employee1), - * flatMapNullable(employee => employee.company?.address?.street?.name), - * ), - * some('high street') - * ) - * - * const employee2: Employee = { company: { address: { street: {} } } } - * - * assert.deepStrictEqual( - * pipe( - * some(employee2), - * flatMapNullable(employee => employee.company?.address?.street?.name), - * ), - * none() - * ) - * - * @dual - * @category sequencing - * @since 1.0.0 - */ -export const flatMapNullable: { - (self: Option, f: (a: A) => B | null | undefined): Option> - (f: (a: A) => B | null | undefined): (self: Option) => Option> -} = dual< - (self: Option, f: (a: A) => B | null | undefined) => Option>, - (f: (a: A) => B | null | undefined) => (self: Option) => Option> ->( - 2, - (self: Option, f: (a: A) => B | null | undefined): Option> => - isNone(self) ? none() : fromNullable(f(self.value)) -) - /** * A utility function that lifts a function that throws exceptions into a function that returns an `Option`. * @@ -642,7 +588,7 @@ export const getOrThrow = (self: Option): A => { } // ------------------------------------------------------------------------------------- -// instances +// mapping // ------------------------------------------------------------------------------------- /** @@ -669,23 +615,24 @@ export const map: { const imap = covariant.imap(map) /** - * @category instances + * @category mapping * @since 1.0.0 */ -export const Covariant: covariant.Covariant = { - imap, - map +export const Invariant: invariant.Invariant = { + imap } /** - * @category instances + * @category mapping * @since 1.0.0 */ -export const Invariant: invariant.Invariant = { - imap +export const Covariant: covariant.Covariant = { + imap, + map } /** + * @category mapping * @since 1.0.0 */ export const tupled: (self: Option) => Option<[A]> = invariant.tupled(Invariant) @@ -723,7 +670,6 @@ export const as: { export const asUnit: <_>(self: Option<_>) => Option = covariant.asUnit(Covariant) /** - * @category instances * @since 1.0.0 */ export const Of: of_.Of = { @@ -736,7 +682,6 @@ export const Of: of_.Of = { export const unit: Option = of_.unit(Of) /** - * @category instances * @since 1.0.0 */ export const Pointed: pointed.Pointed = { @@ -745,6 +690,10 @@ export const Pointed: pointed.Pointed = { map } +// ------------------------------------------------------------------------------------- +// sequencing +// ------------------------------------------------------------------------------------- + /** * Applies a function to the value of an `Option` and flattens the result, if the input is `Some`. * @@ -765,7 +714,92 @@ export const flatMap: { ) /** - * @category instances + * Applies a provided function that returns an `Either` to the contents of an `Option`, flattening the result into another `Option`. + * + * @param self - The `Option` to apply the function to. + * @param f - The function to be applied to the contents of the `Option`. + * + * @example + * import * as O from '@fp-ts/core/Option' + * import * as E from '@fp-ts/core/Either' + * import { pipe } from '@fp-ts/core/Function' + * + * const f = (n: number) => (n > 2 ? E.left('Too big') : E.right(n + 1)) + * + * assert.deepStrictEqual(pipe(O.some(1), O.flatMapEither(f)), O.some(2)) + * assert.deepStrictEqual(pipe(O.some(3), O.flatMapEither(f)), O.none()) + * + * @dual + * @category sequencing + * @since 1.0.0 + */ +export const flatMapEither: { + (self: Option, f: (a: A) => Either): Option + (f: (a: A) => Either): (self: Option) => Option +} = dual< + (self: Option, f: (a: A) => Either) => Option, + (f: (a: A) => Either) => (self: Option) => Option +>( + 2, + (self: Option, f: (a: A) => Either): Option => + pipe(self, flatMap(liftEither(f))) +) + +/** + * This is `flatMap` + `fromNullable`, useful when working with optional values. + * + * @example + * import { some, none, flatMapNullable } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * interface Employee { + * company?: { + * address?: { + * street?: { + * name?: string + * } + * } + * } + * } + * + * const employee1: Employee = { company: { address: { street: { name: 'high street' } } } } + * + * assert.deepStrictEqual( + * pipe( + * some(employee1), + * flatMapNullable(employee => employee.company?.address?.street?.name), + * ), + * some('high street') + * ) + * + * const employee2: Employee = { company: { address: { street: {} } } } + * + * assert.deepStrictEqual( + * pipe( + * some(employee2), + * flatMapNullable(employee => employee.company?.address?.street?.name), + * ), + * none() + * ) + * + * @dual + * @category sequencing + * @since 1.0.0 + */ +export const flatMapNullable: { + (self: Option, f: (a: A) => B | null | undefined): Option> + (f: (a: A) => B | null | undefined): (self: Option) => Option> +} = dual< + (self: Option, f: (a: A) => B | null | undefined) => Option>, + (f: (a: A) => B | null | undefined) => (self: Option) => Option> +>( + 2, + (self: Option, f: (a: A) => B | null | undefined): Option> => + isNone(self) ? none() : fromNullable(f(self.value)) +) + +/** + * @category sequencing * @since 1.0.0 */ export const FlatMap: flatMap_.FlatMap = { @@ -773,6 +807,7 @@ export const FlatMap: flatMap_.FlatMap = { } /** + * @category sequencing * @since 1.0.0 */ export const flatten: (self: Option>) => Option = flatMap_ @@ -780,6 +815,7 @@ export const flatten: (self: Option>) => Option = flatMap_ /** * @dual + * @category sequencing * @since 1.0.0 */ export const andThen: { @@ -789,6 +825,7 @@ export const andThen: { /** * @dual + * @category sequencing * @since 1.0.0 */ export const composeKleisliArrow: { @@ -797,7 +834,7 @@ export const composeKleisliArrow: { } = flatMap_.composeKleisliArrow(FlatMap) /** - * @category instances + * @category sequencing * @since 1.0.0 */ export const Chainable: chainable.Chainable = { @@ -833,7 +870,7 @@ export const andThenDiscard: { * @param self - The `Option` to apply the function to * * @dual - * @category combinators + * @category sequencing * @since 1.0.0 */ export const tap: { @@ -1023,6 +1060,10 @@ export const getOptionalMonoid = ( none() ) +// ------------------------------------------------------------------------------------- +// combining +// ------------------------------------------------------------------------------------- + /** * Zips two `Option` values together using a provided function, returning a new `Option` of the result. * @@ -1041,6 +1082,7 @@ export const zipWith: { /** * @dual + * @category combining * @since 1.0.0 */ export const ap: { @@ -1055,7 +1097,7 @@ export const ap: { * * See also `getFailureMonoid` if you need a `Monoid` instead of a `Semigroup`. * - * @category instances + * @category combining * @since 1.0.0 */ export const getFailureSemigroup: (S: Semigroup) => Semigroup> = semiApplicative @@ -1083,7 +1125,7 @@ export const Applicative: applicative.Applicative = { * * See also `getFailureSemigroup` if you need a `Semigroup` instead of a `Monoid`. * - * @category instances + * @category combining * @since 1.0.0 */ export const getFailureMonoid: (M: Monoid) => Monoid> = applicative.getMonoid( @@ -1119,7 +1161,7 @@ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { /** * Semigroup returning the first `Some` value encountered. * - * @category instances + * @category combining * @since 1.0.0 */ export const getFirstSomeSemigroup: () => Semigroup> = semiCoproduct @@ -1161,11 +1203,52 @@ export const Alternative: alternative.Alternative = { zero: none } +// ------------------------------------------------------------------------------------- +// folding +// ------------------------------------------------------------------------------------- + +/** + * Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. + * + * @param self - The Iterable of `Option` to be reduced. + * @param b - The initial value of the accumulator. + * @param f - The reducing function that takes the current accumulator value and the unwrapped value of an `Option`. + * + * @example + * import { some, none, reduceCompact } from '@fp-ts/core/Option' + * import { pipe } from '@fp-ts/core/Function' + * + * const iterable = [some(1), none(), some(2), none()] + * assert.deepStrictEqual(pipe(iterable, reduceCompact(0, (b, a) => b + a)), 3) + * + * @dual + * @category folding + * @since 1.0.0 + */ +export const reduceCompact: { + (self: Iterable>, b: B, f: (b: B, a: A) => B): B + (b: B, f: (b: B, a: A) => B): (self: Iterable>) => B +} = dual< + (self: Iterable>, b: B, f: (b: B, a: A) => B) => B, + (b: B, f: (b: B, a: A) => B) => (self: Iterable>) => B +>( + 3, + (self: Iterable>, b: B, f: (b: B, a: A) => B): B => { + let out: B = b + for (const oa of self) { + if (isSome(oa)) { + out = f(out, oa.value) + } + } + return out + } +) + const reduce = (b: B, f: (b: B, a: A) => B) => (self: Option): B => isNone(self) ? b : f(b, self.value) /** - * @category instances + * @category folding * @since 1.0.0 */ export const Foldable: foldable.Foldable = { @@ -1185,10 +1268,15 @@ export const Foldable: foldable.Foldable = { * assert.deepStrictEqual(toArray(some(1)), [1]) * assert.deepStrictEqual(toArray(none()), []) * + * @category folding * @since 1.0.0 */ export const toArray: (self: Option) => Array = foldable.toArray(Foldable) +// ------------------------------------------------------------------------------------- +// filtering +// ------------------------------------------------------------------------------------- + /** * @category instances * @since 1.0.0 @@ -1204,10 +1292,6 @@ export const Compactable: compactable.Compactable = { export const separate: (self: Option>) => [Option, Option] = compactable .separate({ ...Covariant, ...Compactable }) -// ------------------------------------------------------------------------------------- -// filtering -// ------------------------------------------------------------------------------------- - /** * Maps over the value of an `Option` and filters out `None`s. * @@ -1442,42 +1526,6 @@ export const liftEither = , E, B>( f: (...a: A) => Either ) => (...a: A): Option => fromEither(f(...a)) -// ------------------------------------------------------------------------------------- -// sequencing -// ------------------------------------------------------------------------------------- - -/** - * Applies a provided function that returns an `Either` to the contents of an `Option`, flattening the result into another `Option`. - * - * @param self - The `Option` to apply the function to. - * @param f - The function to be applied to the contents of the `Option`. - * - * @example - * import * as O from '@fp-ts/core/Option' - * import * as E from '@fp-ts/core/Either' - * import { pipe } from '@fp-ts/core/Function' - * - * const f = (n: number) => (n > 2 ? E.left('Too big') : E.right(n + 1)) - * - * assert.deepStrictEqual(pipe(O.some(1), O.flatMapEither(f)), O.some(2)) - * assert.deepStrictEqual(pipe(O.some(3), O.flatMapEither(f)), O.none()) - * - * @dual - * @category sequencing - * @since 1.0.0 - */ -export const flatMapEither: { - (self: Option, f: (a: A) => Either): Option - (f: (a: A) => Either): (self: Option) => Option -} = dual< - (self: Option, f: (a: A) => Either) => Option, - (f: (a: A) => Either) => (self: Option) => Option ->( - 2, - (self: Option, f: (a: A) => Either): Option => - pipe(self, flatMap(liftEither(f))) -) - // ------------------------------------------------------------------------------------- // utils // ------------------------------------------------------------------------------------- @@ -1541,43 +1589,6 @@ export const exists: { isNone(self) ? false : predicate(self.value) ) -/** - * Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. - * - * @param self - The Iterable of `Option` to be reduced. - * @param b - The initial value of the accumulator. - * @param f - The reducing function that takes the current accumulator value and the unwrapped value of an `Option`. - * - * @example - * import { some, none, reduceCompact } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' - * - * const iterable = [some(1), none(), some(2), none()] - * assert.deepStrictEqual(pipe(iterable, reduceCompact(0, (b, a) => b + a)), 3) - * - * @dual - * @category folding - * @since 1.0.0 - */ -export const reduceCompact: { - (self: Iterable>, b: B, f: (b: B, a: A) => B): B - (b: B, f: (b: B, a: A) => B): (self: Iterable>) => B -} = dual< - (self: Iterable>, b: B, f: (b: B, a: A) => B) => B, - (b: B, f: (b: B, a: A) => B) => (self: Iterable>) => B ->( - 3, - (self: Iterable>, b: B, f: (b: B, a: A) => B): B => { - let out: B = b - for (const oa of self) { - if (isSome(oa)) { - out = f(out, oa.value) - } - } - return out - } -) - // ------------------------------------------------------------------------------------- // algebraic operations // ------------------------------------------------------------------------------------- @@ -1622,36 +1633,6 @@ export const divide: { (that: Option): (self: Option) => Option } = lift2(N.divide) -/** - * @dual - * @category algebraic operations - * @since 1.0.0 - */ -export const sumBigint: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} = lift2(BI.sum) - -/** - * @dual - * @category algebraic operations - * @since 1.0.0 - */ -export const multiplyBigint: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} = lift2(BI.multiply) - -/** - * @dual - * @category algebraic operations - * @since 1.0.0 - */ -export const subtractBigint: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} = lift2(BI.subtract) - /** * Sum all numbers in an iterable of `Option` ignoring the `None` values. * diff --git a/src/These.ts b/src/These.ts index ca5892cd6..ee93534d8 100644 --- a/src/These.ts +++ b/src/These.ts @@ -2,7 +2,6 @@ * @since 1.0.0 */ -import * as BI from "@fp-ts/core/Bigint" import type { Either, Left, Right } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" @@ -1289,33 +1288,6 @@ export const divide: { (that: Validated): (self: Validated) => Validated } = lift2(N.divide) -/** - * @category algebraic operations - * @since 1.0.0 - */ -export const sumBigint: { - (self: Validated, that: Validated): Validated - (that: Validated): (self: Validated) => Validated -} = lift2(BI.sum) - -/** - * @category algebraic operations - * @since 1.0.0 - */ -export const multiplyBigint: { - (self: Validated, that: Validated): Validated - (that: Validated): (self: Validated) => Validated -} = lift2(BI.multiply) - -/** - * @category algebraic operations - * @since 1.0.0 - */ -export const subtractBigint: { - (self: Validated, that: Validated): Validated - (that: Validated): (self: Validated) => Validated -} = lift2(BI.subtract) - // ------------------------------------------------------------------------------------- // do notation // ------------------------------------------------------------------------------------- diff --git a/test/Either.ts b/test/Either.ts index a0076c53b..a48a4642f 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -489,24 +489,6 @@ describe.concurrent("Either", () => { expect(pipe(_.right(6), _.divide(_.right(3)))).toEqual(_.right(2)) }) - it("sumBigint", () => { - expect(pipe(_.left("a"), _.sumBigint(_.right(2n)))).toEqual(_.left("a")) - expect(pipe(_.right(1n), _.sumBigint(_.left("a")))).toEqual(_.left("a")) - expect(pipe(_.right(2n), _.sumBigint(_.right(3n)))).toEqual(_.right(5n)) - }) - - it("multiplyBigint", () => { - expect(pipe(_.left("a"), _.multiplyBigint(_.right(2n)))).toEqual(_.left("a")) - expect(pipe(_.right(1n), _.multiplyBigint(_.left("a")))).toEqual(_.left("a")) - expect(pipe(_.right(2n), _.multiplyBigint(_.right(3n)))).toEqual(_.right(6n)) - }) - - it("subtractBigint", () => { - expect(pipe(_.left("a"), _.subtractBigint(_.right(2n)))).toEqual(_.left("a")) - expect(pipe(_.right(1n), _.subtractBigint(_.left("a")))).toEqual(_.left("a")) - expect(pipe(_.right(2n), _.subtractBigint(_.right(3n)))).toEqual(_.right(-1n)) - }) - it("getOptionalSemigroup", () => { const OS = _.getOptionalSemigroup(S.Semigroup) Util.deepStrictEqual(OS.combine(_.left("e"), _.left("e")), _.left("e")) diff --git a/test/Option.ts b/test/Option.ts index 203fcbc7d..1a16a6b67 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -577,24 +577,6 @@ describe.concurrent("Option", () => { expect(pipe(_.some(6), _.divide(_.some(3)))).toEqual(_.some(2)) }) - it("sumBigint", () => { - expect(pipe(_.none(), _.sumBigint(_.some(2n)))).toEqual(_.none()) - expect(pipe(_.some(1n), _.sumBigint(_.none()))).toEqual(_.none()) - expect(pipe(_.some(2n), _.sumBigint(_.some(3n)))).toEqual(_.some(5n)) - }) - - it("multiplyBigint", () => { - expect(pipe(_.none(), _.multiplyBigint(_.some(2n)))).toEqual(_.none()) - expect(pipe(_.some(1n), _.multiplyBigint(_.none()))).toEqual(_.none()) - expect(pipe(_.some(2n), _.multiplyBigint(_.some(3n)))).toEqual(_.some(6n)) - }) - - it("subtractBigint", () => { - expect(pipe(_.none(), _.subtractBigint(_.some(2n)))).toEqual(_.none()) - expect(pipe(_.some(1n), _.subtractBigint(_.none()))).toEqual(_.none()) - expect(pipe(_.some(2n), _.subtractBigint(_.some(3n)))).toEqual(_.some(-1n)) - }) - it("reduce", () => { expect(pipe(_.none(), _.Foldable.reduce(0, (b, a) => b + a))).toEqual(0) expect(pipe(_.some(1), _.Foldable.reduce(0, (b, a) => b + a))).toEqual(1) diff --git a/test/These.ts b/test/These.ts index 7e98e2827..20b9aab12 100644 --- a/test/These.ts +++ b/test/These.ts @@ -760,27 +760,6 @@ describe("These", () => { expect(pipe(_.right(6), _.divide(_.right(3)))).toEqual(_.right(2)) }) - it("sumBigint", () => { - const e: _.Validated = _.left(["a"]) - expect(pipe(e, _.sumBigint(_.right(2n)))).toEqual(e) - expect(pipe(_.right(1n), _.sumBigint(e))).toEqual(e) - expect(pipe(_.right(2n), _.sumBigint(_.right(3n)))).toEqual(_.right(5n)) - }) - - it("multiplyBigint", () => { - const e: _.Validated = _.left(["a"]) - expect(pipe(e, _.multiplyBigint(_.right(2n)))).toEqual(e) - expect(pipe(_.right(1n), _.multiplyBigint(e))).toEqual(e) - expect(pipe(_.right(2n), _.multiplyBigint(_.right(3n)))).toEqual(_.right(6n)) - }) - - it("subtractBigint", () => { - const e: _.Validated = _.left(["a"]) - expect(pipe(e, _.subtractBigint(_.right(2n)))).toEqual(e) - expect(pipe(_.right(1n), _.subtractBigint(e))).toEqual(e) - expect(pipe(_.right(2n), _.subtractBigint(_.right(3n)))).toEqual(_.right(-1n)) - }) - it("getEquivalence", () => { const isEquivalent = _.getEquivalence(N.Equivalence, N.Equivalence) Util.deepStrictEqual(isEquivalent(_.left(2), _.left(2)), true) From bd2ef3c897e246068ba96c5f0c9d25e96c1830a2 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 1 Feb 2023 18:44:38 +0100 Subject: [PATCH 149/255] For now the guide on Option should be sufficient --- guides/Option.md | 116 +++++++++++++++++++++++++++++++++++------------ src/Option.ts | 4 +- 2 files changed, 88 insertions(+), 32 deletions(-) diff --git a/guides/Option.md b/guides/Option.md index f46a3c686..23f8b9a44 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -382,18 +382,37 @@ getOrElse(some(5), () => 0); // 5 getOrElse(none(), () => 0); // 0 ``` +It often happens that the action you want to take when a computation returns `None` is to continue with another computation that returns an `Option`, in this case you can use the `orElse` API: + +```ts +import * as O from "@fp-ts/core/Option"; +import { pipe } from "@fp-ts/core/Function"; + +const fetchData = (): O.Option => { + // Imagine we have a function that returns an `Option` of data + return Math.random() < 0.5 ? O.some("Data fetched successfully") : O.none(); +}; + +const retryFetchData = (): O.Option => + pipe( + fetchData(), // Call the function for the first time + O.orElse(() => fetchData()) // If it fails, call it again + ); + +const result = retryFetchData(); +``` + **Cheat sheet** (error handling) -| Name | Given | To | -| ---------------- | --------------------------------------------------- | ---------------------- | -| `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | -| `getOrThrow` | `Option` | `A` | -| `getOrNull` | `Option` | `A \| null` | -| `getOrUndefined` | `Option` | `A \| undefined` | -| `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | -| `orElse` | `Option`, `LazyArg>` | `Option` | -| `orElseEither` | `Option`, `LazyArg>` | `Option>` | -| `firstSomeOf` | `Iterable>` | `Option` | +| Name | Given | To | +| ---------------- | --------------------------------------------------- | ---------------- | +| `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | +| `getOrThrow` | `Option` | `A` | +| `getOrNull` | `Option` | `A \| null` | +| `getOrUndefined` | `Option` | `A \| undefined` | +| `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | +| `orElse` | `Option`, `LazyArg>` | `Option` | +| `firstSomeOf` | `Iterable>` | `Option` | # Interop @@ -507,30 +526,67 @@ console.log(pipe(none(), getOrThrow); // throws new Error("getOrThrow called on # Combining two or more `Option`s +The `zipWith` function allows you to combine two or more `Option` values using a provided function. The resulting value is a new `Option` that holds the combined value of both original `Option`s. + +Let's consider the following example where we have two `Option`s that hold values of two different types, `string` and `number`: + +```ts +import * as O from "@fp-ts/core/Option"; + +const name: O.Option = O.some("John"); +const age: O.Option = O.some(25); +``` + +If we want to combine these two `Option`s into a single `Option` that holds an object with properties `name` and `age`, we can use the `zipWith` function: + +```ts +const combine = O.zipWith(name, age, (n, a) => ({ name: n, age: a })); +console.log(combine); // Some({ name: 'John', age: 25 }) +``` + +The `zipWith` function takes three arguments: the two `Option`s that you want to combine, and a function that takes two arguments - the values held by the two `Option`s - and returns the combined value. + +If either of the two `Option`s is `None`, the resulting `Option` will be `None` as well: + +```ts +const name: O.Option = O.none; +const age: O.Option = O.some(25); +const combine = O.zipWith(name, age, (n, a) => ({ name: n, age: a })); +console.log(combine); // None +``` + +This is because the `zipWith` function only combines the values if both `Option`s are `Some`. + **Cheat sheet** (combining) -| Name | Given | To | -| ----------------------- | --------------------------------------- | ---------------------- | -| `zipWith` | `Option`, `Option`, `(A, B) => C` | `C` | -| `ap` | `Option<(a: A) => B>`, `Option` | `Option` | -| `getFailureSemigroup` | `Semigroup` | `Semigroup>` | -| `getFailureMonoid` | `Monoid` | `Monoid>` | -| `getFirstSomeSemigroup` | | `Semigroup>` | +| Name | Given | To | +| --------- | --------------------------------------- | ----------- | +| `zipWith` | `Option`, `Option`, `(A, B) => C` | `Option` | +| `ap` | `Option<(a: A) => B>`, `Option` | `Option` | -**Cheat sheet** (folding) +For convenience, a series of algebraic operations such as sums and products are exported. + +```ts +import * as O from "@fp-ts/core/Option"; -| Name | Given | To | -| --------------- | ----------------------------------------- | ---------- | -| `reduceCompact` | `Iterable>`, `B`, `(B, A) => B` | `B` | -| `toArray` | `Option` | `Array` | +const num1 = O.some(3); +const num2 = O.some(4); +const num3 = O.none; + +// Summing two `Some` values will result in a `Some` with the sum of the values +const sumOfSome = O.sum(num1, num2); +console.log(sumOfSome); // Output: Some(7) + +// Summing a `Some` and a `None` will result in a `None` +const sumOfSomeAndNone = O.sum(num1, num3); +console.log(sumOfSomeAndNone); // Output: None +``` **Cheat sheet** (algebraic operations) -| Name | Given | To | -| ----------------- | ---------------------------------- | ---------------- | -| `sum` | `Option`, `Option` | `Option` | -| `multiply` | `Option`, `Option` | `Option` | -| `subtract` | `Option`, `Option` | `Option` | -| `divide` | `Option`, `Option` | `Option` | -| `sumCompact` | `Iterable>` | `number` | -| `multiplyCompact` | `Iterable>` | `number` | +| Name | Given | To | +| ---------- | ---------------------------------- | ---------------- | +| `sum` | `Option`, `Option` | `Option` | +| `multiply` | `Option`, `Option` | `Option` | +| `subtract` | `Option`, `Option` | `Option` | +| `divide` | `Option`, `Option` | `Option` | diff --git a/src/Option.ts b/src/Option.ts index 84b1f6fad..169f813e0 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1067,8 +1067,8 @@ export const getOptionalMonoid = ( /** * Zips two `Option` values together using a provided function, returning a new `Option` of the result. * - * @param fa - The left-hand side of the zip operation - * @param fb - The right-hand side of the zip operation + * @param self - The left-hand side of the zip operation + * @param that - The right-hand side of the zip operation * @param f - The function used to combine the values of the two `Option`s * * @dual From c7ef8dd0db5b0b8d21f58247a2afc954033d57b9 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 07:39:58 +0100 Subject: [PATCH 150/255] Either: add toArray --- docs/modules/Either.ts.md | 35 ++++++++++++++++++++-------- docs/modules/Option.ts.md | 48 +++++++++++++++++++-------------------- guides/Either.md | 36 +++++++++++++++++++++-------- guides/Option.md | 31 +++++++++++++++---------- src/Either.ts | 25 ++++++++++++++++---- src/Option.ts | 2 +- test/Either.ts | 5 ++++ 7 files changed, 123 insertions(+), 59 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 7f55ad86f..e3a82a10f 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -33,6 +33,7 @@ Added in v1.0.0 - [fromOption](#fromoption) - [getLeft](#getleft) - [getRight](#getright) + - [toArray](#toarray) - [toOption](#tooption) - [toRefinement](#torefinement) - [debugging](#debugging) @@ -339,21 +340,14 @@ export declare const fromOption: { ```ts import * as E from '@fp-ts/core/Either' -import { pipe } from '@fp-ts/core/Function' import * as O from '@fp-ts/core/Option' assert.deepStrictEqual( - pipe( - O.some(1), - E.fromOption(() => 'error') - ), + E.fromOption(O.some(1), () => 'error'), E.right(1) ) assert.deepStrictEqual( - pipe( - O.none(), - E.fromOption(() => 'error') - ), + E.fromOption(O.none(), () => 'error'), E.left('error') ) ``` @@ -406,6 +400,29 @@ assert.deepStrictEqual(E.getRight(E.left('err')), O.none()) Added in v1.0.0 +## toArray + +Transforms an `Either` into an `Array`. +If the input is `Left`, an empty array is returned. +If the input is `Right`, the value is wrapped in an array. + +**Signature** + +```ts +export declare const toArray: (self: Either) => A[] +``` + +**Example** + +```ts +import { right, left, toArray } from '@fp-ts/core/Either' + +assert.deepStrictEqual(toArray(right(1)), [1]) +assert.deepStrictEqual(toArray(left('error')), []) +``` + +Added in v1.0.0 + ## toOption Converts a `Either` to an `Option` discarding the error. diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 8fb4ad7aa..5a85477ad 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -34,6 +34,7 @@ Added in v1.0.0 - [fromIterable](#fromiterable) - [getLeft](#getleft) - [getRight](#getright) + - [toArray](#toarray) - [toEither](#toeither) - [toRefinement](#torefinement) - [debugging](#debugging) @@ -59,7 +60,6 @@ Added in v1.0.0 - [folding](#folding) - [Foldable](#foldable) - [reduceCompact](#reducecompact) - - [toArray](#toarray) - [guards](#guards) - [isNone](#isnone) - [isOption](#isoption) @@ -442,6 +442,29 @@ assert.deepStrictEqual(O.getRight(E.left('err')), O.none()) Added in v1.0.0 +## toArray + +Transforms an `Option` into an `Array`. +If the input is `None`, an empty array is returned. +If the input is `Some`, the value is wrapped in an array. + +**Signature** + +```ts +export declare const toArray: (self: Option) => A[] +``` + +**Example** + +```ts +import { some, none, toArray } from '@fp-ts/core/Option' + +assert.deepStrictEqual(toArray(some(1)), [1]) +assert.deepStrictEqual(toArray(none()), []) +``` + +Added in v1.0.0 + ## toEither Converts an `Option` to an `Either`, allowing you to provide a value to be used in the case of a `None`. @@ -814,29 +837,6 @@ assert.deepStrictEqual( Added in v1.0.0 -## toArray - -Transforms an `Option` into an `Array`. -If the input is `None`, an empty array is returned. -If the input is `Some`, the value is wrapped in an array. - -**Signature** - -```ts -export declare const toArray: (self: Option) => A[] -``` - -**Example** - -```ts -import { some, none, toArray } from '@fp-ts/core/Option' - -assert.deepStrictEqual(toArray(some(1)), [1]) -assert.deepStrictEqual(toArray(none()), []) -``` - -Added in v1.0.0 - # guards ## isNone diff --git a/guides/Either.md b/guides/Either.md index 9592b6333..f0a06064d 100644 --- a/guides/Either.md +++ b/guides/Either.md @@ -9,26 +9,42 @@ In this usage, `None` is replaced with a `Left` which can contain useful informa # Definition -The `Either` data type is the union of two members: `Left` and `Right`. The way chosen by the `@fp-ts/core` library to model this union in TypeScript is to use a feature of the language called [Discriminating Unions](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions): +The `Either` data type is the union of two members: `Left` and `Right`. The way chosen by the `@fp-ts/core` library to model this union in TypeScript is to use a feature of the language called [Discriminating Unions](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions). > A common technique for working with unions is to have a single field which uses literal types which you can use to let TypeScript narrow down the possible current type +By convention in `@fp-ts/core`, this single field which uses literal types is named "\_tag" (but you can use any name when defining your unions). + +Furthermore, `Either` is a "polymorphic" data type, that is, it makes use of a feature of TypeScript named ["Generics"](https://www.typescriptlang.org/docs/handbook/2/generics.html), meaning that the `Either` data type is a container that can hold any type. + Here's the complete definition of the `Either` type: ```ts +// Holds the information for a failure case export type Left = { + // Discriminating field used to identify the variant readonly _tag: "Left"; + // The actual error readonly left: E; }; +// Holds the result of a successful computation export type Right = { + // Discriminating field used to identify the variant readonly _tag: "Right"; + // The actual value readonly right: A; }; export type Either = Left | Right; ``` +The `Either` data type is defined as a union of two other types, `Left` and `Right`, that represent the two possible outcomes of a computation: a failure or a success. + +The type parameters `E` and `A` are used to specify the type of the failure value and the success value that the `Either` holds respectively. + +The `_tag` field is used to distinguish between the two variants, `Left` and `Right`. + # Using `Either` To create an instance of `Either`, you can use the `right` and `left` constructors, which construct a new `Either` holding a `Right` or `Left` value respectively. @@ -40,6 +56,8 @@ const success: Either = right(1); const failure: Either = left("error message"); ``` +Let's summarize the two cases in a table: + **Cheat sheet** (constructors) | Name | Given | To | @@ -52,32 +70,32 @@ const failure: Either = left("error message"); You can also use the `fromOption` function to convert an `Option` to an `Either`. ```ts -import { pipe } from "@fp-ts/core/Function"; import { fromOption } from "@fp-ts/core/Either"; import { none, some } from "@fp-ts/core/Option"; -const success: Either = pipe( +const success: Either = fromOption( some(1), - fromOption("error message") + () => "error message" ); -const failure: Either = pipe( +const failure: Either = fromOption( none(), - fromOption("error message") + () => "error message" ); ``` -The `fromOption` function requires an argument because it needs to know what value to use for the `Left` variant of the `Either` type when given a `None`. In the example, the argument "error message" is used as the value for the `Left` variant when `None` is encountered. This allows `Either` to provide more information about why a failure occurred. +The `fromOption` function requires a second argument because it needs to know what value to use for the `Left` variant of the `Either` type when given a `None`. In the example, the argument "error message" is used as the value for the `Left` variant when `None` is encountered. This allows `Either` to provide more information about why a failure occurred. **Cheat sheet** (conversions) | Name | Given | To | Note | | -------------- | ------------------------------------ | ------------------ | ------------------- | -| `toRefinement` | `A => Either` | `Refinement` | | -| `fromIterable` | `Iterable`, `onEmpty: LazyArg` | `Either` | | | `fromOption` | `Option`, `onNone: LazyArg` | `Either` | | | `toOption` | `Either` | `Option` | | | `getRight` | `Either` | `Option` | alias of `toOption` | | `getLeft` | `Either` | `Option` | | +| `toRefinement` | `A => Either` | `Refinement` | | +| `fromIterable` | `Iterable`, `onEmpty: LazyArg` | `Either` | | +| `toArray` | `Either` | `Array` | | # Working with `Either` diff --git a/guides/Option.md b/guides/Option.md index 23f8b9a44..49ea14887 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -17,34 +17,40 @@ In the second of these two interpretations, the `None` union member represents t # Definition -The `Option` data type is the union of two members: `None` and `Some`. The way chosen by the `@fp-ts/core` library to model this union in TypeScript is to use a feature of the language called [Discriminating Unions](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions): +The `Option` data type is the union of two members: `None` and `Some`. The way chosen by the `@fp-ts/core` library to model this union in TypeScript is to use a feature of the language called [Discriminating Unions](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions). > A common technique for working with unions is to have a single field which uses literal types which you can use to let TypeScript narrow down the possible current type By convention in `@fp-ts/core`, this single field which uses literal types is named "\_tag" (but you can use any name when defining your unions). -Furthermore, the data type `Option` is a "polymorphic" data type, that is, it makes use of a feature of TypeScript named ["Generics"](https://www.typescriptlang.org/docs/handbook/2/generics.html), meaning that the `Option` data type is a container that can hold any type. +Furthermore, `Option` is a "polymorphic" data type, that is, it makes use of a feature of TypeScript named ["Generics"](https://www.typescriptlang.org/docs/handbook/2/generics.html), meaning that the `Option` data type is a container that can hold any type. Here's the complete definition of the `Option` type: ```ts +// Represents the absence of a value export type None = { - readonly _tag: "None"; // represents the absence of a value + // Discriminating field used to identify the variant + readonly _tag: "None"; }; +// Represents the presence of a value export type Some = { - readonly _tag: "Some"; // represents the presence of a value - readonly value: A; // the actual value + // Discriminating field used to identify the variant + readonly _tag: "Some"; + // The actual value + readonly value: A; }; -export type Option = None | Some; // union type representing the option of having a value or not +// Define the `Option` data type as the union of `None` and `Some` +export type Option = None | Some; ``` -The `Option` type is defined as a union of two other types, `None` and `Some`, that represent the two possible states of the option: having a value or not. +The `Option` type is defined as a union of two other types, `None` and `Some`, that represent the two possible states of the `Option`: having a value or not. -The type parameter `A` is used to specify the type of the value that the option holds. +The type parameter `A` is used to specify the type of the value that the `Option` holds. -The `_tag` field is used to distinguish between the two options, "None" and "Some". +The `_tag` field is used to distinguish between the two variants, `None` and `Some`. # Using `Option` @@ -90,12 +96,13 @@ In this way you don't need to specify the type of the variables `optionNumber`, | Name | Given | To | Note | | -------------- | --------------------------------- | ------------------ | --------------------- | -| `toRefinement` | `A => Option` | `Refinement` | | -| `fromIterable` | `Iterable` | `Option` | | | `fromEither` | `Either` | `Option` | | +| `toEither` | `Option`, `onNone: LazyArg` | `Either` | | | `getRight` | `Either` | `Option` | alias of `fromEither` | | `getLeft` | `Either` | `Option` | | -| `toEither` | `Option`, `onNone: LazyArg` | `Either` | | +| `toRefinement` | `A => Option` | `Refinement` | | +| `fromIterable` | `Iterable` | `Option` | | +| `toArray` | `Option` | `Array` | | # Modeling optional properties with `Option` diff --git a/src/Either.ts b/src/Either.ts index 2982743f0..268975527 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -17,7 +17,7 @@ import * as chainable from "@fp-ts/core/typeclass/Chainable" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" -import type * as foldable from "@fp-ts/core/typeclass/Foldable" +import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" @@ -207,11 +207,10 @@ export const getLeft: (self: Either) => Option = either.getLeft /** * @example * import * as E from '@fp-ts/core/Either' - * import { pipe } from '@fp-ts/core/Function' * import * as O from '@fp-ts/core/Option' * - * assert.deepStrictEqual(pipe(O.some(1), E.fromOption(() => 'error')), E.right(1)) - * assert.deepStrictEqual(pipe(O.none(), E.fromOption(() => 'error')), E.left('error')) + * assert.deepStrictEqual(E.fromOption(O.some(1), () => 'error'), E.right(1)) + * assert.deepStrictEqual(E.fromOption(O.none(), () => 'error'), E.left('error')) * * @category conversions * @since 1.0.0 @@ -775,6 +774,24 @@ export const Foldable: foldable.Foldable = { reduce } +/** + * Transforms an `Either` into an `Array`. + * If the input is `Left`, an empty array is returned. + * If the input is `Right`, the value is wrapped in an array. + * + * @param self - The `Either` to convert to an array. + * + * @example + * import { right, left, toArray } from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(toArray(right(1)), [1]) + * assert.deepStrictEqual(toArray(left("error")), []) + * + * @category conversions + * @since 1.0.0 + */ +export const toArray: (self: Either) => Array = foldable.toArray(Foldable) + /** * Takes two functions and an `Either` value, if the value is a `Left` the inner value is applied to the first function, * if the value is a `Right` the inner value is applied to the second function. diff --git a/src/Option.ts b/src/Option.ts index 169f813e0..75a3f9cfb 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1268,7 +1268,7 @@ export const Foldable: foldable.Foldable = { * assert.deepStrictEqual(toArray(some(1)), [1]) * assert.deepStrictEqual(toArray(none()), []) * - * @category folding + * @category conversions * @since 1.0.0 */ export const toArray: (self: Option) => Array = foldable.toArray(Foldable) diff --git a/test/Either.ts b/test/Either.ts index a48a4642f..a7cd8a83b 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -511,4 +511,9 @@ describe.concurrent("Either", () => { Util.deepStrictEqual(isEquivalent(_.left("foo"), _.left("bar")), false) Util.deepStrictEqual(isEquivalent(_.left("foo"), _.right(1)), false) }) + + it("toArray", () => { + expect(_.toArray(_.right(1))).toEqual([1]) + expect(_.toArray(_.left("error"))).toEqual([]) + }) }) From beb6d51bc04cb435f11911b1c5b525c286aaee69 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 08:22:40 +0100 Subject: [PATCH 151/255] Bicovariant: apply dual --- docs/modules/Either.ts.md | 20 ++++++--- docs/modules/Option.ts.md | 2 +- docs/modules/These.ts.md | 23 ++++++---- docs/modules/typeclass/Bicovariant.ts.md | 10 ++++- src/Either.ts | 49 +++++++++++++++----- src/Option.ts | 2 +- src/These.ts | 57 +++++++++++++++--------- src/typeclass/Bicovariant.ts | 31 ++++++++----- 8 files changed, 131 insertions(+), 63 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index e3a82a10f..c6a0b9668 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -569,13 +569,15 @@ Added in v1.0.0 ## mapLeft -Returns an effect with its error channel mapped using the specified -function. This can be used to lift a "smaller" error into a "larger" error. +Maps the `Left` side of an `Either` value to a new `Either` value. **Signature** ```ts -export declare const mapLeft: (f: (e: E) => G) => (self: Either) => Either +export declare const mapLeft: { + (self: Either, f: (e: E) => G): Either + (f: (e: E) => G): (self: Either) => Either +} ``` Added in v1.0.0 @@ -1130,7 +1132,10 @@ the specified pair of functions, `f` and `g`. **Signature** ```ts -export declare const bimap: (f: (e: E) => G, g: (a: A) => B) => (self: Either) => Either +export declare const bimap: { + (self: Either, f: (e: E) => G, g: (a: A) => B): Either + (f: (e: E) => G, g: (a: A) => B): (self: Either) => Either +} ``` Added in v1.0.0 @@ -1150,12 +1155,15 @@ Added in v1.0.0 ## map -Returns an effect whose Right is mapped by the specified `f` function. +Maps the `Right` side of an `Either` value to a new `Either` value. **Signature** ```ts -export declare const map: (f: (a: A) => B) => (self: Either) => Either +export declare const map: { + (self: Either, f: (a: A) => B): Either + (f: (a: A) => B): (self: Either) => Either +} ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 5a85477ad..6e847115d 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -1333,7 +1333,7 @@ Added in v1.0.0 ## map -Maps the given function to the value of the `Option` if it is a `Some`, otherwise it returns `None`. +Maps the `Some` side of an `Option` value to a new `Option` value. **Signature** diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 83f68b0cb..d2f9ccacb 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -642,13 +642,15 @@ Added in v1.0.0 ## mapLeft -Returns an effect with its error channel mapped using the specified -function. This can be used to lift a "smaller" error into a "larger" error. +Maps the `Left` side of an `These` value to a new `These` value. **Signature** ```ts -export declare const mapLeft: (f: (e: E) => G) => (self: These) => These +export declare const mapLeft: { + (self: These, f: (e: E) => G): These + (f: (e: E) => G): (self: These) => These +} ``` Added in v1.0.0 @@ -1224,13 +1226,13 @@ Added in v1.0.0 ## bimap -Returns an effect whose left and right channels have been mapped by -the specified pair of functions, `f` and `g`. - **Signature** ```ts -export declare const bimap: (f: (e: E) => G, g: (a: A) => B) => (self: These) => These +export declare const bimap: { + (self: These, f: (e: E) => G, g: (a: A) => B): These + (f: (e: E) => G, g: (a: A) => B): (self: These) => These +} ``` Added in v1.0.0 @@ -1250,12 +1252,15 @@ Added in v1.0.0 ## map -Returns an effect whose right is mapped by the specified `f` function. +Maps the `Right` side of an `These` value to a new `These` value. **Signature** ```ts -export declare const map: (f: (a: A) => B) => (self: These) => These +export declare const map: { + (self: These, f: (a: A) => B): These + (f: (a: A) => B): (self: These) => These +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Bicovariant.ts.md b/docs/modules/typeclass/Bicovariant.ts.md index d0b8bb4e2..71705fde8 100644 --- a/docs/modules/typeclass/Bicovariant.ts.md +++ b/docs/modules/typeclass/Bicovariant.ts.md @@ -69,7 +69,10 @@ Returns a default `map` implementation. ```ts export declare const map: ( F: Bicovariant -) => (f: (a: A) => B) => (self: Kind) => Kind +) => { + (self: Kind, f: (a: A) => B): Kind + (f: (a: A) => B): (self: Kind) => Kind +} ``` Added in v1.0.0 @@ -81,7 +84,10 @@ Added in v1.0.0 ```ts export declare const mapLeft: ( F: Bicovariant -) => (f: (e: E1) => E2) => (self: Kind) => Kind +) => { + (self: Kind, f: (e: E) => G): Kind + (f: (e: E) => G): (self: Kind) => Kind +} ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index 268975527..3b3dd7a59 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -239,13 +239,26 @@ export const getEquivalence = ( isRight(y) && EA(x.right, y.right)) /** - * Returns an effect whose Right is mapped by the specified `f` function. + * Maps the `Right` side of an `Either` value to a new `Either` value. * + * @param self - An `Either` to map + * @param f - The function to map over the value of the `Either` + * + * @dual * @category mapping * @since 1.0.0 */ -export const map = (f: (a: A) => B) => - (self: Either): Either => isRight(self) ? right(f(self.right)) : self +export const map: { + (self: Either, f: (a: A) => B): Either + (f: (a: A) => B): (self: Either) => Either +} = dual< + (self: Either, f: (a: A) => B) => Either, + (f: (a: A) => B) => (self: Either) => Either +>( + 2, + (self: Either, f: (a: A) => B): Either => + isRight(self) ? right(f(self.right)) : self +) const imap = covariant.imap(map) @@ -310,13 +323,21 @@ export const asUnit: (self: Either) => Either = covariant.a * Returns an effect whose Left and Right channels have been mapped by * the specified pair of functions, `f` and `g`. * + * @dual * @category mapping * @since 1.0.0 */ -export const bimap = ( - f: (e: E) => G, - g: (a: A) => B -) => (self: Either): Either => isLeft(self) ? left(f(self.left)) : right(g(self.right)) +export const bimap: { + (self: Either, f: (e: E) => G, g: (a: A) => B): Either + (f: (e: E) => G, g: (a: A) => B): (self: Either) => Either +} = dual< + (self: Either, f: (e: E) => G, g: (a: A) => B) => Either, + (f: (e: E) => G, g: (a: A) => B) => (self: Either) => Either +>( + 3, + (self: Either, f: (e: E) => G, g: (a: A) => B): Either => + isLeft(self) ? left(f(self.left)) : right(g(self.right)) +) /** * @category instances @@ -327,15 +348,19 @@ export const Bicovariant: bicovariant.Bicovariant = { } /** - * Returns an effect with its error channel mapped using the specified - * function. This can be used to lift a "smaller" error into a "larger" error. + * Maps the `Left` side of an `Either` value to a new `Either` value. + * + * @param self - The input `Either` value to map. + * @param f - A transformation function to apply to the `Left` value of the input `Either`. * + * @dual * @category error handling * @since 1.0.0 */ -export const mapLeft: (f: (e: E) => G) => (self: Either) => Either = - bicovariant - .mapLeft(Bicovariant) +export const mapLeft: { + (self: Either, f: (e: E) => G): Either + (f: (e: E) => G): (self: Either) => Either +} = bicovariant.mapLeft(Bicovariant) /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index 75a3f9cfb..cae18e157 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -592,7 +592,7 @@ export const getOrThrow = (self: Option): A => { // ------------------------------------------------------------------------------------- /** - * Maps the given function to the value of the `Option` if it is a `Some`, otherwise it returns `None`. + * Maps the `Some` side of an `Option` value to a new `Option` value. * * @param self - An `Option` to map * @param f - The function to map over the value of the `Option` diff --git a/src/These.ts b/src/These.ts index ee93534d8..9aed9a4fa 100644 --- a/src/These.ts +++ b/src/These.ts @@ -5,7 +5,7 @@ import type { Either, Left, Right } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" -import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" +import { constNull, constUndefined, dual, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { proto, structural } from "@fp-ts/core/internal/effect" import * as N from "@fp-ts/core/Number" @@ -549,22 +549,25 @@ export const inspectBoth = ( } /** - * Returns an effect whose left and right channels have been mapped by - * the specified pair of functions, `f` and `g`. - * + * @dual * @category mapping * @since 1.0.0 */ -export const bimap: ( - f: (e: E) => G, - g: (a: A) => B -) => (self: These) => These = (f, g) => - (fa) => - isLeft(fa) ? - left(f(fa.left)) : - isRight(fa) ? - right(g(fa.right)) : - both(f(fa.left), g(fa.right)) +export const bimap: { + (self: These, f: (e: E) => G, g: (a: A) => B): These + (f: (e: E) => G, g: (a: A) => B): (self: These) => These +} = dual< + (self: These, f: (e: E) => G, g: (a: A) => B) => These, + (f: (e: E) => G, g: (a: A) => B) => (self: These) => These +>( + 3, + (self: These, f: (e: E) => G, g: (a: A) => B): These => + isLeft(self) ? + left(f(self.left)) : + isRight(self) ? + right(g(self.right)) : + both(f(self.left), g(self.right)) +) /** * @category instances @@ -575,14 +578,19 @@ export const Bicovariant: bicovariant.Bicovariant = { } /** - * Returns an effect with its error channel mapped using the specified - * function. This can be used to lift a "smaller" error into a "larger" error. + * Maps the `Left` side of an `These` value to a new `These` value. * + * @param self - The input `These` value to map. + * @param f - A transformation function to apply to the `Left` value of the input `These`. + * + * @dual * @category error handling * @since 1.0.0 */ -export const mapLeft: (f: (e: E) => G) => (self: These) => These = bicovariant - .mapLeft(Bicovariant) +export const mapLeft: { + (self: These, f: (e: E) => G): These + (f: (e: E) => G): (self: These) => These +} = bicovariant.mapLeft(Bicovariant) /** * @category conversions @@ -591,14 +599,19 @@ export const mapLeft: (f: (e: E) => G) => (self: These) => These< export const fromThese: (self: These) => Validated = mapLeft((e) => [e]) /** - * Returns an effect whose right is mapped by the specified `f` function. + * Maps the `Right` side of an `These` value to a new `These` value. + * + * @param self - An `These` to map + * @param f - The function to map over the value of the `These` * + * @dual * @category mapping * @since 1.0.0 */ -export const map: (f: (a: A) => B) => (self: These) => These = bicovariant.map( - Bicovariant -) +export const map: { + (self: These, f: (a: A) => B): These + (f: (a: A) => B): (self: These) => These +} = bicovariant.map(Bicovariant) const imap = covariant.imap(map) diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index dda5d076a..ff274c952 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { identity } from "@fp-ts/core/Function" +import { dual, identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" @@ -37,18 +37,29 @@ export const bimapComposition = ( */ export const mapLeft = ( F: Bicovariant -): (( - f: (e: E1) => E2 -) => (self: Kind) => Kind) => - (f: (e: E) => G): ((self: Kind) => Kind) => - F.bimap(f, identity) +): { + (self: Kind, f: (e: E) => G): Kind + (f: (e: E) => G): (self: Kind) => Kind +} => + dual< + (self: Kind, f: (e: E) => G) => Kind, + (f: (e: E) => G) => (self: Kind) => Kind + >(2, (self: Kind, f: (e: E) => G): Kind => + pipe(self, F.bimap(f, identity))) /** * Returns a default `map` implementation. * * @since 1.0.0 */ -export const map = (F: Bicovariant): Covariant["map"] => - ( - f: (a: A) => B - ): ((self: Kind) => Kind) => F.bimap(identity, f) +export const map = ( + F: Bicovariant +): { + (self: Kind, f: (a: A) => B): Kind + (f: (a: A) => B): (self: Kind) => Kind +} => + dual< + (self: Kind, f: (a: A) => B) => Kind, + (f: (a: A) => B) => (self: Kind) => Kind + >(2, (self: Kind, f: (a: A) => B): Kind => + pipe(self, F.bimap(identity, f))) From d9c551e1c96991873f2454d596ab365a10264e26 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 11:23:42 +0100 Subject: [PATCH 152/255] Either: make fromNullable dual --- docs/modules/Either.ts.md | 5 +- guides/Either.md | 462 ++++++++++++++++++++++++++++++++++---- guides/Option.md | 125 +++++++---- src/Either.ts | 17 +- 4 files changed, 516 insertions(+), 93 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index c6a0b9668..b5e102d8a 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -968,7 +968,10 @@ the provided default as a `Left`. **Signature** ```ts -export declare const fromNullable: (onNullable: LazyArg) => (a: A) => Either> +export declare const fromNullable: { + (a: A, onNullable: (a: A) => E): Either> + (onNullable: (a: A) => E): (a: A) => Either> +} ``` **Example** diff --git a/guides/Either.md b/guides/Either.md index f0a06064d..926de5601 100644 --- a/guides/Either.md +++ b/guides/Either.md @@ -70,7 +70,7 @@ Let's summarize the two cases in a table: You can also use the `fromOption` function to convert an `Option` to an `Either`. ```ts -import { fromOption } from "@fp-ts/core/Either"; +import { Either, fromOption } from "@fp-ts/core/Either"; import { none, some } from "@fp-ts/core/Option"; const success: Either = fromOption( @@ -101,16 +101,40 @@ The `fromOption` function requires a second argument because it needs to know wh Once you have an instance of `Either`, you can use the various functions provided in the `@fp-ts/core/Either` module to work with it. -The `map` and `mapLeft` functions can be used to transform the `Right` and `Left` values respectively. +The `map` function can be used to transform the `Right` values: ```ts import { pipe } from "@fp-ts/core/Function"; -import { left, right, map, mapLeft } from "@fp-ts/core/Either"; +import { Either, right, map } from "@fp-ts/core/Either"; const success: Either = pipe( right(1), map((x) => x + 1) ); // right(2) +``` + +As you can see you can transform the result of your computation without unwrapping and wrapping the underlying value of `Either`. + +What is very convenient about `Either` is how the absence of value (i.e. a `Left`) is handled. See the example below: + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { Either, left, map } from "@fp-ts/core/Either"; + +const failure: Either = pipe( + left("error"), + // tries to map the value inside the `Right`, but it does not exist, resulting in `Left` + map((x) => x + 1) +); +``` + +As you can see, even though we started with a `Left` value, we can still operate on our `Either`. No errors are thrown or shown to the user, unless we do it intentionally. What happens is that when the `Either` is `Left`, the mapping doesn't even happen and the `Left` value representing the failed computation is returned unchanged. + +In case you want to map the value contained in the `Left`, for example to change the type of error you want to express, you can use the `mapLeft` API which acts like `map` but this time on the `Left` part of an `Either`: + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { Either, left, mapLeft } from "@fp-ts/core/Either"; const failure: Either = pipe( left("error message"), @@ -151,6 +175,43 @@ console.log(parseNumber("2")); // right(2) console.log(parseNumber("Not a number")); // left("Cannot parse 'Not a number' as a number") ``` +What happens if we add a call to the `parseNumber` function to a pipeline that already involves an `Either`? + +```ts +const result = pipe( + right("2"), + map((s) => parseNumber(s)), + map((n) => n2) // type-checker error! +); +``` + +There's something wrong, we received an error from the type checker, what happened? + +The problem is that in the second `map` the parameter `n` is of type `Either` and not `number`. + +```ts +const result = pipe( + right("2"), + map((s) => parseNumber(s)), + map((x: Either) => ...) +); +``` + +Fortunately, the fix is simple, when adding a computation that returns an `Either` to our pipeline we should use the `flatMap` function instead of the `map` function: + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { right, flatMap, map } from "@fp-ts/core/Either"; + +const result = pipe( + right("2"), + flatMap((s) => parseNumber(s)), + map((n) => n2) // ok! now `n` has type `number` +); +``` + +Let's summarize the two cases in a table: + **Cheat sheet** (sequencing) | Name | Given | To | @@ -158,69 +219,392 @@ console.log(parseNumber("Not a number")); // left("Cannot parse 'Not a number' a | `map` | `Either`, `A => B` | `Either` | | `flatMap` | `Either`, `E1 => Either` | `Either` | +The `flatMap` function offers the same convenience as the `map` function, which only continues with the computations contained in the pipeline if a `Left` value is **not** encountered: + +**Happy path, starting with a valid input** + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { Either, right, flatMap, map } from "@fp-ts/core/Either"; + +const success: Either = pipe( + right("2"), + flatMap((s) => parseNumber(s)), // parse the input to number + map((x) => x2), // double the parsed number + map((x) => x - 3) // subtract 3 +); // right(1) +``` + +**Error path, starting with an invalid input** + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { Either, right, flatMap, map } from "@fp-ts/core/Either"; + +const failure: Either = pipe( + right("Not a number"), + flatMap((s) => parseNumber(s)), // parse the input to number + map((x) => x2), // This will not be executed because parseNumber will return Left + map((x) => x - 3) // This will not be executed +); // left("Cannot parse 'Not a number' as a number") +``` + +**Error path, starting with None** + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { Either, left, flatMap, map } from "@fp-ts/core/Either"; + +const leftStart: Either = pipe( + left("error message"), + flatMap((s) => parseNumber(s)), // This will not be executed because it starts with Left + map((x) => x2), // This will not be executed + map((x) => x - 3) // This will not be executed +); // left("error message") +``` + +When using this approach, the **desired outcome** is always in clear view while defining your pipeline. This allows you to focus on the expected result, while leaving it to `Either` to handle any potential errors that may arise seamlessly and transparently. + +You can focus on the successful scenario and let `Either` handle the tedious task of managing potential errors at every step of the pipeline, without the need for explicit handling. + # Debugging At any time, it is possible to inspect what is happening in your pipeline using two utility functions: **Cheat sheet** (debugging) -| Name | Given | To | Description | +| Name | Given | To | Note | | -------------- | --------------------------- | -------------- | ------------------------------------- | | `inspectRight` | `Either`, `A => void` | `Either` | callback called if it is a `Right` | | `inspectLeft` | `Either`, `E => void` | `Either` | callback called if it is a `Left` | +Let's see an example where both are in action: + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { + Either, + right, + inspectRight, + flatMap, + inspectLeft, + map, +} from "@fp-ts/core/Option"; + +const failure: Either = pipe( + right("Not a number"), + inspectRight(console.log), + flatMap((s) => parseNumber(s)), + inspectLeft(console.error), + map((x) => x2), + map((x) => x - 3) +); +// "Not a number" +// "Cannot parse 'Not a number' as a number" +``` + +Please note that these two functions should only be used for debugging purposes and it is not recommended to use them for performing side effects or encoding business logic. + # Pattern matching and error handling -The `match` function allows us to match on the `Left` and `Right` cases of an `Either` value and provide different actions for each. +We have seen how easy and convenient it is to build pipelines involving the `Either` data type, leaving it to handle any errors that may occur at any step. However, at some point, you will be interested in manually handling the error to understand the overall result obtained from the pipeline and decide what to do accordingly. -We can use the `match` function to handle the `Either` value returned by `parseNumber` and decide what to do based on whether it's a `Left` or a `Right`. +The fastest way to get the value wrapped in an `Either` is to call the `getOrThrow` function, but be aware that, as the name suggests, an exception will be thrown in case the `Either` you are querying is a `Left`: + +```ts +import { getOrThrow } from "@fp-ts/core/Either"; + +console.log(getOrThrow(right(10)); // 10 +console.log(getOrThrow(left("error message")); // throws new Error("getOrThrow called on a Left") +``` + +A more safe alternative is using the `isRight` and `isLeft` guards: + +```ts +import { right, left, isRight, isLeft } from "@fp-ts/core/Either"; + +const success = some(1); + +// Use the `isRight` function to check if the `success` is an instance of `Right` +if (isRight(success)) { + console.log(`Either has a value: ${success.right}`); +} else { + console.log(`Either is a Left.`); +} +// Either has a value: 1 + +const failure = left("error message"); + +// Use the `isLeft` function to check if the `failure` is an instance of `Left` +if (isLeft(failure)) { + console.log(`Either has error: ${failure.left}`); +} else { + console.log(`Either is a Right.`); +} +// Either has error: error message +``` + +Another alternative is [pattern matching](https://github.com/gvergnaud/ts-pattern#what-is-pattern-matching) on the `Either`. + +The `match` function allows us to match on the `Left` and `Right` cases of an `Either` value and provide different actions for each. ```ts import { pipe } from "@fp-ts/core/Function"; -import { match } from "@fp-ts/core/Either"; - -// parseNumber returns an Either -const result = parseNumber("Not a number"); - -// Using pipe and match to pattern match on the result -const output = pipe( - result, - match( - // If the result is a Left, return an error string - (error) => `Error: ${error}`, - // If the result is a Right, return a string with the number - (n) => `The number is ${n}` - ) +import { right, match } from "@fp-ts/core/Either"; + +const either = right(1); + +/** + * Use the `match` function to conditionally return a string based on whether the `Either` is `Left` or `Right`. + * If the `Either` is `Left`, the `left` will be passed to the first function. + * If the `Either` is `Right`, the `right` will be passed to the second function. + */ +const output = match( + option, + (left) => `Either has error. ${left}`, + (right) => `Either has a value: ${right}` ); -console.log(output); // Output: Error: Cannot parse 'Not a number' as a number +console.log(output); // Either has a value: 1 +``` + +One reason to use `match` instead of `isRight` or `isLeft` is that `match` is more expressive and provides a clear way to handle both cases of an `Either`. With `match`, you can directly provide two functions to handle the case of the `Either` being `Left` or `Right`, respectively. On the other hand, with `isRight` or `isLeft`, you would need to manually check the value and take separate actions based on whether it's `Right` or `Left`. With `match`, the code can be more concise and easy to understand. Additionally, if you have complex logic to handle both cases, using `match` can make the code easier to read and maintain. + +There are specializations of `match` to make working with code that does not use `Either` more convenient and faster, particularly `getOrNull` and `getOrUndefined`. + +```ts +import { getOrNull, getOrUndefined, right, left } from "@fp-ts/core/Either"; + +getOrNull(right(5)); // 5 +getOrNull(left("error")); // null + +getOrUndefined(right(5)); // 5 +getOrUndefined(left("error")); // undefined +``` + +For greater flexibility, there is also the `getOrElse` function which allows you to set what value corresponds to the `Left` case: + +```ts +import { getOrElse, right, left } from "@fp-ts/core/Either"; + +getOrElse(right(5), () => 0); // 5 +getOrElse(left("error"), () => 0); // 0 +``` + +It often happens that the action you want to take when a computation returns `None` is to continue with another computation that returns an `Option`, in this case you can use the `orElse` API: + +```ts +import { pipe } from "@fp-ts/core/Function"; +import { Either, some, none, orElse } from "@fp-ts/core/Either"; + +const fetchData = (): Either => { + // Imagine we have a function that returns an `Either` of data + return Math.random() < 0.5 + ? right("Data fetched successfully") + : left("Data fetched unsuccessfully"); +}; + +const retryFetchData = (): Either => + pipe( + fetchData(), // Call the function for the first time + orElse(() => fetchData()) // If it fails, call it again + ); + +const result = retryFetchData(); ``` **Cheat sheet** (error handling) -| Name | Given | To | -| ---------------- | --------------------------------------------------- | ---------------- | -| `match` | `Either`, `onLeft: E => B`, `onRight: A => C` | `B \| C` | -| `getOrThrow` | `Either` | `A` | -| `getOrNull` | `Either` | `A \| null` | -| `getOrUndefined` | `Either` | `A \| undefined` | -| `getOrElse` | `Either`, `onLeft: E => B` | `A \| B` | +| Name | Given | To | +| ---------------- | --------------------------------------------------- | -------------------- | +| `match` | `Either`, `onLeft: E => B`, `onRight: A => C` | `B \| C` | +| `getOrThrow` | `Either` | `A` (may throw) | +| `getOrNull` | `Either` | `A \| null` | +| `getOrUndefined` | `Either` | `A \| undefined` | +| `getOrElse` | `Either`, `onLeft: E => B` | `A \| B` | +| `orElse` | `Either`, `LazyArg>` | `Either` | +| `firstRightOf` | `Either`, `Iterable>` | `Either` | # Interop +A need that arises quickly when using the `Either` data type is the ability to interoperate with code that does not share the same style, in particular code that for example uses `undefined` or `null` to indicate that a value is optional, or code that throws exceptions. + +The `Either` data type offers a series of APIs to make this task easier, let's start with the first of the two cases, that is when the need is to interoperate with code that use a nullable type to indicate that a value is optional. + +It is possible to create an `Eitehr` from a nullable value using the `fromNullable` API, let's see an example: + +```ts +import { fromNullable, right, left } from "@fp-ts/core/Either"; + +console.log(fromNullable(null, () => "error")); // left("erro") +console.log(fromNullable(undefined, () => "error")); // left("erro") +console.log(fromNullable(1, () => "error")); // right(1) +``` + +Instead of a single value, we can also modify the definition of a function that returns a nullable value to a function that returns an `Either` (a process that goes by the name of "lifting"): + +```ts +import { liftNullable, left, right } from "@fp-ts/core/Either"; + +const parse = (s: string): number | undefined => { + const n = parseFloat(s); + return isNaN(n) ? undefined : n; +}; + +// const parseEither: (s: string) => Either +const parseEither = liftNullable( + parse, + (s) => `Cannot parse '${s}' as a number` +); + +console.log(parseEither("1")); // right(1) +console.log(parseEither("not a number")); // left("Cannot parse 'not a number' as a number") +``` + +On the other hand, if we have a value of type `Either` and we want to convert it into a nullable value we have two possibilities: + +- convert `Left` to `null` +- convert `Left` to `undefined` + +The two APIs `getOrNull` and `getOrUndefined` respectively achieve these two tasks: + +```ts +import { getOrNull, getOrUndefined, right, left } from "@fp-ts/core/Either"; + +console.log(getOrNull(right(1))); // 1 +console.log(getOrNull(left("error message"))); // null + +console.log(getOrUndefined(right(1))); // 1 +console.log(getOrUndefined(left("error message"))); // undefined +``` + **Cheat sheet** (interop - nullable) -| Name | Given | To | -| ----------------- | ----------------------------------------------------- | ------------------------------------ | -| `fromNullable` | `A` | `Option>` | -| `liftNullable` | `(...a: A) => B \| null \| undefined` | `(...a: A) => Option` | -| `flatMapNullable` | `Either`, `(...a: A) => B \| null \| undefined` | `Option>` | -| `getOrNull` | `Either` | `A \| null` | -| `getOrUndefined` | `Either` | `A \| undefined` | +| Name | Given | To | +| ----------------- | ----------------------------------------------------------------- | --------------------------------------- | +| `fromNullable` | `A`, `A => E` | `Either>` | +| `liftNullable` | `(...a: A) => B \| null \| undefined`, `(...a: A) => E` | `(...a: A) => Either` | +| `flatMapNullable` | `Either`, `(...a: A) => B \| null \| undefined`, `A => E2` | `Either>` | +| `getOrNull` | `Either` | `A \| null` | +| `getOrUndefined` | `Either` | `A \| undefined` | + +Now let's see the other case, that is when we need to interoperate with code that throws exceptions. + +In a previous section, we saw how to convert the following function that can throw exceptions: + +```ts +function parseNumber(s: string): number { + const n = parseFloat(s); + if (isNaN(n)) { + throw new Error(`Cannot parse '${s}' as a number`); + } + return n; +} +``` + +into a function that returns a `Option`: + +```ts +import { Either, left, right } from "@fp-ts/core/Either"; + +function parseNumber(s: string): Either { + const n = parseFloat(s); + return isNaN(n) ? left(`Cannot parse '${s}' as a number`) : right(n); +} +``` + +However, this involves tedious, error-prone, and boilerplate-heavy work. It would be much more convenient not to have to rewrite the `parseNumber` function from scratch but only to transform it into the desired result in one step, and that's exactly what the `fromThrowable` API takes care of doing: + +```ts +import { liftThrowable } from "@fp-ts/core/Either"; + +const parse = liftThrowable(JSON.parse, () => "parse error"); + +console.log(parse("1")); // right(1) +console.log(parse("")); // left("parse error") +``` + +On the other hand, if we have a value of type `Option` and want to get the wrapped value, accepting the fact that if the `Option` is a `None` we will get an exception, we can use the `getOrThrow` API: + +```ts +import { getOrThrow, right, left } from "@fp-ts/core/Either"; + +console.log(getOrThrow(right(10)); // 10 +console.log(getOrThrow(left("error message")); // throws new Error("getOrThrow called on a Left") +``` **Cheat sheet** (interop - throwing) -| Name | Given | To | -| --------------- | ---------------------------- | ------------------------ | -| `liftThrowable` | `(...a: A) => B` (may throw) | `(...a: A) => Option` | -| `getOrThrow` | `Either` | `A` | +| Name | Given | To | +| --------------- | -------------------------------------------- | --------------------------- | +| `liftThrowable` | `(...a: A) => B` (may throw), `unknown => E` | `(...a: A) => Either` | +| `getOrThrow` | `Either` | `A` (may throw) | + +# Combining two or more `Either`s + +The `zipWith` function allows you to combine two `Either`s using a provided function. The resulting value is a new `Either` that holds the combined value of both original `Either`s. + +Let's consider the following example where we have two `Either`s that hold values of two different types, `string` and `number`: + +```ts +import { Either, right } from "@fp-ts/core/Either"; + +const name: Either = right("John"); +const age: Either = right(25); +``` + +If we want to combine these two `Either`s into a single `Either` that holds an object with properties `name` and `age`, we can use the `zipWith` function: + +```ts +import { zipWith } from "@fp-ts/core/Either"; + +const combine = zipWith(name, age, (n, a) => ({ name: n, age: a })); +console.log(combine); // right({ name: 'John', age: 25 }) +``` + +The `zipWith` function takes three arguments: the two `Either`s that you want to combine, and a function that takes two arguments - the values held by the two `Either`s - and returns the combined value. + +If either of the two `Either`s is `Left`, the resulting `Either` will be `Left` as well: + +```ts +const name: Either = left("missing name"); +const age: Either = right(25); +const combine = zipWith(name, age, (n, a) => ({ name: n, age: a })); +console.log(combine); // left("missing name") +``` + +This is because the `zipWith` function only combines the values if both `Either`s are `Right`. + +**Cheat sheet** (combining) + +| Name | Given | To | +| --------- | ----------------------------------------------- | --------------------- | +| `zipWith` | `Either`, `Either`, `(A, B) => C` | `Either` | +| `ap` | `Either B>`, `Either` | `Either` | + +For convenience, a series of algebraic operations such as sums and products are exported. + +```ts +import { right, left, sum } from "@fp-ts/core/Either"; + +const num1 = right(3); +const num2 = right(4); +const num3 = left("not a number"); + +// Summing two `Right` values will result in a `Right` with the sum of the values +const sumOfRight = sum(num1, num2); +console.log(sumOfRight); // right(7) + +// Summing a `Right` and a `Left` will result in a `Left` +const sumOfRightAndLeft = sum(num1, num3); +console.log(sumOfRightAndLeft); // left("not a number") +``` + +**Cheat sheet** (algebraic operations) + +| Name | Given | To | +| ---------- | ------------------------------------------ | -------------------------- | +| `sum` | `Either`, `Either` | `Either` | +| `multiply` | `Either`, `Either` | `Either` | +| `subtract` | `Either`, `Either` | `Either` | +| `divide` | `Either`, `Either` | `Either` | diff --git a/guides/Option.md b/guides/Option.md index 49ea14887..c682320b1 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -144,9 +144,8 @@ The `map` function can be used to transform the `Some` values: ```ts import { pipe } from "@fp-ts/core/Function"; -import { some, map } from "@fp-ts/core/Option"; +import { Opiton, some, map } from "@fp-ts/core/Option"; -// create a value of type Option with the value of 1 const success: Option = pipe( some(1), // maps the value inside the Option, adding 1, resulting in some(2) @@ -156,12 +155,15 @@ const success: Option = pipe( As you can see you can transform the result of your computation without unwrapping and wrapping the underlying value of `Option`. -What is very convenient about `Option` is how the absence of value is handled (i.e. a `None`). See the example below: +What is very convenient about `Option` is how the absence of value (i.e. a `None`) is handled. See the example below: ```ts +import { pipe } from "@fp-ts/core/Function"; +import { Option, none, map } from "@fp-ts/core/Option"; + const failure: Option = pipe( none(), - // tries to map the value inside the none, but it does not exist, resulting in none() + // tries to map the value inside the `Some`, but it does not exist, resulting in `None` map((x) => x + 1) ); ``` @@ -204,6 +206,9 @@ console.log(parseNumber("Not a number")); // none() What happens if we add a call to the `parseNumber` function to a pipeline that already involves an `Option`? ```ts +import { pipe } from "@fp-ts/core/Function"; +import { some, map } from "@fp-ts/core/Option"; + const result = pipe( some("2"), map((s) => parseNumber(s)), @@ -226,7 +231,8 @@ const result = pipe( Fortunately, the fix is simple, when adding a computation that returns an `Option` to our pipeline we should use the `flatMap` function instead of the `map` function: ```ts -import { flatMap } from "@fp-ts/core/Option"; +import { pipe } from "@fp-ts/core/Function"; +import { some, flatMap, map } from "@fp-ts/core/Option"; const result = pipe( some("2"), @@ -249,6 +255,9 @@ The `flatMap` function offers the same convenience as the `map` function, which **Happy path, starting with a valid input** ```ts +import { pipe } from "@fp-ts/core/Function"; +import { Option, some, flatMap, map } from "@fp-ts/core/Option"; + const success: Option = pipe( some("2"), flatMap((s) => parseNumber(s)), // parse the input to number @@ -260,8 +269,11 @@ const success: Option = pipe( **Error path, starting with an invalid input** ```ts +import { pipe } from "@fp-ts/core/Function"; +import { Option, some, flatMap, map } from "@fp-ts/core/Option"; + const failure: Option = pipe( - some("a"), + some("Not a number"), flatMap((s) => parseNumber(s)), // parse the input to number map((x) => x2), // This will not be executed because parseNumber will return None map((x) => x - 3) // This will not be executed @@ -271,6 +283,9 @@ const failure: Option = pipe( **Error path, starting with None** ```ts +import { pipe } from "@fp-ts/core/Function"; +import { Option, none, flatMap, map } from "@fp-ts/core/Option"; + const noneStart: Option = pipe( none, flatMap((s) => parseNumber(s)), // This will not be executed because it starts with None @@ -289,7 +304,7 @@ At any time, it is possible to inspect what is happening in your pipeline using **Cheat sheet** (debugging) -| Name | Given | To | Description | +| Name | Given | To | Note | | ------------- | ------------------------- | ----------- | ------------------------------------ | | `inspectSome` | `Option`, `A => void` | `Option` | callback called if it is a `Some` | | `inspectNone` | `Option`, `() => void` | `Option` | callback called if it is a `None` | @@ -297,17 +312,25 @@ At any time, it is possible to inspect what is happening in your pipeline using Let's see an example where both are in action: ```ts -import { inspectSome, inspectNone } from "@fp-ts/core/Option"; +import { pipe } from "@fp-ts/core/Function"; +import { + Option, + some, + inspectSome, + flatMap, + inspectNone, + map, +} from "@fp-ts/core/Option"; const failure: Option = pipe( - some("a"), + some("Not a number"), inspectSome(console.log), flatMap((s) => parseNumber(s)), inspectNone(() => console.error("none")), map((x) => x2), map((x) => x - 3) ); -// "a" +// "Not a number" // "none" ``` @@ -317,10 +340,10 @@ Please note that these two functions should only be used for debugging purposes We have seen how easy and convenient it is to build pipelines involving the `Option` data type, leaving it to handle any errors that may occur at any step. However, at some point, you will be interested in manually handling the error to understand the overall result obtained from the pipeline and decide what to do accordingly. -The fastest way to get the value wrapped in an option is to call the `getOrThrow` function, but be aware that, as the name suggests, an exception will be thrown in case the `Option` you are querying is a `None`: +The fastest way to get the value wrapped in an `Option` is to call the `getOrThrow` function, but be aware that, as the name suggests, an exception will be thrown in case the `Option` you are querying is a `None`: ```ts -import { getOrThrow } from "@fp-ts/core/Option"; +import { getOrThrow, some, none } from "@fp-ts/core/Option"; console.log(getOrThrow(some(10)); // 10 console.log(getOrThrow(none()); // throws new Error("getOrThrow called on a None") @@ -331,11 +354,11 @@ A more safe alternative is using the `isSome` and `isNone` guards: ```ts import { some, isSome } from "@fp-ts/core/Option"; -const option = some(1); +const success = some(1); -// Use the `isSome` function to check if the `option` is an instance of `Some` -if (isSome(option)) { - console.log(`Option has a value: ${option.value}`); +// Use the `isSome` function to check if the `success` is an instance of `Some` +if (isSome(success)) { + console.log(`Option has a value: ${success.value}`); } else { console.log(`Option is empty.`); } @@ -347,8 +370,8 @@ Another alternative is [pattern matching](https://github.com/gvergnaud/ts-patter The `match` function allows you to match on the `None` and `Some` cases of an `Option` value and provide different actions for each. ```ts -import { some, match } from "@fp-ts/core/Option"; import { pipe } from "@fp-ts/core/Function"; +import { some, match } from "@fp-ts/core/Option"; const option = some(1); @@ -366,12 +389,12 @@ const output = match( console.log(output); // Option has a value: 1 ``` -One reason to use `match` instead of `isSome` is that `match` is more expressive and provides a clear way to handle both cases of an `Option`. With `match`, you can directly provide two functions to handle the case of the `Option` being `None` or `Some`, respectively. On the other hand, with `isSome`, you would need to manually check the value and take separate actions based on whether it's `Some` or `None`. With `match`, the code can be more concise and easy to understand. Additionally, if you have complex logic to handle both cases, using `match` can make the code easier to read and maintain. +One reason to use `match` instead of `isSome` or `isNone` is that `match` is more expressive and provides a clear way to handle both cases of an `Option`. With `match`, you can directly provide two functions to handle the case of the `Option` being `None` or `Some`, respectively. On the other hand, with `isSome`, you would need to manually check the value and take separate actions based on whether it's `Some` or `None`. With `match`, the code can be more concise and easy to understand. Additionally, if you have complex logic to handle both cases, using `match` can make the code easier to read and maintain. There are specializations of `match` to make working with code that does not use `Option` more convenient and faster, particularly `getOrNull` and `getOrUndefined`. ```ts -import { getOrNull, getOrUndefined } from "@fp-ts/core/Option"; +import { getOrNull, getOrUndefined, some, none } from "@fp-ts/core/Option"; getOrNull(some(5)); // 5 getOrNull(none()); // null @@ -383,7 +406,7 @@ getOrUndefined(none()); // undefined For greater flexibility, there is also the `getOrElse` function which allows you to set what value corresponds to the `None` case: ```ts -import { getOrElse } from "@fp-ts/core/Option"; +import { getOrElse, some, none } from "@fp-ts/core/Option"; getOrElse(some(5), () => 0); // 5 getOrElse(none(), () => 0); // 0 @@ -392,18 +415,18 @@ getOrElse(none(), () => 0); // 0 It often happens that the action you want to take when a computation returns `None` is to continue with another computation that returns an `Option`, in this case you can use the `orElse` API: ```ts -import * as O from "@fp-ts/core/Option"; import { pipe } from "@fp-ts/core/Function"; +import { Option, some, none, orElse } from "@fp-ts/core/Option"; -const fetchData = (): O.Option => { +const fetchData = (): Option => { // Imagine we have a function that returns an `Option` of data - return Math.random() < 0.5 ? O.some("Data fetched successfully") : O.none(); + return Math.random() < 0.5 ? some("Data fetched successfully") : none(); }; -const retryFetchData = (): O.Option => +const retryFetchData = (): Option => pipe( fetchData(), // Call the function for the first time - O.orElse(() => fetchData()) // If it fails, call it again + orElse(() => fetchData()) // If it fails, call it again ); const result = retryFetchData(); @@ -414,7 +437,7 @@ const result = retryFetchData(); | Name | Given | To | | ---------------- | --------------------------------------------------- | ---------------- | | `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | -| `getOrThrow` | `Option` | `A` | +| `getOrThrow` | `Option` | `A` (may throw) | | `getOrNull` | `Option` | `A \| null` | | `getOrUndefined` | `Option` | `A \| undefined` | | `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | @@ -498,6 +521,8 @@ function parseNumber(s: string): number { into a function that returns a `Option`: ```ts +import { some, none } from "@fp-ts/core/Option"; + function parseNumber(s: string): Option { const n = parseFloat(s); return isNaN(n) ? none() : some(n); @@ -507,7 +532,7 @@ function parseNumber(s: string): Option { However, this involves tedious, error-prone, and boilerplate-heavy work. It would be much more convenient not to have to rewrite the `parseNumber` function from scratch but only to transform it into the desired result in one step, and that's exactly what the `fromThrowable` API takes care of doing: ```ts -import { liftThrowable, some, none } from "@fp-ts/core/Option"; +import { liftThrowable } from "@fp-ts/core/Option"; const parse = liftThrowable(JSON.parse); @@ -518,10 +543,10 @@ console.log(parse("")); // none() On the other hand, if we have a value of type `Option` and want to get the wrapped value, accepting the fact that if the `Option` is a `None` we will get an exception, we can use the `getOrThrow` API: ```ts -import { getOrThrow } from "@fp-ts/core/Option"; +import { getOrThrow, some, none } from "@fp-ts/core/Option"; -console.log(pipe(some(10), getOrThrow); // 10 -console.log(pipe(none(), getOrThrow); // throws new Error("getOrThrow called on a None") +console.log(getOrThrow(some(10)); // 10 +console.log(getOrThrow(none()); // throws new Error("getOrThrow called on a None") ``` **Cheat sheet** (interop - throwing) @@ -529,26 +554,28 @@ console.log(pipe(none(), getOrThrow); // throws new Error("getOrThrow called on | Name | Given | To | | --------------- | ---------------------------- | ------------------------ | | `liftThrowable` | `(...a: A) => B` (may throw) | `(...a: A) => Option` | -| `getOrThrow` | `Option` | `A` | +| `getOrThrow` | `Option` | `A` (may throw) | # Combining two or more `Option`s -The `zipWith` function allows you to combine two or more `Option` values using a provided function. The resulting value is a new `Option` that holds the combined value of both original `Option`s. +The `zipWith` function allows you to combine two `Option`s using a provided function. The resulting value is a new `Option` that holds the combined value of both original `Option`s. Let's consider the following example where we have two `Option`s that hold values of two different types, `string` and `number`: ```ts -import * as O from "@fp-ts/core/Option"; +import { Option, some } from "@fp-ts/core/Option"; -const name: O.Option = O.some("John"); -const age: O.Option = O.some(25); +const name: Option = some("John"); +const age: Option = some(25); ``` If we want to combine these two `Option`s into a single `Option` that holds an object with properties `name` and `age`, we can use the `zipWith` function: ```ts -const combine = O.zipWith(name, age, (n, a) => ({ name: n, age: a })); -console.log(combine); // Some({ name: 'John', age: 25 }) +import { zipWith } from "@fp-ts/core/Option"; + +const combine = zipWith(name, age, (n, a) => ({ name: n, age: a })); +console.log(combine); // some({ name: 'John', age: 25 }) ``` The `zipWith` function takes three arguments: the two `Option`s that you want to combine, and a function that takes two arguments - the values held by the two `Option`s - and returns the combined value. @@ -556,10 +583,10 @@ The `zipWith` function takes three arguments: the two `Option`s that you want to If either of the two `Option`s is `None`, the resulting `Option` will be `None` as well: ```ts -const name: O.Option = O.none; -const age: O.Option = O.some(25); -const combine = O.zipWith(name, age, (n, a) => ({ name: n, age: a })); -console.log(combine); // None +const name: Option = none(); +const age: Option = some(25); +const combine = zipWith(name, age, (n, a) => ({ name: n, age: a })); +console.log(combine); // none() ``` This is because the `zipWith` function only combines the values if both `Option`s are `Some`. @@ -574,19 +601,19 @@ This is because the `zipWith` function only combines the values if both `Option` For convenience, a series of algebraic operations such as sums and products are exported. ```ts -import * as O from "@fp-ts/core/Option"; +import { some, none, sum } from "@fp-ts/core/Option"; -const num1 = O.some(3); -const num2 = O.some(4); -const num3 = O.none; +const num1 = some(3); +const num2 = some(4); +const num3 = none(); // Summing two `Some` values will result in a `Some` with the sum of the values -const sumOfSome = O.sum(num1, num2); -console.log(sumOfSome); // Output: Some(7) +const sumOfSome = sum(num1, num2); +console.log(sumOfSome); // some(7) // Summing a `Some` and a `None` will result in a `None` -const sumOfSomeAndNone = O.sum(num1, num3); -console.log(sumOfSomeAndNone); // Output: None +const sumOfSomeAndNone = sum(num1, num3); +console.log(sumOfSomeAndNone); // none() ``` **Cheat sheet** (algebraic operations) diff --git a/src/Either.ts b/src/Either.ts index 3b3dd7a59..b2e252466 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -866,12 +866,21 @@ export const match = (onLeft: (e: E) => B, onRight: (a: A) => C) * assert.deepStrictEqual(parse(1), E.right(1)) * assert.deepStrictEqual(parse(null), E.left('nullable')) * + * @dual * @category interop * @since 1.0.0 */ -export const fromNullable = (onNullable: LazyArg) => - (a: A): Either> => - a == null ? left(onNullable()) : right(a as NonNullable) +export const fromNullable: { + (a: A, onNullable: (a: A) => E): Either> + (onNullable: (a: A) => E): (a: A) => Either> +} = dual< + (a: A, onNullable: (a: A) => E) => Either>, + (onNullable: (a: A) => E) => (a: A) => Either> +>( + 2, + (a: A, onNullable: (a: A) => E): Either> => + a == null ? left(onNullable(a)) : right(a as NonNullable) +) /** * @category interop @@ -880,7 +889,7 @@ export const fromNullable = (onNullable: LazyArg) => export const liftNullable = , B, E>( f: (...a: A) => B | null | undefined, onNullable: (...a: A) => E -) => (...a: A): Either> => fromNullable(() => onNullable(...a))(f(...a)) +) => (...a: A): Either> => fromNullable(f(...a), () => onNullable(...a)) /** * @category sequencing From ce7bc289428b2472d2cba51ba28a07096d9b387d Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 15:05:28 +0100 Subject: [PATCH 153/255] switch dual overloads order --- docs/modules/Either.ts.md | 8 +- docs/modules/Function.ts.md | 11 ++- docs/modules/Option.ts.md | 30 +++--- docs/modules/ReadonlyRecord.ts.md | 12 +-- docs/modules/These.ts.md | 2 +- docs/modules/typeclass/Bicovariant.ts.md | 4 +- docs/modules/typeclass/Chainable.ts.md | 38 +++++--- docs/modules/typeclass/Covariant.ts.md | 12 ++- docs/modules/typeclass/Filterable.ts.md | 8 +- docs/modules/typeclass/FlatMap.ts.md | 34 ++++--- docs/modules/typeclass/Order.ts.md | 18 ++-- docs/modules/typeclass/SemiApplicative.ts.md | 91 ++++++++++++------- docs/modules/typeclass/SemiProduct.ts.md | 16 ++-- docs/modules/typeclass/Traversable.ts.md | 6 +- src/Bigint.ts | 16 ++-- src/Either.ts | 24 ++--- src/Function.ts | 12 +-- src/Number.ts | 16 ++-- src/Option.ts | 96 ++++++++++---------- src/ReadonlyRecord.ts | 36 ++++---- src/These.ts | 6 +- src/internal/Either.ts | 4 +- src/typeclass/Bicovariant.ts | 12 +-- src/typeclass/Chainable.ts | 36 ++++++-- src/typeclass/Covariant.ts | 18 ++-- src/typeclass/Filterable.ts | 16 ++-- src/typeclass/FlatMap.ts | 38 ++++++-- src/typeclass/Order.ts | 54 +++++------ src/typeclass/SemiApplicative.ts | 96 ++++++++++++++------ src/typeclass/SemiProduct.ts | 20 +++- src/typeclass/Traversable.ts | 12 +-- test/Function.ts | 4 +- 32 files changed, 470 insertions(+), 336 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index b5e102d8a..cfaf48ab4 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -691,8 +691,8 @@ Returns the wrapped value if it's a `Right` or a default value if is a `Left`. ```ts export declare const getOrElse: { - (self: Either, onLeft: (e: E) => B): A | B (onLeft: (e: E) => B): (self: Either) => B | A + (self: Either, onLeft: (e: E) => B): A | B } ``` @@ -969,8 +969,8 @@ the provided default as a `Left`. ```ts export declare const fromNullable: { - (a: A, onNullable: (a: A) => E): Either> (onNullable: (a: A) => E): (a: A) => Either> + (a: A, onNullable: (a: A) => E): Either> } ``` @@ -1136,8 +1136,8 @@ the specified pair of functions, `f` and `g`. ```ts export declare const bimap: { - (self: Either, f: (e: E) => G, g: (a: A) => B): Either (f: (e: E) => G, g: (a: A) => B): (self: Either) => Either + (self: Either, f: (e: E) => G, g: (a: A) => B): Either } ``` @@ -1164,8 +1164,8 @@ Maps the `Right` side of an `Either` value to a new `Either` value. ```ts export declare const map: { - (self: Either, f: (a: A) => B): Either (f: (a: A) => B): (self: Either) => Either + (self: Either, f: (a: A) => B): Either } ``` diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index f38be7df4..86fc91e97 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -288,10 +288,13 @@ Added in v1.0.0 **Signature** ```ts -export declare const dual: ) => any, P extends (...args: Array) => any>( - dfLen: Parameters['length'], - body: DF -) => DF & P +export declare const dual: < + DataLast extends (...args: Array) => any, + DataFirst extends (...args: Array) => any +>( + dataFirstArity: Parameters['length'], + body: DataFirst +) => DataLast & DataFirst ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 6e847115d..1f4ae767f 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -515,8 +515,8 @@ Useful for debugging purposes, the `onNone` callback is is called if `self` is a ```ts export declare const inspectNone: { - (self: Option, onNone: () => void): Option (onNone: () => void): (self: Option) => Option + (self: Option, onNone: () => void): Option } ``` @@ -530,8 +530,8 @@ Useful for debugging purposes, the `onSome` callback is called with the value of ```ts export declare const inspectSome: { - (self: Option, onSome: (a: A) => void): Option (onSome: (a: A) => void): (self: Option) => Option + (self: Option, onSome: (a: A) => void): Option } ``` @@ -648,8 +648,8 @@ Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` ```ts export declare const getOrElse: { - (self: Option, onNone: LazyArg): A | B (onNone: LazyArg): (self: Option) => B | A + (self: Option, onNone: LazyArg): A | B } ``` @@ -685,8 +685,8 @@ Returns the provided `Option` `that` if `self` is `None`, otherwise returns `sel ```ts export declare const orElse: { - (self: Option, that: LazyArg>): Option (that: LazyArg>): (self: Option) => Option + (self: Option, that: LazyArg>): Option } ``` @@ -739,8 +739,8 @@ This is useful when it's important to know whether the value was retrieved from ```ts export declare const orElseEither: { - (self: Option, that: LazyArg>): Option> (that: LazyArg>): (self: Option) => Option> + (self: Option, that: LazyArg>): Option> } ``` @@ -777,8 +777,8 @@ Useful when in addition to filtering you also want to change the type of the `Op ```ts export declare const filterMap: { - (self: Option, f: (a: A) => Option): Option (f: (a: A) => Option): (self: Option) => Option + (self: Option, f: (a: A) => Option): Option } ``` @@ -814,8 +814,8 @@ Reduces an `Iterable` of `Option` to a single value of type `B`, elements tha ```ts export declare const reduceCompact: { - (self: Iterable>, b: B, f: (b: B, a: A) => B): B (b: B, f: (b: B, a: A) => B): (self: Iterable>) => B + (self: Iterable>, b: B, f: (b: B, a: A) => B): B } ``` @@ -1339,8 +1339,8 @@ Maps the `Some` side of an `Option` value to a new `Option` value. ```ts export declare const map: { - (self: Option, f: (a: A) => B): Option (f: (a: A) => B): (self: Option) => Option + (self: Option, f: (a: A) => B): Option } ``` @@ -1404,8 +1404,8 @@ function when passed the `Option`'s value. ```ts export declare const match: { - (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C (onNone: LazyArg, onSome: (a: A) => C): (self: Option) => B | C + (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C } ``` @@ -1513,8 +1513,8 @@ Applies a function to the value of an `Option` and flattens the result, if the i ```ts export declare const flatMap: { - (self: Option, f: (a: A) => Option): Option (f: (a: A) => Option): (self: Option) => Option + (self: Option, f: (a: A) => Option): Option } ``` @@ -1528,8 +1528,8 @@ Applies a provided function that returns an `Either` to the contents of an `Opti ```ts export declare const flatMapEither: { - (self: Option, f: (a: A) => Either): Option (f: (a: A) => Either): (self: Option) => Option + (self: Option, f: (a: A) => Either): Option } ``` @@ -1556,8 +1556,8 @@ This is `flatMap` + `fromNullable`, useful when working with optional values. ```ts export declare const flatMapNullable: { - (self: Option, f: (a: A) => B | null | undefined): Option> (f: (a: A) => B | null | undefined): (self: Option) => Option> + (self: Option, f: (a: A) => B | null | undefined): Option> } ``` @@ -1683,8 +1683,8 @@ Added in v1.0.0 export declare const traverse: ( F: applicative.Applicative ) => { - (self: Option, f: (a: A) => Kind): Kind> (f: (a: A) => Kind): (self: Option) => Kind> + (self: Option, f: (a: A) => Kind): Kind> } ``` @@ -1764,8 +1764,8 @@ Returns a function that checks if an `Option` contains a given value using a pro ```ts export declare const contains: (equivalence: Equivalence) => { - (self: Option, a: A): boolean (a: A): (self: Option) => boolean + (self: Option, a: A): boolean } ``` @@ -1791,8 +1791,8 @@ Check if a value in an `Option` type meets a certain predicate. ```ts export declare const exists: { - (self: Option, predicate: Predicate): boolean (predicate: Predicate): (self: Option) => boolean + (self: Option, predicate: Predicate): boolean } ``` diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md index 6fa7c630f..1170b6799 100644 --- a/docs/modules/ReadonlyRecord.ts.md +++ b/docs/modules/ReadonlyRecord.ts.md @@ -40,8 +40,8 @@ The projection function maps each value of the iterable to a tuple of a key and ```ts export declare const fromIterable: { - (self: Iterable, f: (a: A) => readonly [string, B]): Record (f: (a: A) => readonly [string, B]): (self: Iterable) => Record + (self: Iterable, f: (a: A) => readonly [string, B]): Record } ``` @@ -70,8 +70,8 @@ Retrieve a value at a particular key from a `ReadonlyRecord`, returning it wrapp ```ts export declare const get: { - (self: ReadonlyRecord, key: string): Option (key: string): (self: ReadonlyRecord) => Option + (self: ReadonlyRecord, key: string): Option } ``` @@ -99,8 +99,8 @@ Maps a `ReadonlyRecord` into another `Record` by applying a transformation funct ```ts export declare const map: { - (self: ReadonlyRecord, f: (a: A) => B): Record (f: (a: A) => B): (self: ReadonlyRecord) => Record + (self: ReadonlyRecord, f: (a: A) => B): Record } ``` @@ -124,8 +124,8 @@ Maps the values of a `ReadonlyRecord` to a new `Record` by applying a transforma ```ts export declare const mapWithKey: { - (self: ReadonlyRecord, f: (k: string, a: A) => B): Record (f: (k: string, a: A) => B): (self: ReadonlyRecord) => Record + (self: ReadonlyRecord, f: (k: string, a: A) => B): Record } ``` @@ -166,8 +166,8 @@ or return `None` if the key doesn't exist. ```ts export declare const modifyOption: { - (self: ReadonlyRecord, key: string, f: (a: A) => B): Option> (key: string, f: (a: A) => B): (self: ReadonlyRecord) => Option> + (self: ReadonlyRecord, key: string, f: (a: A) => B): Option> } ``` @@ -193,8 +193,8 @@ Replaces a value in the record with the new value passed as parameter. ```ts export declare const replaceOption: { - (self: ReadonlyRecord, key: string, b: B): Option> (key: string, b: B): (self: ReadonlyRecord) => Option> + (self: ReadonlyRecord, key: string, b: B): Option> } ``` diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index d2f9ccacb..04f0c295d 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1230,8 +1230,8 @@ Added in v1.0.0 ```ts export declare const bimap: { - (self: These, f: (e: E) => G, g: (a: A) => B): These (f: (e: E) => G, g: (a: A) => B): (self: These) => These + (self: These, f: (e: E) => G, g: (a: A) => B): These } ``` diff --git a/docs/modules/typeclass/Bicovariant.ts.md b/docs/modules/typeclass/Bicovariant.ts.md index 71705fde8..c40f30161 100644 --- a/docs/modules/typeclass/Bicovariant.ts.md +++ b/docs/modules/typeclass/Bicovariant.ts.md @@ -70,8 +70,8 @@ Returns a default `map` implementation. export declare const map: ( F: Bicovariant ) => { - (self: Kind, f: (a: A) => B): Kind (f: (a: A) => B): (self: Kind) => Kind + (self: Kind, f: (a: A) => B): Kind } ``` @@ -85,8 +85,8 @@ Added in v1.0.0 export declare const mapLeft: ( F: Bicovariant ) => { - (self: Kind, f: (e: E) => G): Kind (f: (e: E) => G): (self: Kind) => Kind + (self: Kind, f: (e: E) => G): Kind } ``` diff --git a/docs/modules/typeclass/Chainable.ts.md b/docs/modules/typeclass/Chainable.ts.md index bb2a686fb..aa0ccbf0e 100644 --- a/docs/modules/typeclass/Chainable.ts.md +++ b/docs/modules/typeclass/Chainable.ts.md @@ -34,13 +34,18 @@ produced by the effect. ```ts export declare const andThenDiscard: ( F: Chainable -) => (( - self: Kind, - that: Kind -) => Kind) & - (( - that: Kind - ) => (self: Kind) => Kind) +) => { + (that: Kind): ( + self: Kind + ) => Kind + (self: Kind, that: Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + A + > +} ``` Added in v1.0.0 @@ -85,13 +90,18 @@ Returns an effect that effectfully "peeks" at the success of this effect. ```ts export declare const tap: ( F: Chainable -) => (( - self: Kind, - f: (a: A) => Kind -) => Kind) & - (( - f: (a: A) => Kind - ) => (self: Kind) => Kind) +) => { + (f: (a: A) => Kind): ( + self: Kind + ) => Kind + (self: Kind, f: (a: A) => Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + A + > +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index a3349216f..89a6e1269 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -68,8 +68,10 @@ Added in v1.0.0 ```ts export declare const as: ( F: Covariant -) => ((self: Kind, b: B) => Kind) & - ((b: B) => (self: Kind) => Kind) +) => { + (b: B): (self: Kind) => Kind + (self: Kind, b: B): Kind +} ``` Added in v1.0.0 @@ -93,8 +95,10 @@ Added in v1.0.0 ```ts export declare const flap: ( F: Covariant -) => ((a: A, self: Kind B>) => Kind) & - ((self: Kind B>) => (a: A) => Kind) +) => { + (self: Kind B>): (a: A) => Kind + (a: A, self: Kind B>): Kind +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Filterable.ts.md b/docs/modules/typeclass/Filterable.ts.md index 8a330719b..aa6c448cf 100644 --- a/docs/modules/typeclass/Filterable.ts.md +++ b/docs/modules/typeclass/Filterable.ts.md @@ -48,6 +48,10 @@ Added in v1.0.0 export declare const filter: ( F: Filterable ) => { + (refinement: (a: A) => a is B): ( + self: Kind + ) => Kind + (predicate: (a: A) => boolean): (self: Kind) => Kind (self: Kind, refinement: (a: A) => a is B): Kind< F, R, @@ -56,10 +60,6 @@ export declare const filter: ( B > (self: Kind, predicate: (a: A) => boolean): Kind - (refinement: (a: A) => a is B): ( - self: Kind - ) => Kind - (predicate: (a: A) => boolean): (self: Kind) => Kind } ``` diff --git a/docs/modules/typeclass/FlatMap.ts.md b/docs/modules/typeclass/FlatMap.ts.md index ab8c8695e..bb160ed06 100644 --- a/docs/modules/typeclass/FlatMap.ts.md +++ b/docs/modules/typeclass/FlatMap.ts.md @@ -48,13 +48,18 @@ A variant of `flatMap` that ignores the value produced by this effect. ```ts export declare const andThen: ( F: FlatMap -) => (( - self: Kind, - that: Kind -) => Kind) & - (( - that: Kind - ) => (self: Kind) => Kind) +) => { + (that: Kind): ( + self: Kind + ) => Kind + (self: Kind, that: Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + B + > +} ``` Added in v1.0.0 @@ -66,13 +71,14 @@ Added in v1.0.0 ```ts export declare const composeKleisliArrow: ( F: FlatMap -) => (( - afb: (a: A) => Kind, - bfc: (b: B) => Kind -) => (a: A) => Kind) & - (( - bfc: (b: B) => Kind - ) => (afb: (a: A) => Kind) => (a: A) => Kind) +) => { + (bfc: (b: B) => Kind): ( + afb: (a: A) => Kind + ) => (a: A) => Kind + (afb: (a: A) => Kind, bfc: (b: B) => Kind): ( + a: A + ) => Kind +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index 686f4f9be..9bce7ed7c 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -250,8 +250,8 @@ Test whether a value is between a minimum and a maximum (inclusive). ```ts export declare const between: (O: Order) => { - (a: A, minimum: A, maximum: A): boolean (minimum: A, maximum: A): (a: A) => boolean + (a: A, minimum: A, maximum: A): boolean } ``` @@ -265,8 +265,8 @@ Clamp a value between a minimum and a maximum. ```ts export declare const clamp: (O: Order) => { - (a: A, minimum: A, maximum: A): A (minimum: A, maximum: A): (a: A) => A + (a: A, minimum: A, maximum: A): A } ``` @@ -278,8 +278,8 @@ Added in v1.0.0 ```ts export declare const contramap: { - (self: Order, f: (b: B) => A): Order (f: (b: B) => A): (self: Order) => Order + (self: Order, f: (b: B) => A): Order } ``` @@ -292,7 +292,7 @@ Test whether one value is _strictly greater than_ another. **Signature** ```ts -export declare const greaterThan: (O: Order) => { (self: A, that: A): boolean; (that: A): (self: A) => boolean } +export declare const greaterThan: (O: Order) => { (that: A): (self: A) => boolean; (self: A, that: A): boolean } ``` Added in v1.0.0 @@ -305,8 +305,8 @@ Test whether one value is _non-strictly greater than_ another. ```ts export declare const greaterThanOrEqualTo: (O: Order) => { - (self: A, that: A): boolean (that: A): (self: A) => boolean + (self: A, that: A): boolean } ``` @@ -319,7 +319,7 @@ Test whether one value is _strictly less than_ another. **Signature** ```ts -export declare const lessThan: (O: Order) => { (self: A, that: A): boolean; (that: A): (self: A) => boolean } +export declare const lessThan: (O: Order) => { (that: A): (self: A) => boolean; (self: A, that: A): boolean } ``` Added in v1.0.0 @@ -332,8 +332,8 @@ Test whether one value is _non-strictly less than_ another. ```ts export declare const lessThanOrEqualTo: (O: Order) => { - (self: A, that: A): boolean (that: A): (self: A) => boolean + (self: A, that: A): boolean } ``` @@ -346,7 +346,7 @@ Take the maximum of two values. If they are considered equal, the first argument **Signature** ```ts -export declare const max: (O: Order) => { (self: A, that: A): A; (that: A): (self: A) => A } +export declare const max: (O: Order) => { (that: A): (self: A) => A; (self: A, that: A): A } ``` Added in v1.0.0 @@ -358,7 +358,7 @@ Take the minimum of two values. If they are considered equal, the first argument **Signature** ```ts -export declare const min: (O: Order) => { (self: A, that: A): A; (that: A): (self: A) => A } +export declare const min: (O: Order) => { (that: A): (self: A) => A; (self: A, that: A): A } ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index 6fbbdb5bf..00765a3da 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -52,13 +52,18 @@ export declare const lift2: ( F: SemiApplicative ) => ( f: (a: A, b: B) => C -) => (( - self: Kind, - that: Kind -) => Kind) & - (( - that: Kind - ) => (self: Kind) => Kind) +) => { + (that: Kind): ( + self: Kind + ) => Kind + (self: Kind, that: Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + C + > +} ``` Added in v1.0.0 @@ -84,13 +89,18 @@ Added in v1.0.0 ```ts export declare const andThen: ( F: SemiApplicative -) => (( - self: Kind, - that: Kind -) => Kind) & - (( - that: Kind - ) => (self: Kind) => Kind) +) => { + (that: Kind): ( + self: Kind + ) => Kind + (self: Kind, that: Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + B + > +} ``` Added in v1.0.0 @@ -102,13 +112,18 @@ Added in v1.0.0 ```ts export declare const andThenDiscard: ( F: SemiApplicative -) => (( - self: Kind, - that: Kind -) => Kind) & - (( - that: Kind - ) => (self: Kind) => Kind) +) => { + (that: Kind): ( + self: Kind + ) => Kind + (self: Kind, that: Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + A + > +} ``` Added in v1.0.0 @@ -120,13 +135,18 @@ Added in v1.0.0 ```ts export declare const ap: ( F: SemiApplicative -) => (( - self: Kind B>, - that: Kind -) => Kind) & - (( - that: Kind - ) => (self: Kind B>) => Kind) +) => { + (that: Kind): ( + self: Kind B> + ) => Kind + (self: Kind B>, that: Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + B + > +} ``` Added in v1.0.0 @@ -140,15 +160,16 @@ Zips two `F` values together using a provided function, returning a new `F` of t ```ts export declare const zipWith: ( F: SemiApplicative -) => (( - self: Kind, - that: Kind, - f: (a: A, b: B) => C -) => Kind) & - (( +) => { + (that: Kind, f: (a: A, b: B) => C): ( + self: Kind + ) => Kind + ( + self: Kind, that: Kind, f: (a: A, b: B) => C - ) => (self: Kind) => Kind) + ): Kind +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index dc69b4048..a9e597601 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -99,15 +99,15 @@ Appends an element to the end of a tuple. ```ts export declare const appendElement: ( F: SemiProduct -) => (( - self: Kind, - that: Kind -) => Kind) & - (( - that: Kind - ) => ( +) => { + (that: Kind): ( self: Kind - ) => Kind) + ) => Kind + ( + self: Kind, + that: Kind + ): Kind +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Traversable.ts.md b/docs/modules/typeclass/Traversable.ts.md index d21b93ca5..b5ba632c6 100644 --- a/docs/modules/typeclass/Traversable.ts.md +++ b/docs/modules/typeclass/Traversable.ts.md @@ -125,6 +125,9 @@ export declare const traverseTap: ( ) => ( F: Applicative ) => { + (f: (a: A) => Kind): ( + self: Kind + ) => Kind> (self: Kind, f: (a: A) => Kind): Kind< F, R, @@ -132,9 +135,6 @@ export declare const traverseTap: ( E, Kind > - (f: (a: A) => Kind): ( - self: Kind - ) => Kind> } ``` diff --git a/src/Bigint.ts b/src/Bigint.ts index 12c2de1bd..ea63ec0be 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -28,8 +28,8 @@ export const sum: { (that: bigint): (self: bigint) => bigint (self: bigint, that: bigint): bigint } = dual< - (self: bigint, that: bigint) => bigint, - (that: bigint) => (self: bigint) => bigint + (that: bigint) => (self: bigint) => bigint, + (self: bigint, that: bigint) => bigint >(2, semigroup.bigintSum.combine) /** @@ -41,8 +41,8 @@ export const multiply: { (that: bigint): (self: bigint) => bigint (self: bigint, that: bigint): bigint } = dual< - (self: bigint, that: bigint) => bigint, - (that: bigint) => (self: bigint) => bigint + (that: bigint) => (self: bigint) => bigint, + (self: bigint, that: bigint) => bigint >(2, semigroup.bigintMultiply.combine) /** @@ -54,8 +54,8 @@ export const subtract: { (that: bigint): (self: bigint) => bigint (self: bigint, that: bigint): bigint } = dual< - (self: bigint, that: bigint) => bigint, - (that: bigint) => (self: bigint) => bigint + (that: bigint) => (self: bigint) => bigint, + (self: bigint, that: bigint) => bigint >(2, (self: bigint, that: bigint): bigint => self - that) /** @@ -67,8 +67,8 @@ export const divide: { (that: bigint): (self: bigint) => bigint (self: bigint, that: bigint): bigint } = dual< - (self: bigint, that: bigint) => bigint, - (that: bigint) => (self: bigint) => bigint + (that: bigint) => (self: bigint) => bigint, + (self: bigint, that: bigint) => bigint >(2, (self: bigint, that: bigint): bigint => self / that) /** diff --git a/src/Either.ts b/src/Either.ts index b2e252466..f859391b6 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -249,11 +249,11 @@ export const getEquivalence = ( * @since 1.0.0 */ export const map: { - (self: Either, f: (a: A) => B): Either (f: (a: A) => B): (self: Either) => Either + (self: Either, f: (a: A) => B): Either } = dual< - (self: Either, f: (a: A) => B) => Either, - (f: (a: A) => B) => (self: Either) => Either + (f: (a: A) => B) => (self: Either) => Either, + (self: Either, f: (a: A) => B) => Either >( 2, (self: Either, f: (a: A) => B): Either => @@ -328,11 +328,11 @@ export const asUnit: (self: Either) => Either = covariant.a * @since 1.0.0 */ export const bimap: { - (self: Either, f: (e: E) => G, g: (a: A) => B): Either (f: (e: E) => G, g: (a: A) => B): (self: Either) => Either + (self: Either, f: (e: E) => G, g: (a: A) => B): Either } = dual< - (self: Either, f: (e: E) => G, g: (a: A) => B) => Either, - (f: (e: E) => G, g: (a: A) => B) => (self: Either) => Either + (f: (e: E) => G, g: (a: A) => B) => (self: Either) => Either, + (self: Either, f: (e: E) => G, g: (a: A) => B) => Either >( 3, (self: Either, f: (e: E) => G, g: (a: A) => B): Either => @@ -729,11 +729,11 @@ export const getFirstRightSemigroup: () => Semigroup> = semiC * @since 1.0.0 */ export const getOrElse: { - (self: Either, onLeft: (e: E) => B): A | B (onLeft: (e: E) => B): (self: Either) => B | A + (self: Either, onLeft: (e: E) => B): A | B } = dual< - (self: Either, onLeft: (e: E) => B) => A | B, - (onLeft: (e: E) => B) => (self: Either) => A | B + (onLeft: (e: E) => B) => (self: Either) => A | B, + (self: Either, onLeft: (e: E) => B) => A | B >( 2, (self: Either, onLeft: (e: E) => B): A | B => @@ -871,11 +871,11 @@ export const match = (onLeft: (e: E) => B, onRight: (a: A) => C) * @since 1.0.0 */ export const fromNullable: { - (a: A, onNullable: (a: A) => E): Either> (onNullable: (a: A) => E): (a: A) => Either> + (a: A, onNullable: (a: A) => E): Either> } = dual< - (a: A, onNullable: (a: A) => E) => Either>, - (onNullable: (a: A) => E) => (a: A) => Either> + (onNullable: (a: A) => E) => (a: A) => Either>, + (a: A, onNullable: (a: A) => E) => Either> >( 2, (a: A, onNullable: (a: A) => E): Either> => diff --git a/src/Function.ts b/src/Function.ts index e743651f6..356f7b51f 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -657,15 +657,15 @@ export const SK = (_: A, b: B): B => b * @since 1.0.0 */ export const dual = < - DF extends (...args: Array) => any, - P extends (...args: Array) => any + DataLast extends (...args: Array) => any, + DataFirst extends (...args: Array) => any >( - dfLen: Parameters["length"], - body: DF -): DF & P => { + dataFirstArity: Parameters["length"], + body: DataFirst +): DataLast & DataFirst => { // @ts-expect-error return function() { - if (arguments.length === dfLen) { + if (arguments.length === dataFirstArity) { // @ts-expect-error return body.apply(this, arguments) } diff --git a/src/Number.ts b/src/Number.ts index 7a30af4d7..a91c0177f 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -35,8 +35,8 @@ export const sum: { (that: number): (self: number) => number (self: number, that: number): number } = dual< - (self: number, that: number) => number, - (that: number) => (self: number) => number + (that: number) => (self: number) => number, + (self: number, that: number) => number >(2, semigroup.numberSum.combine) /** @@ -54,8 +54,8 @@ export const multiply: { (that: number): (self: number) => number (self: number, that: number): number } = dual< - (self: number, that: number) => number, - (that: number) => (self: number) => number + (that: number) => (self: number) => number, + (self: number, that: number) => number >(2, semigroup.numberMultiply.combine) /** @@ -73,8 +73,8 @@ export const subtract: { (that: number): (self: number) => number (self: number, that: number): number } = dual< - (self: number, that: number) => number, - (that: number) => (self: number) => number + (that: number) => (self: number) => number, + (self: number, that: number) => number >(2, (self: number, that: number): number => self - that) /** @@ -92,8 +92,8 @@ export const divide: { (that: number): (self: number) => number (self: number, that: number): number } = dual< - (self: number, that: number) => number, - (that: number) => (self: number) => number + (that: number) => (self: number) => number, + (self: number, that: number) => number >(2, (self: number, that: number): number => self / that) /** diff --git a/src/Option.ts b/src/Option.ts index cae18e157..56387c1e5 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -199,11 +199,11 @@ export const isSome: (self: Option) => self is Some = option.isSome * @since 1.0.0 */ export const match: { - (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C (onNone: LazyArg, onSome: (a: A) => C): (self: Option) => B | C + (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C } = dual< - (self: Option, onNone: LazyArg, onSome: (a: A) => C) => B | C, - (onNone: LazyArg, onSome: (a: A) => C) => (self: Option) => B | C + (onNone: LazyArg, onSome: (a: A) => C) => (self: Option) => B | C, + (self: Option, onNone: LazyArg, onSome: (a: A) => C) => B | C >( 3, (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C => @@ -342,11 +342,11 @@ export const toEither: { * @since 1.0.0 */ export const getOrElse: { - (self: Option, onNone: LazyArg): A | B (onNone: LazyArg): (self: Option) => B | A + (self: Option, onNone: LazyArg): A | B } = dual< - (self: Option, onNone: LazyArg) => A | B, - (onNone: LazyArg) => (self: Option) => A | B + (onNone: LazyArg) => (self: Option) => A | B, + (self: Option, onNone: LazyArg) => A | B >( 2, (self: Option, onNone: LazyArg): A | B => isNone(self) ? onNone() : self.value @@ -396,11 +396,11 @@ export const getOrElse: { * @since 1.0.0 */ export const orElse: { - (self: Option, that: LazyArg>): Option (that: LazyArg>): (self: Option) => Option + (self: Option, that: LazyArg>): Option } = dual< - (self: Option, that: LazyArg>) => Option, - (that: LazyArg>) => (self: Option) => Option + (that: LazyArg>) => (self: Option) => Option, + (self: Option, that: LazyArg>) => Option >( 2, (self: Option, that: LazyArg>): Option => isNone(self) ? that() : self @@ -420,13 +420,11 @@ export const orElse: { * @since 1.0.0 */ export const orElseEither: { - (self: Option, that: LazyArg>): Option> (that: LazyArg>): (self: Option) => Option> + (self: Option, that: LazyArg>): Option> } = dual< - (self: Option, that: LazyArg>) => Option>, - ( - that: LazyArg> - ) => (self: Option) => Option> + (that: LazyArg>) => (self: Option) => Option>, + (self: Option, that: LazyArg>) => Option> >( 2, (self: Option, that: LazyArg>): Option> => @@ -602,11 +600,11 @@ export const getOrThrow = (self: Option): A => { * @since 1.0.0 */ export const map: { - (self: Option, f: (a: A) => B): Option (f: (a: A) => B): (self: Option) => Option + (self: Option, f: (a: A) => B): Option } = dual< - (self: Option, f: (a: A) => B) => Option, - (f: (a: A) => B) => (self: Option) => Option + (f: (a: A) => B) => (self: Option) => Option, + (self: Option, f: (a: A) => B) => Option >( 2, (self: Option, f: (a: A) => B): Option => isNone(self) ? none() : some(f(self.value)) @@ -702,11 +700,11 @@ export const Pointed: pointed.Pointed = { * @since 1.0.0 */ export const flatMap: { - (self: Option, f: (a: A) => Option): Option (f: (a: A) => Option): (self: Option) => Option + (self: Option, f: (a: A) => Option): Option } = dual< - (self: Option, f: (a: A) => Option) => Option, - (f: (a: A) => Option) => (self: Option) => Option + (f: (a: A) => Option) => (self: Option) => Option, + (self: Option, f: (a: A) => Option) => Option >( 2, (self: Option, f: (a: A) => Option): Option => @@ -734,11 +732,11 @@ export const flatMap: { * @since 1.0.0 */ export const flatMapEither: { - (self: Option, f: (a: A) => Either): Option (f: (a: A) => Either): (self: Option) => Option + (self: Option, f: (a: A) => Either): Option } = dual< - (self: Option, f: (a: A) => Either) => Option, - (f: (a: A) => Either) => (self: Option) => Option + (f: (a: A) => Either) => (self: Option) => Option, + (self: Option, f: (a: A) => Either) => Option >( 2, (self: Option, f: (a: A) => Either): Option => @@ -787,11 +785,11 @@ export const flatMapEither: { * @since 1.0.0 */ export const flatMapNullable: { - (self: Option, f: (a: A) => B | null | undefined): Option> (f: (a: A) => B | null | undefined): (self: Option) => Option> + (self: Option, f: (a: A) => B | null | undefined): Option> } = dual< - (self: Option, f: (a: A) => B | null | undefined) => Option>, - (f: (a: A) => B | null | undefined) => (self: Option) => Option> + (f: (a: A) => B | null | undefined) => (self: Option) => Option>, + (self: Option, f: (a: A) => B | null | undefined) => Option> >( 2, (self: Option, f: (a: A) => B | null | undefined): Option> => @@ -893,13 +891,11 @@ export const tap: { * @since 1.0.0 */ export const inspectSome: { - (self: Option, onSome: (a: A) => void): Option (onSome: (a: A) => void): (self: Option) => Option + (self: Option, onSome: (a: A) => void): Option } = dual< - (self: Option, onSome: (a: A) => void) => Option, - ( - onSome: (a: A) => void - ) => (self: Option) => Option + (onSome: (a: A) => void) => (self: Option) => Option, + (self: Option, onSome: (a: A) => void) => Option >(2, (self: Option, onSome: (a: A) => void): Option => { if (isSome(self)) { onSome(self.value) @@ -918,11 +914,11 @@ export const inspectSome: { * @since 1.0.0 */ export const inspectNone: { - (self: Option, onNone: () => void): Option (onNone: () => void): (self: Option) => Option + (self: Option, onNone: () => void): Option } = dual< - (self: Option, onNone: () => void) => Option, - (onNone: () => void) => (self: Option) => Option + (onNone: () => void) => (self: Option) => Option, + (self: Option, onNone: () => void) => Option >(2, (self: Option, onNone: () => void): Option => { if (isNone(self)) { onNone() @@ -1226,11 +1222,11 @@ export const Alternative: alternative.Alternative = { * @since 1.0.0 */ export const reduceCompact: { - (self: Iterable>, b: B, f: (b: B, a: A) => B): B (b: B, f: (b: B, a: A) => B): (self: Iterable>) => B + (self: Iterable>, b: B, f: (b: B, a: A) => B): B } = dual< - (self: Iterable>, b: B, f: (b: B, a: A) => B) => B, - (b: B, f: (b: B, a: A) => B) => (self: Iterable>) => B + (b: B, f: (b: B, a: A) => B) => (self: Iterable>) => B, + (self: Iterable>, b: B, f: (b: B, a: A) => B) => B >( 3, (self: Iterable>, b: B, f: (b: B, a: A) => B): B => { @@ -1305,11 +1301,11 @@ export const separate: (self: Option>) => [Option, Option< * @since 1.0.0 */ export const filterMap: { - (self: Option, f: (a: A) => Option): Option (f: (a: A) => Option): (self: Option) => Option + (self: Option, f: (a: A) => Option): Option } = dual< - (self: Option, f: (a: A) => Option) => Option, - (f: (a: A) => Option) => (self: Option) => Option + (f: (a: A) => Option) => (self: Option) => Option, + (self: Option, f: (a: A) => Option) => Option >( 2, (self: Option, f: (a: A) => Option): Option => @@ -1354,19 +1350,19 @@ export const filter: { export const traverse = ( F: applicative.Applicative ): { - (self: Option, f: (a: A) => Kind): Kind> ( f: (a: A) => Kind ): (self: Option) => Kind> + (self: Option, f: (a: A) => Kind): Kind> } => dual< ( - self: Option, f: (a: A) => Kind - ) => Kind>, + ) => (self: Option) => Kind>, ( + self: Option, f: (a: A) => Kind - ) => (self: Option) => Kind> + ) => Kind> >( 2, ( @@ -1550,12 +1546,12 @@ export const liftEither = , E, B>( * @since 1.0.0 */ export const contains = (equivalence: Equivalence): { - (self: Option, a: A): boolean (a: A): (self: Option) => boolean + (self: Option, a: A): boolean } => dual< - (self: Option, a: A) => boolean, - (a: A) => (self: Option) => boolean + (a: A) => (self: Option) => boolean, + (self: Option, a: A) => boolean >(2, (self: Option, a: A): boolean => isNone(self) ? false : equivalence(self.value, a)) /** @@ -1578,11 +1574,11 @@ export const contains = (equivalence: Equivalence): { * @since 1.0.0 */ export const exists: { - (self: Option, predicate: Predicate): boolean (predicate: Predicate): (self: Option) => boolean + (self: Option, predicate: Predicate): boolean } = dual< - (self: Option, predicate: Predicate) => boolean, - (predicate: Predicate) => (self: Option) => boolean + (predicate: Predicate) => (self: Option) => boolean, + (self: Option, predicate: Predicate) => boolean >( 2, (self: Option, predicate: Predicate): boolean => diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index 3477263da..80ac46dda 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -38,11 +38,11 @@ export interface ReadonlyRecord { * @since 1.0.0 */ export const fromIterable: { - (self: Iterable, f: (a: A) => readonly [string, B]): Record (f: (a: A) => readonly [string, B]): (self: Iterable) => Record + (self: Iterable, f: (a: A) => readonly [string, B]): Record } = dual< - (self: Iterable, f: (a: A) => readonly [string, B]) => Record, - (f: (a: A) => readonly [string, B]) => (self: Iterable) => Record + (f: (a: A) => readonly [string, B]) => (self: Iterable) => Record, + (self: Iterable, f: (a: A) => readonly [string, B]) => Record >(2, ( self: Iterable, f: (a: A) => readonly [string, B] @@ -75,11 +75,11 @@ export const fromIterable: { * @since 1.0.0 */ export const get: { - (self: ReadonlyRecord, key: string): Option (key: string): (self: ReadonlyRecord) => Option + (self: ReadonlyRecord, key: string): Option } = dual< - (self: ReadonlyRecord, key: string) => Option, - (key: string) => (self: ReadonlyRecord) => Option + (key: string) => (self: ReadonlyRecord) => Option, + (self: ReadonlyRecord, key: string) => Option >( 2, (self: ReadonlyRecord, key: string): Option => @@ -113,11 +113,11 @@ export const get: { * @since 1.0.0 */ export const modifyOption: { - (self: ReadonlyRecord, key: string, f: (a: A) => B): Option> (key: string, f: (a: A) => B): (self: ReadonlyRecord) => Option> + (self: ReadonlyRecord, key: string, f: (a: A) => B): Option> } = dual< - (self: ReadonlyRecord, key: string, f: (a: A) => B) => Option>, - (key: string, f: (a: A) => B) => (self: ReadonlyRecord) => Option> + (key: string, f: (a: A) => B) => (self: ReadonlyRecord) => Option>, + (self: ReadonlyRecord, key: string, f: (a: A) => B) => Option> >( 3, (self: ReadonlyRecord, key: string, f: (a: A) => B): Option> => { @@ -151,11 +151,11 @@ export const modifyOption: { * @since 1.0.0 */ export const replaceOption: { - (self: ReadonlyRecord, key: string, b: B): Option> (key: string, b: B): (self: ReadonlyRecord) => Option> + (self: ReadonlyRecord, key: string, b: B): Option> } = dual< - (self: ReadonlyRecord, key: string, b: B) => Option>, - (key: string, b: B) => (self: ReadonlyRecord) => Option> + (key: string, b: B) => (self: ReadonlyRecord) => Option>, + (self: ReadonlyRecord, key: string, b: B) => Option> >( 3, (self: ReadonlyRecord, key: string, b: B): Option> => @@ -180,11 +180,11 @@ export const replaceOption: { * @since 1.0.0 */ export const mapWithKey: { - (self: ReadonlyRecord, f: (k: string, a: A) => B): Record (f: (k: string, a: A) => B): (self: ReadonlyRecord) => Record + (self: ReadonlyRecord, f: (k: string, a: A) => B): Record } = dual< - (self: ReadonlyRecord, f: (k: string, a: A) => B) => Record, - (f: (k: string, a: A) => B) => (self: ReadonlyRecord) => Record + (f: (k: string, a: A) => B) => (self: ReadonlyRecord) => Record, + (self: ReadonlyRecord, f: (k: string, a: A) => B) => Record >( 2, (self: ReadonlyRecord, f: (k: string, a: A) => B): Record => { @@ -216,11 +216,11 @@ export const mapWithKey: { * @since 1.0.0 */ export const map: { - (self: ReadonlyRecord, f: (a: A) => B): Record (f: (a: A) => B): (self: ReadonlyRecord) => Record + (self: ReadonlyRecord, f: (a: A) => B): Record } = dual< - (self: ReadonlyRecord, f: (a: A) => B) => Record, - (f: (a: A) => B) => (self: ReadonlyRecord) => Record + (f: (a: A) => B) => (self: ReadonlyRecord) => Record, + (self: ReadonlyRecord, f: (a: A) => B) => Record >( 2, (self: ReadonlyRecord, f: (a: A) => B): Record => diff --git a/src/These.ts b/src/These.ts index 9aed9a4fa..f5d8b9a48 100644 --- a/src/These.ts +++ b/src/These.ts @@ -554,11 +554,11 @@ export const inspectBoth = ( * @since 1.0.0 */ export const bimap: { - (self: These, f: (e: E) => G, g: (a: A) => B): These (f: (e: E) => G, g: (a: A) => B): (self: These) => These + (self: These, f: (e: E) => G, g: (a: A) => B): These } = dual< - (self: These, f: (e: E) => G, g: (a: A) => B) => These, - (f: (e: E) => G, g: (a: A) => B) => (self: These) => These + (f: (e: E) => G, g: (a: A) => B) => (self: These) => These, + (self: These, f: (e: E) => G, g: (a: A) => B) => These >( 3, (self: These, f: (e: E) => G, g: (a: A) => B): These => diff --git a/src/internal/Either.ts b/src/internal/Either.ts index 4d3fd0d62..5e5b4e25d 100644 --- a/src/internal/Either.ts +++ b/src/internal/Either.ts @@ -34,8 +34,8 @@ export const getRight = ( /** @internal */ export const fromOption = dual< - (self: Option, onNone: () => E) => Either, - (onNone: () => E) => (self: Option) => Either + (onNone: () => E) => (self: Option) => Either, + (self: Option, onNone: () => E) => Either >( 2, (self: Option, onNone: () => E): Either => diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index ff274c952..92b233bb2 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -38,12 +38,12 @@ export const bimapComposition = ( export const mapLeft = ( F: Bicovariant ): { - (self: Kind, f: (e: E) => G): Kind (f: (e: E) => G): (self: Kind) => Kind + (self: Kind, f: (e: E) => G): Kind } => dual< - (self: Kind, f: (e: E) => G) => Kind, - (f: (e: E) => G) => (self: Kind) => Kind + (f: (e: E) => G) => (self: Kind) => Kind, + (self: Kind, f: (e: E) => G) => Kind >(2, (self: Kind, f: (e: E) => G): Kind => pipe(self, F.bimap(f, identity))) @@ -55,11 +55,11 @@ export const mapLeft = ( export const map = ( F: Bicovariant ): { - (self: Kind, f: (a: A) => B): Kind (f: (a: A) => B): (self: Kind) => Kind + (self: Kind, f: (a: A) => B): Kind } => dual< - (self: Kind, f: (a: A) => B) => Kind, - (f: (a: A) => B) => (self: Kind) => Kind + (f: (a: A) => B) => (self: Kind) => Kind, + (self: Kind, f: (a: A) => B) => Kind >(2, (self: Kind, f: (a: A) => B): Kind => pipe(self, F.bimap(identity, f))) diff --git a/src/typeclass/Chainable.ts b/src/typeclass/Chainable.ts index fdd0a7bf5..090af10be 100644 --- a/src/typeclass/Chainable.ts +++ b/src/typeclass/Chainable.ts @@ -19,16 +19,24 @@ export interface Chainable extends FlatMap, Covariant(F: Chainable) => +export const andThenDiscard = (F: Chainable): { + ( + that: Kind + ): (self: Kind) => Kind + ( + self: Kind, + that: Kind + ): Kind +} => dual< - ( - self: Kind, - that: Kind - ) => Kind, ( that: Kind ) => ( self: Kind + ) => Kind, + ( + self: Kind, + that: Kind ) => Kind >(2, ( self: Kind, @@ -40,15 +48,23 @@ export const andThenDiscard = (F: Chainable) => * * @since 1.0.0 */ -export const tap = (F: Chainable) => +export const tap = (F: Chainable): { + ( + f: (a: A) => Kind + ): (self: Kind) => Kind + ( + self: Kind, + f: (a: A) => Kind + ): Kind +} => dual< + ( + f: (a: A) => Kind + ) => (self: Kind) => Kind, ( self: Kind, f: (a: A) => Kind - ) => Kind, - ( - f: (a: A) => Kind - ) => (self: Kind) => Kind + ) => Kind >( 2, ( diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index 2c94b8712..24478e28e 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -50,10 +50,13 @@ export const make = (map: Covariant["map"]): Covariant< * @category mapping * @since 1.0.0 */ -export const flap = (F: Covariant) => +export const flap = (F: Covariant): { + (self: Kind B>): (a: A) => Kind + (a: A, self: Kind B>): Kind +} => dual< - (a: A, self: Kind B>) => Kind, - (self: Kind B>) => (a: A) => Kind + (self: Kind B>) => (a: A) => Kind, + (a: A, self: Kind B>) => Kind >( 2, (a: A, self: Kind B>): Kind => @@ -64,10 +67,13 @@ export const flap = (F: Covariant) => * @category mapping * @since 1.0.0 */ -export const as = (F: Covariant) => +export const as = (F: Covariant): { + (b: B): (self: Kind) => Kind + (self: Kind, b: B): Kind +} => dual< - (self: Kind, b: B) => Kind, - (b: B) => (self: Kind) => Kind + (b: B) => (self: Kind) => Kind, + (self: Kind, b: B) => Kind >( 2, (self: Kind, b: B): Kind => diff --git a/src/typeclass/Filterable.ts b/src/typeclass/Filterable.ts index 58a08ca35..c9b195dea 100644 --- a/src/typeclass/Filterable.ts +++ b/src/typeclass/Filterable.ts @@ -42,6 +42,12 @@ export const filterMapComposition = export const filter: ( F: Filterable ) => { + (refinement: (a: A) => a is B): ( + self: Kind + ) => Kind + ( + predicate: (a: A) => boolean + ): (self: Kind) => Kind ( self: Kind, refinement: (a: A) => a is B @@ -50,18 +56,12 @@ export const filter: ( self: Kind, predicate: (a: A) => boolean ): Kind - (refinement: (a: A) => a is B): ( - self: Kind - ) => Kind - ( - predicate: (a: A) => boolean - ): (self: Kind) => Kind } = (Filterable: Filterable) => dual< - (self: Kind, predicate: (a: A) => boolean) => Kind, ( predicate: (a: A) => boolean - ) => (self: Kind) => Kind + ) => (self: Kind) => Kind, + (self: Kind, predicate: (a: A) => boolean) => Kind >( 2, (self: Kind, predicate: (a: A) => boolean): Kind => diff --git a/src/typeclass/FlatMap.ts b/src/typeclass/FlatMap.ts index 5bfc49206..25808f8fb 100644 --- a/src/typeclass/FlatMap.ts +++ b/src/typeclass/FlatMap.ts @@ -27,16 +27,24 @@ export const flatten = (F: FlatMap) => * * @since 1.0.0 */ -export const andThen = (F: FlatMap) => +export const andThen = (F: FlatMap): { + ( + that: Kind + ): (self: Kind) => Kind + ( + self: Kind, + that: Kind + ): Kind +} => dual< - ( - self: Kind, - that: Kind - ) => Kind, ( that: Kind ) => ( self: Kind + ) => Kind, + ( + self: Kind, + that: Kind ) => Kind >(2, ( self: Kind, @@ -48,16 +56,26 @@ export const andThen = (F: FlatMap) => */ export const composeKleisliArrow = ( F: FlatMap -) => +): { + ( + bfc: (b: B) => Kind + ): ( + afb: (a: A) => Kind + ) => (a: A) => Kind + ( + afb: (a: A) => Kind, + bfc: (b: B) => Kind + ): (a: A) => Kind +} => dual< - ( - afb: (a: A) => Kind, - bfc: (b: B) => Kind - ) => (a: A) => Kind, ( bfc: (b: B) => Kind ) => ( afb: (a: A) => Kind + ) => (a: A) => Kind, + ( + afb: (a: A) => Kind, + bfc: (b: B) => Kind ) => (a: A) => Kind >( 2, diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 66a928be6..da2b1c2f7 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -147,11 +147,11 @@ export const reverse = (O: Order): Order => * @since 1.0.0 */ export const contramap: { - (self: Order, f: (b: B) => A): Order (f: (b: B) => A): (self: Order) => Order + (self: Order, f: (b: B) => A): Order } = dual< - (self: Order, f: (b: B) => A) => Order, - (f: (b: B) => A) => (self: Order) => Order + (f: (b: B) => A) => (self: Order) => Order, + (self: Order, f: (b: B) => A) => Order >( 2, (self: Order, f: (b: B) => A): Order => @@ -252,12 +252,12 @@ export const Product: product.Product = { * @since 1.0.0 */ export const lessThan = (O: Order): { - (self: A, that: A): boolean (that: A): (self: A) => boolean + (self: A, that: A): boolean } => dual< - (self: A, that: A) => boolean, - (that: A) => (self: A) => boolean + (that: A) => (self: A) => boolean, + (self: A, that: A) => boolean >(2, (self: A, that: A) => O.compare(self, that) === -1) /** @@ -266,12 +266,12 @@ export const lessThan = (O: Order): { * @since 1.0.0 */ export const greaterThan = (O: Order): { - (self: A, that: A): boolean (that: A): (self: A) => boolean + (self: A, that: A): boolean } => dual< - (self: A, that: A) => boolean, - (that: A) => (self: A) => boolean + (that: A) => (self: A) => boolean, + (self: A, that: A) => boolean >(2, (self: A, that: A) => O.compare(self, that) === 1) /** @@ -280,12 +280,12 @@ export const greaterThan = (O: Order): { * @since 1.0.0 */ export const lessThanOrEqualTo = (O: Order): { - (self: A, that: A): boolean (that: A): (self: A) => boolean + (self: A, that: A): boolean } => dual< - (self: A, that: A) => boolean, - (that: A) => (self: A) => boolean + (that: A) => (self: A) => boolean, + (self: A, that: A) => boolean >(2, (self: A, that: A) => O.compare(self, that) !== 1) /** @@ -294,12 +294,12 @@ export const lessThanOrEqualTo = (O: Order): { * @since 1.0.0 */ export const greaterThanOrEqualTo = (O: Order): { - (self: A, that: A): boolean (that: A): (self: A) => boolean + (self: A, that: A): boolean } => dual< - (self: A, that: A) => boolean, - (that: A) => (self: A) => boolean + (that: A) => (self: A) => boolean, + (self: A, that: A) => boolean >(2, (self: A, that: A) => O.compare(self, that) !== -1) /** @@ -308,12 +308,12 @@ export const greaterThanOrEqualTo = (O: Order): { * @since 1.0.0 */ export const min = (O: Order): { - (self: A, that: A): A (that: A): (self: A) => A + (self: A, that: A): A } => dual< - (self: A, that: A) => A, - (that: A) => (self: A) => A + (that: A) => (self: A) => A, + (self: A, that: A) => A >(2, (self: A, that: A) => self === that || O.compare(self, that) < 1 ? self : that) /** @@ -322,12 +322,12 @@ export const min = (O: Order): { * @since 1.0.0 */ export const max = (O: Order): { - (self: A, that: A): A (that: A): (self: A) => A + (self: A, that: A): A } => dual< - (self: A, that: A) => A, - (that: A) => (self: A) => A + (that: A) => (self: A) => A, + (self: A, that: A) => A >(2, (self: A, that: A) => self === that || O.compare(self, that) > -1 ? self : that) /** @@ -336,12 +336,12 @@ export const max = (O: Order): { * @since 1.0.0 */ export const clamp = (O: Order): { - (a: A, minimum: A, maximum: A): A (minimum: A, maximum: A): (a: A) => A + (a: A, minimum: A, maximum: A): A } => dual< - (a: A, minimum: A, maximum: A) => A, - (minimum: A, maximum: A) => (a: A) => A + (minimum: A, maximum: A) => (a: A) => A, + (a: A, minimum: A, maximum: A) => A >( 3, (a: A, minimum: A, maximum: A): A => min(O)(maximum, max(O)(minimum, a)) @@ -353,12 +353,12 @@ export const clamp = (O: Order): { * @since 1.0.0 */ export const between = (O: Order): { - (a: A, minimum: A, maximum: A): boolean (minimum: A, maximum: A): (a: A) => boolean + (a: A, minimum: A, maximum: A): boolean } => dual< - (a: A, minimum: A, maximum: A) => boolean, - (minimum: A, maximum: A) => (a: A) => boolean + (minimum: A, maximum: A) => (a: A) => boolean, + (a: A, minimum: A, maximum: A) => boolean >( 3, (a: A, minimum: A, maximum: A): boolean => diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 4e6948479..9fcd938c3 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -38,17 +38,27 @@ export const getSemigroup = (F: SemiApplicative) => * * @since 1.0.0 */ -export const zipWith = (F: SemiApplicative) => +export const zipWith = (F: SemiApplicative): { + ( + that: Kind, + f: (a: A, b: B) => C + ): (self: Kind) => Kind + ( + self: Kind, + that: Kind, + f: (a: A, b: B) => C + ): Kind +} => dual< - ( - self: Kind, + ( that: Kind, f: (a: A, b: B) => C - ) => Kind, - ( + ) => (self: Kind) => Kind, + ( + self: Kind, that: Kind, f: (a: A, b: B) => C - ) => (self: Kind) => Kind + ) => Kind >( 3, ( @@ -62,16 +72,26 @@ export const zipWith = (F: SemiApplicative) => /** * @since 1.0.0 */ -export const ap = (F: SemiApplicative) => +export const ap = (F: SemiApplicative): { + ( + that: Kind + ): ( + self: Kind B> + ) => Kind + ( + self: Kind B>, + that: Kind + ): Kind +} => dual< - ( - self: Kind B>, - that: Kind - ) => Kind, ( that: Kind ) => ( self: Kind B> + ) => Kind, + ( + self: Kind B>, + that: Kind ) => Kind >(2, ( self: Kind B>, @@ -81,16 +101,24 @@ export const ap = (F: SemiApplicative) => /** * @since 1.0.0 */ -export const andThenDiscard = (F: SemiApplicative) => +export const andThenDiscard = (F: SemiApplicative): { + ( + that: Kind + ): (self: Kind) => Kind + ( + self: Kind, + that: Kind + ): Kind +} => dual< - ( - self: Kind, - that: Kind - ) => Kind, ( that: Kind ) => ( self: Kind + ) => Kind, + ( + self: Kind, + that: Kind ) => Kind >(2, ( self: Kind, @@ -100,16 +128,24 @@ export const andThenDiscard = (F: SemiApplicative) => /** * @since 1.0.0 */ -export const andThen = (F: SemiApplicative) => +export const andThen = (F: SemiApplicative): { + ( + that: Kind + ): (self: Kind) => Kind + ( + self: Kind, + that: Kind + ): Kind +} => dual< - ( - self: Kind, - that: Kind - ) => Kind, ( that: Kind ) => ( self: Kind + ) => Kind, + ( + self: Kind, + that: Kind ) => Kind >(2, ( self: Kind, @@ -125,15 +161,23 @@ export const andThen = (F: SemiApplicative) => * @since 1.0.0 */ export const lift2 = (F: SemiApplicative) => - (f: (a: A, b: B) => C) => + (f: (a: A, b: B) => C): { + ( + that: Kind + ): (self: Kind) => Kind + ( + self: Kind, + that: Kind + ): Kind + } => dual< + ( + that: Kind + ) => (self: Kind) => Kind, ( self: Kind, that: Kind - ) => Kind, - ( - that: Kind - ) => (self: Kind) => Kind + ) => Kind >(2, ( self: Kind, that: Kind diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index ad8a522e4..78fcc0de0 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -119,16 +119,26 @@ export const andThenBind = (F: SemiProduct) => * * @since 1.0.0 */ -export const appendElement = (F: SemiProduct) => +export const appendElement = (F: SemiProduct): { + ( + that: Kind + ): >( + self: Kind + ) => Kind + , R2, O2, E2, B>( + self: Kind, + that: Kind + ): Kind +} => dual< - , R2, O2, E2, B>( - self: Kind, - that: Kind - ) => Kind, ( that: Kind ) => >( self: Kind + ) => Kind, + , R2, O2, E2, B>( + self: Kind, + that: Kind ) => Kind >(2, , R2, O2, E2, B>( self: Kind, diff --git a/src/typeclass/Traversable.ts b/src/typeclass/Traversable.ts index 00257be14..929949a80 100644 --- a/src/typeclass/Traversable.ts +++ b/src/typeclass/Traversable.ts @@ -76,21 +76,21 @@ export const sequence = ( */ export const traverseTap = (T: Traversable) => (F: Applicative): { + ( + f: (a: A) => Kind + ): (self: Kind) => Kind> ( self: Kind, f: (a: A) => Kind ): Kind> - ( - f: (a: A) => Kind - ): (self: Kind) => Kind> } => dual< + (f: (a: A) => Kind) => ( + self: Kind + ) => Kind>, ( self: Kind, f: (a: A) => Kind - ) => Kind>, - (f: (a: A) => Kind) => ( - self: Kind ) => Kind> >(2, ( self: Kind, diff --git a/test/Function.ts b/test/Function.ts index 6a749a6be..1c1ab13e7 100644 --- a/test/Function.ts +++ b/test/Function.ts @@ -147,8 +147,8 @@ describe.concurrent("Function", () => { it("dual", () => { const f = _.dual< - (self: number, that: number) => number, - (that: number) => (self: number) => number + (that: number) => (self: number) => number, + (self: number, that: number) => number >(2, (a: number, b: number): number => a - b) deepStrictEqual(f(3, 2), 1) deepStrictEqual(_.pipe(3, f(2)), 1) From a7a416fb58fb8792a0c6d6e0ae9887ca47f63801 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 15:46:34 +0100 Subject: [PATCH 154/255] Semigroup: make dual --- docs/modules/Boolean.ts.md | 9 +- docs/modules/Function.ts.md | 7 +- docs/modules/typeclass/Semigroup.ts.md | 43 ++++---- src/Bigint.ts | 10 +- src/Boolean.ts | 30 ++++-- src/Function.ts | 22 +--- src/Number.ts | 10 +- src/Ordering.ts | 10 +- src/Predicate.ts | 53 +++++----- src/internal/Function.ts | 21 ++++ src/internal/ReadonlyArray.ts | 1 + src/typeclass/Equivalence.ts | 26 ++--- src/typeclass/Order.ts | 44 ++++---- src/typeclass/SemiApplicative.ts | 18 ++-- src/typeclass/SemiCoproduct.ts | 10 +- src/typeclass/Semigroup.ts | 140 ++++++++++++------------- 16 files changed, 235 insertions(+), 219 deletions(-) create mode 100644 src/internal/Function.ts diff --git a/docs/modules/Boolean.ts.md b/docs/modules/Boolean.ts.md index 4f530ab10..0c02e35ee 100644 --- a/docs/modules/Boolean.ts.md +++ b/docs/modules/Boolean.ts.md @@ -44,7 +44,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const and: (that: boolean) => (self: boolean) => boolean +export declare const and: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } ``` Added in v1.0.0 @@ -64,7 +64,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const or: (that: boolean) => (self: boolean) => boolean +export declare const or: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } ``` Added in v1.0.0 @@ -187,7 +187,10 @@ If `value` is `false`, `onFalse()` is returned, otherwise `onTrue()`. **Signature** ```ts -export declare const match: (onFalse: LazyArg, onTrue: LazyArg) => (value: boolean) => A | B +export declare const match: { + (onFalse: LazyArg, onTrue: LazyArg): (value: boolean) => A | B + (value: boolean, onFalse: LazyArg, onTrue: LazyArg): A | B +} ``` **Example** diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 86fc91e97..091460a20 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -84,7 +84,7 @@ Unary functions form a semigroup as long as you can provide a semigroup for the **Signature** ```ts -export declare const getSemigroup: (Semigroup: Semigroup) => () => Semigroup<(a: A) => S> +export declare const getSemigroup: (S: Semigroup) => () => Semigroup<(a: A) => S> ``` **Example** @@ -288,10 +288,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const dual: < - DataLast extends (...args: Array) => any, - DataFirst extends (...args: Array) => any ->( +export declare const dual: any, DataFirst extends (...args: any[]) => any>( dataFirstArity: Parameters['length'], body: DataFirst ) => DataLast & DataFirst diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index b91f9eeda..dd6fc1ac2 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -6,25 +6,6 @@ parent: Modules ## Semigroup overview -`Semigroup` describes a way of combining two values of type `A` that is associative. - -```ts -export interface Semigroup { - combine: (self: A, that: A) => A - combineMany: (self: A, collection: Iterable) => A -} -``` - -The combine operator must be associative, meaning that if we combine `a` with `b` and then combine the result -with `c` we must get the same value as if we combine `b` with `c` and then combine `a` with the result. - -``` -(a <> b) <> c === a <> (b <> c) -``` - -The `Semigroup` abstraction allows us to combine values of a data type to build a new value of that data type -with richer structure. - Added in v1.0.0 --- @@ -39,6 +20,7 @@ Added in v1.0.0 - [constructors](#constructors) - [constant](#constant) - [fromCombine](#fromcombine) + - [make](#make) - [max](#max) - [min](#min) - [instances](#instances) @@ -151,6 +133,19 @@ export declare const fromCombine: (combine: (self: A, that: A) => A) => Semig Added in v1.0.0 +## make + +**Signature** + +```ts +export declare const make: ( + combine: (self: A, that: A) => A, + combineMany: (self: A, collection: Iterable) => A +) => Semigroup +``` + +Added in v1.0.0 + ## max `Semigroup` that returns last maximum of elements. @@ -321,8 +316,14 @@ Added in v1.0.0 ```ts export interface Semigroup { - readonly combine: (self: A, that: A) => A - readonly combineMany: (self: A, collection: Iterable) => A + readonly combine: { + (that: A): (self: A) => A + (self: A, that: A): A + } + readonly combineMany: { + (collection: Iterable): (self: A) => A + (self: A, collection: Iterable): A + } } ``` diff --git a/src/Bigint.ts b/src/Bigint.ts index ea63ec0be..a69f621e0 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -27,10 +27,7 @@ export const isBigint: (u: unknown) => u is bigint = predicate.isBigInt export const sum: { (that: bigint): (self: bigint) => bigint (self: bigint, that: bigint): bigint -} = dual< - (that: bigint) => (self: bigint) => bigint, - (self: bigint, that: bigint) => bigint ->(2, semigroup.bigintSum.combine) +} = semigroup.bigintSum.combine /** * @dual @@ -40,10 +37,7 @@ export const sum: { export const multiply: { (that: bigint): (self: bigint) => bigint (self: bigint, that: bigint): bigint -} = dual< - (that: bigint) => (self: bigint) => bigint, - (self: bigint, that: bigint) => bigint ->(2, semigroup.bigintMultiply.combine) +} = semigroup.bigintMultiply.combine /** * @dual diff --git a/src/Boolean.ts b/src/Boolean.ts index af8651faa..83410c8f2 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -6,6 +6,7 @@ * @since 1.0.0 */ import type { LazyArg } from "@fp-ts/core/Function" +import { dual } from "@fp-ts/core/Function" import type { Refinement } from "@fp-ts/core/Predicate" import * as predicate from "@fp-ts/core/Predicate" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" @@ -40,8 +41,17 @@ export const isBoolean: Refinement = predicate.isBoolean * @category pattern matching * @since 1.0.0 */ -export const match = (onFalse: LazyArg, onTrue: LazyArg) => - (value: boolean): A | B => value ? onTrue() : onFalse() +export const match: { + (onFalse: LazyArg, onTrue: LazyArg): (value: boolean) => A | B + (value: boolean, onFalse: LazyArg, onTrue: LazyArg): A | B +} = dual< + (onFalse: LazyArg, onTrue: LazyArg) => (value: boolean) => A | B, + (value: boolean, onFalse: LazyArg, onTrue: LazyArg) => A | B +>( + 3, + (value: boolean, onFalse: LazyArg, onTrue: LazyArg): A | B => + value ? onTrue() : onFalse() +) /** * @category instances @@ -110,15 +120,19 @@ export const MonoidAny: monoid.Monoid = monoid.booleanAny * @category combinators * @since 1.0.0 */ -export const and = (that: boolean) => - (self: boolean): boolean => semigroup.booleanAll.combine(self, that) +export const and: { + (that: boolean): (self: boolean) => boolean + (self: boolean, that: boolean): boolean +} = semigroup.booleanAll.combine /** * @category combinators * @since 1.0.0 */ -export const or = (that: boolean) => - (self: boolean): boolean => semigroup.booleanAny.combine(self, that) +export const or: { + (that: boolean): (self: boolean) => boolean + (self: boolean, that: boolean): boolean +} = semigroup.booleanAny.combine /** * @category combinators @@ -129,9 +143,9 @@ export const not = (self: boolean): boolean => !self /** * @since 1.0.0 */ -export const all = MonoidAll.combineAll +export const all: (collection: Iterable) => boolean = MonoidAll.combineAll /** * @since 1.0.0 */ -export const any = MonoidAny.combineAll +export const any: (collection: Iterable) => boolean = MonoidAny.combineAll diff --git a/src/Function.ts b/src/Function.ts index 356f7b51f..70a531b7d 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -2,6 +2,7 @@ * @since 1.0.0 */ import type { TypeLambda } from "@fp-ts/core/HKT" +import * as internal from "@fp-ts/core/internal/Function" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" @@ -48,9 +49,9 @@ export const compose: (bc: (b: B) => C) => (ab: (a: A) => B) => (a: A) * @category instances * @since 1.0.0 */ -export const getSemigroup = (Semigroup: Semigroup) => +export const getSemigroup = (S: Semigroup) => (): Semigroup<(a: A) => S> => - semigroup.fromCombine((self, that) => (a) => Semigroup.combine(self(a), that(a))) + semigroup.fromCombine((self, that) => (a) => S.combine(self(a), that(a))) /** * Unary functions form a monoid as long as you can provide a monoid for the codomain. @@ -656,19 +657,4 @@ export const SK = (_: A, b: B): B => b /** * @since 1.0.0 */ -export const dual = < - DataLast extends (...args: Array) => any, - DataFirst extends (...args: Array) => any ->( - dataFirstArity: Parameters["length"], - body: DataFirst -): DataLast & DataFirst => { - // @ts-expect-error - return function() { - if (arguments.length === dataFirstArity) { - // @ts-expect-error - return body.apply(this, arguments) - } - return ((self: any) => body(self, ...arguments)) as any - } -} +export const dual = internal.dual diff --git a/src/Number.ts b/src/Number.ts index a91c0177f..0d655a24f 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -34,10 +34,7 @@ export const isNumber = predicate.isNumber export const sum: { (that: number): (self: number) => number (self: number, that: number): number -} = dual< - (that: number) => (self: number) => number, - (self: number, that: number) => number ->(2, semigroup.numberSum.combine) +} = semigroup.numberSum.combine /** * @example @@ -53,10 +50,7 @@ export const sum: { export const multiply: { (that: number): (self: number) => number (self: number, that: number): number -} = dual< - (that: number) => (self: number) => number, - (self: number, that: number) => number ->(2, semigroup.numberMultiply.combine) +} = semigroup.numberMultiply.combine /** * @example diff --git a/src/Ordering.ts b/src/Ordering.ts index 65782eefe..2e95676ea 100644 --- a/src/Ordering.ts +++ b/src/Ordering.ts @@ -3,7 +3,7 @@ */ import type { LazyArg } from "@fp-ts/core/Function" import * as monoid from "@fp-ts/core/typeclass/Monoid" -import type * as semigroup from "@fp-ts/core/typeclass/Semigroup" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** * @category model @@ -30,9 +30,9 @@ export const match = ( * @category instances * @since 1.0.0 */ -export const Semigroup: semigroup.Semigroup = { - combine: (self, that) => self !== 0 ? self : that, - combineMany: (self, collection) => { +export const Semigroup: semigroup.Semigroup = semigroup.make( + (self, that) => self !== 0 ? self : that, + (self, collection) => { let ordering = self if (ordering !== 0) { return ordering @@ -44,7 +44,7 @@ export const Semigroup: semigroup.Semigroup = { } return ordering } -} +) /** * @category instances diff --git a/src/Predicate.ts b/src/Predicate.ts index 146b2a27a..f3d4a4359 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -9,7 +9,8 @@ import * as invariant from "@fp-ts/core/typeclass/Invariant" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as of_ from "@fp-ts/core/typeclass/Of" import * as product_ from "@fp-ts/core/typeclass/Product" -import type * as semigroup from "@fp-ts/core/typeclass/Semigroup" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" +import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** @@ -269,21 +270,22 @@ export const and = (that: Predicate) => * @category instances * @since 1.0.0 */ -export const getSemigroupAny = (): semigroup.Semigroup> => ({ - combine: (self, that) => pipe(self, or(that)), - combineMany: (self, collection) => - a => { - if (self(a)) { - return true - } - for (const p of collection) { - if (p(a)) { +export const getSemigroupAny = (): Semigroup> => + semigroup.make( + (self, that) => pipe(self, or(that)), + (self, collection) => + a => { + if (self(a)) { return true } + for (const p of collection) { + if (p(a)) { + return true + } + } + return false } - return false - } -}) + ) /** * @category instances @@ -296,21 +298,22 @@ export const getMonoidAny = (): monoid.Monoid> => * @category instances * @since 1.0.0 */ -export const getSemigroupAll = (): semigroup.Semigroup> => ({ - combine: (self, that) => pipe(self, and(that)), - combineMany: (self, collection) => - a => { - if (!self(a)) { - return false - } - for (const p of collection) { - if (!p(a)) { +export const getSemigroupAll = (): Semigroup> => + semigroup.make( + (self, that) => pipe(self, and(that)), + (self, collection) => + a => { + if (!self(a)) { return false } + for (const p of collection) { + if (!p(a)) { + return false + } + } + return true } - return true - } -}) + ) /** * @category instances diff --git a/src/internal/Function.ts b/src/internal/Function.ts new file mode 100644 index 000000000..256daaea8 --- /dev/null +++ b/src/internal/Function.ts @@ -0,0 +1,21 @@ +/** + * @since 1.0.0 + */ + +/** @internal */ +export const dual = < + DataLast extends (...args: Array) => any, + DataFirst extends (...args: Array) => any +>( + dataFirstArity: Parameters["length"], + body: DataFirst +): DataLast & DataFirst => { + // @ts-expect-error + return function() { + if (arguments.length >= dataFirstArity) { + // @ts-expect-error + return body.apply(this, arguments) + } + return ((self: any) => body(self, ...arguments)) as any + } +} diff --git a/src/internal/ReadonlyArray.ts b/src/internal/ReadonlyArray.ts index 0754a3224..b57460040 100644 --- a/src/internal/ReadonlyArray.ts +++ b/src/internal/ReadonlyArray.ts @@ -1,6 +1,7 @@ /** * @since 1.0.0 */ + import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" /** @internal */ diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index a75dcbc34..7de4427d2 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -13,6 +13,7 @@ import type { Monoid } from "@fp-ts/core/typeclass/Monoid" import * as monoid from "@fp-ts/core/typeclass/Monoid" import type * as product from "@fp-ts/core/typeclass/Product" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** @@ -141,21 +142,22 @@ export const record = ( * @category instances * @since 1.0.0 */ -export const getSemigroup = (): Semigroup> => ({ - combine: (self, that) => (x, y) => self(x, y) && that(x, y), - combineMany: (self, collection) => - (x, y) => { - if (!self(x, y)) { - return false - } - for (const equivalence of collection) { - if (!equivalence(x, y)) { +export const getSemigroup = (): Semigroup> => + semigroup.make( + (self, that) => (x, y) => self(x, y) && that(x, y), + (self, collection) => + (x, y) => { + if (!self(x, y)) { return false } + for (const equivalence of collection) { + if (!equivalence(x, y)) { + return false + } + } + return true } - return true - } -}) + ) const empty: Equivalence = () => true diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index da2b1c2f7..67278fe3e 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -9,6 +9,7 @@ import type { Monoid } from "@fp-ts/core/typeclass/Monoid" import * as monoid from "@fp-ts/core/typeclass/Monoid" import type * as product from "@fp-ts/core/typeclass/Product" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** @@ -162,30 +163,31 @@ export const contramap: { * @category instances * @since 1.0.0 */ -export const getSemigroup = (): Semigroup> => ({ - combine: (O1, O2) => - fromCompare((self, that) => { - const out = O1.compare(self, that) - if (out !== 0) { - return out - } - return O2.compare(self, that) - }), - combineMany: (self, collection) => - fromCompare((a1, a2) => { - let out = self.compare(a1, a2) - if (out !== 0) { - return out - } - for (const O of collection) { - out = O.compare(a1, a2) +export const getSemigroup = (): Semigroup> => + semigroup.make( + (O1, O2) => + fromCompare((self, that) => { + const out = O1.compare(self, that) if (out !== 0) { return out } - } - return out - }) -}) + return O2.compare(self, that) + }), + (self, collection) => + fromCompare((a1, a2) => { + let out = self.compare(a1, a2) + if (out !== 0) { + return out + } + for (const O of collection) { + out = O.compare(a1, a2) + if (out !== 0) { + return out + } + } + return out + }) + ) const empty: Order = fromCompare(() => 0) diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 9fcd938c3..1de85e34e 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -5,6 +5,7 @@ import { dual, identity, pipe, SK } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import type { SemiProduct } from "@fp-ts/core/typeclass/SemiProduct" /** @@ -20,14 +21,15 @@ export interface SemiApplicative extends SemiProduct, C * @since 1.0.0 */ export const getSemigroup = (F: SemiApplicative) => - (S: Semigroup): Semigroup> => ({ - combine: (self, that) => pipe(F.product(self, that), F.map(([a1, a2]) => S.combine(a1, a2))), - combineMany: (self, collection) => - pipe( - F.productMany(self, collection), - F.map(([head, ...tail]) => S.combineMany(head, tail)) - ) - }) + (S: Semigroup): Semigroup> => + semigroup.make( + (self, that) => pipe(F.product(self, that), F.map(([a1, a2]) => S.combine(a1, a2))), + (self, collection) => + pipe( + F.productMany(self, collection), + F.map(([head, ...tail]) => S.combineMany(head, tail)) + ) + ) /** * Zips two `F` values together using a provided function, returning a new `F` of the result. diff --git a/src/typeclass/SemiCoproduct.ts b/src/typeclass/SemiCoproduct.ts index 57d85526d..28e1a0a50 100644 --- a/src/typeclass/SemiCoproduct.ts +++ b/src/typeclass/SemiCoproduct.ts @@ -5,6 +5,7 @@ import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" +import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** * @category type class @@ -26,7 +27,8 @@ export interface SemiCoproduct extends Invariant { * @since 1.0.0 */ export const getSemigroup = (F: SemiCoproduct) => - (): Semigroup> => ({ - combine: F.coproduct, - combineMany: F.coproductMany - }) + (): Semigroup> => + semigroup.make( + F.coproduct, + F.coproductMany + ) diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index a0c6217c5..e6f6e77af 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -1,26 +1,8 @@ /** - * `Semigroup` describes a way of combining two values of type `A` that is associative. - * - * ```ts - * export interface Semigroup { - * combine: (self: A, that: A) => A - * combineMany: (self: A, collection: Iterable) => A - * } - * ``` - * - * The combine operator must be associative, meaning that if we combine `a` with `b` and then combine the result - * with `c` we must get the same value as if we combine `b` with `c` and then combine `a` with the result. - * - * ``` - * (a <> b) <> c === a <> (b <> c) - * ``` - * - * The `Semigroup` abstraction allows us to combine values of a data type to build a new value of that data type - * with richer structure. - * * @since 1.0.0 */ import type { TypeLambda } from "@fp-ts/core/HKT" +import { dual } from "@fp-ts/core/internal/Function" import { fromIterable } from "@fp-ts/core/internal/ReadonlyArray" import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Order } from "@fp-ts/core/typeclass/Order" @@ -32,8 +14,14 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Semigroup { - readonly combine: (self: A, that: A) => A - readonly combineMany: (self: A, collection: Iterable) => A + readonly combine: { + (that: A): (self: A) => A + (self: A, that: A): A + } + readonly combineMany: { + (collection: Iterable): (self: A) => A + (self: A, collection: Iterable): A + } } /** @@ -44,22 +32,32 @@ export interface SemigroupTypeLambda extends TypeLambda { readonly type: Semigroup } +/** + * @category constructors + * @since 1.0.0 + */ +export const make = ( + combine: (self: A, that: A) => A, + combineMany: (self: A, collection: Iterable) => A +): Semigroup => ({ + combine: dual(2, combine), + combineMany: dual(2, combineMany) +}) + /** * Useful when `combineMany` can't be optimised. * * @category constructors * @since 1.0.0 */ -export const fromCombine = (combine: Semigroup["combine"]): Semigroup => ({ - combine, - combineMany: (self, collection) => { +export const fromCombine = (combine: (self: A, that: A) => A): Semigroup => + make(combine, (self, collection) => { let out: A = self for (const a of collection) { out = combine(out, a) } return out - } -}) + }) /** * @category instances @@ -81,9 +79,9 @@ export const numberSum: Semigroup = fromCombine((self, that) => self + t * @category instances * @since 1.0.0 */ -export const numberMultiply: Semigroup = { - combine: (self, that) => self * that, - combineMany: (self, collection) => { +export const numberMultiply: Semigroup = make( + (self, that) => self * that, + (self, collection) => { if (self === 0) { return 0 } @@ -96,7 +94,7 @@ export const numberMultiply: Semigroup = { } return out } -} +) /** * `bigint` semigroup under addition. @@ -112,9 +110,9 @@ export const bigintSum: Semigroup = fromCombine((self, that) => self + t * @category instances * @since 1.0.0 */ -export const bigintMultiply: Semigroup = { - combine: (self, that) => self * that, - combineMany: (self, collection) => { +export const bigintMultiply: Semigroup = make( + (self, that) => self * that, + (self, collection) => { if (self === 0n) { return 0n } @@ -127,7 +125,7 @@ export const bigintMultiply: Semigroup = { } return out } -} +) /** * `boolean` semigroup under conjunction. @@ -135,9 +133,9 @@ export const bigintMultiply: Semigroup = { * @category instances * @since 1.0.0 */ -export const booleanAll: Semigroup = { - combine: (self, that) => self && that, - combineMany: (self, collection) => { +export const booleanAll: Semigroup = make( + (self, that) => self && that, + (self, collection) => { if (self === false) { return false } @@ -148,7 +146,7 @@ export const booleanAll: Semigroup = { } return true } -} +) /** * `boolean` semigroup under disjunction. @@ -156,9 +154,9 @@ export const booleanAll: Semigroup = { * @category instances * @since 1.0.0 */ -export const booleanAny: Semigroup = { - combine: (self, that) => self || that, - combineMany: (self, collection) => { +export const booleanAny: Semigroup = make( + (self, that) => self || that, + (self, collection) => { if (self === true) { return true } @@ -169,7 +167,7 @@ export const booleanAny: Semigroup = { } return false } -} +) /** * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. @@ -247,25 +245,23 @@ export const max = (O: Order): Semigroup => * @category constructors * @since 1.0.0 */ -export const constant = (a: A): Semigroup => ({ - combine: () => a, - combineMany: () => a -}) +export const constant = (a: A): Semigroup => make(() => a, () => a) /** * The dual of a `Semigroup`, obtained by flipping the arguments of `combine`. * * @since 1.0.0 */ -export const reverse = (S: Semigroup): Semigroup => ({ - combine: (self, that) => S.combine(that, self), - combineMany: (self, collection) => { - const reversed = Array.from(collection).reverse() - return reversed.length > 0 ? - S.combine(S.combineMany(reversed[0], reversed.slice(1)), self) : - self - } -}) +export const reverse = (S: Semigroup): Semigroup => + make( + (self, that) => S.combine(that, self), + (self, collection) => { + const reversed = Array.from(collection).reverse() + return reversed.length > 0 ? + S.combine(S.combineMany(reversed[0], reversed.slice(1)), self) : + self + } + ) /** * @since 1.0.0 @@ -280,10 +276,7 @@ export const intercalate = (separator: A) => * @category instances * @since 1.0.0 */ -export const first = (): Semigroup => ({ - combine: (a) => a, - combineMany: (a) => a -}) +export const first = (): Semigroup => make((a) => a, (a) => a) /** * Always return the last argument. @@ -291,15 +284,16 @@ export const first = (): Semigroup => ({ * @category instances * @since 1.0.0 */ -export const last = (): Semigroup => ({ - combine: (_, second) => second, - combineMany: (self, collection) => { - let a: A = self - // eslint-disable-next-line no-empty - for (a of collection) {} - return a - } -}) +export const last = (): Semigroup => + make( + (_, second) => second, + (self, collection) => { + let a: A = self + // eslint-disable-next-line no-empty + for (a of collection) {} + return a + } + ) /** * @since 1.0.0 @@ -308,11 +302,11 @@ export const imap = ( to: (a: A) => B, from: (b: B) => A ) => - (S: Semigroup): Semigroup => ({ - combine: (self, that) => to(S.combine(from(self), from(that))), - combineMany: (self, collection) => - to(S.combineMany(from(self), (fromIterable(collection)).map(from))) - }) + (S: Semigroup): Semigroup => + make( + (self, that) => to(S.combine(from(self), from(that))), + (self, collection) => to(S.combineMany(from(self), (fromIterable(collection)).map(from))) + ) /** * @category instances From b175b764e1a5b889665dbaa6d844c6863d727338 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 15:55:19 +0100 Subject: [PATCH 155/255] simplify Monoid code --- src/typeclass/Monoid.ts | 55 ++++++++--------------------------------- 1 file changed, 10 insertions(+), 45 deletions(-) diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index 0ac481c29..ed42ae462 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -19,7 +19,8 @@ export interface Monoid extends Semigroup { * @since 1.0.0 */ export const fromSemigroup = (S: Semigroup, empty: Monoid["empty"]): Monoid => ({ - ...S, + combine: S.combine, + combineMany: S.combineMany, empty, combineAll: collection => S.combineMany(empty, collection) }) @@ -56,11 +57,7 @@ export const reverse = (M: Monoid): Monoid => fromSemigroup(semigroup.r * @category instances * @since 1.0.0 */ -export const string: Monoid = { - ...semigroup.string, - combineAll: (collection) => semigroup.string.combineMany("", collection), - empty: "" -} +export const string: Monoid = fromSemigroup(semigroup.string, "") /** * `number` monoid under addition. @@ -70,11 +67,7 @@ export const string: Monoid = { * @category instances * @since 1.0.0 */ -export const numberSum: Monoid = { - ...semigroup.numberSum, - combineAll: (collection) => semigroup.numberSum.combineMany(0, collection), - empty: 0 -} +export const numberSum: Monoid = fromSemigroup(semigroup.numberSum, 0) /** * `number` monoid under multiplication. @@ -84,11 +77,7 @@ export const numberSum: Monoid = { * @category instances * @since 1.0.0 */ -export const numberMultiply: Monoid = { - ...semigroup.numberMultiply, - combineAll: (collection) => semigroup.numberMultiply.combineMany(1, collection), - empty: 1 -} +export const numberMultiply: Monoid = fromSemigroup(semigroup.numberMultiply, 1) /** * `number` monoid under addition. @@ -98,11 +87,7 @@ export const numberMultiply: Monoid = { * @category instances * @since 1.0.0 */ -export const bigintSum: Monoid = { - ...semigroup.bigintSum, - combineAll: (collection) => semigroup.bigintSum.combineMany(0n, collection), - empty: 0n -} +export const bigintSum: Monoid = fromSemigroup(semigroup.bigintSum, 0n) /** * `bigint` monoid under multiplication. @@ -112,11 +97,7 @@ export const bigintSum: Monoid = { * @category instances * @since 1.0.0 */ -export const bigintMultiply: Monoid = { - ...semigroup.bigintMultiply, - combineAll: (collection) => semigroup.bigintMultiply.combineMany(1n, collection), - empty: 1n -} +export const bigintMultiply: Monoid = fromSemigroup(semigroup.bigintMultiply, 1n) /** * `boolean` monoid under conjunction. @@ -126,11 +107,7 @@ export const bigintMultiply: Monoid = { * @category instances * @since 1.0.0 */ -export const booleanAll: Monoid = { - ...semigroup.booleanAll, - combineAll: (collection) => semigroup.booleanAll.combineMany(true, collection), - empty: true -} +export const booleanAll: Monoid = fromSemigroup(semigroup.booleanAll, true) /** * `boolean` monoid under disjunction. @@ -140,11 +117,7 @@ export const booleanAll: Monoid = { * @category instances * @since 1.0.0 */ -export const booleanAny: Monoid = { - ...semigroup.booleanAny, - combineAll: (collection) => semigroup.booleanAny.combineMany(false, collection), - empty: false -} +export const booleanAny: Monoid = fromSemigroup(semigroup.booleanAny, false) /** * This function creates and returns a new `Monoid` for a tuple of values based on the given `Monoid`s for each element in the tuple. @@ -171,15 +144,7 @@ export const tuple = >( * @category combinators * @since 1.0.0 */ -export const array = (): Monoid> => { - const S = semigroup.array() - return ({ - combine: S.combine, - combineMany: S.combineMany, - combineAll: (collection) => S.combineMany([], collection), - empty: [] - }) -} +export const array = (): Monoid> => fromSemigroup(semigroup.array(), []) /** * Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. From cc40f7a9881c43e02ef9d1da4a606ef85ec82431 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 16:51:39 +0100 Subject: [PATCH 156/255] Bicovariant: make dual --- docs/modules/Either.ts.md | 9 +-- docs/modules/These.ts.md | 20 +++--- docs/modules/typeclass/Bicovariant.ts.md | 29 ++++++--- src/Either.ts | 78 +++++++++++------------- src/These.ts | 47 +++++++------- src/typeclass/Bicovariant.ts | 39 +++++++++--- test/These.ts | 8 +-- test/typeclass/Bicovariant.ts | 13 ++-- 8 files changed, 130 insertions(+), 113 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index cfaf48ab4..b699f2d3d 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -575,8 +575,8 @@ Maps the `Left` side of an `Either` value to a new `Either` value. ```ts export declare const mapLeft: { - (self: Either, f: (e: E) => G): Either (f: (e: E) => G): (self: Either) => Either + (self: Either, f: (e: E) => G): Either } ``` @@ -1129,15 +1129,12 @@ Added in v1.0.0 ## bimap -Returns an effect whose Left and Right channels have been mapped by -the specified pair of functions, `f` and `g`. - **Signature** ```ts export declare const bimap: { - (f: (e: E) => G, g: (a: A) => B): (self: Either) => Either - (self: Either, f: (e: E) => G, g: (a: A) => B): Either + (f: (e: E1) => E2, g: (a: A) => B): (self: Either) => Either + (self: Either, f: (e: E1) => E2, g: (a: A) => B): Either } ``` diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 04f0c295d..4e7a09dd9 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -40,9 +40,9 @@ Added in v1.0.0 - [fromIterable](#fromiterable) - [fromNullable](#fromnullable) - [fromOption](#fromoption) - - [fromThese](#fromthese) - [fromTuple](#fromtuple) - [toEither](#toeither) + - [toValidated](#tovalidated) - [debugging](#debugging) - [inspectBoth](#inspectboth) - [inspectLeft](#inspectleft) @@ -449,32 +449,32 @@ export declare const fromOption: (onNone: LazyArg) => (self: O.Option(self: These) => These +export declare const fromTuple: (self: readonly [E, A]) => These ``` Added in v1.0.0 -## fromTuple +## toEither **Signature** ```ts -export declare const fromTuple: (self: readonly [E, A]) => These +export declare const toEither: (onBoth: (e: E, a: A) => Either) => (self: These) => Either ``` Added in v1.0.0 -## toEither +## toValidated **Signature** ```ts -export declare const toEither: (onBoth: (e: E, a: A) => Either) => (self: These) => Either +export declare const toValidated: (self: These) => These ``` Added in v1.0.0 @@ -648,8 +648,8 @@ Maps the `Left` side of an `These` value to a new `These` value. ```ts export declare const mapLeft: { - (self: These, f: (e: E) => G): These (f: (e: E) => G): (self: These) => These + (self: These, f: (e: E) => G): These } ``` @@ -1230,8 +1230,8 @@ Added in v1.0.0 ```ts export declare const bimap: { - (f: (e: E) => G, g: (a: A) => B): (self: These) => These - (self: These, f: (e: E) => G, g: (a: A) => B): These + (f: (e: E1) => E2, g: (a: A) => B): (self: These) => These + (self: These, f: (e: E1) => E2, g: (a: A) => B): These } ``` diff --git a/docs/modules/typeclass/Bicovariant.ts.md b/docs/modules/typeclass/Bicovariant.ts.md index c40f30161..acb05e592 100644 --- a/docs/modules/typeclass/Bicovariant.ts.md +++ b/docs/modules/typeclass/Bicovariant.ts.md @@ -12,6 +12,8 @@ Added in v1.0.0

Table of contents

+- [constructors](#constructors) + - [make](#make) - [type class](#type-class) - [Bicovariant (interface)](#bicovariant-interface) - [utils](#utils) @@ -21,6 +23,20 @@ Added in v1.0.0 --- +# constructors + +## make + +**Signature** + +```ts +export declare const make: ( + bimap: (self: Kind, f: (e: E1) => E2, g: (a: A) => B) => Kind +) => Bicovariant +``` + +Added in v1.0.0 + # type class ## Bicovariant (interface) @@ -29,10 +45,10 @@ Added in v1.0.0 ```ts export interface Bicovariant extends TypeClass { - readonly bimap: ( - f: (e: E1) => E2, - g: (a: A) => B - ) => (self: Kind) => Kind + readonly bimap: { + (f: (e: E1) => E2, g: (a: A) => B): (self: Kind) => Kind + (self: Kind, f: (e: E1) => E2, g: (a: A) => B): Kind + } } ``` @@ -50,11 +66,10 @@ Returns a default `bimap` composition. export declare const bimapComposition: ( CovariantF: Covariant, BicovariantG: Bicovariant -) => ( +) => ( + self: Kind>, f: (e: E1) => E2, g: (a: A) => B -) => ( - self: Kind> ) => Kind> ``` diff --git a/src/Either.ts b/src/Either.ts index f859391b6..b526b2f66 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -238,6 +238,41 @@ export const getEquivalence = ( isLeft(y) && EE(x.left, y.left) : isRight(y) && EA(x.right, y.right)) +/** + * @category instances + * @since 1.0.0 + */ +export const Bicovariant: bicovariant.Bicovariant = bicovariant.make(( + self, + f, + g +) => isLeft(self) ? left(f(self.left)) : right(g(self.right))) + +/** + * @dual + * @category mapping + * @since 1.0.0 + */ +export const bimap: { + (f: (e: E1) => E2, g: (a: A) => B): (self: Either) => Either + (self: Either, f: (e: E1) => E2, g: (a: A) => B): Either +} = Bicovariant.bimap + +/** + * Maps the `Left` side of an `Either` value to a new `Either` value. + * + * @param self - The input `Either` value to map. + * @param f - A transformation function to apply to the `Left` value of the input `Either`. + * + * @dual + * @category error handling + * @since 1.0.0 + */ +export const mapLeft: { + (f: (e: E) => G):
(self: Either) => Either + (self: Either, f: (e: E) => G): Either +} = bicovariant.mapLeft(Bicovariant) + /** * Maps the `Right` side of an `Either` value to a new `Either` value. * @@ -319,49 +354,6 @@ export const asUnit: (self: Either) => Either = covariant.a Covariant ) -/** - * Returns an effect whose Left and Right channels have been mapped by - * the specified pair of functions, `f` and `g`. - * - * @dual - * @category mapping - * @since 1.0.0 - */ -export const bimap: { - (f: (e: E) => G, g: (a: A) => B): (self: Either) => Either - (self: Either, f: (e: E) => G, g: (a: A) => B): Either -} = dual< - (f: (e: E) => G, g: (a: A) => B) => (self: Either) => Either, - (self: Either, f: (e: E) => G, g: (a: A) => B) => Either ->( - 3, - (self: Either, f: (e: E) => G, g: (a: A) => B): Either => - isLeft(self) ? left(f(self.left)) : right(g(self.right)) -) - -/** - * @category instances - * @since 1.0.0 - */ -export const Bicovariant: bicovariant.Bicovariant = { - bimap -} - -/** - * Maps the `Left` side of an `Either` value to a new `Either` value. - * - * @param self - The input `Either` value to map. - * @param f - A transformation function to apply to the `Left` value of the input `Either`. - * - * @dual - * @category error handling - * @since 1.0.0 - */ -export const mapLeft: { - (self: Either, f: (e: E) => G): Either - (f: (e: E) => G): (self: Either) => Either -} = bicovariant.mapLeft(Bicovariant) - /** * @category instances * @since 1.0.0 diff --git a/src/These.ts b/src/These.ts index f5d8b9a48..d72c3ef86 100644 --- a/src/These.ts +++ b/src/These.ts @@ -5,7 +5,7 @@ import type { Either, Left, Right } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" -import { constNull, constUndefined, dual, pipe } from "@fp-ts/core/Function" +import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { proto, structural } from "@fp-ts/core/internal/effect" import * as N from "@fp-ts/core/Number" @@ -382,7 +382,7 @@ export const liftEither = , E, B>( */ export const liftThese = , E, B>( f: (...a: A) => These -) => (...a: A): Validated => fromThese(f(...a)) +) => (...a: A): Validated => toValidated(f(...a)) /** * @category sequencing @@ -549,33 +549,30 @@ export const inspectBoth = ( } /** - * @dual - * @category mapping + * @category instances * @since 1.0.0 */ -export const bimap: { - (f: (e: E) => G, g: (a: A) => B): (self: These) => These - (self: These, f: (e: E) => G, g: (a: A) => B): These -} = dual< - (f: (e: E) => G, g: (a: A) => B) => (self: These) => These, - (self: These, f: (e: E) => G, g: (a: A) => B) => These ->( - 3, - (self: These, f: (e: E) => G, g: (a: A) => B): These => - isLeft(self) ? - left(f(self.left)) : - isRight(self) ? - right(g(self.right)) : - both(f(self.left), g(self.right)) +export const Bicovariant: bicovariant.Bicovariant = bicovariant.make(( + self, + f, + g +) => + isLeft(self) ? + left(f(self.left)) : + isRight(self) ? + right(g(self.right)) : + both(f(self.left), g(self.right)) ) /** - * @category instances + * @dual + * @category mapping * @since 1.0.0 */ -export const Bicovariant: bicovariant.Bicovariant = { - bimap -} +export const bimap: { + (f: (e: E1) => E2, g: (a: A) => B): (self: These) => These + (self: These, f: (e: E1) => E2, g: (a: A) => B): These +} = Bicovariant.bimap /** * Maps the `Left` side of an `These` value to a new `These` value. @@ -588,15 +585,15 @@ export const Bicovariant: bicovariant.Bicovariant = { * @since 1.0.0 */ export const mapLeft: { - (self: These, f: (e: E) => G): These (f: (e: E) => G): (self: These) => These + (self: These, f: (e: E) => G): These } = bicovariant.mapLeft(Bicovariant) /** * @category conversions * @since 1.0.0 */ -export const fromThese: (self: These) => Validated = mapLeft((e) => [e]) +export const toValidated: (self: These) => Validated = mapLeft((e) => [e]) /** * Maps the `Right` side of an `These` value to a new `These` value. @@ -1223,7 +1220,7 @@ export const bindThese = ( ): ( self: Validated ) => Validated => - bind(name, (a) => fromThese(f(a))) + bind(name, (a) => toValidated(f(a))) /** * Sequences the specified effect after this effect, but ignores the value diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index 92b233bb2..15c07d72c 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -10,11 +10,32 @@ import type { Covariant } from "@fp-ts/core/typeclass/Covariant" * @since 1.0.0 */ export interface Bicovariant extends TypeClass { - readonly bimap: ( + readonly bimap: { + ( + f: (e: E1) => E2, + g: (a: A) => B + ): (self: Kind) => Kind + ( + self: Kind, + f: (e: E1) => E2, + g: (a: A) => B + ): Kind + } +} + +/** + * @category constructors + * @since 1.0.0 + */ +export const make = ( + bimap: ( + self: Kind, f: (e: E1) => E2, g: (a: A) => B - ) => (self: Kind) => Kind -} + ) => Kind +): Bicovariant => ({ + bimap: dual(3, bimap) +}) /** * Returns a default `bimap` composition. @@ -25,12 +46,12 @@ export const bimapComposition = ( CovariantF: Covariant, BicovariantG: Bicovariant ) => - ( + ( + self: Kind>, f: (e: E1) => E2, g: (a: A) => B - ): (( - self: Kind> - ) => Kind>) => CovariantF.map(BicovariantG.bimap(f, g)) + ): Kind> => + pipe(self, CovariantF.map(BicovariantG.bimap(f, g))) /** * @since 1.0.0 @@ -45,7 +66,7 @@ export const mapLeft = ( (f: (e: E) => G) => (self: Kind) => Kind, (self: Kind, f: (e: E) => G) => Kind >(2, (self: Kind, f: (e: E) => G): Kind => - pipe(self, F.bimap(f, identity))) + F.bimap(self, f, identity)) /** * Returns a default `map` implementation. @@ -62,4 +83,4 @@ export const map = ( (f: (a: A) => B) => (self: Kind) => Kind, (self: Kind, f: (a: A) => B) => Kind >(2, (self: Kind, f: (a: A) => B): Kind => - pipe(self, F.bimap(identity, f))) + F.bimap(self, identity, f)) diff --git a/test/These.ts b/test/These.ts index 20b9aab12..56b7e8303 100644 --- a/test/These.ts +++ b/test/These.ts @@ -552,10 +552,10 @@ describe("These", () => { expect(_.fromEither(E.left("e"))).toEqual(_.left(["e"])) }) - it("fromThese", () => { - Util.deepStrictEqual(_.fromThese(_.right(1)), _.right(1)) - Util.deepStrictEqual(_.fromThese(_.left("e")), _.fail("e")) - Util.deepStrictEqual(_.fromThese(_.both("e", 1)), _.warn("e", 1)) + it("toValidated", () => { + Util.deepStrictEqual(_.toValidated(_.right(1)), _.right(1)) + Util.deepStrictEqual(_.toValidated(_.left("e")), _.fail("e")) + Util.deepStrictEqual(_.toValidated(_.both("e", 1)), _.warn("e", 1)) }) it("toEither", () => { diff --git a/test/typeclass/Bicovariant.ts b/test/typeclass/Bicovariant.ts index 5bc02c0f5..b6a0110d3 100644 --- a/test/typeclass/Bicovariant.ts +++ b/test/typeclass/Bicovariant.ts @@ -1,34 +1,29 @@ -import type { EitherTypeLambda } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" import { pipe } from "@fp-ts/core/Function" import * as RA from "@fp-ts/core/ReadonlyArray" import * as _ from "@fp-ts/core/typeclass/Bicovariant" import * as U from "../util" -export const Bicovariant: _.Bicovariant = { - bimap: (f, g) => (self) => E.isLeft(self) ? E.left(f(self.left)) : E.right(g(self.right)) -} - describe("Bicovariant", () => { it("mapLeft", () => { - const mapLeft = _.mapLeft(Bicovariant) + const mapLeft = _.mapLeft(E.Bicovariant) const f = (s: string) => s.length U.deepStrictEqual(pipe(E.right(1), mapLeft(f)), E.right(1)) U.deepStrictEqual(pipe(E.left("eee"), mapLeft(f)), E.left(3)) }) it("map", () => { - const map = _.map(Bicovariant) + const map = _.map(E.Bicovariant) const g = (n: number) => n * 2 U.deepStrictEqual(pipe(E.right(1), map(g)), E.right(2)) U.deepStrictEqual(pipe(E.left("eee"), map(g)), E.left("eee")) }) it("bimapComposition", () => { - const bimap = _.bimapComposition(RA.Covariant, Bicovariant) + const bimap = _.bimapComposition(RA.Covariant, E.Bicovariant) const f = (s: string) => s.length const g = (n: number) => n * 2 - U.deepStrictEqual(pipe([E.right(1), E.right(2), E.left("eee")], bimap(f, g)), [ + U.deepStrictEqual(bimap([E.right(1), E.right(2), E.left("eee")], f, g), [ E.right(2), E.right(4), E.left(3) From 79c9ae103c2718a831c82915e503ce2e2f4e2a08 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 17:20:28 +0100 Subject: [PATCH 157/255] Invariant: make dual --- docs/modules/typeclass/Contravariant.ts.md | 5 ++- docs/modules/typeclass/Covariant.ts.md | 5 ++- docs/modules/typeclass/Invariant.ts.md | 29 +++++++++++---- docs/modules/typeclass/Semigroup.ts.md | 5 ++- src/typeclass/Bicovariant.ts | 1 + src/typeclass/Contravariant.ts | 3 +- src/typeclass/Covariant.ts | 2 +- src/typeclass/Invariant.ts | 41 ++++++++++++++++------ src/typeclass/Semigroup.ts | 26 +++++++------- test/typeclass/Invariant.ts | 2 +- 10 files changed, 84 insertions(+), 35 deletions(-) diff --git a/docs/modules/typeclass/Contravariant.ts.md b/docs/modules/typeclass/Contravariant.ts.md index 6bac8e419..ab336bc37 100644 --- a/docs/modules/typeclass/Contravariant.ts.md +++ b/docs/modules/typeclass/Contravariant.ts.md @@ -82,7 +82,10 @@ Returns a default `imap` implementation. ```ts export declare const imap: ( contramap: (f: (b: B) => A) => (self: Kind) => Kind -) => (to: (a: A) => B, from: (b: B) => A) => (self: Kind) => Kind +) => { + (to: (a: A) => B, from: (b: B) => A): (self: Kind) => Kind + (self: Kind, to: (a: A) => B, from: (b: B) => A): Kind +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index 89a6e1269..d845a5ae8 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -128,7 +128,10 @@ Returns a default `imap` implementation. ```ts export declare const imap: ( map: (f: (a: A) => B) => (self: Kind) => Kind -) => (to: (a: A) => B, from: (b: B) => A) => (self: Kind) => Kind +) => { + (to: (a: A) => B, from: (b: B) => A): (self: Kind) => Kind + (self: Kind, to: (a: A) => B, from: (b: B) => A): Kind +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Invariant.ts.md b/docs/modules/typeclass/Invariant.ts.md index b05f74f35..4273e9e7e 100644 --- a/docs/modules/typeclass/Invariant.ts.md +++ b/docs/modules/typeclass/Invariant.ts.md @@ -12,6 +12,8 @@ Added in v1.0.0

Table of contents

+- [constructors](#constructors) + - [make](#make) - [type class](#type-class) - [Invariant (interface)](#invariant-interface) - [utils](#utils) @@ -21,6 +23,20 @@ Added in v1.0.0 --- +# constructors + +## make + +**Signature** + +```ts +export declare const make: ( + imap: (self: Kind, to: (a: A) => B, from: (b: B) => A) => Kind +) => Invariant +``` + +Added in v1.0.0 + # type class ## Invariant (interface) @@ -29,10 +45,10 @@ Added in v1.0.0 ```ts export interface Invariant extends TypeClass { - readonly imap: ( - to: (a: A) => B, - from: (b: B) => A - ) => (self: Kind) => Kind + readonly imap: { + (to: (a: A) => B, from: (b: B) => A): (self: Kind) => Kind + (self: Kind, to: (a: A) => B, from: (b: B) => A): Kind + } } ``` @@ -64,11 +80,10 @@ Returns a default `imap` composition. export declare const imapComposition: ( F: Invariant, G: Invariant -) => ( +) => ( + self: Kind>, to: (a: A) => B, from: (b: B) => A -) => ( - self: Kind> ) => Kind> ``` diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index dd6fc1ac2..54efdb521 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -350,7 +350,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const imap: (to: (a: A) => B, from: (b: B) => A) => (S: Semigroup
) => Semigroup +export declare const imap: { + (to: (a: A) => B, from: (b: B) => A): (self: Semigroup) => Semigroup + (self: Semigroup, to: (a: A) => B, from: (b: B) => A): Semigroup +} ``` Added in v1.0.0 diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index 15c07d72c..c7b8b5d0d 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -51,6 +51,7 @@ export const bimapComposition = ( f: (e: E1) => E2, g: (a: A) => B ): Kind> => + // TODO pipe(self, CovariantF.map(BicovariantG.bimap(f, g))) /** diff --git a/src/typeclass/Contravariant.ts b/src/typeclass/Contravariant.ts index 414bc890f..e8c3bc968 100644 --- a/src/typeclass/Contravariant.ts +++ b/src/typeclass/Contravariant.ts @@ -1,6 +1,7 @@ /** * @since 1.0.0 */ +import { dual, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" @@ -37,7 +38,7 @@ export const contramapComposition = */ export const imap = ( contramap: Contravariant["contramap"] -): Invariant["imap"] => (_, from) => contramap(from) +): Invariant["imap"] => dual(3, (self, _, from) => pipe(self, contramap(from))) // TODO remove pipe /** * @category constructors diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index 24478e28e..0146071e8 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -35,7 +35,7 @@ export const mapComposition = ( * @since 1.0.0 */ export const imap = (map: Covariant["map"]): Invariant["imap"] => - (to, _) => map(to) + dual(3, (self, to, _) => pipe(self, map(to))) /** * @category constructors diff --git a/src/typeclass/Invariant.ts b/src/typeclass/Invariant.ts index 2b7c19265..bf80c3394 100644 --- a/src/typeclass/Invariant.ts +++ b/src/typeclass/Invariant.ts @@ -2,17 +2,39 @@ * @since 1.0.0 */ import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" +import { dual } from "@fp-ts/core/internal/Function" /** * @category type class * @since 1.0.0 */ export interface Invariant extends TypeClass { - readonly imap: ( + readonly imap: { + ( + to: (a: A) => B, + from: (b: B) => A + ): (self: Kind) => Kind + ( + self: Kind, + to: (a: A) => B, + from: (b: B) => A + ): Kind + } +} + +/** + * @category constructors + * @since 1.0.0 + */ +export const make = ( + imap: ( + self: Kind, to: (a: A) => B, from: (b: B) => A - ) => (self: Kind) => Kind -} + ) => Kind +): Invariant => ({ + imap: dual(3, imap) +}) /** * Returns a default `imap` composition. @@ -22,13 +44,12 @@ export interface Invariant extends TypeClass { export const imapComposition = ( F: Invariant, G: Invariant -): (( - to: (a: A) => B, - from: (b: B) => A -) => ( - self: Kind> -) => Kind>) => - (to, from) => F.imap(G.imap(to, from), G.imap(from, to)) +) => + ( + self: Kind>, + to: (a: A) => B, + from: (b: B) => A + ): Kind> => F.imap(self, G.imap(to, from), G.imap(from, to)) /** * @since 1.0.0 diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index e6f6e77af..7358891a5 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -4,7 +4,7 @@ import type { TypeLambda } from "@fp-ts/core/HKT" import { dual } from "@fp-ts/core/internal/Function" import { fromIterable } from "@fp-ts/core/internal/ReadonlyArray" -import type * as invariant from "@fp-ts/core/typeclass/Invariant" +import * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Order } from "@fp-ts/core/typeclass/Order" import type * as product from "@fp-ts/core/typeclass/Product" import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" @@ -296,25 +296,27 @@ export const last = (): Semigroup => ) /** + * @category instances * @since 1.0.0 */ -export const imap = ( +export const Invariant: invariant.Invariant = invariant.make(( + S: Semigroup, to: (a: A) => B, from: (b: B) => A -) => - (S: Semigroup): Semigroup => - make( - (self, that) => to(S.combine(from(self), from(that))), - (self, collection) => to(S.combineMany(from(self), (fromIterable(collection)).map(from))) - ) +): Semigroup => + make( + (self, that) => to(S.combine(from(self), from(that))), + (self, collection) => to(S.combineMany(from(self), (fromIterable(collection)).map(from))) + ) +) /** - * @category instances * @since 1.0.0 */ -export const Invariant: invariant.Invariant = { - imap -} +export const imap: { + (to: (a: A) => B, from: (b: B) => A): (self: Semigroup) => Semigroup + (self: Semigroup, to: (a: A) => B, from: (b: B) => A): Semigroup +} = Invariant.imap /** * @category instances diff --git a/test/typeclass/Invariant.ts b/test/typeclass/Invariant.ts index 2076dbed4..2d2aae648 100644 --- a/test/typeclass/Invariant.ts +++ b/test/typeclass/Invariant.ts @@ -9,7 +9,7 @@ import * as U from "../util" describe("Invariant", () => { it("imapComposition", () => { const imap = _.imapComposition(semigroup.Invariant, O.Invariant) - const S = pipe(O.getOptionalMonoid(String.Semigroup), imap(s => [s], ([s]) => s)) + const S = imap(O.getOptionalMonoid(String.Semigroup), s => [s], ([s]) => s) U.deepStrictEqual(S.combine(O.none(), O.none()), O.none()) U.deepStrictEqual(S.combine(O.none(), O.some(["b"])), O.some(["b"])) U.deepStrictEqual(S.combine(O.some(["a"]), O.none()), O.some(["a"])) From 4f9e99a7d58213e88e809604ccf70f1b37ea5156 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 17:36:11 +0100 Subject: [PATCH 158/255] Contravariant: make dual --- docs/modules/Predicate.ts.md | 28 +++++++---- docs/modules/typeclass/Bicovariant.ts.md | 2 +- docs/modules/typeclass/Contravariant.ts.md | 16 +++--- docs/modules/typeclass/Invariant.ts.md | 2 +- docs/modules/typeclass/Order.ts.md | 28 +++++------ src/Predicate.ts | 25 ++++++---- src/typeclass/Bicovariant.ts | 2 +- src/typeclass/Contravariant.ts | 58 +++++++++++++--------- src/typeclass/Covariant.ts | 20 ++++---- src/typeclass/Equivalence.ts | 15 +++--- src/typeclass/Invariant.ts | 2 +- src/typeclass/Order.ts | 1 + test/typeclass/Contravariant.ts | 3 +- 13 files changed, 115 insertions(+), 87 deletions(-) diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index e6acbc0ba..a05606208 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -12,6 +12,8 @@ Added in v1.0.0

Table of contents

+- [combinators](#combinators) + - [contramap](#contramap) - [constructors](#constructors) - [id](#id) - [do notation](#do-notation) @@ -45,7 +47,6 @@ Added in v1.0.0 - [any](#any) - [appendElement](#appendelement) - [compose](#compose) - - [contramap](#contramap) - [not](#not) - [of](#of) - [or](#or) @@ -56,6 +57,21 @@ Added in v1.0.0 --- +# combinators + +## contramap + +**Signature** + +```ts +export declare const contramap: { + (f: (b: B) => A): (self: Predicate
) => Predicate + (self: Predicate, f: (b: B) => A): Predicate +} +``` + +Added in v1.0.0 + # constructors ## id @@ -348,16 +364,6 @@ export declare const compose: ( Added in v1.0.0 -## contramap - -**Signature** - -```ts -export declare const contramap: (f: (b: B) => A) => (self: Predicate) => Predicate -``` - -Added in v1.0.0 - ## not **Signature** diff --git a/docs/modules/typeclass/Bicovariant.ts.md b/docs/modules/typeclass/Bicovariant.ts.md index acb05e592..1dfb0cea9 100644 --- a/docs/modules/typeclass/Bicovariant.ts.md +++ b/docs/modules/typeclass/Bicovariant.ts.md @@ -58,7 +58,7 @@ Added in v1.0.0 ## bimapComposition -Returns a default `bimap` composition. +Returns a default ternary `bimap` composition. **Signature** diff --git a/docs/modules/typeclass/Contravariant.ts.md b/docs/modules/typeclass/Contravariant.ts.md index ab336bc37..914928d08 100644 --- a/docs/modules/typeclass/Contravariant.ts.md +++ b/docs/modules/typeclass/Contravariant.ts.md @@ -30,7 +30,7 @@ Added in v1.0.0 ```ts export declare const make: ( - contramap: (f: (b: B) => A) => (self: Kind) => Kind + contramap: (self: Kind, f: (b: B) => A) => Kind ) => Contravariant ``` @@ -44,7 +44,10 @@ Added in v1.0.0 ```ts export interface Contravariant extends Invariant { - readonly contramap: (f: (b: B) => A) => (self: Kind) => Kind + readonly contramap: { + (f: (b: B) => A): (self: Kind) => Kind + (self: Kind, f: (b: B) => A): Kind + } } ``` @@ -56,7 +59,7 @@ Added in v1.0.0 Composing two contravariant functors yields a Covariant functor. -Returns a default `map` composition. +Returns a default binary `map` composition. **Signature** @@ -64,10 +67,9 @@ Returns a default `map` composition. export declare const contramapComposition: ( F: Contravariant, G: Contravariant -) => ( +) => ( + self: Kind>, f: (a: A) => B -) => ( - self: Kind> ) => Kind> ``` @@ -81,7 +83,7 @@ Returns a default `imap` implementation. ```ts export declare const imap: ( - contramap: (f: (b: B) => A) => (self: Kind) => Kind + contramap: (self: Kind, f: (b: B) => A) => Kind ) => { (to: (a: A) => B, from: (b: B) => A): (self: Kind) => Kind (self: Kind, to: (a: A) => B, from: (b: B) => A): Kind diff --git a/docs/modules/typeclass/Invariant.ts.md b/docs/modules/typeclass/Invariant.ts.md index 4273e9e7e..0849357ac 100644 --- a/docs/modules/typeclass/Invariant.ts.md +++ b/docs/modules/typeclass/Invariant.ts.md @@ -72,7 +72,7 @@ Added in v1.0.0 ## imapComposition -Returns a default `imap` composition. +Returns a default ternary `imap` composition. **Signature** diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index 9bce7ed7c..7e8d98467 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -14,6 +14,7 @@ Added in v1.0.0 - [combinators](#combinators) - [array](#array) + - [contramap](#contramap) - [struct](#struct) - [tuple](#tuple) - [constructors](#constructors) @@ -36,7 +37,6 @@ Added in v1.0.0 - [utils](#utils) - [between](#between) - [clamp](#clamp) - - [contramap](#contramap) - [greaterThan](#greaterthan) - [greaterThanOrEqualTo](#greaterthanorequalto) - [lessThan](#lessthan) @@ -64,6 +64,19 @@ export declare const array: (O: Order) => Order Added in v1.0.0 +## contramap + +**Signature** + +```ts +export declare const contramap: { + (f: (b: B) => A): (self: Order) => Order + (self: Order, f: (b: B) => A): Order +} +``` + +Added in v1.0.0 + ## struct This function creates and returns a new `Order` for a struct of values based on the given `Order`s @@ -272,19 +285,6 @@ export declare const clamp: (O: Order) => { Added in v1.0.0 -## contramap - -**Signature** - -```ts -export declare const contramap: { - (f: (b: B) => A): (self: Order) => Order - (self: Order, f: (b: B) => A): Order -} -``` - -Added in v1.0.0 - ## greaterThan Test whether one value is _strictly greater than_ another. diff --git a/src/Predicate.ts b/src/Predicate.ts index f3d4a4359..8a493aa5a 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -82,21 +82,28 @@ export const compose = (bc: Refinement) => (ab: Refinement): Refinement => (i): i is C => ab(i) && bc(i) /** + * @category instances * @since 1.0.0 */ -export const contramap = (f: (b: B) => A) => - (self: Predicate): Predicate => (b) => self(f(b)) - -const imap = contravariant.imap(contramap) +export const Contravariant: contravariant.Contravariant = contravariant.make(< + A, + B +>( + self: Predicate, + f: (b: B) => A +): Predicate => (b) => self(f(b))) /** - * @category instances + * @dual + * @category combinators * @since 1.0.0 */ -export const Contravariant: contravariant.Contravariant = { - imap, - contramap -} +export const contramap: { + (f: (b: B) => A): (self: Predicate) => Predicate + (self: Predicate, f: (b: B) => A): Predicate +} = Contravariant.contramap + +const imap = Contravariant.imap /** * @category instances diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index c7b8b5d0d..5a65c9ac9 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -38,7 +38,7 @@ export const make = ( }) /** - * Returns a default `bimap` composition. + * Returns a default ternary `bimap` composition. * * @since 1.0.0 */ diff --git a/src/typeclass/Contravariant.ts b/src/typeclass/Contravariant.ts index e8c3bc968..4894de27e 100644 --- a/src/typeclass/Contravariant.ts +++ b/src/typeclass/Contravariant.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { dual, pipe } from "@fp-ts/core/Function" +import { dual } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" @@ -10,26 +10,46 @@ import type { Invariant } from "@fp-ts/core/typeclass/Invariant" * @since 1.0.0 */ export interface Contravariant extends Invariant { - readonly contramap: ( - f: (b: B) => A - ) => (self: Kind) => Kind + readonly contramap: { + ( + f: (b: B) => A + ): (self: Kind) => Kind + ( + self: Kind, + f: (b: B) => A + ): Kind + } } +/** + * @category constructors + * @since 1.0.0 + */ +export const make = ( + contramap: ( + self: Kind, + f: (b: B) => A + ) => Kind +): Contravariant => ({ + contramap: dual(2, contramap), + imap: imap(contramap) +}) + /** * Composing two contravariant functors yields a Covariant functor. * - * Returns a default `map` composition. + * Returns a default binary `map` composition. * * @since 1.0.0 */ export const contramapComposition = ( F: Contravariant, G: Contravariant -): (( - f: (a: A) => B -) => ( - self: Kind> -) => Kind>) => f => F.contramap(G.contramap(f)) +) => + ( + self: Kind>, + f: (a: A) => B + ): Kind> => F.contramap(self, G.contramap(f)) /** * Returns a default `imap` implementation. @@ -37,16 +57,8 @@ export const contramapComposition = * @since 1.0.0 */ export const imap = ( - contramap: Contravariant["contramap"] -): Invariant["imap"] => dual(3, (self, _, from) => pipe(self, contramap(from))) // TODO remove pipe - -/** - * @category constructors - * @since 1.0.0 - */ -export const make = ( - contramap: Contravariant["contramap"] -): Contravariant => ({ - contramap, - imap: imap(contramap) -}) + contramap: ( + self: Kind, + f: (b: B) => A + ) => Kind +): Invariant["imap"] => dual(3, (self, _, from) => contramap(self, from)) diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index 0146071e8..fd9ddb9fd 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -15,6 +15,15 @@ export interface Covariant extends Invariant { ) => (self: Kind) => Kind } +/** + * @category constructors + * @since 1.0.0 + */ +export const make = (map: Covariant["map"]): Covariant => ({ + map, + imap: imap(map) +}) + /** * Returns a default `map` composition. * @@ -35,16 +44,7 @@ export const mapComposition = ( * @since 1.0.0 */ export const imap = (map: Covariant["map"]): Invariant["imap"] => - dual(3, (self, to, _) => pipe(self, map(to))) - -/** - * @category constructors - * @since 1.0.0 - */ -export const make = (map: Covariant["map"]): Covariant => ({ - map, - imap: imap(map) -}) + dual(3, (self, to, _) => pipe(self, map(to))) // TODO remove pipe /** * @category mapping diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 7de4427d2..89147af43 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -169,19 +169,20 @@ export const getMonoid = (): Monoid> => monoid.fromSemigroup(getSemigroup(), empty) /** - * @category combinators + * @category instances * @since 1.0.0 */ -export const contramap = (f: (b: B) => A) => - (self: Equivalence): Equivalence => (x, y) => self(f(x), f(y)) +export const Contravariant: contravariant.Contravariant = contravariant.make( + (self: Equivalence, f: (b: B) => A): Equivalence => (x, y) => self(f(x), f(y)) +) /** - * @category instances + * @dual + * @category combinators * @since 1.0.0 */ -export const Contravariant: contravariant.Contravariant = contravariant.make( - contramap -) +export const contramap = (f: (b: B) => A) => + (self: Equivalence): Equivalence => (x, y) => self(f(x), f(y)) /** * @category instances diff --git a/src/typeclass/Invariant.ts b/src/typeclass/Invariant.ts index bf80c3394..55f91498a 100644 --- a/src/typeclass/Invariant.ts +++ b/src/typeclass/Invariant.ts @@ -37,7 +37,7 @@ export const make = ( }) /** - * Returns a default `imap` composition. + * Returns a default ternary `imap` composition. * * @since 1.0.0 */ diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 67278fe3e..caa4b72fe 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -145,6 +145,7 @@ export const reverse = (O: Order): Order => /** * @dual + * @category combinators * @since 1.0.0 */ export const contramap: { diff --git a/test/typeclass/Contravariant.ts b/test/typeclass/Contravariant.ts index 5f8e50fd5..e7008f948 100644 --- a/test/typeclass/Contravariant.ts +++ b/test/typeclass/Contravariant.ts @@ -1,4 +1,3 @@ -import { pipe } from "@fp-ts/core/Function" import * as P from "@fp-ts/core/Predicate" import * as S from "@fp-ts/core/String" import * as _ from "@fp-ts/core/typeclass/Contravariant" @@ -9,7 +8,7 @@ describe("Contravariant", () => { it("mapComposition", () => { const map = _.contramapComposition(P.Contravariant, P.Contravariant) const emptyString: P.Predicate> = p => p("") === true - const a = pipe(emptyString, map(s => s.length)) + const a = map(emptyString, s => s.length) U.deepStrictEqual(a(S.isString), false) U.deepStrictEqual(a(n => n === 0), true) }) From ec9b004afb3224c078fc1382ac4cb7b4877a8515 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 17:55:12 +0100 Subject: [PATCH 159/255] Covariant: make dual --- docs/modules/ReadonlyArray.ts.md | 10 ++++-- docs/modules/typeclass/Covariant.ts.md | 9 +++-- src/Either.ts | 29 ++++++---------- src/Identity.ts | 4 +-- src/Option.ts | 28 ++++++--------- src/ReadonlyArray.ts | 47 ++++++++++++++++---------- src/typeclass/Bicovariant.ts | 6 ++-- src/typeclass/Contravariant.ts | 9 ++--- src/typeclass/Covariant.ts | 18 ++++++---- test/limbo/CovariantWithIndex.ts | 18 +++++----- test/typeclass/CovariantWithIndex.ts | 12 +++---- 11 files changed, 97 insertions(+), 93 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 35936b750..c5c0b005e 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -1455,7 +1455,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const map: (f: (a: A) => B) => (self: readonly A[]) => B[] +export declare const map: { + (f: (a: A) => B): (self: readonly A[]) => B[] + (self: readonly A[], f: (a: A) => B): B[] +} ``` Added in v1.0.0 @@ -1465,7 +1468,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const mapNonEmpty: (f: (a: A) => B) => (self: readonly [A, ...A[]]) => [B, ...B[]] +export declare const mapNonEmpty: { + (f: (a: A) => B): (self: readonly [A, ...A[]]) => [B, ...B[]] + (self: readonly [A, ...A[]], f: (a: A) => B): [B, ...B[]] +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index d845a5ae8..ccc229729 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -36,7 +36,7 @@ Added in v1.0.0 ```ts export declare const make: ( - map: (f: (a: A) => B) => (self: Kind) => Kind + map: (self: Kind, f: (a: A) => B) => Kind ) => Covariant ``` @@ -111,7 +111,10 @@ Added in v1.0.0 ```ts export interface Covariant extends Invariant { - readonly map: (f: (a: A) => B) => (self: Kind) => Kind + readonly map: { + (f: (a: A) => B): (self: Kind) => Kind + (self: Kind, f: (a: A) => B): Kind + } } ``` @@ -127,7 +130,7 @@ Returns a default `imap` implementation. ```ts export declare const imap: ( - map: (f: (a: A) => B) => (self: Kind) => Kind + map: (self: Kind, f: (a: A) => B) => Kind ) => { (to: (a: A) => B, from: (b: B) => A): (self: Kind) => Kind (self: Kind, to: (a: A) => B, from: (b: B) => A): Kind diff --git a/src/Either.ts b/src/Either.ts index b526b2f66..65f8af3aa 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -273,6 +273,15 @@ export const mapLeft: { (self: Either, f: (e: E) => G): Either } = bicovariant.mapLeft(Bicovariant) +/** + * @category instances + * @since 1.0.0 + */ +export const Covariant: covariant.Covariant = covariant.make(( + self: Either, + f: (a: A) => B +): Either => isRight(self) ? right(f(self.right)) : self) + /** * Maps the `Right` side of an `Either` value to a new `Either` value. * @@ -286,25 +295,9 @@ export const mapLeft: { export const map: { (f: (a: A) => B): (self: Either) => Either (self: Either, f: (a: A) => B): Either -} = dual< - (f: (a: A) => B) => (self: Either) => Either, - (self: Either, f: (a: A) => B) => Either ->( - 2, - (self: Either, f: (a: A) => B): Either => - isRight(self) ? right(f(self.right)) : self -) - -const imap = covariant.imap(map) +} = Covariant.map -/** - * @category instances - * @since 1.0.0 - */ -export const Covariant: covariant.Covariant = { - imap, - map -} +const imap = Covariant.imap /** * @category instances diff --git a/src/Identity.ts b/src/Identity.ts index be9a592d1..8edb0141e 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -49,9 +49,7 @@ export interface IdentityTypeLambdaFix extends TypeLambda { */ export const Covariant: covariant.Covariant = covariant.make< IdentityTypeLambda ->( - f => self => f(self) -) +>((self, f) => f(self)) /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index 56387c1e5..a18b937d9 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -589,6 +589,15 @@ export const getOrThrow = (self: Option): A => { // mapping // ------------------------------------------------------------------------------------- +/** + * @category mapping + * @since 1.0.0 + */ +export const Covariant: covariant.Covariant = covariant.make(( + self: Option, + f: (a: A) => B +): Option => isNone(self) ? none() : some(f(self.value))) + /** * Maps the `Some` side of an `Option` value to a new `Option` value. * @@ -602,15 +611,9 @@ export const getOrThrow = (self: Option): A => { export const map: { (f: (a: A) => B): (self: Option) => Option (self: Option, f: (a: A) => B): Option -} = dual< - (f: (a: A) => B) => (self: Option) => Option, - (self: Option, f: (a: A) => B) => Option ->( - 2, - (self: Option, f: (a: A) => B): Option => isNone(self) ? none() : some(f(self.value)) -) +} = Covariant.map -const imap = covariant.imap(map) +const imap = Covariant.imap /** * @category mapping @@ -620,15 +623,6 @@ export const Invariant: invariant.Invariant = { imap } -/** - * @category mapping - * @since 1.0.0 - */ -export const Covariant: covariant.Covariant = { - imap, - map -} - /** * @category mapping * @since 1.0.0 diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 1c2b43ac0..5084a483d 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -5,7 +5,7 @@ */ import type { Either } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" -import { identity, pipe } from "@fp-ts/core/Function" +import { dual, identity, pipe } from "@fp-ts/core/Function" import type { LazyArg } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" @@ -1214,19 +1214,23 @@ export const of = (a: A): NonEmptyArray => [a] export const empty: () => Array = () => [] /** + * @dual * @category mapping * @since 1.0.0 */ -export const map = (f: (a: A) => B): (self: ReadonlyArray) => Array => - mapWithIndex((a) => f(a)) - -/** - * @category mapping - * @since 1.0.0 - */ -export const mapNonEmpty = ( - f: (a: A) => B -): (self: NonEmptyReadonlyArray) => NonEmptyArray => mapNonEmptyWithIndex(f) +export const mapNonEmpty: { + (f: (a: A) => B): (self: readonly [A, ...Array]) => [B, ...Array] + (self: readonly [A, ...Array], f: (a: A) => B): [B, ...Array] +} = dual< + ( + f: (a: A) => B + ) => (self: NonEmptyReadonlyArray) => NonEmptyArray, + (self: NonEmptyReadonlyArray, f: (a: A) => B) => NonEmptyArray +>( + 2, + (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray => + pipe(self, mapNonEmptyWithIndex(f)) +) /** * @category mapping @@ -1265,16 +1269,25 @@ export const Of: of_.Of = { */ export const Do: ReadonlyArray<{}> = of_.Do(Of) -const imap = covariant.imap(map) - /** * @category instances * @since 1.0.0 */ -export const Covariant: covariant.Covariant = { - imap, - map -} +export const Covariant: covariant.Covariant = covariant.make(( + self: ReadonlyArray, + f: (a: A) => B +): ReadonlyArray => self.map(a => f(a))) + +/** + * @category mapping + * @since 1.0.0 + */ +export const map: { + (f: (a: A) => B): (self: ReadonlyArray) => Array + (self: ReadonlyArray, f: (a: A) => B): Array +} = Covariant.map as any + +const imap = Covariant.imap /** * @category instances diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index 5a65c9ac9..aa3f867e0 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { dual, identity, pipe } from "@fp-ts/core/Function" +import { dual, identity } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" @@ -50,9 +50,7 @@ export const bimapComposition = ( self: Kind>, f: (e: E1) => E2, g: (a: A) => B - ): Kind> => - // TODO - pipe(self, CovariantF.map(BicovariantG.bimap(f, g))) + ): Kind> => CovariantF.map(self, BicovariantG.bimap(f, g)) /** * @since 1.0.0 diff --git a/src/typeclass/Contravariant.ts b/src/typeclass/Contravariant.ts index 4894de27e..c9677d5a3 100644 --- a/src/typeclass/Contravariant.ts +++ b/src/typeclass/Contravariant.ts @@ -11,13 +11,8 @@ import type { Invariant } from "@fp-ts/core/typeclass/Invariant" */ export interface Contravariant extends Invariant { readonly contramap: { - ( - f: (b: B) => A - ): (self: Kind) => Kind - ( - self: Kind, - f: (b: B) => A - ): Kind + (f: (b: B) => A): (self: Kind) => Kind + (self: Kind, f: (b: B) => A): Kind } } diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index fd9ddb9fd..d973d4563 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -10,17 +10,20 @@ import type { Invariant } from "@fp-ts/core/typeclass/Invariant" * @since 1.0.0 */ export interface Covariant extends Invariant { - readonly map: ( - f: (a: A) => B - ) => (self: Kind) => Kind + readonly map: { + (f: (a: A) => B): (self: Kind) => Kind + (self: Kind, f: (a: A) => B): Kind + } } /** * @category constructors * @since 1.0.0 */ -export const make = (map: Covariant["map"]): Covariant => ({ - map, +export const make = ( + map: (self: Kind, f: (a: A) => B) => Kind +): Covariant => ({ + map: dual(2, map), imap: imap(map) }) @@ -43,8 +46,9 @@ export const mapComposition = ( * * @since 1.0.0 */ -export const imap = (map: Covariant["map"]): Invariant["imap"] => - dual(3, (self, to, _) => pipe(self, map(to))) // TODO remove pipe +export const imap = ( + map: (self: Kind, f: (a: A) => B) => Kind +): Invariant["imap"] => dual(3, (self, to, _) => map(self, to)) /** * @category mapping diff --git a/test/limbo/CovariantWithIndex.ts b/test/limbo/CovariantWithIndex.ts index d9e8fb7ec..f4a2efa23 100644 --- a/test/limbo/CovariantWithIndex.ts +++ b/test/limbo/CovariantWithIndex.ts @@ -3,7 +3,7 @@ */ import { pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import type { Covariant } from "@fp-ts/core/typeclass/Covariant" +// import type { Covariant } from "@fp-ts/core/typeclass/Covariant" /** * @category type class @@ -30,11 +30,11 @@ export const mapWithIndexComposition = Kind>) => (f) => F.mapWithIndex((ga, i) => pipe(ga, G.mapWithIndex((a, j) => f(a, [i, j])))) -/** - * Returns a default `map` implementation. - * - * @since 1.0.0 - */ -export const map = ( - F: CovariantWithIndex -): Covariant["map"] => (f) => F.mapWithIndex(f) +// /** +// * Returns a default `map` implementation. +// * +// * @since 1.0.0 +// */ +// export const map = ( +// F: CovariantWithIndex +// ): Covariant["map"] => (f) => F.mapWithIndex(f) diff --git a/test/typeclass/CovariantWithIndex.ts b/test/typeclass/CovariantWithIndex.ts index 0bbe11bc8..d038fb7bd 100644 --- a/test/typeclass/CovariantWithIndex.ts +++ b/test/typeclass/CovariantWithIndex.ts @@ -22,10 +22,10 @@ describe("CovariantWithIndex", () => { ]]) }) - it("map", () => { - const map = _.map(CovariantWithIndex) - const f = (a: string) => a + "!" - U.deepStrictEqual(pipe([], map(f)), []) - U.deepStrictEqual(pipe(["a", "b", "c"], map(f)), ["a!", "b!", "c!"]) - }) + // it("map", () => { + // const map = _.map(CovariantWithIndex) + // const f = (a: string) => a + "!" + // U.deepStrictEqual(pipe([], map(f)), []) + // U.deepStrictEqual(pipe(["a", "b", "c"], map(f)), ["a!", "b!", "c!"]) + // }) }) From 64cf9740c8fdcdcbf0e9f9c261d3231849cb2f44 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 18:28:40 +0100 Subject: [PATCH 160/255] Order: make dual --- docs/modules/typeclass/Order.ts.md | 13 +++-- src/Option.ts | 2 +- src/typeclass/Bicovariant.ts | 15 ++--- src/typeclass/Order.ts | 94 +++++++++++++----------------- test/typeclass/Order.ts | 4 ++ 5 files changed, 58 insertions(+), 70 deletions(-) diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index 7e8d98467..513ef68ef 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -18,7 +18,7 @@ Added in v1.0.0 - [struct](#struct) - [tuple](#tuple) - [constructors](#constructors) - - [fromCompare](#fromcompare) + - [make](#make) - [instances](#instances) - [Contravariant](#contravariant) - [Invariant](#invariant) @@ -111,14 +111,12 @@ Added in v1.0.0 # constructors -## fromCompare - -Main constructor. +## make **Signature** ```ts -export declare const fromCompare: (compare: (self: A, that: A) => 0 | 1 | -1) => Order +export declare const make: (compare: (self: A, that: A) => -1 | 0 | 1) => Order ``` Added in v1.0.0 @@ -233,7 +231,10 @@ Added in v1.0.0 ```ts export interface Order { - readonly compare: (self: A, that: A) => -1 | 0 | 1 + readonly compare: { + (that: A): (self: A) => -1 | 0 | 1 + (self: A, that: A): -1 | 0 | 1 + } } ``` diff --git a/src/Option.ts b/src/Option.ts index a18b937d9..d5715c20f 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1449,7 +1449,7 @@ export const getEquivalence = (E: Equivalence): Equivalence> => * @since 1.0.0 */ export const getOrder = (O: Order): Order> => - order.fromCompare((self, that) => + order.make((self, that) => isSome(self) ? (isSome(that) ? O.compare(self.value, that.value) : 1) : -1 ) diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index aa3f867e0..b36c4041c 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -74,12 +74,9 @@ export const mapLeft = ( */ export const map = ( F: Bicovariant -): { - (f: (a: A) => B): (self: Kind) => Kind - (self: Kind, f: (a: A) => B): Kind -} => - dual< - (f: (a: A) => B) => (self: Kind) => Kind, - (self: Kind, f: (a: A) => B) => Kind - >(2, (self: Kind, f: (a: A) => B): Kind => - F.bimap(self, identity, f)) +): Covariant["map"] => + dual( + 2, + (self: Kind, f: (a: A) => B): Kind => + F.bimap(self, identity, f) + ) diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index caa4b72fe..4e99242d9 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -17,7 +17,10 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Order { - readonly compare: (self: A, that: A) => -1 | 0 | 1 + readonly compare: { + (that: A): (self: A) => -1 | 0 | 1 + (self: A, that: A): -1 | 0 | 1 + } } /** @@ -29,46 +32,38 @@ export interface OrderTypeLambda extends TypeLambda { } /** - * @category instances + * @category constructors * @since 1.0.0 */ -export const string: Order = { - compare: (self, that) => self < that ? -1 : self > that ? 1 : 0 -} +export const make = ( + compare: (self: A, that: A) => -1 | 0 | 1 +): Order => ({ + compare: dual(2, (self, that) => self === that ? 0 : compare(self, that)) +}) /** * @category instances * @since 1.0.0 */ -export const number: Order = { - compare: (self, that) => self < that ? -1 : self > that ? 1 : 0 -} +export const string: Order = make((self, that) => self < that ? -1 : 1) /** * @category instances * @since 1.0.0 */ -export const boolean: Order = { - compare: (self, that) => self < that ? -1 : self > that ? 1 : 0 -} +export const number: Order = make((self, that) => self < that ? -1 : 1) /** * @category instances * @since 1.0.0 */ -export const bigint: Order = { - compare: (self, that) => self < that ? -1 : self > that ? 1 : 0 -} +export const boolean: Order = make((self, that) => self < that ? -1 : 1) /** - * Main constructor. - * - * @category constructors + * @category instances * @since 1.0.0 */ -export const fromCompare = (compare: Order["compare"]): Order => ({ - compare: (self, that) => self === that ? 0 : compare(self, that) -}) +export const bigint: Order = make((self, that) => self < that ? -1 : 1) /** * This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. @@ -82,7 +77,7 @@ export const fromCompare = (compare: Order["compare"]): Order => ({ export const tuple = >( ...orders: { readonly [K in keyof A]: Order } ): Order> => - fromCompare((self, that) => { + make((self, that) => { let i = 0 for (; i < orders.length - 1; i++) { const r = orders[i].compare(self[i], that[i]) @@ -103,7 +98,7 @@ export const tuple = >( * @since 1.0.0 */ export const array = (O: Order): Order> => - fromCompare((self, that) => { + make((self, that) => { const aLen = self.length const bLen = that.length const len = Math.min(aLen, bLen) @@ -125,8 +120,8 @@ export const array = (O: Order): Order> => */ export const struct = (orders: { readonly [K in keyof A]: Order }): Order< { readonly [K in keyof A]: A[K] } -> => ({ - compare: (self, that) => { +> => + make((self, that) => { for (const key of Object.keys(orders)) { const o = orders[key].compare(self[key], that[key]) if (o !== 0) { @@ -134,31 +129,12 @@ export const struct = (orders: { readonly [K in keyof A]: Order }): Ord } } return 0 - } -}) + }) /** * @since 1.0.0 */ -export const reverse = (O: Order): Order => - fromCompare((self, that) => O.compare(that, self)) - -/** - * @dual - * @category combinators - * @since 1.0.0 - */ -export const contramap: { - (f: (b: B) => A): (self: Order) => Order - (self: Order, f: (b: B) => A): Order -} = dual< - (f: (b: B) => A) => (self: Order) => Order, - (self: Order, f: (b: B) => A) => Order ->( - 2, - (self: Order, f: (b: B) => A): Order => - fromCompare((b1, b2) => self.compare(f(b1), f(b2))) -) +export const reverse = (O: Order): Order => make((self, that) => O.compare(that, self)) /** * @category instances @@ -167,7 +143,7 @@ export const contramap: { export const getSemigroup = (): Semigroup> => semigroup.make( (O1, O2) => - fromCompare((self, that) => { + make((self, that) => { const out = O1.compare(self, that) if (out !== 0) { return out @@ -175,7 +151,7 @@ export const getSemigroup = (): Semigroup> => return O2.compare(self, that) }), (self, collection) => - fromCompare((a1, a2) => { + make((a1, a2) => { let out = self.compare(a1, a2) if (out !== 0) { return out @@ -190,7 +166,7 @@ export const getSemigroup = (): Semigroup> => }) ) -const empty: Order = fromCompare(() => 0) +const empty: Order = make(() => 0) /** * @category instances @@ -198,16 +174,26 @@ const empty: Order = fromCompare(() => 0) */ export const getMonoid = (): Monoid> => monoid.fromSemigroup(getSemigroup(), empty) -const imap = contravariant.imap(contramap) - /** * @category instances * @since 1.0.0 */ -export const Contravariant: contravariant.Contravariant = { - imap, - contramap -} +export const Contravariant: contravariant.Contravariant = contravariant.make(< + A, + B +>(self: Order, f: (b: B) => A): Order => make((b1, b2) => self.compare(f(b1), f(b2)))) + +/** + * @dual + * @category combinators + * @since 1.0.0 + */ +export const contramap: { + (f: (b: B) => A): (self: Order) => Order + (self: Order, f: (b: B) => A): Order +} = Contravariant.contramap + +const imap = Contravariant.imap /** * @category instances diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index b0379e29a..5ee002070 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -6,6 +6,10 @@ import * as U from "../util" describe("Order", () => { it("exports", () => { expect(_.Contravariant).exist + expect(_.string).exist + expect(_.number).exist + expect(_.boolean).exist + expect(_.bigint).exist }) it("bigint", () => { From e71e2b1c51740c77b84e1fb9b83f344cadee1d8b Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 18:40:43 +0100 Subject: [PATCH 161/255] Equivalence: make dual --- docs/modules/typeclass/Equivalence.ts.md | 14 ++++++++- src/Either.ts | 4 ++- src/Option.ts | 5 +++- src/These.ts | 4 ++- src/typeclass/Bicovariant.ts | 10 +++---- src/typeclass/Chainable.ts | 22 ++------------ src/typeclass/Compactable.ts | 10 +++---- src/typeclass/Covariant.ts | 10 ++----- src/typeclass/Equivalence.ts | 38 +++++++++++++++--------- 9 files changed, 60 insertions(+), 57 deletions(-) diff --git a/docs/modules/typeclass/Equivalence.ts.md b/docs/modules/typeclass/Equivalence.ts.md index 432e1fbf9..f89c9e06e 100644 --- a/docs/modules/typeclass/Equivalence.ts.md +++ b/docs/modules/typeclass/Equivalence.ts.md @@ -23,6 +23,7 @@ Added in v1.0.0 - [struct](#struct) - [tuple](#tuple) - [constructors](#constructors) + - [make](#make) - [strict](#strict) - [instances](#instances) - [Contravariant](#contravariant) @@ -115,6 +116,16 @@ Added in v1.0.0 # constructors +## make + +**Signature** + +```ts +export declare const make: (equivalent: (self: A, that: A) => boolean) => Equivalence +``` + +Added in v1.0.0 + ## strict Return an `Equivalence` that uses strict equality (===) to compare values @@ -247,7 +258,8 @@ Added in v1.0.0 ```ts export interface Equivalence { - (x: A, y: A): boolean + (that: A): (self: A) => boolean + (self: A, that: A): boolean } ``` diff --git a/src/Either.ts b/src/Either.ts index 65f8af3aa..da30bd60e 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -16,6 +16,7 @@ import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" import * as chainable from "@fp-ts/core/typeclass/Chainable" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" +import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" @@ -232,11 +233,12 @@ export const getEquivalence = ( EE: Equivalence, EA: Equivalence ): Equivalence> => - (x, y) => + equivalence.make((x, y) => x === y || (isLeft(x) ? isLeft(y) && EE(x.left, y.left) : isRight(y) && EA(x.right, y.right)) + ) /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index d5715c20f..4df772c98 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -17,6 +17,7 @@ import * as compactable from "@fp-ts/core/typeclass/Compactable" import type * as coproduct_ from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" +import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as filterable from "@fp-ts/core/typeclass/Filterable" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" @@ -1420,7 +1421,9 @@ export const traverseTap: ( * @since 1.0.0 */ export const getEquivalence = (E: Equivalence): Equivalence> => - (x, y) => x === y || (isNone(x) ? isNone(y) : isNone(y) ? false : E(x.value, y.value)) + equivalence.make((x, y) => + x === y || (isNone(x) ? isNone(y) : isNone(y) ? false : E(x.value, y.value)) + ) // ------------------------------------------------------------------------------------- // sorting diff --git a/src/These.ts b/src/These.ts index d72c3ef86..6a18120fa 100644 --- a/src/These.ts +++ b/src/These.ts @@ -19,6 +19,7 @@ import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" import * as chainable from "@fp-ts/core/typeclass/Chainable" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" +import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" import type * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" @@ -137,12 +138,13 @@ export const getEquivalence = ( EE: Equivalence, EA: Equivalence ): Equivalence> => - (x, y) => + equivalence.make((x, y) => isLeft(x) ? isLeft(y) && EE(x.left, y.left) : isRight(x) ? isRight(y) && EA(x.right, y.right) : isBoth(y) && EE(x.left, y.left) && EA(x.right, y.right) + ) /** * @category pattern matching diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index b36c4041c..ef31a8d68 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -61,11 +61,11 @@ export const mapLeft = ( (f: (e: E) => G): (self: Kind) => Kind (self: Kind, f: (e: E) => G): Kind } => - dual< - (f: (e: E) => G) => (self: Kind) => Kind, - (self: Kind, f: (e: E) => G) => Kind - >(2, (self: Kind, f: (e: E) => G): Kind => - F.bimap(self, f, identity)) + dual( + 2, + (self: Kind, f: (e: E) => G): Kind => + F.bimap(self, f, identity) + ) /** * Returns a default `map` implementation. diff --git a/src/typeclass/Chainable.ts b/src/typeclass/Chainable.ts index 090af10be..62d20c226 100644 --- a/src/typeclass/Chainable.ts +++ b/src/typeclass/Chainable.ts @@ -28,17 +28,7 @@ export const andThenDiscard = (F: Chainable): { that: Kind ): Kind } => - dual< - ( - that: Kind - ) => ( - self: Kind - ) => Kind, - ( - self: Kind, - that: Kind - ) => Kind - >(2, ( + dual(2, ( self: Kind, that: Kind ): Kind => tap(F)(self, () => that)) @@ -57,15 +47,7 @@ export const tap = (F: Chainable): { f: (a: A) => Kind ): Kind } => - dual< - ( - f: (a: A) => Kind - ) => (self: Kind) => Kind, - ( - self: Kind, - f: (a: A) => Kind - ) => Kind - >( + dual( 2, ( self: Kind, diff --git a/src/typeclass/Compactable.ts b/src/typeclass/Compactable.ts index 80de788d4..0dd5e5ec1 100644 --- a/src/typeclass/Compactable.ts +++ b/src/typeclass/Compactable.ts @@ -38,9 +38,7 @@ export const separate = ( ) => ( self: Kind> - ): [Kind, Kind] => { - return [ - pipe(self, F.map(either.getLeft), F.compact), - pipe(self, F.map(either.getRight), F.compact) - ] - } + ): [Kind, Kind] => [ + pipe(self, F.map(either.getLeft), F.compact), + pipe(self, F.map(either.getRight), F.compact) + ] diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index d973d4563..c3b278d9f 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -58,10 +58,7 @@ export const flap = (F: Covariant): { (self: Kind B>): (a: A) => Kind (a: A, self: Kind B>): Kind } => - dual< - (self: Kind B>) => (a: A) => Kind, - (a: A, self: Kind B>) => Kind - >( + dual( 2, (a: A, self: Kind B>): Kind => pipe(self, F.map(f => f(a))) @@ -75,10 +72,7 @@ export const as = (F: Covariant): { (b: B): (self: Kind) => Kind (self: Kind, b: B): Kind } => - dual< - (b: B) => (self: Kind) => Kind, - (self: Kind, b: B) => Kind - >( + dual( 2, (self: Kind, b: B): Kind => pipe(self, F.map(() => b)) diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 89147af43..8395cde8a 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -5,6 +5,7 @@ * * @since 1.0.0 */ +import { dual } from "@fp-ts/core/Function" import type { TypeLambda } from "@fp-ts/core/HKT" import type { ReadonlyRecord } from "@fp-ts/core/ReadonlyRecord" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" @@ -21,7 +22,8 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Equivalence { - (x: A, y: A): boolean + (that: A): (self: A) => boolean + (self: A, that: A): boolean } /** @@ -32,13 +34,21 @@ export interface EquivalenceTypeLambda extends TypeLambda { readonly type: Equivalence } +/** + * @category constructors + * @since 1.0.0 + */ +export const make = ( + equivalent: (self: A, that: A) => boolean +): Equivalence => dual(2, (self, that) => self === that || equivalent(self, that)) + /** * Return an `Equivalence` that uses strict equality (===) to compare values * * @since 1.0.0 * @category constructors */ -export const strict: () => Equivalence = () => (x, y) => x === y +export const strict: () => Equivalence = () => dual(2, (x, y) => x === y) /** * @category instances @@ -80,7 +90,7 @@ export const symbol: Equivalence = strict() export const tuple = >( ...equivalences: { readonly [K in keyof A]: Equivalence } ): Equivalence> => - (x, y) => equivalences.every((equivalence, i) => equivalence(x[i], y[i])) + make((x, y) => equivalences.every((equivalence, i) => equivalence(x[i], y[i]))) /** * Given an `Equivalence` of type `A`, returns a new `Equivalence` of type `ReadonlyArray`. @@ -93,7 +103,7 @@ export const tuple = >( export const array = ( equivalence: Equivalence ): Equivalence> => - (x, y) => x.length === y.length && x.every((a, i) => equivalence(a, y[i])) + make((x, y) => x.length === y.length && x.every((a, i) => equivalence(a, y[i]))) /** * Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct @@ -105,14 +115,14 @@ export const array = ( export const struct = ( equivalences: { [K in keyof A]: Equivalence } ): Equivalence<{ readonly [K in keyof A]: A[K] }> => - (x, y) => { + make((x, y) => { for (const key in equivalences) { if (!equivalences[key](x[key], y[key])) { return false } } return true - } + }) /** * Given an `Equivalence` of type `A`, returns a new `Equivalence` of type `{ readonly [x: string]: A }`. @@ -125,7 +135,7 @@ export const struct = ( export const record = ( equivalence: Equivalence ): Equivalence> => - (x, y) => { + make((x, y) => { const keys = Object.keys(x) if (Object.keys(y).length !== keys.length) { return false @@ -136,7 +146,7 @@ export const record = ( } } return true - } + }) /** * @category instances @@ -144,9 +154,9 @@ export const record = ( */ export const getSemigroup = (): Semigroup> => semigroup.make( - (self, that) => (x, y) => self(x, y) && that(x, y), + (self, that) => make((x, y) => self(x, y) && that(x, y)), (self, collection) => - (x, y) => { + make((x, y) => { if (!self(x, y)) { return false } @@ -156,10 +166,10 @@ export const getSemigroup = (): Semigroup> => } } return true - } + }) ) -const empty: Equivalence = () => true +const empty: Equivalence = dual(2, (_x, _y) => true) /** * @category instances @@ -173,7 +183,7 @@ export const getMonoid = (): Monoid> => * @since 1.0.0 */ export const Contravariant: contravariant.Contravariant = contravariant.make( - (self: Equivalence, f: (b: B) => A): Equivalence => (x, y) => self(f(x), f(y)) + (self: Equivalence, f: (b: B) => A): Equivalence => make((x, y) => self(f(x), f(y))) ) /** @@ -182,7 +192,7 @@ export const Contravariant: contravariant.Contravariant = * @since 1.0.0 */ export const contramap = (f: (b: B) => A) => - (self: Equivalence): Equivalence => (x, y) => self(f(x), f(y)) + (self: Equivalence): Equivalence => make((x, y) => self(f(x), f(y))) /** * @category instances From d696ade0bdd77e0f53f95f0e20d2840220b209b1 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 19:12:34 +0100 Subject: [PATCH 162/255] Filterable: make dual --- docs/modules/ReadonlyArray.ts.md | 5 +- docs/modules/typeclass/Filterable.ts.md | 45 +++++++++--- src/ReadonlyArray.ts | 46 ++++++------ src/typeclass/Filterable.ts | 93 ++++++++++++++++--------- test/limbo/FilterableWithIndex.ts | 18 ++--- test/typeclass/Filterable.ts | 10 +-- test/typeclass/FilterableWithIndex.ts | 16 ++--- 7 files changed, 146 insertions(+), 87 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index c5c0b005e..45ba7a895 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -442,7 +442,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const filterMap: (f: (a: A) => Option) => (self: Iterable) => B[] +export declare const filterMap: { + (f: (a: A) => Option): (self: Iterable) => B[] + (self: Iterable, f: (a: A) => Option): B[] +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Filterable.ts.md b/docs/modules/typeclass/Filterable.ts.md index aa6c448cf..20bf8d7e7 100644 --- a/docs/modules/typeclass/Filterable.ts.md +++ b/docs/modules/typeclass/Filterable.ts.md @@ -14,6 +14,8 @@ Added in v1.0.0

Table of contents

+- [constructors](#constructors) + - [make](#make) - [models](#models) - [Filterable (interface)](#filterable-interface) - [utils](#utils) @@ -24,6 +26,20 @@ Added in v1.0.0 --- +# constructors + +## make + +**Signature** + +```ts +export declare const make: ( + filterMap: (self: Kind, f: (a: A) => Option) => Kind +) => Filterable +``` + +Added in v1.0.0 + # models ## Filterable (interface) @@ -32,7 +48,10 @@ Added in v1.0.0 ```ts export interface Filterable extends TypeClass { - readonly filterMap: (f: (a: A) => Option) => (self: Kind) => Kind + readonly filterMap: { + (f: (a: A) => Option): (self: Kind) => Kind + (self: Kind, f: (a: A) => Option): Kind + } } ``` @@ -67,7 +86,7 @@ Added in v1.0.0 ## filterMapComposition -Returns a default `filterMap` composition. +Returns a default binary `filterMap` composition. **Signature** @@ -75,10 +94,9 @@ Returns a default `filterMap` composition. export declare const filterMapComposition: ( F: Covariant, G: Filterable -) => ( +) => ( + self: Kind>, f: (a: A) => Option -) => ( - self: Kind> ) => Kind> ``` @@ -98,6 +116,14 @@ export declare const partition: ( (predicate: (a: A) => boolean): ( self: Kind ) => [Kind, Kind] + (self: Kind, refinement: (a: A) => a is B): [ + Kind, + Kind + ] + (self: Kind, predicate: (a: A) => boolean): [ + Kind, + Kind + ] } ``` @@ -110,9 +136,12 @@ Added in v1.0.0 ```ts export declare const partitionMap: ( F: Filterable -) => ( - f: (a: A) => Either -) => (self: Kind) => [Kind, Kind] +) => { + (f: (a: A) => Either): ( + self: Kind + ) => [Kind, Kind] + (self: Kind, f: (a: A) => Either): [Kind, Kind] +} ``` Added in v1.0.0 diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 5084a483d..0eb4b970a 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1484,50 +1484,51 @@ export const filterMapWithIndex = (f: (a: A, i: number) => Option) => * @category filtering * @since 1.0.0 */ -export const filterMap: (f: (a: A) => Option) => (self: Iterable
) => Array = (f) => - filterMapWithIndex(f) +export const separate = ( + self: ReadonlyArray> +): [Array, Array] => { + const left: Array = [] + const right: Array = [] + for (const e of self) { + if (E.isLeft(e)) { + left.push(e.left) + } else { + right.push(e.right) + } + } + return [left, right] +} /** * @category filtering * @since 1.0.0 */ -export const compact: (self: Iterable>) => Array = filterMap(identity) +export const filterMap: { + (f: (a: A) => Option): (self: Iterable) => Array + (self: Iterable, f: (a: A) => Option): Array +} = dual(2, (self, f) => pipe(self, filterMapWithIndex(f))) /** * @category instances * @since 1.0.0 */ -export const Compactable: compactable.Compactable = { - compact -} +export const Filterable: filterable.Filterable = filterable.make(filterMap) /** * @category filtering * @since 1.0.0 */ -export const separate = ( - self: ReadonlyArray> -): [Array, Array] => { - const left: Array = [] - const right: Array = [] - for (const e of self) { - if (E.isLeft(e)) { - left.push(e.left) - } else { - right.push(e.right) - } - } - return [left, right] -} +export const compact: (self: Iterable>) => Array = filterMap(identity) /** * @category instances * @since 1.0.0 */ -export const Filterable: filterable.Filterable = { - filterMap +export const Compactable: compactable.Compactable = { + compact } +// TODO: input as interables /** * @dual * @category filtering @@ -1561,6 +1562,7 @@ export const filterWithIndex: { ): ((self: ReadonlyArray) => Array) => filterMapWithIndex((b, i) => (predicate(b, i) ? O.some(b) : O.none())) +// TODO: input as iterables /** * @category filtering * @since 1.0.0 diff --git a/src/typeclass/Filterable.ts b/src/typeclass/Filterable.ts index c9b195dea..7cfee5f51 100644 --- a/src/typeclass/Filterable.ts +++ b/src/typeclass/Filterable.ts @@ -4,7 +4,7 @@ * @since 1.0.0 */ import type { Either } from "@fp-ts/core/Either" -import { dual, pipe } from "@fp-ts/core/Function" +import { dual } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" @@ -16,13 +16,27 @@ import type { Covariant } from "@fp-ts/core/typeclass/Covariant" * @since 1.0.0 */ export interface Filterable extends TypeClass { - readonly filterMap: ( - f: (a: A) => Option - ) => (self: Kind) => Kind + readonly filterMap: { + (f: (a: A) => Option): (self: Kind) => Kind + (self: Kind, f: (a: A) => Option): Kind + } } /** - * Returns a default `filterMap` composition. + * @category constructors + * @since 1.0.0 + */ +export const make = ( + filterMap: ( + self: Kind, + f: (a: A) => Option + ) => Kind +): Filterable => ({ + filterMap: dual(2, filterMap) +}) + +/** + * Returns a default binary `filterMap` composition. * * @since 1.0.0 */ @@ -30,11 +44,10 @@ export const filterMapComposition = F: Covariant, G: Filterable ) => - ( + ( + self: Kind>, f: (a: A) => Option - ): ( - self: Kind> - ) => Kind> => F.map(G.filterMap(f)) + ): Kind> => F.map(self, G.filterMap(f)) /** * @since 1.0.0 @@ -57,47 +70,59 @@ export const filter: ( predicate: (a: A) => boolean ): Kind } = (Filterable: Filterable) => - dual< - ( - predicate: (a: A) => boolean - ) => (self: Kind) => Kind, - (self: Kind, predicate: (a: A) => boolean) => Kind - >( + dual( 2, (self: Kind, predicate: (a: A) => boolean): Kind => - pipe(self, Filterable.filterMap((b) => (predicate(b) ? option.some(b) : option.none))) + Filterable.filterMap(self, (b) => (predicate(b) ? option.some(b) : option.none)) ) /** * @since 1.0.0 */ -export const partitionMap = (F: Filterable) => - (f: (a: A) => Either) => - ( - self: Kind - ): [Kind, Kind] => { - return [ - pipe(self, F.filterMap((a) => either.getLeft(f(a)))), - pipe(self, F.filterMap((a) => either.getRight(f(a)))) - ] - } +export const partitionMap = (F: Filterable): { + ( + f: (a: A) => Either + ): (self: Kind) => [Kind, Kind] + ( + self: Kind, + f: (a: A) => Either + ): [Kind, Kind] +} => + dual(2, ( + self: Kind, + f: (a: A) => Either + ): [Kind, Kind] => [ + F.filterMap(self, (a) => either.getLeft(f(a))), + F.filterMap(self, (a) => either.getRight(f(a))) + ]) /** * @since 1.0.0 */ -export const partition: ( +export const partition = ( F: Filterable -) => { +): { (refinement: (a: A) => a is B): ( self: Kind ) => [Kind, Kind] (predicate: (a: A) => boolean): ( self: Kind ) => [Kind, Kind] -} = (Filterable: Filterable) => - ( + + ( + self: Kind, + refinement: (a: A) => a is B + ): [Kind, Kind] + ( + self: Kind, predicate: (a: A) => boolean - ): (( - self: Kind - ) => [Kind, Kind]) => - partitionMap(Filterable)((b) => (predicate(b) ? either.right(b) : either.left(b))) + ): [Kind, Kind] +} => + dual( + 2, + ( + self: Kind, + predicate: (a: A) => boolean + ): [Kind, Kind] => + partitionMap(F)(self, (b) => (predicate(b) ? either.right(b) : either.left(b))) + ) diff --git a/test/limbo/FilterableWithIndex.ts b/test/limbo/FilterableWithIndex.ts index 7525a7a4a..2db48857e 100644 --- a/test/limbo/FilterableWithIndex.ts +++ b/test/limbo/FilterableWithIndex.ts @@ -8,7 +8,7 @@ import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" import * as O from "@fp-ts/core/Option" import type { Option } from "@fp-ts/core/Option" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" -import type { Filterable } from "@fp-ts/core/typeclass/Filterable" +// import type { Filterable } from "@fp-ts/core/typeclass/Filterable" /** * @category models @@ -35,14 +35,14 @@ export const filterMapWithIndexComposition = > ) => Kind> => F.map(G.filterMapWithIndex(f)) -/** - * Returns a default `filterMap` implementation. - * - * @since 1.0.0 - */ -export const filterMap = ( - F: FilterableWithIndex -): Filterable["filterMap"] => (f) => F.filterMapWithIndex(f) +// /** +// * Returns a default `filterMap` implementation. +// * +// * @since 1.0.0 +// */ +// export const filterMap = ( +// F: FilterableWithIndex +// ): Filterable["filterMap"] => (f) => F.filterMapWithIndex(f) /** * @since 1.0.0 diff --git a/test/typeclass/Filterable.ts b/test/typeclass/Filterable.ts index a22477b65..24ab1ae46 100644 --- a/test/typeclass/Filterable.ts +++ b/test/typeclass/Filterable.ts @@ -8,11 +8,11 @@ import * as U from "../util" describe("Filterable", () => { it("filterMapComposition", () => { const filterMap = _.filterMapComposition(RA.Covariant, O.Filterable) - const f = filterMap((s: string) => s.length > 1 ? O.some(s.length) : O.none()) - U.deepStrictEqual(pipe([], f), []) - U.deepStrictEqual(pipe([O.none()], f), [O.none()]) - U.deepStrictEqual(pipe([O.some("a")], f), [O.none()]) - U.deepStrictEqual(pipe([O.some("aa")], f), [O.some(2)]) + const f = (s: string) => s.length > 1 ? O.some(s.length) : O.none() + U.deepStrictEqual(filterMap([], f), []) + U.deepStrictEqual(filterMap([O.none()], f), [O.none()]) + U.deepStrictEqual(filterMap([O.some("a")], f), [O.none()]) + U.deepStrictEqual(filterMap([O.some("aa")], f), [O.some(2)]) }) it("filter", () => { diff --git a/test/typeclass/FilterableWithIndex.ts b/test/typeclass/FilterableWithIndex.ts index 64ec04ade..36103dceb 100644 --- a/test/typeclass/FilterableWithIndex.ts +++ b/test/typeclass/FilterableWithIndex.ts @@ -26,14 +26,14 @@ describe("FilterableWithIndex", () => { U.deepStrictEqual(pipe([["aa", "a"]], f), [[2, 1]]) }) - it("filterMap", () => { - const filterMap: ( - f: (a: A) => O.Option - ) => (self: ReadonlyArray) => ReadonlyArray = _.filterMap(FilterableWithIndex) - const f = (n: number) => (n % 2 === 0 ? O.none() : O.some(n)) - U.deepStrictEqual(pipe([1, 2, 3], filterMap(f)), [1, 3]) - U.deepStrictEqual(pipe([], filterMap(f)), []) - }) + // it("filterMap", () => { + // const filterMap: ( + // f: (a: A) => O.Option + // ) => (self: ReadonlyArray) => ReadonlyArray = _.filterMap(FilterableWithIndex) + // const f = (n: number) => (n % 2 === 0 ? O.none() : O.some(n)) + // U.deepStrictEqual(pipe([1, 2, 3], filterMap(f)), [1, 3]) + // U.deepStrictEqual(pipe([], filterMap(f)), []) + // }) it("filterWithIndex", () => { const filterWithIndex = _.filterWithIndex(FilterableWithIndex) From b6751279f4e259062b41deab2508aefc9f8bef14 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 2 Feb 2023 19:36:02 +0100 Subject: [PATCH 163/255] FlatMap: make dual --- docs/modules/Either.ts.md | 5 ++- docs/modules/ReadonlyArray.ts.md | 5 ++- docs/modules/These.ts.md | 12 ++++-- docs/modules/typeclass/FlatMap.ts.md | 34 +++++++++++++++-- src/Either.ts | 12 ++++-- src/Identity.ts | 9 +++-- src/ReadonlyArray.ts | 18 +++++++-- src/These.ts | 14 ++++--- src/typeclass/FlatMap.ts | 57 ++++++++++++++-------------- 9 files changed, 113 insertions(+), 53 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index b699f2d3d..8725af87a 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -1268,7 +1268,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMap: (f: (a: A) => Either) => (self: Either) => Either +export declare const flatMap: { + (f: (a: A) => Either): (self: Either) => Either + (self: Either, f: (a: A) => Either): Either +} ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 45ba7a895..f68a27173 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -1618,7 +1618,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMap: (f: (a: A) => readonly B[]) => (self: readonly A[]) => B[] +export declare const flatMap: { + (f: (a: A) => readonly B[]): (self: readonly A[]) => B[] + (self: readonly A[], f: (a: A) => readonly B[]): B[] +} ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 4e7a09dd9..fc03d3b19 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1367,9 +1367,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMap: ( - f: (a: A) => These -) => (self: These) => These +export declare const flatMap: { + (f: (a: A) => These): ( + self: These + ) => These + (self: These, f: (a: A) => These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + B + > +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/FlatMap.ts.md b/docs/modules/typeclass/FlatMap.ts.md index bb160ed06..1999ba8ec 100644 --- a/docs/modules/typeclass/FlatMap.ts.md +++ b/docs/modules/typeclass/FlatMap.ts.md @@ -12,6 +12,8 @@ Added in v1.0.0

Table of contents

+- [constructors](#constructors) + - [make](#make) - [type class](#type-class) - [FlatMap (interface)](#flatmap-interface) - [utils](#utils) @@ -21,6 +23,23 @@ Added in v1.0.0 --- +# constructors + +## make + +**Signature** + +```ts +export declare const make: ( + flatMap: ( + self: Kind, + f: (a: A) => Kind + ) => Kind +) => FlatMap +``` + +Added in v1.0.0 + # type class ## FlatMap (interface) @@ -29,9 +48,18 @@ Added in v1.0.0 ```ts export interface FlatMap extends TypeClass { - readonly flatMap: ( - f: (a: A) => Kind - ) => (self: Kind) => Kind + readonly flatMap: { + (f: (a: A) => Kind): ( + self: Kind + ) => Kind + (self: Kind, f: (a: A) => Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + B + > + } } ``` diff --git a/src/Either.ts b/src/Either.ts index da30bd60e..e1d18a1fd 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -373,12 +373,18 @@ export const Pointed: pointed.Pointed = { } /** + * @dual * @category sequencing * @since 1.0.0 */ -export const flatMap = ( - f: (a: A) => Either -) => (self: Either): Either => isLeft(self) ? self : f(self.right) +export const flatMap: { + (f: (a: A) => Either): (self: Either) => Either + (self: Either, f: (a: A) => Either): Either +} = dual( + 2, + (self: Either, f: (a: A) => Either): Either => + isLeft(self) ? self : f(self.right) +) /** * @category instances diff --git a/src/Identity.ts b/src/Identity.ts index 8edb0141e..f5ac510b9 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -7,7 +7,7 @@ import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type * as applicative from "@fp-ts/core/typeclass/Applicative" import * as chainable from "@fp-ts/core/typeclass/Chainable" import * as covariant from "@fp-ts/core/typeclass/Covariant" -import type * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" +import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" import type * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" @@ -112,9 +112,10 @@ export const Pointed: pointed.Pointed = { * @category instances * @since 1.0.0 */ -export const FlatMap: flatMap_.FlatMap = { - flatMap: f => self => f(self) -} +export const FlatMap: flatMap_.FlatMap = flatMap_.make(( + self: Identity
, + f: (a: A) => Identity +): Identity => f(self)) /** * @category instances diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 0eb4b970a..48aeadb20 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1377,12 +1377,18 @@ export const flatMapWithIndex = (f: (a: A, i: number) => ReadonlyArray) } /** + * @dual * @category sequencing * @since 1.0.0 */ -export const flatMap: ( - f: (a: A) => ReadonlyArray -) => (self: ReadonlyArray) => Array = (f) => flatMapWithIndex(f) +export const flatMap: { + (f: (a: A) => ReadonlyArray): (self: ReadonlyArray) => Array + (self: ReadonlyArray, f: (a: A) => ReadonlyArray): Array +} = dual( + 2, + (self: ReadonlyArray, f: (a: A) => ReadonlyArray): Array => + pipe(self, flatMapWithIndex(f)) +) /** * @category sequencing @@ -1500,13 +1506,17 @@ export const separate = ( } /** + * @dual * @category filtering * @since 1.0.0 */ export const filterMap: { (f: (a: A) => Option): (self: Iterable) => Array (self: Iterable, f: (a: A) => Option): Array -} = dual(2, (self, f) => pipe(self, filterMapWithIndex(f))) +} = dual( + 2, + (self: Iterable, f: (a: A) => Option): Array => pipe(self, filterMapWithIndex(f)) +) /** * @category instances diff --git a/src/These.ts b/src/These.ts index 6a18120fa..76e360bdd 100644 --- a/src/These.ts +++ b/src/These.ts @@ -5,7 +5,7 @@ import type { Either, Left, Right } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" -import { constNull, constUndefined, pipe } from "@fp-ts/core/Function" +import { constNull, constUndefined, dual, pipe } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { proto, structural } from "@fp-ts/core/internal/effect" import * as N from "@fp-ts/core/Number" @@ -1094,13 +1094,16 @@ export const struct: >>( .struct(Product) /** + * @dual * @category sequencing * @since 1.0.0 */ -export const flatMap = ( - f: (a: A) => Validated -) => - (self: Validated): Validated => { +export const flatMap: { + (f: (a: A) => Validated): (self: Validated) => Validated + (self: Validated, f: (a: A) => Validated): Validated +} = dual( + 2, + (self: Validated, f: (a: A) => Validated): Validated => { if (isLeft(self)) { return self } @@ -1116,6 +1119,7 @@ export const flatMap = ( } return both(RA.appendAllNonEmpty(that.left)(self.left), that.right) } +) /** * @category instances diff --git a/src/typeclass/FlatMap.ts b/src/typeclass/FlatMap.ts index 25808f8fb..e426f8f26 100644 --- a/src/typeclass/FlatMap.ts +++ b/src/typeclass/FlatMap.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { dual, identity, pipe } from "@fp-ts/core/Function" +import { dual, identity } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" /** @@ -9,18 +9,37 @@ import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" * @since 1.0.0 */ export interface FlatMap extends TypeClass { - readonly flatMap: ( - f: (a: A) => Kind - ) => (self: Kind) => Kind + readonly flatMap: { + ( + f: (a: A) => Kind + ): (self: Kind) => Kind + ( + self: Kind, + f: (a: A) => Kind + ): Kind + } } +/** + * @category constructors + * @since 1.0.0 + */ +export const make = ( + flatMap: ( + self: Kind, + f: (a: A) => Kind + ) => Kind +): FlatMap => ({ + flatMap: dual(2, flatMap) +}) + /** * @since 1.0.0 */ export const flatten = (F: FlatMap) => ( self: Kind> - ): Kind => pipe(self, F.flatMap(identity)) + ): Kind => F.flatMap(self, identity) /** * A variant of `flatMap` that ignores the value produced by this effect. @@ -36,20 +55,10 @@ export const andThen = (F: FlatMap): { that: Kind ): Kind } => - dual< - ( - that: Kind - ) => ( - self: Kind - ) => Kind, - ( - self: Kind, - that: Kind - ) => Kind - >(2, ( + dual(2, ( self: Kind, that: Kind - ): Kind => pipe(self, F.flatMap(() => that))) + ): Kind => F.flatMap(self, () => that)) /** * @since 1.0.0 @@ -67,20 +76,10 @@ export const composeKleisliArrow = ( bfc: (b: B) => Kind ): (a: A) => Kind } => - dual< - ( - bfc: (b: B) => Kind - ) => ( - afb: (a: A) => Kind - ) => (a: A) => Kind, - ( - afb: (a: A) => Kind, - bfc: (b: B) => Kind - ) => (a: A) => Kind - >( + dual( 2, ( afb: (a: A) => Kind, bfc: (b: B) => Kind - ): ((a: A) => Kind) => a => pipe(afb(a), F.flatMap(bfc)) + ): ((a: A) => Kind) => a => F.flatMap(afb(a), bfc) ) From 1e94bb8c58dea961534911381ed9f60e8ae3cf2e Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 3 Feb 2023 07:20:26 +0100 Subject: [PATCH 164/255] Foldable: make dual --- docs/modules/ReadonlyArray.ts.md | 18 +--- docs/modules/typeclass/Foldable.ts.md | 110 +++++++++++------------ src/Either.ts | 9 +- src/Identity.ts | 8 +- src/Option.ts | 9 +- src/ReadonlyArray.ts | 39 ++++---- src/These.ts | 11 +-- src/typeclass/Foldable.ts | 123 ++++++++++++++------------ test/ReadonlyArray.ts | 1 - test/limbo/FoldableWithIndex.ts | 18 ++-- test/typeclass/Foldable.ts | 59 +++++------- 11 files changed, 186 insertions(+), 219 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index f68a27173..2e80f55de 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -56,7 +56,6 @@ Added in v1.0.0 - [reduce](#reduce) - [reduceKind](#reducekind) - [reduceRight](#reduceright) - - [reduceRightKind](#reducerightkind) - [reduceRightWithIndex](#reducerightwithindex) - [reduceWithIndex](#reducewithindex) - [scan](#scan) @@ -641,7 +640,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduce: (b: B, f: (b: B, a: A) => B) => (self: readonly A[]) => B +export declare const reduce: { + (b: B, f: (b: B, a: A) => B): (self: readonly A[]) => B + (self: readonly A[], b: B, f: (b: B, a: A) => B): B +} ``` Added in v1.0.0 @@ -668,18 +670,6 @@ export declare const reduceRight: (b: B, f: (b: B, a: A) => B) => (self: r Added in v1.0.0 -## reduceRightKind - -**Signature** - -```ts -export declare const reduceRightKind: ( - F: monad.Monad -) => (b: B, f: (b: B, a: A) => Kind) => (self: readonly A[]) => Kind -``` - -Added in v1.0.0 - ## reduceRightWithIndex **Signature** diff --git a/docs/modules/typeclass/Foldable.ts.md b/docs/modules/typeclass/Foldable.ts.md index 64c8cf57b..81eb7d5d7 100644 --- a/docs/modules/typeclass/Foldable.ts.md +++ b/docs/modules/typeclass/Foldable.ts.md @@ -12,20 +12,34 @@ Added in v1.0.0

Table of contents

+- [constructors](#constructors) + - [make](#make) - [type class](#type-class) - [Foldable (interface)](#foldable-interface) - [utils](#utils) - - [foldMap](#foldmap) - - [foldMapKind](#foldmapkind) + - [combineMap](#combinemap) + - [coproductMapKind](#coproductmapkind) - [reduceComposition](#reducecomposition) - [reduceKind](#reducekind) - - [reduceRight](#reduceright) - - [reduceRightKind](#reducerightkind) - [toArray](#toarray) - - [toArrayWith](#toarraywith) + - [toArrayMap](#toarraymap) --- +# constructors + +## make + +**Signature** + +```ts +export declare const make: ( + reduce: (self: Kind, b: B, f: (b: B, a: A) => B) => B +) => Foldable +``` + +Added in v1.0.0 + # type class ## Foldable (interface) @@ -34,7 +48,10 @@ Added in v1.0.0 ```ts export interface Foldable extends TypeClass { - readonly reduce: (b: B, f: (b: B, a: A) => B) => (self: Kind) => B + readonly reduce: { + (b: B, f: (b: B, a: A) => B): (self: Kind) => B + (self: Kind, b: B, f: (b: B, a: A) => B): B + } } ``` @@ -42,37 +59,41 @@ Added in v1.0.0 # utils -## foldMap +## combineMap **Signature** ```ts -export declare const foldMap: ( +export declare const combineMap: ( F: Foldable -) => (M: Monoid) =>
(f: (a: A) => M) => (self: Kind) => M +) => (M: Monoid) => { + (f: (a: A) => M): (self: Kind) => M + (self: Kind, f: (a: A) => M): M +} ``` Added in v1.0.0 -## foldMapKind +## coproductMapKind **Signature** ```ts -export declare const foldMapKind: ( +export declare const coproductMapKind: ( F: Foldable ) => ( G: Coproduct -) => ( - f: (a: A) => Kind -) => (self: Kind) => Kind +) => { + (f: (a: A) => Kind): (self: Kind) => Kind + (self: Kind, f: (a: A) => Kind): Kind +} ``` Added in v1.0.0 ## reduceComposition -Returns a default `reduce` composition. +Returns a default binary `reduce` composition. **Signature** @@ -80,10 +101,7 @@ Returns a default `reduce` composition. export declare const reduceComposition: ( F: Foldable, G: Foldable -) => ( - b: B, - f: (b: B, a: A) => B -) => (self: Kind>) => B +) => (self: Kind>, b: B, f: (b: B, a: A) => B) => B ``` Added in v1.0.0 @@ -97,39 +115,18 @@ export declare const reduceKind: ( F: Foldable ) => ( G: Monad -) => ( - b: B, - f: (b: B, a: A) => Kind -) => (self: Kind) => Kind -``` - -Added in v1.0.0 - -## reduceRight - -**Signature** - -```ts -export declare const reduceRight: ( - F: Foldable -) => (b: B, f: (b: B, a: A) => B) => (self: Kind) => B -``` - -Added in v1.0.0 - -## reduceRightKind - -**Signature** - -```ts -export declare const reduceRightKind: ( - F: Foldable -) => ( - G: Monad -) => ( - b: B, - f: (b: B, a: A) => Kind -) => (self: Kind) => Kind +) => { + (b: B, f: (b: B, a: A) => Kind): ( + self: Kind + ) => Kind + (self: Kind, b: B, f: (b: B, a: A) => Kind): Kind< + G, + R, + O, + E, + B + > +} ``` Added in v1.0.0 @@ -144,14 +141,17 @@ export declare const toArray: (F: Foldable) => ( +export declare const toArrayMap: ( F: Foldable -) => (f: (a: A) => B) => (self: Kind) => B[] +) => { + (f: (a: A) => B): (self: Kind) => B[] + (self: Kind, f: (a: A) => B): B[] +} ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index e1d18a1fd..ed493916f 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -781,16 +781,13 @@ export const SemiAlternative: semiAlternative.SemiAlternative coproductMany } -const reduce = (b: B, f: (b: B, a: A) => B) => - (self: Either): B => isLeft(self) ? b : f(b, self.right) - /** * @category instances * @since 1.0.0 */ -export const Foldable: foldable.Foldable = { - reduce -} +export const Foldable: foldable.Foldable = foldable.make((self, b, f) => + isLeft(self) ? b : f(b, self.right) +) /** * Transforms an `Either` into an `Array`. diff --git a/src/Identity.ts b/src/Identity.ts index f5ac510b9..ffdf8fd6c 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -8,7 +8,7 @@ import type * as applicative from "@fp-ts/core/typeclass/Applicative" import * as chainable from "@fp-ts/core/typeclass/Chainable" import * as covariant from "@fp-ts/core/typeclass/Covariant" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" -import type * as foldable from "@fp-ts/core/typeclass/Foldable" +import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" import * as of_ from "@fp-ts/core/typeclass/Of" @@ -224,9 +224,9 @@ export const getSemiAlternative = ( * @category instances * @since 1.0.0 */ -export const Foldable: foldable.Foldable = { - reduce: (b, f) => self => f(b, self) -} +export const Foldable: foldable.Foldable = foldable.make((self, b, f) => + f(b, self) +) /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index 4df772c98..8fe413230 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1235,16 +1235,13 @@ export const reduceCompact: { } ) -const reduce = (b: B, f: (b: B, a: A) => B) => - (self: Option): B => isNone(self) ? b : f(b, self.value) - /** * @category folding * @since 1.0.0 */ -export const Foldable: foldable.Foldable = { - reduce -} +export const Foldable: foldable.Foldable = foldable.make((self, b, f) => + isNone(self) ? b : f(b, self.value) +) /** * Transforms an `Option` into an `Array`. diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 48aeadb20..371a9105c 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1853,13 +1853,6 @@ export const Monad: monad.Monad = { flatMap } -/** - * @category folding - * @since 1.0.0 - */ -export const reduce = (b: B, f: (b: B, a: A) => B) => - (self: ReadonlyArray): B => self.reduce((b, a) => f(b, a), b) - /** * @category folding * @since 1.0.0 @@ -1885,16 +1878,18 @@ export const reduceRightWithIndex = (b: B, f: (b: B, a: A, i: number) => B * @category instances * @since 1.0.0 */ -export const Foldable: foldable.Foldable = { - reduce -} +export const Foldable: foldable.Foldable = foldable.make((self, b, f) => + self.reduce((b, a) => f(b, a), b) +) /** * @category folding * @since 1.0.0 */ -export const foldMap: (M: Monoid) => (f: (a: A) => M) => (self: ReadonlyArray) => M = - foldable.foldMap(Foldable) +export const reduce: { + (b: B, f: (b: B, a: A) => B): (self: ReadonlyArray) => B + (self: ReadonlyArray, b: B, f: (b: B, a: A) => B): B +} = Foldable.reduce /** * @category folding @@ -1905,6 +1900,14 @@ export const foldMapWithIndex = (Monoid: Monoid) => (self: ReadonlyArray): M => self.reduce((m, a, i) => Monoid.combine(m, f(a, i)), Monoid.empty) +/** + * @category folding + * @since 1.0.0 + */ +export const foldMap = (M: Monoid) => + (f: (a: A) => M) => + (self: ReadonlyArray): M => self.reduce((m, a) => M.combine(m, f(a)), M.empty) + /** * @category folding * @since 1.0.0 @@ -1930,23 +1933,13 @@ export const reduceKind: (F: monad.Monad) => Kind ) => (self: ReadonlyArray) => Kind = foldable.reduceKind(Foldable) -/** - * @category folding - * @since 1.0.0 - */ -export const reduceRightKind: (F: monad.Monad) => ( - b: B, - f: (b: B, a: A) => Kind -) => (self: ReadonlyArray) => Kind = foldable - .reduceRightKind(Foldable) - /** * @category folding * @since 1.0.0 */ export const foldMapKind: (F: Coproduct) => ( f: (a: A) => Kind -) => (self: ReadonlyArray) => Kind = foldable.foldMapKind(Foldable) +) => (self: ReadonlyArray) => Kind = foldable.coproductMapKind(Foldable) /** * @category filtering diff --git a/src/These.ts b/src/These.ts index 76e360bdd..234f054fd 100644 --- a/src/These.ts +++ b/src/These.ts @@ -21,7 +21,7 @@ import * as covariant from "@fp-ts/core/typeclass/Covariant" import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" -import type * as foldable from "@fp-ts/core/typeclass/Foldable" +import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" @@ -762,16 +762,13 @@ export const contains = (equivalence: Equivalence) => export const exists = (predicate: Predicate) => (self: These): boolean => isLeft(self) ? false : predicate(self.right) -const reduce = (b: B, f: (b: B, a: A) => B) => - (self: These): B => isLeft(self) ? b : f(b, self.right) - /** * @category instances * @since 1.0.0 */ -export const Foldable: foldable.Foldable = { - reduce -} +export const Foldable: foldable.Foldable = foldable.make((self, b, f) => + isLeft(self) ? b : f(b, self.right) +) /** * Executes this effect and returns its value, if it succeeds, but otherwise diff --git a/src/typeclass/Foldable.ts b/src/typeclass/Foldable.ts index 73bb55e9a..a3bc5029d 100644 --- a/src/typeclass/Foldable.ts +++ b/src/typeclass/Foldable.ts @@ -2,7 +2,7 @@ * @since 1.0.0 */ -import { identity, pipe } from "@fp-ts/core/Function" +import { dual, identity } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" import type { Coproduct } from "@fp-ts/core/typeclass/Coproduct" import type { Monad } from "@fp-ts/core/typeclass/Monad" @@ -13,99 +13,112 @@ import type { Monoid } from "@fp-ts/core/typeclass/Monoid" * @since 1.0.0 */ export interface Foldable extends TypeClass { - readonly reduce: ( - b: B, - f: (b: B, a: A) => B - ) => (self: Kind) => B + readonly reduce: { + (b: B, f: (b: B, a: A) => B): (self: Kind) => B + (self: Kind, b: B, f: (b: B, a: A) => B): B + } } /** - * Returns a default `reduce` composition. - * + * @category constructors * @since 1.0.0 */ -export const reduceComposition = ( - F: Foldable, - G: Foldable -) => - (b: B, f: (b: B, a: A) => B) => - ( - self: Kind> - ): B => pipe(self, F.reduce(b, (b, ga) => pipe(ga, G.reduce(b, f)))) +export const make = ( + reduce: (self: Kind, b: B, f: (b: B, a: A) => B) => B +): Foldable => ({ + reduce: dual(3, reduce) +}) /** + * Returns a default binary `reduce` composition. + * * @since 1.0.0 */ -export const reduceRight = ( - F: Foldable +export const reduceComposition = ( + F: Foldable, + G: Foldable ) => - ( + ( + self: Kind>, b: B, f: (b: B, a: A) => B - ) => (self: Kind): B => toArray(F)(self).reduceRight(f, b) + ): B => F.reduce(self, b, (b, ga) => G.reduce(ga, b, f)) /** * @since 1.0.0 */ -export const foldMap = (F: Foldable) => - (M: Monoid) => - (f: (a: A) => M) => - (self: Kind): M => M.combineAll(toArrayWith(F)(f)(self)) +export const toArrayMap = ( + F: Foldable +): { + (f: (a: A) => B): (self: Kind) => Array + (self: Kind, f: (a: A) => B): Array +} => + dual( + 2, + (self: Kind, f: (a: A) => B): Array => + F.reduce(self, [], (out: Array, a) => [...out, f(a)]) + ) /** * @since 1.0.0 */ -export const toArrayWith = ( +export const toArray = ( F: Foldable -) => - (f: (a: A) => B) => - (self: Kind): Array => - F.reduce>([], (out, a) => { - out.push(f(a)) - return out - })(self) +): (self: Kind) => Array => toArrayMap(F)(identity) /** * @since 1.0.0 */ -export const toArray = ( - F: Foldable -): (self: Kind) => Array => toArrayWith(F)(identity) +export const combineMap = (F: Foldable) => + (M: Monoid): { + (f: (a: A) => M): (self: Kind) => M + (self: Kind, f: (a: A) => M): M + } => + dual(2, (self: Kind, f: (a: A) => M): M => + F.reduce(self, M.empty, (m, a) => + M.combine(m, f(a)))) /** * @since 1.0.0 */ export const reduceKind = (F: Foldable) => - (G: Monad) => + (G: Monad): { ( b: B, f: (b: B, a: A) => Kind - ): (self: Kind) => Kind => - F.reduce>( - G.of(b), - (gb, a) => pipe(gb, G.flatMap(b => f(b, a))) - ) - -/** - * @since 1.0.0 - */ -export const reduceRightKind = (F: Foldable) => - (G: Monad) => - ( + ): (self: Kind) => Kind + ( + self: Kind, + b: B, + f: (b: B, a: A) => Kind + ): Kind + } => + dual(3, ( + self: Kind, b: B, f: (b: B, a: A) => Kind - ): (self: Kind) => Kind => - reduceRight(F)>( + ): Kind => + F.reduce( + self, G.of(b), - (gb, a) => pipe(gb, G.flatMap(b => f(b, a))) - ) + (gb: Kind, a) => G.flatMap(gb, b => f(b, a)) + )) /** * @since 1.0.0 */ -export const foldMapKind = (F: Foldable) => - (G: Coproduct) => +export const coproductMapKind = (F: Foldable) => + (G: Coproduct): { ( f: (a: A) => Kind - ): (self: Kind) => Kind => - F.reduce>(G.zero(), (gb, a) => G.coproduct(gb, f(a))) + ): (self: Kind) => Kind + ( + self: Kind, + f: (a: A) => Kind + ): Kind + } => + dual(2, ( + self: Kind, + f: (a: A) => Kind + ): Kind => + F.reduce(self, G.zero(), (gb: Kind, a) => G.coproduct(gb, f(a)))) diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 3840f87b2..869468ebf 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -55,7 +55,6 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.reduceRight).exist expect(RA.foldMap).exist expect(RA.reduceKind).exist - expect(RA.reduceRightKind).exist expect(RA.foldMapKind).exist expect(RA.Traversable).exist diff --git a/test/limbo/FoldableWithIndex.ts b/test/limbo/FoldableWithIndex.ts index 1fb577e6c..2ba05f9ec 100644 --- a/test/limbo/FoldableWithIndex.ts +++ b/test/limbo/FoldableWithIndex.ts @@ -4,7 +4,7 @@ import { identity, pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import type { Foldable } from "@fp-ts/core/typeclass/Foldable" +// import type { Foldable } from "@fp-ts/core/typeclass/Foldable" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" /** @@ -61,14 +61,14 @@ export const reduceRightWithIndexComposition = f(b, a, [i, j])))) ) -/** - * Returns a default `reduce` implementation. - * - * @since 1.0.0 - */ -export const reduce = ( - F: FoldableWithIndex -): Foldable["reduce"] => (b, f) => F.reduceWithIndex(b, f) +// /** +// * Returns a default `reduce` implementation. +// * +// * @since 1.0.0 +// */ +// export const reduce = ( +// F: FoldableWithIndex +// ): Foldable["reduce"] => (b, f) => F.reduceWithIndex(b, f) /** * @since 1.0.0 diff --git a/test/typeclass/Foldable.ts b/test/typeclass/Foldable.ts index a2569c4a3..26a469a2d 100644 --- a/test/typeclass/Foldable.ts +++ b/test/typeclass/Foldable.ts @@ -9,9 +9,9 @@ describe("Foldable", () => { it("reduceComposition", () => { const reduce = _.reduceComposition(RA.Foldable, RA.Foldable) const f = (b: string, a: string) => b + a - U.deepStrictEqual(pipe([], reduce("-", f)), "-") - U.deepStrictEqual(pipe([[]], reduce("-", f)), "-") - U.deepStrictEqual(pipe([["a", "c"], ["b", "d"]], reduce("-", f)), "-acbd") + U.deepStrictEqual(reduce([], "-", f), "-") + U.deepStrictEqual(reduce([[]], "-", f), "-") + U.deepStrictEqual(reduce([["a", "c"], ["b", "d"]], "-", f), "-acbd") }) it("toArray", () => { @@ -20,57 +20,38 @@ describe("Foldable", () => { U.deepStrictEqual(toArray(O.some(2)), [2]) }) - it("toArrayWith", () => { - const toArrayWith = _.toArrayWith(O.Foldable) - U.deepStrictEqual(pipe(O.none(), toArrayWith(U.double)), []) - U.deepStrictEqual(pipe(O.some(2), toArrayWith(U.double)), [4]) + it("toArrayMap", () => { + const toArrayMap = _.toArrayMap(O.Foldable) + U.deepStrictEqual(toArrayMap(O.none(), U.double), []) + U.deepStrictEqual(toArrayMap(O.some(2), U.double), [4]) }) - it("foldMap", () => { - const foldMap = _.foldMap(RA.Foldable) - U.deepStrictEqual(pipe([1, 2, 3], foldMap(N.MonoidSum)(U.double)), 12) - }) - - it("reduceRight", () => { - const reduceRight = _.reduceRight(RA.Foldable) - U.deepStrictEqual(pipe(["a", "b", "c"], reduceRight("-", (b, a) => b + a)), "-cba") + it("combineMap", () => { + const combineMap = _.combineMap(RA.Foldable) + U.deepStrictEqual(combineMap(N.MonoidSum)([1, 2, 3], U.double), 12) }) it("reduceKind", () => { const reduceKind = _.reduceKind(RA.Foldable)(O.Monad) - U.deepStrictEqual(pipe([], reduceKind("-", () => O.none())), O.some("-")) - U.deepStrictEqual(pipe(["a"], reduceKind("-", () => O.none())), O.none()) + U.deepStrictEqual(reduceKind([], "-", () => O.none()), O.some("-")) + U.deepStrictEqual(reduceKind(["a"], "-", () => O.none()), O.none()) U.deepStrictEqual( - pipe(["a", "b", "c"], reduceKind("-", (b, a) => O.some(b + a))), + reduceKind(["a", "b", "c"], "-", (b, a) => O.some(b + a)), O.some("-abc") ) U.deepStrictEqual( - pipe(["a", "b", "c"], reduceKind("-", (b, a) => a === "b" ? O.none() : O.some(b + a))), - O.none() - ) - }) - - it("reduceRightKind", () => { - const reduceRightKind = _.reduceRightKind(RA.Foldable)(O.Monad) - U.deepStrictEqual(pipe([], reduceRightKind("-", () => O.none())), O.some("-")) - U.deepStrictEqual(pipe(["a"], reduceRightKind("-", () => O.none())), O.none()) - U.deepStrictEqual( - pipe(["a", "b", "c"], reduceRightKind("-", (b, a) => O.some(b + a))), - O.some("-cba") - ) - U.deepStrictEqual( - pipe(["a", "b", "c"], reduceRightKind("-", (b, a) => a === "b" ? O.none() : O.some(b + a))), + reduceKind(["a", "b", "c"], "-", (b, a) => a === "b" ? O.none() : O.some(b + a)), O.none() ) }) - it("foldMapKind", () => { - const foldMapKind = _.foldMapKind(RA.Foldable)(O.Alternative) - U.deepStrictEqual(pipe([], foldMapKind(() => O.none())), O.none()) - U.deepStrictEqual(pipe(["a"], foldMapKind(() => O.none())), O.none()) - U.deepStrictEqual(pipe(["a", "b", "c"], foldMapKind((a) => O.some(a))), O.some("a")) + it("coproductMapKind", () => { + const coproductMapKind = _.coproductMapKind(RA.Foldable)(O.Alternative) + U.deepStrictEqual(pipe([], coproductMapKind(() => O.none())), O.none()) + U.deepStrictEqual(pipe(["a"], coproductMapKind(() => O.none())), O.none()) + U.deepStrictEqual(pipe(["a", "b", "c"], coproductMapKind((a) => O.some(a))), O.some("a")) U.deepStrictEqual( - pipe(["a", "b", "c"], foldMapKind((a) => a === "b" ? O.none() : O.some(a))), + pipe(["a", "b", "c"], coproductMapKind((a) => a === "b" ? O.none() : O.some(a))), O.some("a") ) }) From f6e7aa150eaa318486e15ded81c11a02070a9c2f Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 3 Feb 2023 07:21:36 +0100 Subject: [PATCH 165/255] remove @dual tag --- src/Bigint.ts | 4 ---- src/Either.ts | 18 ------------------ src/Number.ts | 4 ---- src/Option.ts | 28 ---------------------------- src/Predicate.ts | 1 - src/ReadonlyArray.ts | 8 -------- src/ReadonlyRecord.ts | 6 ------ src/These.ts | 12 ------------ src/typeclass/Equivalence.ts | 1 - src/typeclass/Order.ts | 1 - 10 files changed, 83 deletions(-) diff --git a/src/Bigint.ts b/src/Bigint.ts index a69f621e0..030eac00d 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -20,7 +20,6 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" export const isBigint: (u: unknown) => u is bigint = predicate.isBigInt /** - * @dual * @category algebraic operations * @since 1.0.0 */ @@ -30,7 +29,6 @@ export const sum: { } = semigroup.bigintSum.combine /** - * @dual * @category algebraic operations * @since 1.0.0 */ @@ -40,7 +38,6 @@ export const multiply: { } = semigroup.bigintMultiply.combine /** - * @dual * @category algebraic operations * @since 1.0.0 */ @@ -53,7 +50,6 @@ export const subtract: { >(2, (self: bigint, that: bigint): bigint => self - that) /** - * @dual * @category algebraic operations * @since 1.0.0 */ diff --git a/src/Either.ts b/src/Either.ts index ed493916f..ebbc78914 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -251,7 +251,6 @@ export const Bicovariant: bicovariant.Bicovariant = bicovarian ) => isLeft(self) ? left(f(self.left)) : right(g(self.right))) /** - * @dual * @category mapping * @since 1.0.0 */ @@ -266,7 +265,6 @@ export const bimap: { * @param self - The input `Either` value to map. * @param f - A transformation function to apply to the `Left` value of the input `Either`. * - * @dual * @category error handling * @since 1.0.0 */ @@ -290,7 +288,6 @@ export const Covariant: covariant.Covariant = covariant.make(< * @param self - An `Either` to map * @param f - The function to map over the value of the `Either` * - * @dual * @category mapping * @since 1.0.0 */ @@ -318,7 +315,6 @@ export const tupled: (self: Either) => Either = invariant.tu ) /** - * @dual * @category mapping * @since 1.0.0 */ @@ -330,7 +326,6 @@ export const flap: { /** * Maps the Right value of this effect to the specified constant value. * - * @dual * @category mapping * @since 1.0.0 */ @@ -373,7 +368,6 @@ export const Pointed: pointed.Pointed = { } /** - * @dual * @category sequencing * @since 1.0.0 */ @@ -401,7 +395,6 @@ export const flatten: (self: Either>) => Either = { * Sequences the specified effect after this effect, but ignores the value * produced by the effect. * - * @dual * @category sequencing * @since 1.0.0 */ @@ -595,7 +586,6 @@ export const lift2: (f: (a: A, b: B) => C) => { } = semiApplicative.lift2(SemiApplicative) /** - * @dual * @category combining * @since 1.0.0 */ @@ -612,7 +602,6 @@ export const zipWith: { } = semiApplicative.zipWith(SemiApplicative) /** - * @dual * @since 1.0.0 */ export const ap: { @@ -717,7 +706,6 @@ export const getFirstRightSemigroup: () => Semigroup> = semiC * 0 * ) * - * @dual * @category getters * @since 1.0.0 */ @@ -856,7 +844,6 @@ export const match = (onLeft: (e: E) => B, onRight: (a: A) => C) * assert.deepStrictEqual(parse(1), E.right(1)) * assert.deepStrictEqual(parse(null), E.left('nullable')) * - * @dual * @category interop * @since 1.0.0 */ @@ -1025,7 +1012,6 @@ export const traverseTap: ( /** * Returns an effect that effectfully "peeks" at the success of this effect. * - * @dual * @category combinators * @since 1.0.0 */ @@ -1188,7 +1174,6 @@ export const getOptionalSemigroup = (S: Semigroup): Semigroup(self: Option) => self is Some = option.isSome * 'a none' * ) * - * @dual * @category pattern matching * @since 1.0.0 */ @@ -312,7 +311,6 @@ export const getLeft: (self: Either) => Option = either.getLeft * assert.deepStrictEqual(pipe(O.some(1), O.toEither(onNone)), E.right(1)) * assert.deepStrictEqual(pipe(O.none(), O.toEither(onNone)), E.left('error')) * - * @dual * @category conversions * @since 1.0.0 */ @@ -338,7 +336,6 @@ export const toEither: { * assert.deepStrictEqual(pipe(some(1), getOrElse(() => 0)), 1) * assert.deepStrictEqual(pipe(none(), getOrElse(() => 0)), 0) * - * @dual * @category error handling * @since 1.0.0 */ @@ -392,7 +389,6 @@ export const getOrElse: { * O.some('a') * ) * - * @dual * @category error handling * @since 1.0.0 */ @@ -416,7 +412,6 @@ export const orElse: { * @param self - The first `Option` to be checked. * @param that - The second `Option` to be considered if the first `Option` is `None`. * - * @dual * @category error handling * @since 1.0.0 */ @@ -605,7 +600,6 @@ export const Covariant: covariant.Covariant = covariant.make(< * @param self - An `Option` to map * @param f - The function to map over the value of the `Option` * - * @dual * @category mapping * @since 1.0.0 */ @@ -631,7 +625,6 @@ export const Invariant: invariant.Invariant = { export const tupled: (self: Option) => Option<[A]> = invariant.tupled(Invariant) /** - * @dual * @category mapping * @since 1.0.0 */ @@ -643,7 +636,6 @@ export const flap: { /** * Maps the `Some` value of this `Option` to the specified constant value. * - * @dual * @category mapping * @since 1.0.0 */ @@ -690,7 +682,6 @@ export const Pointed: pointed.Pointed = { /** * Applies a function to the value of an `Option` and flattens the result, if the input is `Some`. * - * @dual * @category sequencing * @since 1.0.0 */ @@ -722,7 +713,6 @@ export const flatMap: { * assert.deepStrictEqual(pipe(O.some(1), O.flatMapEither(f)), O.some(2)) * assert.deepStrictEqual(pipe(O.some(3), O.flatMapEither(f)), O.none()) * - * @dual * @category sequencing * @since 1.0.0 */ @@ -775,7 +765,6 @@ export const flatMapEither: { * none() * ) * - * @dual * @category sequencing * @since 1.0.0 */ @@ -807,7 +796,6 @@ export const flatten: (self: Option>) => Option = flatMap_ .flatten(FlatMap) /** - * @dual * @category sequencing * @since 1.0.0 */ @@ -817,7 +805,6 @@ export const andThen: { } = flatMap_.andThen(FlatMap) /** - * @dual * @category sequencing * @since 1.0.0 */ @@ -844,7 +831,6 @@ export const Chainable: chainable.Chainable = { * @param that - The `Option` that will be ignored in the chain and discarded * @param self - The `Option` we care about * - * @dual * @category sequencing * @since 1.0.0 */ @@ -862,7 +848,6 @@ export const andThenDiscard: { * @param f - Function to apply to the value of the `Option` if it is `Some` * @param self - The `Option` to apply the function to * - * @dual * @category sequencing * @since 1.0.0 */ @@ -881,7 +866,6 @@ export const tap: { * @param self - the `Option` to inspect * @param onSome - callback function that is called with the value of `self` if it is a `Some` * - * @dual * @category debugging * @since 1.0.0 */ @@ -904,7 +888,6 @@ export const inspectSome: { * @param self - the `Option` to inspect * @param onNone - callback function that is is called if `self` is a `None` * - * @dual * @category debugging * @since 1.0.0 */ @@ -1062,7 +1045,6 @@ export const getOptionalMonoid = ( * @param that - The right-hand side of the zip operation * @param f - The function used to combine the values of the two `Option`s * - * @dual * @category combining * @since 1.0.0 */ @@ -1072,7 +1054,6 @@ export const zipWith: { } = semiApplicative.zipWith(SemiApplicative) /** - * @dual * @category combining * @since 1.0.0 */ @@ -1212,7 +1193,6 @@ export const Alternative: alternative.Alternative = { * const iterable = [some(1), none(), some(2), none()] * assert.deepStrictEqual(pipe(iterable, reduceCompact(0, (b, a) => b + a)), 3) * - * @dual * @category folding * @since 1.0.0 */ @@ -1288,7 +1268,6 @@ export const separate: (self: Option>) => [Option, Option< * @param self - The `Option` to map over. * @param f - A function to apply to the value of the `Option`. * - * @dual * @category filtering * @since 1.0.0 */ @@ -1320,7 +1299,6 @@ export const Filterable: filterable.Filterable = { * @param predicate - A predicate function to apply to the `Option` value. * @param fb - The `Option` to filter. * - * @dual * @category filtering * @since 1.0.0 */ @@ -1536,7 +1514,6 @@ export const liftEither = , E, B>( * assert.deepStrictEqual(pipe(some(1), contains(Equivalence)(2)), false) * assert.deepStrictEqual(pipe(none(), contains(Equivalence)(2)), false) * - * @dual * @since 1.0.0 */ export const contains = (equivalence: Equivalence): { @@ -1564,7 +1541,6 @@ export const contains = (equivalence: Equivalence): { * assert.deepStrictEqual(pipe(some(1), exists(isEven)), false) * assert.deepStrictEqual(pipe(none(), exists(isEven)), false) * - * @dual * @since 1.0.0 */ export const exists: { @@ -1584,7 +1560,6 @@ export const exists: { // ------------------------------------------------------------------------------------- /** - * @dual * @category algebraic operations * @since 1.0.0 */ @@ -1594,7 +1569,6 @@ export const sum: { } = lift2(N.sum) /** - * @dual * @category algebraic operations * @since 1.0.0 */ @@ -1604,7 +1578,6 @@ export const multiply: { } = lift2(N.multiply) /** - * @dual * @category algebraic operations * @since 1.0.0 */ @@ -1614,7 +1587,6 @@ export const subtract: { } = lift2(N.subtract) /** - * @dual * @category algebraic operations * @since 1.0.0 */ diff --git a/src/Predicate.ts b/src/Predicate.ts index 8a493aa5a..d926e53e8 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -94,7 +94,6 @@ export const Contravariant: contravariant.Contravariant = c ): Predicate => (b) => self(f(b))) /** - * @dual * @category combinators * @since 1.0.0 */ diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 371a9105c..a9c6a2215 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1214,7 +1214,6 @@ export const of = (a: A): NonEmptyArray => [a] export const empty: () => Array = () => [] /** - * @dual * @category mapping * @since 1.0.0 */ @@ -1329,7 +1328,6 @@ export { } /** - * @dual * @category mapping * @since 1.0.0 */ @@ -1341,7 +1339,6 @@ export const flap: { /** * Maps the success value of this effect to the specified constant value. * - * @dual * @category mapping * @since 1.0.0 */ @@ -1377,7 +1374,6 @@ export const flatMapWithIndex = (f: (a: A, i: number) => ReadonlyArray) } /** - * @dual * @category sequencing * @since 1.0.0 */ @@ -1435,7 +1431,6 @@ export const flattenNonEmpty: ( ) => NonEmptyArray = flatMapNonEmpty(identity) /** - * @dual * @since 1.0.0 */ export const composeKleisliArrow: { @@ -1506,7 +1501,6 @@ export const separate = ( } /** - * @dual * @category filtering * @since 1.0.0 */ @@ -1540,7 +1534,6 @@ export const Compactable: compactable.Compactable = { // TODO: input as interables /** - * @dual * @category filtering * @since 1.0.0 */ @@ -1787,7 +1780,6 @@ export const SemiApplicative: semiApplicative.SemiApplicative { * { '1': 2, '2': 4, '3': 6, '4': 8 } * ) * - * @dual * @category constructors * @since 1.0.0 */ @@ -70,7 +69,6 @@ export const fromIterable: { * assert.deepStrictEqual(get(person, "name"), some("John Doe")) * assert.deepStrictEqual(get(person, "email"), none()) * - * @dual * @category getters * @since 1.0.0 */ @@ -109,7 +107,6 @@ export const get: { * none() * ) * - * @dual * @since 1.0.0 */ export const modifyOption: { @@ -147,7 +144,6 @@ export const modifyOption: { * ) * assert.deepStrictEqual(replaceOption({}, 'a', 10), none()) * - * @dual * @since 1.0.0 */ export const replaceOption: { @@ -175,7 +171,6 @@ export const replaceOption: { * * assert.deepStrictEqual(mapWithKey({ a: 3, b: 5 }, f), { a: "A-3", b: "B-5" }) * - * @dual * @category mapping * @since 1.0.0 */ @@ -211,7 +206,6 @@ export const mapWithKey: { * * assert.deepStrictEqual(map({ a: 3, b: 5 }, f), { a: "-3-", b: "-5-" }) * - * @dual * @category mapping * @since 1.0.0 */ diff --git a/src/These.ts b/src/These.ts index 234f054fd..9800e4218 100644 --- a/src/These.ts +++ b/src/These.ts @@ -567,7 +567,6 @@ export const Bicovariant: bicovariant.Bicovariant = bicovariant ) /** - * @dual * @category mapping * @since 1.0.0 */ @@ -582,7 +581,6 @@ export const bimap: { * @param self - The input `These` value to map. * @param f - A transformation function to apply to the `Left` value of the input `These`. * - * @dual * @category error handling * @since 1.0.0 */ @@ -603,7 +601,6 @@ export const toValidated: (self: These) => Validated = mapLeft * @param self - An `These` to map * @param f - The function to map over the value of the `These` * - * @dual * @category mapping * @since 1.0.0 */ @@ -640,7 +637,6 @@ export const tupled: (self: These) => These = invariant.tupl ) /** - * @dual * @category mapping * @since 1.0.0 */ @@ -652,7 +648,6 @@ export const flap: { /** * Maps the right value of this effect to the specified constant value. * - * @dual * @category mapping * @since 1.0.0 */ @@ -982,7 +977,6 @@ export const lift2: (f: (a: A, b: B) => C) => { } = semiApplicative.lift2(SemiApplicative) /** - * @dual * @category combining * @since 1.0.0 */ @@ -1001,7 +995,6 @@ export const zipWith: { ) /** - * @dual * @since 1.0.0 */ export const ap: { @@ -1091,7 +1084,6 @@ export const struct: >>( .struct(Product) /** - * @dual * @category sequencing * @since 1.0.0 */ @@ -1157,7 +1149,6 @@ export const flatten: ( .flatten(FlatMap) /** - * @dual * @since 1.0.0 */ export const andThen: { @@ -1166,7 +1157,6 @@ export const andThen: { } = flatMap_.andThen(FlatMap) /** - * @dual * @since 1.0.0 */ export const composeKleisliArrow: { @@ -1229,7 +1219,6 @@ export const bindThese = ( * Sequences the specified effect after this effect, but ignores the value * produced by the effect. * - * @dual * @category sequencing * @since 1.0.0 */ @@ -1241,7 +1230,6 @@ export const andThenDiscard: { /** * Returns an effect that effectfully "peeks" at the success of this effect. * - * @dual * @category combinators * @since 1.0.0 */ diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 8395cde8a..558e5d8a8 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -187,7 +187,6 @@ export const Contravariant: contravariant.Contravariant = ) /** - * @dual * @category combinators * @since 1.0.0 */ diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 4e99242d9..d5f8669d6 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -184,7 +184,6 @@ export const Contravariant: contravariant.Contravariant = contr >(self: Order, f: (b: B) => A): Order => make((b1, b2) => self.compare(f(b1), f(b2)))) /** - * @dual * @category combinators * @since 1.0.0 */ From c1d4606061d089a67c4d730d368e288c8ec74bd8 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 3 Feb 2023 07:27:43 +0100 Subject: [PATCH 166/255] rename foldMap to combineMap --- docs/modules/ReadonlyArray.ts.md | 44 +++++++++++++++-------------- src/ReadonlyArray.ts | 12 ++++---- test/ReadonlyArray.ts | 22 +++++++-------- test/limbo/FoldableWithIndex.ts | 2 +- test/typeclass/FoldableWithIndex.ts | 6 ++-- 5 files changed, 44 insertions(+), 42 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 2e80f55de..83d7e61c6 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -48,11 +48,11 @@ Added in v1.0.0 - [traverseFilterMap](#traversefiltermap) - [traversePartitionMap](#traversepartitionmap) - [folding](#folding) - - [foldMap](#foldmap) - - [foldMapKind](#foldmapkind) - - [foldMapNonEmpty](#foldmapnonempty) - - [foldMapNonEmptyWithIndex](#foldmapnonemptywithindex) - - [foldMapWithIndex](#foldmapwithindex) + - [combineMap](#combinemap) + - [combineMapNonEmpty](#combinemapnonempty) + - [combineMapNonEmptyWithIndex](#combinemapnonemptywithindex) + - [combineMapWithIndex](#combinemapwithindex) + - [coproductMapKind](#coproductmapkind) - [reduce](#reduce) - [reduceKind](#reducekind) - [reduceRight](#reduceright) @@ -579,58 +579,60 @@ Added in v1.0.0 # folding -## foldMap +## combineMap **Signature** ```ts -export declare const foldMap: (M: Monoid) => (f: (a: A) => M) => (self: readonly A[]) => M +export declare const combineMap: (M: Monoid) => (f: (a: A) => M) => (self: readonly A[]) => M ``` Added in v1.0.0 -## foldMapKind +## combineMapNonEmpty **Signature** ```ts -export declare const foldMapKind: ( - F: Coproduct -) => (f: (a: A) => Kind) => (self: readonly A[]) => Kind +export declare const combineMapNonEmpty: ( + S: Semigroup +) => (f: (a: A) => S) => (self: readonly [A, ...A[]]) => S ``` Added in v1.0.0 -## foldMapNonEmpty +## combineMapNonEmptyWithIndex **Signature** ```ts -export declare const foldMapNonEmpty: (S: Semigroup) => (f: (a: A) => S) => (self: readonly [A, ...A[]]) => S +export declare const combineMapNonEmptyWithIndex: ( + S: Semigroup +) => (f: (a: A, i: number) => S) => (self: readonly [A, ...A[]]) => S ``` Added in v1.0.0 -## foldMapNonEmptyWithIndex +## combineMapWithIndex **Signature** ```ts -export declare const foldMapNonEmptyWithIndex: ( - S: Semigroup -) => (f: (a: A, i: number) => S) => (self: readonly [A, ...A[]]) => S +export declare const combineMapWithIndex: ( + Monoid: Monoid +) => (f: (a: A, i: number) => M) => (self: readonly A[]) => M ``` Added in v1.0.0 -## foldMapWithIndex +## coproductMapKind **Signature** ```ts -export declare const foldMapWithIndex: ( - Monoid: Monoid -) => (f: (a: A, i: number) => M) => (self: readonly A[]) => M +export declare const coproductMapKind: ( + F: Coproduct +) => (f: (a: A) => Kind) => (self: readonly A[]) => Kind ``` Added in v1.0.0 diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index a9c6a2215..d57dca8ba 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1887,7 +1887,7 @@ export const reduce: { * @category folding * @since 1.0.0 */ -export const foldMapWithIndex = (Monoid: Monoid) => +export const combineMapWithIndex = (Monoid: Monoid) => (f: (a: A, i: number) => M) => (self: ReadonlyArray): M => self.reduce((m, a, i) => Monoid.combine(m, f(a, i)), Monoid.empty) @@ -1896,7 +1896,7 @@ export const foldMapWithIndex = (Monoid: Monoid) => * @category folding * @since 1.0.0 */ -export const foldMap = (M: Monoid) => +export const combineMap = (M: Monoid) => (f: (a: A) => M) => (self: ReadonlyArray): M => self.reduce((m, a) => M.combine(m, f(a)), M.empty) @@ -1904,14 +1904,14 @@ export const foldMap = (M: Monoid) => * @category folding * @since 1.0.0 */ -export const foldMapNonEmpty = (S: Semigroup) => - (f: (a: A) => S): (self: NonEmptyReadonlyArray) => S => foldMapNonEmptyWithIndex(S)(f) +export const combineMapNonEmpty = (S: Semigroup) => + (f: (a: A) => S): (self: NonEmptyReadonlyArray) => S => combineMapNonEmptyWithIndex(S)(f) /** * @category folding * @since 1.0.0 */ -export const foldMapNonEmptyWithIndex = (S: Semigroup) => +export const combineMapNonEmptyWithIndex = (S: Semigroup) => (f: (a: A, i: number) => S) => (self: NonEmptyReadonlyArray): S => tailNonEmpty(self).reduce((s, a, i) => S.combine(s, f(a, i + 1)), f(headNonEmpty(self), 0)) @@ -1929,7 +1929,7 @@ export const reduceKind: (F: monad.Monad) => (F: Coproduct) => ( +export const coproductMapKind: (F: Coproduct) => ( f: (a: A) => Kind ) => (self: ReadonlyArray) => Kind = foldable.coproductMapKind(Foldable) diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 869468ebf..5eed2fe61 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -53,9 +53,9 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.Foldable).exist expect(RA.reduce).exist expect(RA.reduceRight).exist - expect(RA.foldMap).exist + expect(RA.combineMap).exist expect(RA.reduceKind).exist - expect(RA.foldMapKind).exist + expect(RA.coproductMapKind).exist expect(RA.Traversable).exist expect(RA.traverse).exist @@ -843,9 +843,9 @@ describe.concurrent("ReadonlyArray", () => { ]) }) - it("foldMap", () => { - deepStrictEqual(pipe(["a", "b", "c"], RA.foldMap(String.Monoid)(identity)), "abc") - deepStrictEqual(pipe([], RA.foldMap(String.Monoid)(identity)), "") + it("combineMap", () => { + deepStrictEqual(pipe(["a", "b", "c"], RA.combineMap(String.Monoid)(identity)), "abc") + deepStrictEqual(pipe([], RA.combineMap(String.Monoid)(identity)), "") }) it("compact", () => { @@ -898,11 +898,11 @@ describe.concurrent("ReadonlyArray", () => { deepStrictEqual(pipe([], RA.filterMap(f)), []) }) - it("foldMapWithIndex", () => { + it("combineMapWithIndex", () => { deepStrictEqual( pipe( ["a", "b"], - RA.foldMapWithIndex(String.Monoid)((a, i) => i + a) + RA.combineMapWithIndex(String.Monoid)((a, i) => i + a) ), "0a1b" ) @@ -1554,21 +1554,21 @@ describe.concurrent("ReadonlyArray", () => { deepStrictEqual(pipe([1, 2, -3], RA.every(isPositive)), false) }) - it("foldMapNonEmpty", () => { + it("combineMapNonEmpty", () => { deepStrictEqual( pipe( RA.make("a", "b", "c"), - RA.foldMapNonEmpty(String.Semigroup)(identity) + RA.combineMapNonEmpty(String.Semigroup)(identity) ), "abc" ) }) - it("foldMapNonEmptyWithIndex", () => { + it("combineMapNonEmptyWithIndex", () => { deepStrictEqual( pipe( RA.make("a", "b"), - RA.foldMapNonEmptyWithIndex(String.Semigroup)((a, i) => i + a) + RA.combineMapNonEmptyWithIndex(String.Semigroup)((a, i) => i + a) ), "0a1b" ) diff --git a/test/limbo/FoldableWithIndex.ts b/test/limbo/FoldableWithIndex.ts index 2ba05f9ec..e68f8f629 100644 --- a/test/limbo/FoldableWithIndex.ts +++ b/test/limbo/FoldableWithIndex.ts @@ -93,7 +93,7 @@ export const toArrayWith = ( /** * @since 1.0.0 */ -export const foldMapWithIndex = ( +export const combineMapWithIndex = ( F: FoldableWithIndex ) => (M: Monoid) => diff --git a/test/typeclass/FoldableWithIndex.ts b/test/typeclass/FoldableWithIndex.ts index 1fc9c8f4d..3d9551dca 100644 --- a/test/typeclass/FoldableWithIndex.ts +++ b/test/typeclass/FoldableWithIndex.ts @@ -57,10 +57,10 @@ describe("FoldableWithIndex", () => { U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith((a, i) => U.double(a) * i)), [0]) }) - it("foldMapWithIndex", () => { - const foldMapWithIndex = _.foldMapWithIndex(FoldableWithIndex) + it("combineMapWithIndex", () => { + const combineMapWithIndex = _.combineMapWithIndex(FoldableWithIndex) U.deepStrictEqual( - pipe([1, 2, 3], foldMapWithIndex(N.MonoidSum)((n, i) => (n * 2) + i)), + pipe([1, 2, 3], combineMapWithIndex(N.MonoidSum)((n, i) => (n * 2) + i)), 15 ) }) From 9ed1cb47358dd9c2092f9ee2f2bb30b2a649da00 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 3 Feb 2023 08:14:29 +0100 Subject: [PATCH 167/255] SemiCoproduct: make dual --- docs/modules/typeclass/SemiCoproduct.ts.md | 46 ++++++++++++++++--- src/Either.ts | 24 +++------- src/Option.ts | 49 ++++++++++----------- src/These.ts | 24 +++------- src/typeclass/SemiCoproduct.ts | 51 +++++++++++++++++----- 5 files changed, 115 insertions(+), 79 deletions(-) diff --git a/docs/modules/typeclass/SemiCoproduct.ts.md b/docs/modules/typeclass/SemiCoproduct.ts.md index f1b124225..e8eae9e73 100644 --- a/docs/modules/typeclass/SemiCoproduct.ts.md +++ b/docs/modules/typeclass/SemiCoproduct.ts.md @@ -12,6 +12,8 @@ Added in v1.0.0

Table of contents

+- [constructors](#constructors) + - [make](#make) - [type class](#type-class) - [SemiCoproduct (interface)](#semicoproduct-interface) - [utils](#utils) @@ -19,23 +21,53 @@ Added in v1.0.0 --- -# type class +# constructors -## SemiCoproduct (interface) +## make **Signature** ```ts -export interface SemiCoproduct extends Invariant { - readonly coproduct: ( +export declare const make: ( + Invariant: Invariant, + coproduct: ( self: Kind, that: Kind - ) => Kind - - readonly coproductMany: ( + ) => Kind, + coproductMany: ( self: Kind, collection: Iterable> ) => Kind +) => SemiCoproduct +``` + +Added in v1.0.0 + +# type class + +## SemiCoproduct (interface) + +**Signature** + +```ts +export interface SemiCoproduct extends Invariant { + readonly coproduct: { + (that: Kind): ( + self: Kind + ) => Kind + (self: Kind, that: Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + A | B + > + } + + readonly coproductMany: { + (collection: Iterable>): (self: Kind) => Kind + (self: Kind, collection: Iterable>): Kind + } } ``` diff --git a/src/Either.ts b/src/Either.ts index ebbc78914..dbfb8d972 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -654,25 +654,15 @@ export const firstRightOf = (collection: Iterable>) => return out } -const coproduct = ( - self: Either, - that: Either -): Either => isRight(self) ? self : that - -const coproductMany = ( - self: Either, - collection: Iterable> -): Either => pipe(self, firstRightOf(collection)) - /** * @category instances * @since 1.0.0 */ -export const SemiCoproduct: semiCoproduct.SemiCoproduct = { - imap, - coproduct, - coproductMany -} +export const SemiCoproduct: semiCoproduct.SemiCoproduct = semiCoproduct.make( + Invariant, + (self, that) => isRight(self) ? self : that, + (self, collection) => pipe(self, firstRightOf(collection)) +) /** * Semigroup returning the left-most `Right` value. @@ -765,8 +755,8 @@ export const orElseFail = ( export const SemiAlternative: semiAlternative.SemiAlternative = { map, imap, - coproduct, - coproductMany + coproduct: SemiCoproduct.coproduct, + coproductMany: SemiCoproduct.coproductMany } /** diff --git a/src/Option.ts b/src/Option.ts index c4605656e..e61d0b51a 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1104,31 +1104,26 @@ export const getFailureMonoid:
(M: Monoid) => Monoid> = applicat Applicative ) -const coproduct = (self: Option, that: Option): Option => - isSome(self) ? self : that - -const coproductMany = (self: Option, collection: Iterable>): Option => { - let out = self - if (isSome(out)) { - return out - } - for (out of collection) { - if (isSome(out)) { - return out - } - } - return out -} - /** * @category instances * @since 1.0.0 */ -export const SemiCoproduct: semiCoproduct.SemiCoproduct = { - imap, - coproduct, - coproductMany -} +export const SemiCoproduct: semiCoproduct.SemiCoproduct = semiCoproduct.make( + Invariant, + (self, that) => isSome(self) ? self : that, + (self, collection) => { + let out = self + if (isSome(out)) { + return out + } + for (out of collection) { + if (isSome(out)) { + return out + } + } + return out + } +) /** * Semigroup returning the first `Some` value encountered. @@ -1145,8 +1140,8 @@ export const getFirstSomeSemigroup: () => Semigroup> = semiCoproduc */ export const Coproduct: coproduct_.Coproduct = { imap, - coproduct, - coproductMany, + coproduct: SemiCoproduct.coproduct, + coproductMany: SemiCoproduct.coproductMany, zero: none, coproductAll: firstSomeOf } @@ -1158,8 +1153,8 @@ export const Coproduct: coproduct_.Coproduct = { export const SemiAlternative: semiAlternative.SemiAlternative = { map, imap, - coproduct, - coproductMany + coproduct: SemiCoproduct.coproduct, + coproductMany: SemiCoproduct.coproductMany } /** @@ -1169,8 +1164,8 @@ export const SemiAlternative: semiAlternative.SemiAlternative export const Alternative: alternative.Alternative = { map, imap, - coproduct, - coproductMany, + coproduct: SemiCoproduct.coproduct, + coproductMany: SemiCoproduct.coproductMany, coproductAll: firstSomeOf, zero: none } diff --git a/src/These.ts b/src/These.ts index 9800e4218..721b810d2 100644 --- a/src/These.ts +++ b/src/These.ts @@ -820,25 +820,15 @@ export const firstRightOrBothOf = (collection: Iterable>) => return out } -const coproduct = ( - self: These, - that: These -): These => isRightOrBoth(self) ? self : that - -const coproductMany = ( - self: These, - collection: Iterable> -): These => pipe(self, firstRightOrBothOf(collection)) - /** * @category instances * @since 1.0.0 */ -export const SemiCoproduct: semiCoproduct.SemiCoproduct = { - imap, - coproduct, - coproductMany -} +export const SemiCoproduct: semiCoproduct.SemiCoproduct = semiCoproduct.make( + Invariant, + (self, that) => isRightOrBoth(self) ? self : that, + (self, collection) => pipe(self, firstRightOrBothOf(collection)) +) /** * @category combining @@ -854,8 +844,8 @@ export const getFirstRightOrBothSemigroup: () => Semigroup> = export const SemiAlternative: semiAlternative.SemiAlternative = { map, imap, - coproduct, - coproductMany + coproduct: SemiCoproduct.coproduct, + coproductMany: SemiCoproduct.coproductMany } /** diff --git a/src/typeclass/SemiCoproduct.ts b/src/typeclass/SemiCoproduct.ts index 28e1a0a50..32f6fb189 100644 --- a/src/typeclass/SemiCoproduct.ts +++ b/src/typeclass/SemiCoproduct.ts @@ -2,33 +2,62 @@ * @since 1.0.0 */ +import { dual } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" -import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** * @category type class * @since 1.0.0 */ export interface SemiCoproduct extends Invariant { - readonly coproduct: ( + readonly coproduct: { + ( + that: Kind + ): (self: Kind) => Kind + ( + self: Kind, + that: Kind + ): Kind + } + + readonly coproductMany: { + ( + collection: Iterable> + ): (self: Kind) => Kind + ( + self: Kind, + collection: Iterable> + ): Kind + } +} + +/** + * @category constructors + * @since 1.0.0 + */ +export const make = ( + Invariant: Invariant, + coproduct: ( self: Kind, that: Kind - ) => Kind - - readonly coproductMany: ( + ) => Kind, + coproductMany: ( self: Kind, collection: Iterable> ) => Kind -} +): SemiCoproduct => ({ + imap: Invariant.imap, + coproduct: dual(2, coproduct), + coproductMany: dual(2, coproductMany) +}) /** * @since 1.0.0 */ export const getSemigroup = (F: SemiCoproduct) => - (): Semigroup> => - semigroup.make( - F.coproduct, - F.coproductMany - ) + (): Semigroup> => ({ + combine: F.coproduct, + combineMany: F.coproductMany + }) From 730b9cd52b861ce1821954e5426bef062fbd8c96 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 3 Feb 2023 09:19:58 +0100 Subject: [PATCH 168/255] SemiProduct: make dual --- docs/modules/Function.ts.md | 76 +-------------- docs/modules/typeclass/Equivalence.ts.md | 5 +- docs/modules/typeclass/SemiProduct.ts.md | 69 ++++++++++---- src/Either.ts | 60 ++++++------ src/Function.ts | 80 ++++------------ src/Identity.ts | 12 +-- src/Option.ts | 57 ++++++------ src/Predicate.ts | 55 +++++------ src/ReadonlyArray.ts | 71 ++++++-------- src/These.ts | 66 ++++++------- src/internal/Function.ts | 21 ----- src/typeclass/Equivalence.ts | 19 ++-- src/typeclass/Invariant.ts | 2 +- src/typeclass/Order.ts | 30 ++---- src/typeclass/SemiProduct.ts | 112 +++++++++++++---------- src/typeclass/Semigroup.ts | 14 +-- test/Function.ts | 23 ----- test/typeclass/Monoid.ts | 16 ++-- test/typeclass/SemiProduct.ts | 35 +------ 19 files changed, 327 insertions(+), 496 deletions(-) delete mode 100644 src/internal/Function.ts diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 091460a20..634a1510f 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -12,9 +12,6 @@ Added in v1.0.0

Table of contents

-- [instances](#instances) - - [getMonoid](#getmonoid) - - [getSemigroup](#getsemigroup) - [type lambdas](#type-lambdas) - [FunctionTypeLambda (interface)](#functiontypelambda-interface) - [utils](#utils) @@ -42,74 +39,6 @@ Added in v1.0.0 --- -# instances - -## getMonoid - -Unary functions form a monoid as long as you can provide a monoid for the codomain. - -**Signature** - -```ts -export declare const getMonoid: (Monoid: Monoid) =>
() => Monoid<(a: A) => M> -``` - -**Example** - -```ts -import { Predicate } from '@fp-ts/core/Predicate' -import { getMonoid, pipe } from '@fp-ts/core/Function' -import * as B from '@fp-ts/core/Boolean' - -const f: Predicate = (n) => n <= 2 -const g: Predicate = (n) => n >= 0 - -const M1 = getMonoid(B.MonoidAll)() - -assert.deepStrictEqual(M1.combine(f, g)(1), true) -assert.deepStrictEqual(M1.combine(f, g)(3), false) - -const M2 = getMonoid(B.MonoidAny)() - -assert.deepStrictEqual(M2.combine(f, g)(1), true) -assert.deepStrictEqual(M2.combine(f, g)(3), true) -``` - -Added in v1.0.0 - -## getSemigroup - -Unary functions form a semigroup as long as you can provide a semigroup for the codomain. - -**Signature** - -```ts -export declare const getSemigroup: (S: Semigroup) => () => Semigroup<(a: A) => S> -``` - -**Example** - -```ts -import { Predicate } from '@fp-ts/core/Predicate' -import { pipe, getSemigroup } from '@fp-ts/core/Function' -import * as B from '@fp-ts/core/Boolean' - -const f: Predicate = (n) => n <= 2 -const g: Predicate = (n) => n >= 0 - -const S1 = getSemigroup(B.SemigroupAll)() - -assert.deepStrictEqual(S1.combine(f, g)(1), true) -assert.deepStrictEqual(S1.combine(f, g)(3), false) - -const S2 = getSemigroup(B.SemigroupAny)() - -assert.deepStrictEqual(S2.combine(f, g)(1), true) -assert.deepStrictEqual(S2.combine(f, g)(3), true) -``` - -Added in v1.0.0 - # type lambdas ## FunctionTypeLambda (interface) @@ -288,7 +217,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const dual: any, DataFirst extends (...args: any[]) => any>( +export declare const dual: < + DataLast extends (...args: Array) => any, + DataFirst extends (...args: Array) => any +>( dataFirstArity: Parameters['length'], body: DataFirst ) => DataLast & DataFirst diff --git a/docs/modules/typeclass/Equivalence.ts.md b/docs/modules/typeclass/Equivalence.ts.md index f89c9e06e..8145f9b01 100644 --- a/docs/modules/typeclass/Equivalence.ts.md +++ b/docs/modules/typeclass/Equivalence.ts.md @@ -65,7 +65,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const contramap: (f: (b: B) => A) => (self: Equivalence) => Equivalence +export declare const contramap: { + (f: (b: B) => A): (self: Equivalence) => Equivalence + (self: Equivalence, f: (b: B) => A): Equivalence +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index a9e597601..c77222074 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -13,7 +13,8 @@ Added in v1.0.0

Table of contents

- [constructors](#constructors) - - [productMany](#productmany) + - [fromProduct](#fromproduct) + - [make](#make) - [do notation](#do-notation) - [andThenBind](#andthenbind) - [type class](#type-class) @@ -29,20 +30,40 @@ Added in v1.0.0 # constructors -## productMany +## fromProduct -Returns a default `productMany` implementation (useful for tests). +Useful when `productMany` can't be optimised. **Signature** ```ts -export declare const productMany: ( +export declare const fromProduct: ( Covariant: Covariant, product: ( self: Kind, that: Kind ) => Kind -) => (self: Kind, collection: Iterable>) => Kind +) => SemiProduct +``` + +Added in v1.0.0 + +## make + +**Signature** + +```ts +export declare const make: ( + Invariant: Invariant, + product: ( + self: Kind, + that: Kind + ) => Kind, + productMany: ( + self: Kind, + collection: Iterable> + ) => Kind +) => SemiProduct ``` Added in v1.0.0 @@ -74,15 +95,31 @@ Added in v1.0.0 ```ts export interface SemiProduct extends Invariant { - readonly product: ( - self: Kind, - that: Kind - ) => Kind - - readonly productMany: ( - self: Kind, - collection: Iterable> - ) => Kind]> + readonly product: { + (that: Kind): ( + self: Kind + ) => Kind + (self: Kind, that: Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + [A, B] + > + } + + readonly productMany: { + (collection: Iterable>): ( + self: Kind + ) => Kind]> + (self: Kind, collection: Iterable>): Kind< + F, + R, + O, + E, + [A, ...Array
] + > + } } ``` @@ -154,7 +191,7 @@ Added in v1.0.0 ## productComposition -Returns a default `product` composition. +Returns a default binary `product` composition. **Signature** @@ -172,7 +209,7 @@ Added in v1.0.0 ## productManyComposition -Returns a default `productMany` composition. +Returns a default binary `productMany` composition. **Signature** diff --git a/src/Either.ts b/src/Either.ts index dbfb8d972..c3cb1454a 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -448,38 +448,30 @@ export const Monad: monad.Monad = { flatMap } -const productMany = ( - self: Either, - collection: Iterable> -): Either]> => { - if (isLeft(self)) { - return self - } - const out: [A, ...Array] = [self.right] - for (const e of collection) { - if (isLeft(e)) { - return e - } - out.push(e.right) - } - return right(out) -} - -const product = ( - self: Either, - that: Either -): Either => - isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self - /** * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = { - imap, - product, - productMany -} +export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( + Invariant, + (self, that) => isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self, + ( + self: Either, + collection: Iterable> + ): Either]> => { + if (isLeft(self)) { + return self + } + const out: [A, ...Array] = [self.right] + for (const e of collection) { + if (isLeft(e)) { + return e + } + out.push(e.right) + } + return right(out) + } +) /** * Appends an element to the end of a tuple. @@ -516,8 +508,8 @@ const productAll = ( export const Product: product_.Product = { of, imap, - product, - productMany, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll } @@ -550,8 +542,8 @@ export const struct: >>( export const SemiApplicative: semiApplicative.SemiApplicative = { imap, map, - product, - productMany + product: SemiProduct.product, + productMany: SemiProduct.productMany } /** @@ -617,8 +609,8 @@ export const Applicative: applicative.Applicative = { imap, of, map, - product, - productMany, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll } diff --git a/src/Function.ts b/src/Function.ts index 70a531b7d..6b38742b1 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -2,10 +2,6 @@ * @since 1.0.0 */ import type { TypeLambda } from "@fp-ts/core/HKT" -import * as internal from "@fp-ts/core/internal/Function" -import type { Monoid } from "@fp-ts/core/typeclass/Monoid" -import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" -import * as semigroup from "@fp-ts/core/typeclass/Semigroup" // ------------------------------------------------------------------------------------- // type lambdas @@ -25,65 +21,6 @@ export interface FunctionTypeLambda extends TypeLambda { export const compose: (bc: (b: B) => C) => (ab: (a: A) => B) => (a: A) => C = (bc) => (ab) => flow(ab, bc) -/** - * Unary functions form a semigroup as long as you can provide a semigroup for the codomain. - * - * @example - * import { Predicate } from '@fp-ts/core/Predicate' - * import { pipe, getSemigroup } from '@fp-ts/core/Function' - * import * as B from '@fp-ts/core/Boolean' - * - * const f: Predicate = (n) => n <= 2 - * const g: Predicate = (n) => n >= 0 - * - * const S1 = getSemigroup(B.SemigroupAll)() - * - * assert.deepStrictEqual(S1.combine(f, g)(1), true) - * assert.deepStrictEqual(S1.combine(f, g)(3), false) - * - * const S2 = getSemigroup(B.SemigroupAny)() - * - * assert.deepStrictEqual(S2.combine(f, g)(1), true) - * assert.deepStrictEqual(S2.combine(f, g)(3), true) - * - * @category instances - * @since 1.0.0 - */ -export const getSemigroup = (S: Semigroup) => - (): Semigroup<(a: A) => S> => - semigroup.fromCombine((self, that) => (a) => S.combine(self(a), that(a))) - -/** - * Unary functions form a monoid as long as you can provide a monoid for the codomain. - * - * @example - * import { Predicate } from '@fp-ts/core/Predicate' - * import { getMonoid, pipe } from '@fp-ts/core/Function' - * import * as B from '@fp-ts/core/Boolean' - * - * const f: Predicate = (n) => n <= 2 - * const g: Predicate = (n) => n >= 0 - * - * const M1 = getMonoid(B.MonoidAll)() - * - * assert.deepStrictEqual(M1.combine(f, g)(1), true) - * assert.deepStrictEqual(M1.combine(f, g)(3), false) - * - * const M2 = getMonoid(B.MonoidAny)() - * - * assert.deepStrictEqual(M2.combine(f, g)(1), true) - * assert.deepStrictEqual(M2.combine(f, g)(3), true) - * - * @category instances - * @since 1.0.0 - */ -export const getMonoid = (Monoid: Monoid) => - (): Monoid<(a: A) => M> => { - const S = getSemigroup(Monoid)() - const empty = () => Monoid.empty - return ({ ...S, combineAll: (collection) => S.combineMany(empty, collection), empty }) - } - /** * Apply a function to a given value. * @@ -657,4 +594,19 @@ export const SK = (_: A, b: B): B => b /** * @since 1.0.0 */ -export const dual = internal.dual +export const dual = < + DataLast extends (...args: Array) => any, + DataFirst extends (...args: Array) => any +>( + dataFirstArity: Parameters["length"], + body: DataFirst +): DataLast & DataFirst => { + // @ts-expect-error + return function() { + if (arguments.length >= dataFirstArity) { + // @ts-expect-error + return body.apply(this, arguments) + } + return ((self: any) => body(self, ...arguments)) as any + } +} diff --git a/src/Identity.ts b/src/Identity.ts index ffdf8fd6c..d65a474d6 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -18,7 +18,7 @@ import type * as semiAlternative from "@fp-ts/core/typeclass/SemiAlternative" import type * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import type * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" -import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import type * as traversable from "@fp-ts/core/typeclass/Traversable" /** @@ -155,11 +155,11 @@ export const Monad: monad.Monad = { * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = { - imap: Invariant.imap, - product: (self, that) => [self, that], - productMany: (self, collection) => [self, ...collection] -} +export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( + Invariant, + (self, that) => [self, that], + (self, collection) => [self, ...collection] +) /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index e61d0b51a..aae41f8b2 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -915,35 +915,30 @@ export const Monad: monad.Monad = { flatMap } -const product = (self: Option, that: Option): Option<[A, B]> => - isSome(self) && isSome(that) ? some([self.value, that.value]) : none() - -const productMany = ( - self: Option, - collection: Iterable> -): Option<[A, ...Array]> => { - if (isNone(self)) { - return none() - } - const out: [A, ...Array] = [self.value] - for (const o of collection) { - if (isNone(o)) { - return none() - } - out.push(o.value) - } - return some(out) -} - /** * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = { - imap, - product, - productMany -} +export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( + Invariant, + (self, that) => isSome(self) && isSome(that) ? some([self.value, that.value]) : none(), + ( + self: Option, + collection: Iterable> + ): Option<[A, ...Array]> => { + if (isNone(self)) { + return none() + } + const out: [A, ...Array] = [self.value] + for (const o of collection) { + if (isNone(o)) { + return none() + } + out.push(o.value) + } + return some(out) + } +) /** * Appends an element to the end of a tuple. @@ -973,8 +968,8 @@ const productAll = (collection: Iterable>): Option> => { export const Product: product_.Product = { of, imap, - product, - productMany, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll } @@ -1002,8 +997,8 @@ export const struct: >>( export const SemiApplicative: semiApplicative.SemiApplicative = { imap, map, - product, - productMany + product: SemiProduct.product, + productMany: SemiProduct.productMany } /** @@ -1083,8 +1078,8 @@ export const Applicative: applicative.Applicative = { imap, of, map, - product, - productMany, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll } diff --git a/src/Predicate.ts b/src/Predicate.ts index d926e53e8..d03aae9de 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -153,38 +153,33 @@ export const Do: Predicate<{}> = of_.Do(Of) */ export const unit: Predicate = of_.unit(Of) -const product = ( - self: Predicate, - that: Predicate -): Predicate<[A, B]> => ([a, b]) => self(a) && that(b) - -const productMany = ( - self: Predicate, - collection: Iterable> -): Predicate]> => { - return ([head, ...tail]) => { - if (self(head) === false) { - return false - } - const predicates = readonlyArray.fromIterable(collection) - for (let i = 0; i < predicates.length; i++) { - if (predicates[i](tail[i]) === false) { - return false - } - } - return true - } -} - /** * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = { - imap, - product, - productMany -} +export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( + Invariant, + ( + self: Predicate, + that: Predicate + ): Predicate<[A, B]> => ([a, b]) => self(a) && that(b), + ( + self: Predicate, + collection: Iterable> + ): Predicate]> => + ([head, ...tail]) => { + if (self(head) === false) { + return false + } + const predicates = readonlyArray.fromIterable(collection) + for (let i = 0; i < predicates.length; i++) { + if (predicates[i](tail[i]) === false) { + return false + } + } + return true + } +) const productAll = ( collection: Iterable> @@ -206,8 +201,8 @@ const productAll = ( export const Product: product_.Product = { of, imap, - product, - productMany, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll } diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index d57dca8ba..3445bba94 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1713,46 +1713,26 @@ export const sequenceNonEmpty = ( self: NonEmptyReadonlyArray> ) => Kind>) => traverseNonEmpty(F)(identity) -const product = ( - self: ReadonlyArray, - that: ReadonlyArray -): Array<[A, B]> => { - if (isEmpty(self) || isEmpty(that)) { - return empty() - } - const out: Array<[A, B]> = [] - for (let i = 0; i < self.length; i++) { - for (let j = 0; j < that.length; j++) { - out.push([self[i], that[j]]) - } - } - return out -} - -const productMany: ( - self: ReadonlyArray, - collection: Iterable> -) => Array<[A, ...Array]> = semiProduct.productMany( - Covariant, - product -) as any - -const productAll = ( - collection: Iterable> -): Array> => { - const arrays = fromIterable(collection) - return isEmpty(arrays) ? empty() : productMany(arrays[0], arrays.slice(1)) -} - /** * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = { - imap, - product, - productMany -} +export const SemiProduct: semiProduct.SemiProduct = semiProduct + .fromProduct(Covariant, ( + self: ReadonlyArray, + that: ReadonlyArray + ): Array<[A, B]> => { + if (isEmpty(self) || isEmpty(that)) { + return empty() + } + const out: Array<[A, B]> = [] + for (let i = 0; i < self.length; i++) { + for (let j = 0; j < that.length; j++) { + out.push([self[i], that[j]]) + } + } + return out + }) /** * A variant of `bind` that sequentially ignores the scope. @@ -1775,8 +1755,8 @@ export const andThenBind: ( export const SemiApplicative: semiApplicative.SemiApplicative = { imap, map, - product, - productMany + product: SemiProduct.product, + productMany: SemiProduct.productMany } /** @@ -1807,9 +1787,12 @@ export const lift2: (f: (a: A, b: B) => C) => { export const Product: product_.Product = { of, imap, - product, - productMany, - productAll + product: SemiProduct.product, + productMany: SemiProduct.productMany, + productAll: (collection) => { + const arrays = fromIterable(collection) + return isEmpty(arrays) ? empty() : SemiProduct.productMany(arrays[0], arrays.slice(1)) + } } /** @@ -1820,9 +1803,9 @@ export const Applicative: applicative.Applicative = { imap, of, map, - product, - productMany, - productAll + product: SemiProduct.product, + productMany: SemiProduct.productMany, + productAll: Product.productAll } /** diff --git a/src/These.ts b/src/These.ts index 721b810d2..a705aec97 100644 --- a/src/These.ts +++ b/src/These.ts @@ -926,6 +926,30 @@ const product = ( return both(RA.appendAllNonEmpty(that.left)(self.left), [self.right, that.right]) } +const productAll = ( + collection: Iterable> +): Validated> => { + const rights: Array = [] + const lefts: Array = [] + let isFatal = false + for (const t of collection) { + if (isLeft(t)) { + lefts.push(...t.left) + isFatal = true + break + } else if (isRight(t)) { + rights.push(t.right) + } else { + lefts.push(...t.left) + rights.push(t.right) + } + } + if (RA.isNonEmpty(lefts)) { + return isFatal ? left(lefts) : both(lefts, rights) + } + return right(rights) +} + const productMany = ( self: Validated, collection: Iterable> @@ -936,11 +960,11 @@ const productMany = ( * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = { - imap, +export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( + { imap }, product, productMany -} +) /** * @category instances @@ -949,8 +973,8 @@ export const SemiProduct: semiProduct.SemiProduct = { export const SemiApplicative: semiApplicative.SemiApplicative = { imap, map, - product, - productMany + product: SemiProduct.product, + productMany: SemiProduct.productMany } /** @@ -1003,30 +1027,6 @@ export const getFirstLeftSemigroup: ( ) => Semigroup> = semiApplicative .getSemigroup(SemiApplicative) -const productAll = ( - collection: Iterable> -): Validated> => { - const rights: Array = [] - const lefts: Array = [] - let isFatal = false - for (const t of collection) { - if (isLeft(t)) { - lefts.push(...t.left) - isFatal = true - break - } else if (isRight(t)) { - rights.push(t.right) - } else { - lefts.push(...t.left) - rights.push(t.right) - } - } - if (RA.isNonEmpty(lefts)) { - return isFatal ? left(lefts) : both(lefts, rights) - } - return right(rights) -} - /** * Appends an element to the end of a tuple. * @@ -1049,8 +1049,8 @@ export const appendElement: { export const Product: product_.Product = { of, imap, - product, - productMany, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll } @@ -1108,8 +1108,8 @@ export const Applicative: applicative.Applicative = { imap, of, map, - product, - productMany, + product: SemiProduct.product, + productMany: SemiProduct.productMany, productAll } diff --git a/src/internal/Function.ts b/src/internal/Function.ts deleted file mode 100644 index 256daaea8..000000000 --- a/src/internal/Function.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @since 1.0.0 - */ - -/** @internal */ -export const dual = < - DataLast extends (...args: Array) => any, - DataFirst extends (...args: Array) => any ->( - dataFirstArity: Parameters["length"], - body: DataFirst -): DataLast & DataFirst => { - // @ts-expect-error - return function() { - if (arguments.length >= dataFirstArity) { - // @ts-expect-error - return body.apply(this, arguments) - } - return ((self: any) => body(self, ...arguments)) as any - } -} diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 558e5d8a8..1b21b904e 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -15,7 +15,7 @@ import * as monoid from "@fp-ts/core/typeclass/Monoid" import type * as product from "@fp-ts/core/typeclass/Product" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" -import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** * @category type class @@ -190,8 +190,10 @@ export const Contravariant: contravariant.Contravariant = * @category combinators * @since 1.0.0 */ -export const contramap = (f: (b: B) => A) => - (self: Equivalence): Equivalence => make((x, y) => self(f(x), f(y))) +export const contramap: { + (f: (b: B) => A): (self: Equivalence) => Equivalence + (self: Equivalence, f: (b: B) => A): Equivalence +} = Contravariant.contramap /** * @category instances @@ -205,12 +207,11 @@ export const Invariant: invariant.Invariant = { * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = { - imap: Contravariant.imap, - product: tuple, - productMany: (self, collection) => tuple(self, ...collection) -} - +export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( + Invariant, + tuple, + (self, collection) => tuple(self, ...collection) +) /** * @category instances * @since 1.0.0 diff --git a/src/typeclass/Invariant.ts b/src/typeclass/Invariant.ts index 55f91498a..85857b09b 100644 --- a/src/typeclass/Invariant.ts +++ b/src/typeclass/Invariant.ts @@ -1,8 +1,8 @@ /** * @since 1.0.0 */ +import { dual } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import { dual } from "@fp-ts/core/internal/Function" /** * @category type class diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index d5f8669d6..461224411 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -10,7 +10,7 @@ import * as monoid from "@fp-ts/core/typeclass/Monoid" import type * as product from "@fp-ts/core/typeclass/Product" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" -import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** * @category type class @@ -202,36 +202,26 @@ export const Invariant: invariant.Invariant = { imap } -const productMany = ( - self: Order, - collection: Iterable> -): Order<[A, ...Array]> => tuple(self, ...collection) - /** * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = { - imap, - product: tuple, - productMany -} - -const productAll = (collection: Iterable>): Order> => - tuple>(...collection) - -const of: (a: A) => Order = () => empty +export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( + Invariant, + tuple, + (self, collection) => tuple(self, ...collection) +) /** * @category instances * @since 1.0.0 */ export const Product: product.Product = { - of, + of: () => empty, imap, - product: tuple, - productMany, - productAll + product: SemiProduct.product, + productMany: SemiProduct.productMany, + productAll: (collection: Iterable>): Order> => tuple>(...collection) } /** diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 78fcc0de0..c85a78058 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -12,19 +12,76 @@ import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" * @since 1.0.0 */ export interface SemiProduct extends Invariant { - readonly product: ( + readonly product: { + ( + that: Kind + ): (self: Kind) => Kind + ( + self: Kind, + that: Kind + ): Kind + } + + readonly productMany: { + ( + collection: Iterable> + ): (self: Kind) => Kind]> + ( + self: Kind, + collection: Iterable> + ): Kind]> + } +} + +/** + * @category constructors + * @since 1.0.0 + */ +export const make = ( + Invariant: Invariant, + product: ( self: Kind, that: Kind - ) => Kind - - readonly productMany: ( + ) => Kind, + productMany: ( self: Kind, collection: Iterable> ) => Kind]> -} +): SemiProduct => ({ + imap: Invariant.imap, + product: dual(2, product), + productMany: dual(2, productMany) +}) + +/** + * Useful when `productMany` can't be optimised. + * + * @category constructors + * @since 1.0.0 + */ +export const fromProduct = ( + Covariant: Covariant, + product: ( + self: Kind, + that: Kind + ) => Kind +): SemiProduct => + make(Covariant, product, ( + self: Kind, + collection: Iterable> + ) => { + let out = Covariant.map(self, (a): [A, ...Array] => [a]) + for (const fa of collection) { + out = Covariant.map( + product(out, fa), + ([[head, ...tail], a]): [A, ...Array] => [head, ...tail, a] + ) + } + return out + }) /** - * Returns a default `product` composition. + * Returns a default binary `product` composition. * * @since 1.0.0 */ @@ -41,10 +98,10 @@ export const productComposition = ( FO1 | FO2, FE1 | FE2, Kind - > => pipe(F.product(self, that), F.map(([ga, gb]) => G.product(ga, gb))) + > => F.map(F.product(self, that), ([ga, gb]) => G.product(ga, gb)) /** - * Returns a default `productMany` composition. + * Returns a default binary `productMany` composition. * * @since 1.0.0 */ @@ -61,33 +118,6 @@ export const productManyComposition = G.productMany(ga, gas)) ) -/** - * Returns a default `productMany` implementation (useful for tests). - * - * @category constructors - * @since 1.0.0 - */ -export const productMany = ( - Covariant: Covariant, - product: SemiProduct["product"] -): SemiProduct["productMany"] => - ( - self: Kind, - collection: Iterable> - ) => { - let out = pipe( - self, - Covariant.map((a): [A, ...Array] => [a]) - ) - for (const fa of collection) { - out = pipe( - product(out, fa), - Covariant.map(([[head, ...tail], a]): [A, ...Array] => [head, ...tail, a]) - ) - } - return out - } - /** * @category do notation * @since 1.0.0 @@ -130,17 +160,7 @@ export const appendElement = (F: SemiProduct): { that: Kind ): Kind } => - dual< - ( - that: Kind - ) => >( - self: Kind - ) => Kind, - , R2, O2, E2, B>( - self: Kind, - that: Kind - ) => Kind - >(2, , R2, O2, E2, B>( + dual(2, , R2, O2, E2, B>( self: Kind, that: Kind ): Kind => diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 7358891a5..11eff41f1 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -1,13 +1,13 @@ /** * @since 1.0.0 */ +import { dual } from "@fp-ts/core/Function" import type { TypeLambda } from "@fp-ts/core/HKT" -import { dual } from "@fp-ts/core/internal/Function" import { fromIterable } from "@fp-ts/core/internal/ReadonlyArray" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Order } from "@fp-ts/core/typeclass/Order" import type * as product from "@fp-ts/core/typeclass/Product" -import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** * @category type class @@ -322,11 +322,11 @@ export const imap: { * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = { - imap: Invariant.imap, - product: tuple, - productMany: (self, collection) => tuple(self, ...collection) -} +export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( + Invariant, + tuple, + (self, collection) => tuple(self, ...collection) +) /** * @category instances diff --git a/test/Function.ts b/test/Function.ts index 1c1ab13e7..264d54ae8 100644 --- a/test/Function.ts +++ b/test/Function.ts @@ -1,5 +1,4 @@ import * as _ from "@fp-ts/core/Function" -import * as Number from "@fp-ts/core/Number" import * as String from "@fp-ts/core/String" import { deepStrictEqual, double } from "@fp-ts/core/test/util" import * as assert from "assert" @@ -8,28 +7,6 @@ const f = (n: number): number => n + 1 const g = double describe.concurrent("Function", () => { - it("getSemigroup", () => { - const S = _.getSemigroup(Number.SemigroupSum)() - const f = (s: string) => s === "a" ? 0 : 1 - const g = S.combine(String.length, f) - deepStrictEqual(g(""), 1) - deepStrictEqual(g("a"), 1) - deepStrictEqual(g("b"), 2) - deepStrictEqual(S.combineMany(String.length, [String.length, String.length])("a"), 3) - }) - - it("getMonoid", () => { - const M = _.getMonoid(Number.MonoidSum)() - const f = (s: string) => s === "a" ? 0 : 1 - const g = M.combine(String.length, f) - deepStrictEqual(g(""), 1) - deepStrictEqual(g("a"), 1) - deepStrictEqual(g("b"), 2) - deepStrictEqual(M.combine(String.length, M.empty)("a"), 1) - deepStrictEqual(M.combine(M.empty, String.length)("a"), 1) - deepStrictEqual(M.combineAll([String.length, String.length])("a"), 2) - }) - it("apply", () => { deepStrictEqual(_.pipe("a", _.apply(String.length)), 1) }) diff --git a/test/typeclass/Monoid.ts b/test/typeclass/Monoid.ts index c8bec081a..ffa346819 100644 --- a/test/typeclass/Monoid.ts +++ b/test/typeclass/Monoid.ts @@ -1,29 +1,29 @@ import * as N from "@fp-ts/core/Number" import * as String from "@fp-ts/core/String" -import * as monoid from "@fp-ts/core/typeclass/Monoid" +import * as _ from "@fp-ts/core/typeclass/Monoid" import * as U from "../util" describe("Monoid", () => { it("exports", () => { - expect(monoid.array).exists + expect(_.array).exists }) it("min", () => { - const M = monoid.min(N.Bounded) + const M = _.min(N.Bounded) U.deepStrictEqual(M.combineAll([]), +Infinity) U.deepStrictEqual(M.combineAll([1]), 1) U.deepStrictEqual(M.combineAll([1, -1]), -1) }) it("max", () => { - const M = monoid.max(N.Bounded) + const M = _.max(N.Bounded) U.deepStrictEqual(M.combineAll([]), -Infinity) U.deepStrictEqual(M.combineAll([1]), 1) U.deepStrictEqual(M.combineAll([1, -1]), 1) }) it("reverse", () => { - const M = monoid.reverse(String.Monoid) + const M = _.reverse(String.Monoid) U.deepStrictEqual(M.combine("a", "b"), "ba") U.deepStrictEqual(M.combine("a", M.empty), "a") U.deepStrictEqual(M.combine(M.empty, "a"), "a") @@ -35,7 +35,7 @@ describe("Monoid", () => { describe("struct", () => { it("baseline", () => { - const M = monoid.struct({ + const M = _.struct({ name: String.Monoid, age: N.MonoidSum }) @@ -48,13 +48,13 @@ describe("Monoid", () => { it("should ignore non own properties", () => { const monoids = Object.create({ a: 1 }) - const M = monoid.struct(monoids) + const M = _.struct(monoids) U.deepStrictEqual(M.empty, {}) }) }) it("tuple", () => { - const M = monoid.tuple( + const M = _.tuple( String.Monoid, N.MonoidSum ) diff --git a/test/typeclass/SemiProduct.ts b/test/typeclass/SemiProduct.ts index c05066dc7..4f0c26b5c 100644 --- a/test/typeclass/SemiProduct.ts +++ b/test/typeclass/SemiProduct.ts @@ -12,7 +12,7 @@ import * as _ from "@fp-ts/core/typeclass/SemiProduct" import * as U from "../util" describe("SemiProduct", () => { - it("productMany", () => { + it("productMany should be equivalent to `ap`", () => { const curry = (f: Function, n: number, acc: ReadonlyArray) => (x: unknown) => { const combined = Array(acc.length + 1) @@ -47,38 +47,13 @@ describe("SemiProduct", () => { } const actual = SemiApplicative.productMany(self, collection) const expected = pipe(self, productManyFromAp(collection)) - // console.log(expected) U.deepStrictEqual(actual, expected) } - const product = ( - self: ReadonlyArray, - that: ReadonlyArray - ): ReadonlyArray<[A, B]> => { - const out: Array<[A, B]> = [] - for (const a of self) { - for (const b of that) { - out.push([a, b]) - } - } - return out - } - - const productMany = _.productMany( - RA.Covariant, - product - ) - - const SemiApplicative = { - ...RA.Covariant, - product, - productMany - } - - assertSameResult(SemiApplicative)([])([]) - assertSameResult(SemiApplicative)([])([1, 2, 3]) - assertSameResult(SemiApplicative)([[4]])([1, 2, 3]) - assertSameResult(SemiApplicative)([[4, 5, 6], [7, 8], [9, 10, 11]])([1, 2, 3]) + assertSameResult(RA.SemiApplicative)([])([]) + assertSameResult(RA.SemiApplicative)([])([1, 2, 3]) + assertSameResult(RA.SemiApplicative)([[4]])([1, 2, 3]) + assertSameResult(RA.SemiApplicative)([[4, 5, 6], [7, 8], [9, 10, 11]])([1, 2, 3]) }) describe("productComposition", () => { From b97ec0507e79912a5840b1211977cee644e0e369 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 3 Feb 2023 14:33:34 +0100 Subject: [PATCH 169/255] Traversable: make dual --- docs/modules/Either.ts.md | 9 +-- docs/modules/ReadonlyArray.ts.md | 5 +- docs/modules/These.ts.md | 7 +- docs/modules/typeclass/Traversable.ts.md | 77 +++++++++++----------- guides/typeclass.md | 3 +- src/Either.ts | 44 ++++++++----- src/Identity.ts | 15 +++-- src/Option.ts | 49 ++++++-------- src/ReadonlyArray.ts | 51 ++++++++------- src/These.ts | 58 +++++++++-------- src/typeclass/Traversable.ts | 82 +++++++++++------------- test/Identity.ts | 5 -- test/limbo/TraversableWithIndex.ts | 18 +++--- test/typeclass/Traversable.ts | 21 +----- test/typeclass/TraversableWithIndex.ts | 14 ++-- 15 files changed, 225 insertions(+), 233 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 8725af87a..4074c05b5 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -1311,7 +1311,7 @@ Added in v1.0.0 ```ts export declare const sequence: ( F: applicative.Applicative -) => (self: Either>) => Kind> +) => (self: Either>) => Kind> ``` Added in v1.0.0 @@ -1323,9 +1323,10 @@ Added in v1.0.0 ```ts export declare const traverse: ( F: applicative.Applicative -) => ( - f: (a: A) => Kind -) => (self: Either) => Kind> +) => { + (f: (a: A) => Kind): (self: Either) => Kind> + (self: Either, f: (a: A) => Kind): Kind> +} ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 83d7e61c6..ec02c421f 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -1770,7 +1770,10 @@ Added in v1.0.0 ```ts export declare const traverse: ( F: applicative.Applicative -) => (f: (a: A) => Kind) => (self: readonly A[]) => Kind +) => { + (f: (a: A) => Kind): (self: readonly A[]) => Kind + (self: readonly A[], f: (a: A) => Kind): Kind +} ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index fc03d3b19..55bf1ac42 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1439,7 +1439,7 @@ Added in v1.0.0 ```ts export declare const sequence: ( F: applicative.Applicative -) => (self: These>) => Kind> +) => (self: These>) => Kind> ``` Added in v1.0.0 @@ -1451,7 +1451,10 @@ Added in v1.0.0 ```ts export declare const traverse: ( F: applicative.Applicative -) => (f: (a: A) => Kind) => (self: These) => Kind> +) => { + (f: (a: A) => Kind): (self: These) => Kind> + (self: These, f: (a: A) => Kind): Kind> +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Traversable.ts.md b/docs/modules/typeclass/Traversable.ts.md index b5ba632c6..9980c9adf 100644 --- a/docs/modules/typeclass/Traversable.ts.md +++ b/docs/modules/typeclass/Traversable.ts.md @@ -12,16 +12,36 @@ Added in v1.0.0

Table of contents

+- [constructors](#constructors) + - [make](#make) - [type class](#type-class) - [Traversable (interface)](#traversable-interface) - [utils](#utils) - [sequence](#sequence) - - [sequenceComposition](#sequencecomposition) - [traverseComposition](#traversecomposition) - [traverseTap](#traversetap) --- +# constructors + +## make + +**Signature** + +```ts +export declare const make: ( + traverse: ( + F: Applicative + ) => ( + self: Kind, + f: (a: A) => Kind + ) => Kind> +) => Traversable +``` + +Added in v1.0.0 + # type class ## Traversable (interface) @@ -32,15 +52,18 @@ Added in v1.0.0 export interface Traversable extends TypeClass { readonly traverse: ( F: Applicative - ) => ( - f: (a: A) => Kind - ) => (self: Kind) => Kind> - - readonly sequence: ( - F: Applicative - ) => ( - self: Kind> - ) => Kind> + ) => { + (f: (a: A) => Kind): ( + self: Kind + ) => Kind> + (self: Kind, f: (a: A) => Kind): Kind< + F, + R, + O, + E, + Kind + > + } } ``` @@ -56,12 +79,8 @@ Returns a default `sequence` implementation. ```ts export declare const sequence: ( - traverse: ( - F: Applicative - ) => ( - f: (a: A) => Kind - ) => (self: Kind) => Kind> -) => ( + T: Traversable +) => ( F: Applicative ) => ( self: Kind> @@ -70,28 +89,9 @@ export declare const sequence: ( Added in v1.0.0 -## sequenceComposition - -Returns a default `sequence` composition. - -**Signature** - -```ts -export declare const sequenceComposition: ( - T: Traversable & Covariant, - G: Traversable -) => ( - F: Applicative -) => ( - self: Kind>> -) => Kind>> -``` - -Added in v1.0.0 - ## traverseComposition -Returns a default `traverse` composition. +Returns a default binary `traverse` composition. **Signature** @@ -101,10 +101,9 @@ export declare const traverseComposition: ) => ( F: Applicative -) => ( +) => ( + self: Kind>, f: (a: A) => Kind -) => ( - self: Kind> ) => Kind>> ``` diff --git a/guides/typeclass.md b/guides/typeclass.md index 04cb78a75..51a39b7f9 100644 --- a/guides/typeclass.md +++ b/guides/typeclass.md @@ -434,9 +434,8 @@ Traversal over a structure with an effect. | Name | Given | To | | ------------------- | ---------------------------------------- | ------------ | | **traverse** | `Applicative`, `T
`, `A => F` | `F>` | -| **sequence** | `Applicative`, `T>` | `F>` | | traverseComposition | `Applicative`, `T>`, `A => F` | `F>>` | -| sequenceComposition | `Applicative`, `T>>` | `F>>` | +| sequence | `Applicative`, `T>` | `F>` | | traverseTap | `Applicative`, `T`, `A => F` | `F>` | ### TraversableFilterable diff --git a/src/Either.ts b/src/Either.ts index c3cb1454a..4d3c58d88 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -946,34 +946,46 @@ export const filterMap = ( ) /** - * @category traversing + * @category instances * @since 1.0.0 */ -export const traverse = (F: applicative.Applicative) => - (f: (a: A) => Kind) => - (self: Either): Kind> => - isLeft(self) ? - F.of>(left(self.left)) : - pipe(f(self.right), F.map>(right)) +export const Traversable: traversable.Traversable = traversable.make(< + F extends TypeLambda +>(F: applicative.Applicative) => + ( + self: Either, + f: (a: A) => Kind + ): Kind> => + isLeft(self) ? + F.of>(left(self.left)) : + pipe(f(self.right), F.map>(right)) +) /** * @category traversing * @since 1.0.0 */ -export const sequence: ( +export const traverse: ( F: applicative.Applicative -) => ( - self: Either> -) => Kind> = traversable.sequence(traverse) +) => { + ( + f: (a: A) => Kind + ): (self: Either) => Kind> + ( + self: Either, + f: (a: A) => Kind + ): Kind> +} = Traversable.traverse /** - * @category instances + * @category traversing * @since 1.0.0 */ -export const Traversable: traversable.Traversable = { - traverse, - sequence -} +export const sequence: ( + F: applicative.Applicative +) => ( + self: Either> +) => Kind> = traversable.sequence(Traversable) /** * @category traversing diff --git a/src/Identity.ts b/src/Identity.ts index d65a474d6..3573e1807 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -2,7 +2,7 @@ * @since 1.0.0 */ import { identity } from "@fp-ts/core/Function" -import type { TypeLambda } from "@fp-ts/core/HKT" +import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type * as applicative from "@fp-ts/core/typeclass/Applicative" import * as chainable from "@fp-ts/core/typeclass/Chainable" @@ -19,7 +19,7 @@ import type * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import type * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" -import type * as traversable from "@fp-ts/core/typeclass/Traversable" +import * as traversable from "@fp-ts/core/typeclass/Traversable" /** * @category models @@ -232,7 +232,10 @@ export const Foldable: foldable.Foldable = foldable.make((se * @category instances * @since 1.0.0 */ -export const Traversable: traversable.Traversable = { - traverse: () => f => self => f(self), - sequence: () => identity -} +export const Traversable: traversable.Traversable = traversable.make( + (_: applicative.Applicative) => + ( + self: Identity, + f: (a: A) => Kind + ): Kind> => f(self) +) diff --git a/src/Option.ts b/src/Option.ts index aae41f8b2..656826403 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1303,34 +1303,32 @@ export const filter: { // traversing // ------------------------------------------------------------------------------------- +/** + * @category instances + * @since 1.0.0 + */ +export const Traversable: traversable.Traversable = traversable.make(< + F extends TypeLambda +>(F: applicative.Applicative) => + (self: Option, f: (a: A) => Kind): Kind> => + isNone(self) ? F.of>(none()) : pipe(f(self.value), F.map(some)) +) + /** * @category traversing * @since 1.0.0 */ -export const traverse = ( +export const traverse: ( F: applicative.Applicative -): { +) => { ( f: (a: A) => Kind ): (self: Option) => Kind> - (self: Option, f: (a: A) => Kind): Kind> -} => - dual< - ( - f: (a: A) => Kind - ) => (self: Option) => Kind>, - ( - self: Option, - f: (a: A) => Kind - ) => Kind> - >( - 2, - ( - self: Option, - f: (a: A) => Kind - ): Kind> => - isNone(self) ? F.of>(none()) : pipe(f(self.value), F.map(some)) - ) + ( + self: Option, + f: (a: A) => Kind + ): Kind> +} = Traversable.traverse /** * @category traversing @@ -1339,16 +1337,7 @@ export const traverse = ( export const sequence: ( F: applicative.Applicative ) => (self: Option>) => Kind> = traversable - .sequence(traverse) - -/** - * @category instances - * @since 1.0.0 - */ -export const Traversable: traversable.Traversable = { - traverse, - sequence -} + .sequence(Traversable) /** * @category traversing diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 3445bba94..b14dbdea0 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1622,15 +1622,6 @@ export const partitionMapWithIndex = (f: (a: A, i: number) => Either(F: applicative.Applicative) => - ( - f: (a: A) => Kind - ): ((self: ReadonlyArray) => Kind>) => traverseWithIndex(F)(f) - /** * @category traversing * @since 1.0.0 @@ -1664,28 +1655,44 @@ export const traverseNonEmptyWithIndex = ( return F.productMany(head, tail) } +/** + * @category instances + * @since 1.0.0 + */ +export const Traversable: traversable.Traversable = traversable.make(< + F extends TypeLambda +>(F: applicative.Applicative) => + ( + self: ReadonlyArray, + f: (a: A) => Kind + ): Kind> => traverseWithIndex(F)(f)(self) as any +) + /** * @category traversing * @since 1.0.0 */ -export const sequence: ( +export const traverse: ( F: applicative.Applicative -) => ( - self: ReadonlyArray> -) => Kind> = traversable.sequence( - traverse as any -) as any +) => { + ( + f: (a: A) => Kind + ): (self: ReadonlyArray) => Kind> + ( + self: ReadonlyArray, + f: (a: A) => Kind + ): Kind> +} = Traversable.traverse as any /** - * @category instances + * @category traversing * @since 1.0.0 */ -export const Traversable: traversable.Traversable = { - // @ts-expect-error - traverse, - // @ts-expect-error - sequence -} +export const sequence: ( + F: applicative.Applicative +) => ( + self: ReadonlyArray> +) => Kind> = traversable.sequence(Traversable) as any /** * @category traversing diff --git a/src/These.ts b/src/These.ts index a705aec97..2f0863c62 100644 --- a/src/These.ts +++ b/src/These.ts @@ -688,43 +688,51 @@ export const Pointed: pointed.Pointed = { } /** - * @category traversing + * @category instances * @since 1.0.0 */ -export const traverse = ( - F: applicative.Applicative -) => - ( - f: (a: A) => Kind - ) => - (self: These): Kind> => - isLeft(self) - ? F.of>(self) - : isRight(self) - ? pipe(f(self.right), F.map>(right)) - : pipe( - f(self.right), - F.map((b) => both(self.left, b)) - ) +export const Traversable: traversable.Traversable = traversable.make(< + F extends TypeLambda +>(F: applicative.Applicative) => + ( + self: These, + f: (a: A) => Kind + ): Kind> => + isLeft(self) + ? F.of>(self) + : isRight(self) + ? pipe(f(self.right), F.map>(right)) + : pipe( + f(self.right), + F.map((b) => both(self.left, b)) + ) +) /** * @category traversing * @since 1.0.0 */ -export const sequence: ( +export const traverse: ( F: applicative.Applicative -) => ( - self: These> -) => Kind> = traversable.sequence(traverse) +) => { + ( + f: (a: A) => Kind + ): (self: These) => Kind> + ( + self: These, + f: (a: A) => Kind + ): Kind> +} = Traversable.traverse /** - * @category instances + * @category traversing * @since 1.0.0 */ -export const Traversable: traversable.Traversable = { - traverse, - sequence -} +export const sequence: ( + F: applicative.Applicative +) => ( + self: These> +) => Kind> = traversable.sequence(Traversable) /** * @category traversing diff --git a/src/typeclass/Traversable.ts b/src/typeclass/Traversable.ts index 929949a80..9a5346e8f 100644 --- a/src/typeclass/Traversable.ts +++ b/src/typeclass/Traversable.ts @@ -1,10 +1,9 @@ /** * @since 1.0.0 */ -import { dual, identity, pipe } from "@fp-ts/core/Function" +import { dual, identity } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" import type { Applicative } from "@fp-ts/core/typeclass/Applicative" -import type { Covariant } from "@fp-ts/core/typeclass/Covariant" /** * @category type class @@ -13,58 +12,58 @@ import type { Covariant } from "@fp-ts/core/typeclass/Covariant" export interface Traversable extends TypeClass { readonly traverse: ( F: Applicative - ) => ( - f: (a: A) => Kind - ) => (self: Kind) => Kind> - - readonly sequence: (F: Applicative) => ( - self: Kind> - ) => Kind> + ) => { + ( + f: (a: A) => Kind + ): (self: Kind) => Kind> + ( + self: Kind, + f: (a: A) => Kind + ): Kind> + } } /** - * Returns a default `traverse` composition. - * + * @category constructors * @since 1.0.0 */ -export const traverseComposition = ( - T: Traversable, - G: Traversable -) => - (F: Applicative) => - ( - f: (a: A) => Kind - ): (( - self: Kind> - ) => Kind>>) => - T.traverse(F)(G.traverse(F)(f)) +export const make = ( + traverse: ( + F: Applicative + ) => ( + self: Kind, + f: (a: A) => Kind + ) => Kind> +): Traversable => ({ + traverse: F => dual(2, traverse(F)) +}) /** - * Returns a default `sequence` composition. + * Returns a default binary `traverse` composition. * * @since 1.0.0 */ -export const sequenceComposition = ( - T: Traversable & Covariant, +export const traverseComposition = ( + T: Traversable, G: Traversable ) => (F: Applicative) => - ( - self: Kind>> - ): Kind>> => - T.sequence(F)(pipe(self, T.map(G.sequence(F)))) + ( + self: Kind>, + f: (a: A) => Kind + ): Kind>> => + T.traverse(F)(self, G.traverse(F)(f)) /** * Returns a default `sequence` implementation. * * @since 1.0.0 */ -export const sequence = ( - traverse: Traversable["traverse"] -): Traversable["sequence"] => - (F: Applicative): (( - self: Kind> - ) => Kind>) => traverse(F)(identity) +export const sequence = (T: Traversable) => + (F: Applicative) => + ( + self: Kind> + ): Kind> => T.traverse(F)(self, identity) /** * Given a function which returns a `F` effect, thread this effect @@ -84,16 +83,7 @@ export const traverseTap = (T: Traversable) => f: (a: A) => Kind ): Kind> } => - dual< - (f: (a: A) => Kind) => ( - self: Kind - ) => Kind>, - ( - self: Kind, - f: (a: A) => Kind - ) => Kind> - >(2, ( + dual(2, ( self: Kind, f: (a: A) => Kind - ): Kind> => - pipe(self, T.traverse(F)(a => pipe(f(a), F.map(() => a))))) + ): Kind> => T.traverse(F)(self, a => F.map(f(a), () => a))) diff --git a/test/Identity.ts b/test/Identity.ts index 45a7caa5e..649e89cf5 100644 --- a/test/Identity.ts +++ b/test/Identity.ts @@ -82,9 +82,4 @@ describe.concurrent("Identity", () => { U.deepStrictEqual(pipe(1, _.Traversable.traverse(O.Applicative)(O.some)), O.some(1)) U.deepStrictEqual(pipe(1, _.Traversable.traverse(O.Applicative)(() => O.none())), O.none()) }) - - it("sequence", () => { - U.deepStrictEqual(_.Traversable.sequence(O.Applicative)(O.some(1)), O.some(1)) - U.deepStrictEqual(_.Traversable.sequence(O.Applicative)(O.none()), O.none()) - }) }) diff --git a/test/limbo/TraversableWithIndex.ts b/test/limbo/TraversableWithIndex.ts index 009e5ec52..d8b22679a 100644 --- a/test/limbo/TraversableWithIndex.ts +++ b/test/limbo/TraversableWithIndex.ts @@ -3,7 +3,7 @@ */ import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" import type { Applicative } from "@fp-ts/core/typeclass/Applicative" -import type { Traversable } from "@fp-ts/core/typeclass/Traversable" +// import type { Traversable } from "@fp-ts/core/typeclass/Traversable" /** * @category type class @@ -38,11 +38,11 @@ export const traverseWithIndexComposition = ((a, j) => f(a, [i, j]))(ga) ) -/** - * Returns a default `traverse` implementation. - * - * @since 1.0.0 - */ -export const traverse = ( - F: TraversableWithIndex -): Traversable["traverse"] => f => F.traverseWithIndex(f) +// /** +// * Returns a default `traverse` implementation. +// * +// * @since 1.0.0 +// */ +// export const traverse = ( +// F: TraversableWithIndex +// ): Traversable["traverse"] => f => F.traverseWithIndex(f) diff --git a/test/typeclass/Traversable.ts b/test/typeclass/Traversable.ts index 79386bae9..5f749befc 100644 --- a/test/typeclass/Traversable.ts +++ b/test/typeclass/Traversable.ts @@ -8,32 +8,15 @@ describe("Traversable", () => { it("traverseComposition", () => { const traverse = _.traverseComposition(RA.Traversable, RA.Traversable)(O.Applicative) U.deepStrictEqual( - pipe([[1, 2], [3]], traverse((a) => (a > 0 ? O.some(a) : O.none()))), + traverse([[1, 2], [3]], (a) => (a > 0 ? O.some(a) : O.none())), O.some([[1, 2], [3]]) ) U.deepStrictEqual( - pipe([[1, -2], [3]], traverse((a) => (a > 0 ? O.some(a) : O.none()))), + traverse([[1, -2], [3]], (a) => (a > 0 ? O.some(a) : O.none())), O.none() ) }) - it("sequenceComposition", () => { - const sequence = _.sequenceComposition({ ...RA.Traversable, ...RA.Covariant }, RA.Traversable)( - O.Applicative - ) - U.deepStrictEqual( - pipe([[O.some(1), O.some(2)], [O.some(3)]], sequence), - O.some([[1, 2], [3]]) - ) - U.deepStrictEqual(pipe([[O.some(1), O.none()], [O.some(3)]], sequence), O.none()) - }) - - it("sequence", () => { - const sequence = _.sequence(RA.Traversable.traverse)(O.Applicative) - U.deepStrictEqual(pipe([O.none(), O.some(2)], sequence), O.none()) - U.deepStrictEqual(pipe([O.some(1), O.some(2)], sequence), O.some([1, 2])) - }) - it("traverseTap", () => { const traverseTap = _.traverseTap(RA.Traversable)(O.Applicative) U.deepStrictEqual( diff --git a/test/typeclass/TraversableWithIndex.ts b/test/typeclass/TraversableWithIndex.ts index 338e6d75a..d1201f33c 100644 --- a/test/typeclass/TraversableWithIndex.ts +++ b/test/typeclass/TraversableWithIndex.ts @@ -31,11 +31,11 @@ describe("TraversableWithIndex", () => { ) }) - it("traverse", () => { - const traverse = _.traverse(TraversableWithIndex)(O.Applicative) - const f = (n: number) => n > 0 ? O.some(n) : O.none() - U.deepStrictEqual(pipe([], traverse(f)), O.some([])) - U.deepStrictEqual(pipe([1, 2, 3], traverse(f)), O.some([1, 2, 3])) - U.deepStrictEqual(pipe([1, -2, 3], traverse(f)), O.none()) - }) + // it("traverse", () => { + // const traverse = _.traverse(TraversableWithIndex)(O.Applicative) + // const f = (n: number) => n > 0 ? O.some(n) : O.none() + // U.deepStrictEqual(pipe([], traverse(f)), O.some([])) + // U.deepStrictEqual(pipe([1, 2, 3], traverse(f)), O.some([1, 2, 3])) + // U.deepStrictEqual(pipe([1, -2, 3], traverse(f)), O.none()) + // }) }) From 979b7734bbea51eccfdce8ce567ba92e36edf77d Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 3 Feb 2023 15:09:10 +0100 Subject: [PATCH 170/255] TraversableFilterable: make dual --- docs/modules/ReadonlyArray.ts.md | 32 +++- .../typeclass/TraversableFilterable.ts.md | 96 +++++++++--- src/ReadonlyArray.ts | 64 ++++---- src/typeclass/TraversableFilterable.ts | 137 ++++++++++++------ 4 files changed, 227 insertions(+), 102 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index ec02c421f..37ddfb5f5 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -558,7 +558,7 @@ Added in v1.0.0 ```ts export declare const traverseFilterMap: ( F: applicative.Applicative -) => (f: (a: A) => Kind>) => (ta: readonly A[]) => Kind +) => (f: (a: A) => Kind>) => (self: readonly A[]) => Kind ``` Added in v1.0.0 @@ -2297,9 +2297,18 @@ Filter values inside a context. ```ts export declare const traverseFilter: ( F: applicative.Applicative -) => ( - predicate: (a: A) => Kind -) => (self: readonly B[]) => Kind +) => { + (predicate: (a: A) => Kind): ( + self: readonly B[] + ) => Kind + (self: readonly B[], predicate: (a: A) => Kind): Kind< + F, + R, + O, + E, + B[] + > +} ``` Added in v1.0.0 @@ -2311,9 +2320,18 @@ Added in v1.0.0 ```ts export declare const traversePartition: ( F: applicative.Applicative -) => ( - predicate: (a: A) => Kind -) => (self: readonly B[]) => Kind +) => { + (predicate: (a: A) => Kind): ( + self: readonly B[] + ) => Kind + (self: readonly B[], predicate: (a: A) => Kind): Kind< + F, + R, + O, + E, + [B[], B[]] + > +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/TraversableFilterable.ts.md b/docs/modules/typeclass/TraversableFilterable.ts.md index 705b3f17c..918f924a0 100644 --- a/docs/modules/typeclass/TraversableFilterable.ts.md +++ b/docs/modules/typeclass/TraversableFilterable.ts.md @@ -17,6 +17,7 @@ Added in v1.0.0 - [models](#models) - [TraversableFilterable (interface)](#traversablefilterable-interface) - [utils](#utils) + - [make](#make) - [traverseFilter](#traversefilter) - [traverseFilterMap](#traversefiltermap) - [traversePartition](#traversepartition) @@ -34,15 +35,33 @@ Added in v1.0.0 export interface TraversableFilterable extends TypeClass { readonly traversePartitionMap: ( F: Applicative - ) => ( - f: (a: A) => Kind> - ) => (self: Kind) => Kind, Kind]> + ) => { + (f: (a: A) => Kind>): ( + self: Kind + ) => Kind, Kind]> + (self: Kind, f: (a: A) => Kind>): Kind< + F, + R, + O, + E, + [Kind, Kind] + > + } readonly traverseFilterMap: ( F: Applicative - ) => ( - f: (a: A) => Kind> - ) => (self: Kind) => Kind> + ) => { + (f: (a: A) => Kind>): ( + self: Kind + ) => Kind> + (self: Kind, f: (a: A) => Kind>): Kind< + F, + R, + O, + E, + Kind + > + } } ``` @@ -50,6 +69,29 @@ Added in v1.0.0 # utils +## make + +**Signature** + +```ts +export declare const make: ( + traversePartitionMap: ( + F: Applicative + ) => ( + self: Kind, + f: (a: A) => Kind> + ) => Kind, Kind]>, + traverseFilterMap: ( + F: Applicative + ) => ( + self: Kind, + f: (a: A) => Kind> + ) => Kind> +) => TraversableFilterable +``` + +Added in v1.0.0 + ## traverseFilter **Signature** @@ -59,27 +101,34 @@ export declare const traverseFilter: ( T: TraversableFilterable ) => ( F: Applicative -) => ( - predicate: (a: A) => Kind -) => (self: Kind) => Kind> +) => { + (predicate: (a: A) => Kind): ( + self: Kind + ) => Kind> + ( + self: Kind, + predicate: (a: A) => Kind + ): Kind> +} ``` Added in v1.0.0 ## traverseFilterMap -Returns a default `traverseFilterMap` implementation. +Returns a default binary `traverseFilterMap` implementation. **Signature** ```ts export declare const traverseFilterMap: ( T: Traversable & compactable.Compactable -) => ( +) => ( F: Applicative -) => ( +) => ( + self: Kind, f: (a: A) => Kind> -) => (self: Kind) => Kind> +) => Kind> ``` Added in v1.0.0 @@ -93,27 +142,34 @@ export declare const traversePartition: ( T: TraversableFilterable ) => ( F: Applicative -) => ( - predicate: (a: A) => Kind -) => (self: Kind) => Kind, Kind]> +) => { + (predicate: (a: A) => Kind): ( + self: Kind + ) => Kind, Kind]> + ( + self: Kind, + predicate: (a: A) => Kind + ): Kind, Kind]> +} ``` Added in v1.0.0 ## traversePartitionMap -Returns a default `traversePartitionMap` implementation. +Returns a default binary `traversePartitionMap` implementation. **Signature** ```ts export declare const traversePartitionMap: ( T: Traversable & Covariant & compactable.Compactable -) => ( +) => ( F: Applicative -) => ( +) => ( + self: Kind, f: (a: A) => Kind> -) => (self: Kind) => Kind, Kind]> +) => Kind, Kind]> ``` Added in v1.0.0 diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index b14dbdea0..5778133cf 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1924,15 +1924,17 @@ export const coproductMapKind: (F: Coproduct) => (self: ReadonlyArray) => Kind = foldable.coproductMapKind(Foldable) /** - * @category filtering + * @category instances * @since 1.0.0 */ -export const traverseFilterMap: ( - F: applicative.Applicative -) => ( - f: (a: A) => Kind> -) => (ta: ReadonlyArray) => Kind> = traversableFilterable - .traverseFilterMap({ ...Traversable, ...Compactable }) as any +export const TraversableFilterable: traversableFilterable.TraversableFilterable< + ReadonlyArrayTypeLambda +> = traversableFilterable.make( + traversableFilterable + .traversePartitionMap({ ...Traversable, ...Covariant, ...Compactable }), + traversableFilterable + .traverseFilterMap({ ...Traversable, ...Compactable }) +) /** * @category filtering @@ -1942,21 +1944,19 @@ export const traversePartitionMap: ( F: applicative.Applicative ) => ( f: (a: A) => Kind> -) => (self: ReadonlyArray) => Kind, Array]> = traversableFilterable - .traversePartitionMap({ ...Traversable, ...Covariant, ...Compactable }) as any +) => (self: ReadonlyArray) => Kind, Array]> = TraversableFilterable + .traversePartitionMap as any /** - * @category instances + * @category filtering * @since 1.0.0 */ -export const TraversableFilterable: traversableFilterable.TraversableFilterable< - ReadonlyArrayTypeLambda -> = { - // @ts-expect-error - traverseFilterMap, - // @ts-expect-error - traversePartitionMap -} +export const traverseFilterMap: ( + F: applicative.Applicative +) => ( + f: (a: A) => Kind> +) => (self: ReadonlyArray) => Kind> = TraversableFilterable + .traverseFilterMap as any /** * Filter values inside a context. @@ -1965,22 +1965,30 @@ export const TraversableFilterable: traversableFilterable.TraversableFilterable< */ export const traverseFilter: ( F: applicative.Applicative -) => ( - predicate: (a: A) => Kind -) => (self: ReadonlyArray) => Kind> = traversableFilterable - .traverseFilter(TraversableFilterable) as any +) => { + ( + predicate: (a: A) => Kind + ): (self: ReadonlyArray) => Kind> + ( + self: ReadonlyArray, + predicate: (a: A) => Kind + ): Kind> +} = traversableFilterable.traverseFilter(TraversableFilterable) as any /** * @since 1.0.0 */ export const traversePartition: ( F: applicative.Applicative -) => ( - predicate: (a: A) => Kind -) => ( - self: ReadonlyArray -) => Kind, Array]> = traversableFilterable - .traversePartition(TraversableFilterable) as any +) => { + ( + predicate: (a: A) => Kind + ): (self: ReadonlyArray) => Kind, Array]> + ( + self: ReadonlyArray, + predicate: (a: A) => Kind + ): Kind, Array]> +} = traversableFilterable.traversePartition(TraversableFilterable) as any /** * @category lifting diff --git a/src/typeclass/TraversableFilterable.ts b/src/typeclass/TraversableFilterable.ts index 9c2b4198a..8581cee88 100644 --- a/src/typeclass/TraversableFilterable.ts +++ b/src/typeclass/TraversableFilterable.ts @@ -5,10 +5,11 @@ */ import type { Either } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" -import { pipe } from "@fp-ts/core/Function" +import { dual } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" import type { Option } from "@fp-ts/core/Option" import * as O from "@fp-ts/core/Option" +import type { TraversableFilterable } from "@fp-ts/core/ReadonlyArray" import type { Applicative } from "@fp-ts/core/typeclass/Applicative" import * as compactable from "@fp-ts/core/typeclass/Compactable" import type { Compactable } from "@fp-ts/core/typeclass/Compactable" @@ -22,47 +23,82 @@ import type { Traversable } from "@fp-ts/core/typeclass/Traversable" export interface TraversableFilterable extends TypeClass { readonly traversePartitionMap: ( F: Applicative - ) => ( - f: (a: A) => Kind> - ) => ( - self: Kind - ) => Kind, Kind]> + ) => { + ( + f: (a: A) => Kind> + ): ( + self: Kind + ) => Kind, Kind]> + ( + self: Kind, + f: (a: A) => Kind> + ): Kind, Kind]> + } readonly traverseFilterMap: ( F: Applicative - ) => ( + ) => { + ( + f: (a: A) => Kind> + ): (self: Kind) => Kind> + ( + self: Kind, + f: (a: A) => Kind> + ): Kind> + } +} + +/** + * @constructors + * @since 1.0.0 + */ +export const make = ( + traversePartitionMap: ( + F: Applicative + ) => ( + self: Kind, + f: (a: A) => Kind> + ) => Kind, Kind]>, + traverseFilterMap: ( + F: Applicative + ) => ( + self: Kind, f: (a: A) => Kind> - ) => ( - self: Kind ) => Kind> -} +): TraversableFilterable => ({ + traversePartitionMap: (F) => dual(2, traversePartitionMap(F)), + traverseFilterMap: (F) => dual(2, traverseFilterMap(F)) +}) /** - * Returns a default `traversePartitionMap` implementation. + * Returns a default binary `traversePartitionMap` implementation. * * @since 1.0.0 */ export const traversePartitionMap = ( T: Traversable & Covariant & Compactable -): TraversableFilterable["traversePartitionMap"] => - (F) => - (f) => - (ta) => - pipe( - ta, - T.traverse(F)(f), - F.map(compactable.separate(T)) - ) +): ( + F: Applicative +) => ( + self: Kind, + f: (a: A) => Kind> +) => Kind, Kind]> => + (F) => (self, f) => F.map(T.traverse(F)(self, f), compactable.separate(T)) /** - * Returns a default `traverseFilterMap` implementation. + * Returns a default binary `traverseFilterMap` implementation. * * @since 1.0.0 */ export const traverseFilterMap = ( T: Traversable & Compactable -): TraversableFilterable["traverseFilterMap"] => - (F) => (f) => (ta) => pipe(ta, T.traverse(F)(f), F.map(T.compact)) +): ( + F: Applicative +) => ( + self: Kind, + f: (a: A) => Kind> +) => Kind> => + (F) => (self, f) => F.map(T.traverse(F)(self, f), T.compact) /** * @since 1.0.0 @@ -72,18 +108,23 @@ export const traverseFilter = ( ) => ( F: Applicative - ): (( - predicate: (a: A) => Kind - ) => ( - self: Kind - ) => Kind>) => - (predicate) => - T.traverseFilterMap(F)((b) => - pipe( - predicate(b), - F.map((keep) => (keep ? O.some(b) : O.none())) - ) - ) + ): { + ( + predicate: (a: A) => Kind + ): ( + self: Kind + ) => Kind> + ( + self: Kind, + predicate: (a: A) => Kind + ): Kind> + } => + dual(2, ( + self: Kind, + predicate: (a: A) => Kind + ): Kind> => + T.traverseFilterMap(F)(self, (b) => + F.map(predicate(b), (keep) => (keep ? O.some(b) : O.none())))) /** * @since 1.0.0 @@ -93,15 +134,17 @@ export const traversePartition = ( ) => ( F: Applicative - ): (( - predicate: (a: A) => Kind - ) => ( - self: Kind - ) => Kind, Kind]>) => - (predicate) => - T.traversePartitionMap(F)((b) => - pipe( - predicate(b), - F.map((keep) => (keep ? E.right(b) : E.left(b))) - ) - ) + ): { + ( + predicate: (a: A) => Kind + ): ( + self: Kind + ) => Kind, Kind]> + ( + self: Kind, + predicate: (a: A) => Kind + ): Kind, Kind]> + } => + dual(2, (self, predicate) => + T.traversePartitionMap(F)(self, (b) => + F.map(predicate(b), (keep) => (keep ? E.right(b) : E.left(b))))) From c6f82841fd39610094afdd473e30e352ef7da667 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 3 Feb 2023 16:23:45 +0100 Subject: [PATCH 171/255] get rid of pipe calls --- docs/modules/Either.ts.md | 5 +- docs/modules/Predicate.ts.md | 10 +- docs/modules/ReadonlyArray.ts.md | 57 +++++-- docs/modules/These.ts.md | 5 +- src/Either.ts | 45 +++--- src/Option.ts | 7 +- src/Predicate.ts | 22 +-- src/ReadonlyArray.ts | 257 +++++++++++++++++-------------- src/These.ts | 43 +++--- src/typeclass/Chainable.ts | 21 +-- src/typeclass/Compactable.ts | 5 +- src/typeclass/Covariant.ts | 7 +- src/typeclass/Product.ts | 19 +-- src/typeclass/SemiApplicative.ts | 12 +- src/typeclass/SemiProduct.ts | 30 ++-- 15 files changed, 289 insertions(+), 256 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 4074c05b5..c8becacce 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -562,7 +562,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const firstRightOf: (collection: Iterable>) => (self: Either) => Either +export declare const firstRightOf: { + (collection: Iterable>): (self: Either) => Either + (self: Either, collection: Iterable>): Either +} ``` Added in v1.0.0 diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index a05606208..754e0c363 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -309,7 +309,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const and: (that: Predicate) => (self: Predicate) => Predicate +export declare const and: { + (that: Predicate): (self: Predicate) => Predicate + (self: Predicate, that: Predicate): Predicate +} ``` Added in v1.0.0 @@ -389,7 +392,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const or: (that: Predicate) => (self: Predicate) => Predicate +export declare const or: { + (that: Predicate): (self: Predicate) => Predicate + (self: Predicate, that: Predicate): Predicate +} ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 37ddfb5f5..bc98ea73c 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -454,7 +454,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const filterMapWithIndex: (f: (a: A, i: number) => Option) => (self: Iterable) => B[] +export declare const filterMapWithIndex: { + (f: (a: A, i: number) => Option): (self: Iterable) => B[] + (self: Iterable, f: (a: A, i: number) => Option): B[] +} ``` Added in v1.0.0 @@ -1476,9 +1479,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const mapNonEmptyWithIndex: ( - f: (a: A, i: number) => B -) => (self: readonly [A, ...A[]]) => [B, ...B[]] +export declare const mapNonEmptyWithIndex: { + (f: (a: A, i: number) => B): (self: readonly [A, ...A[]]) => [B, ...B[]] + (self: readonly [A, ...A[]], f: (a: A, i: number) => B): [B, ...B[]] +} ``` Added in v1.0.0 @@ -1659,7 +1663,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapWithIndex: (f: (a: A, i: number) => readonly B[]) => (self: readonly A[]) => B[] +export declare const flatMapWithIndex: { + (f: (a: A, i: number) => readonly B[]): (self: readonly A[]) => B[] + (self: readonly A[], f: (a: A, i: number) => readonly B[]): B[] +} ``` Added in v1.0.0 @@ -1881,7 +1888,10 @@ Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`. **Signature** ```ts -export declare const append: (last: B) => (self: Iterable) => [B | A, ...(B | A)[]] +export declare const append: { + (last: B): (self: Iterable) => [B | A, ...(B | A)[]] + (self: Iterable, last: B): [A | B, ...(A | B)[]] +} ``` Added in v1.0.0 @@ -1936,9 +1946,10 @@ value and the tail of the `NonEmptyReadonlyArray`. **Signature** ```ts -export declare const chopNonEmpty: ( - f: (as: readonly [A, ...A[]]) => readonly [B, readonly A[]] -) => (self: readonly [A, ...A[]]) => [B, ...B[]] +export declare const chopNonEmpty: { + (f: (as: readonly [A, ...A[]]) => readonly [B, readonly A[]]): (self: readonly [A, ...A[]]) => [B, ...B[]] + (self: readonly [A, ...A[]], f: (as: readonly [A, ...A[]]) => readonly [B, readonly A[]]): [B, ...B[]] +} ``` Added in v1.0.0 @@ -2036,7 +2047,10 @@ The order and references of result values are determined by the first `Iterable` **Signature** ```ts -export declare const intersection: (equivalence: Equivalence) => (that: Iterable) => (self: Iterable) => A[] +export declare const intersection: (equivalence: Equivalence) => { + (that: Iterable): (self: Iterable) => A[] + (self: Iterable, that: Iterable): A[] +} ``` Added in v1.0.0 @@ -2140,7 +2154,10 @@ or return `None` if the index is out of bounds. **Signature** ```ts -export declare const modifyOption: (i: number, f: (a: A) => B) => (self: Iterable) => Option<(A | B)[]> +export declare const modifyOption: { + (i: number, f: (a: A) => B): (self: Iterable) => Option<(A | B)[]> + (self: Iterable, i: number, f: (a: A) => B): Option<(A | B)[]> +} ``` Added in v1.0.0 @@ -2152,7 +2169,10 @@ Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray` **Signature** ```ts -export declare const prepend: (head: B) => (self: Iterable) => [B | A, ...(B | A)[]] +export declare const prepend: { + (head: B): (self: Iterable) => [B | A, ...(B | A)[]] + (self: Iterable, head: B): [A | B, ...(A | B)[]] +} ``` Added in v1.0.0 @@ -2341,7 +2361,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const union: (equivalence: Equivalence) => (that: readonly A[]) => (self: readonly A[]) => A[] +export declare const union: (equivalence: Equivalence) => { + (that: readonly A[]): (self: readonly A[]) => A[] + (self: readonly A[], that: readonly A[]): A[] +} ``` Added in v1.0.0 @@ -2436,10 +2459,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const zipNonEmptyWith: ( - that: readonly [B, ...B[]], - f: (a: A, b: B) => C -) => (self: readonly [A, ...A[]]) => [C, ...C[]] +export declare const zipNonEmptyWith: { + (that: readonly [B, ...B[]], f: (a: A, b: B) => C): (self: readonly [A, ...A[]]) => [C, ...C[]] + (self: readonly [A, ...A[]], that: readonly [B, ...B[]], f: (a: A, b: B) => C): [C, ...C[]] +} ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 55bf1ac42..29fe790d0 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -635,7 +635,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const firstRightOrBothOf: (collection: Iterable>) => (self: These) => These +export declare const firstRightOrBothOf: { + (collection: Iterable>): (self: These) => These + (self: These, collection: Iterable>): These +} ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index 4d3c58d88..231f65d08 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -3,7 +3,7 @@ */ import type { LazyArg } from "@fp-ts/core/Function" -import { constNull, constUndefined, dual, identity, pipe } from "@fp-ts/core/Function" +import { constNull, constUndefined, dual, identity } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { structural } from "@fp-ts/core/internal/effect" import * as either from "@fp-ts/core/internal/Either" @@ -632,19 +632,21 @@ export const getFirstLeftMonoid: (M: Monoid) => Monoid> = * @category error handling * @since 1.0.0 */ -export const firstRightOf = (collection: Iterable>) => - (self: Either): Either => { - let out = self +export const firstRightOf: { + (collection: Iterable>): (self: Either) => Either + (self: Either, collection: Iterable>): Either +} = dual(2, (self: Either, collection: Iterable>): Either => { + let out = self + if (isRight(out)) { + return out + } + for (out of collection) { if (isRight(out)) { return out } - for (out of collection) { - if (isRight(out)) { - return out - } - } - return out } + return out +}) /** * @category instances @@ -653,7 +655,7 @@ export const firstRightOf = (collection: Iterable>) => export const SemiCoproduct: semiCoproduct.SemiCoproduct = semiCoproduct.make( Invariant, (self, that) => isRight(self) ? self : that, - (self, collection) => pipe(self, firstRightOf(collection)) + firstRightOf ) /** @@ -726,8 +728,8 @@ export const orElseEither = ( ) => (self: Either): Either> => isLeft(self) ? - pipe(that(self.left), map(right)) : - pipe, Either>>(self, map(left)) + map(that(self.left), right) : + map(self, left) /** * Executes this effect and returns its value, if it succeeds, but otherwise @@ -937,13 +939,10 @@ export const filterMap = ( onNone: LazyArg ) => (self: Either): Either => - pipe( - self, - flatMap((a) => { - const ob = f(a) - return option.isNone(ob) ? left(onNone()) : right(ob.value) - }) - ) + flatMap(self, (a) => { + const ob = f(a) + return option.isNone(ob) ? left(onNone()) : right(ob.value) + }) /** * @category instances @@ -957,8 +956,8 @@ export const Traversable: traversable.Traversable = traversabl f: (a: A) => Kind ): Kind> => isLeft(self) ? - F.of>(left(self.left)) : - pipe(f(self.right), F.map>(right)) + F.of>(self) : + F.map>(f(self.right), right) ) /** @@ -1123,7 +1122,7 @@ export const liftOption = , B, E>( export const flatMapOption = ( f: (a: A) => Option, onNone: (a: A) => E2 -) => (self: Either): Either => pipe(self, flatMap(liftOption(f, onNone))) +) => (self: Either): Either => flatMap(self, liftOption(f, onNone)) /** * Returns a function that checks if an `Either` contains a given value using a provided `equivalence` function. diff --git a/src/Option.ts b/src/Option.ts index 656826403..2c3b0f42d 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -3,7 +3,7 @@ */ import type { Either } from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" -import { constNull, constUndefined, dual, pipe } from "@fp-ts/core/Function" +import { constNull, constUndefined, dual } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { structural } from "@fp-ts/core/internal/effect" import * as either from "@fp-ts/core/internal/Either" @@ -724,8 +724,7 @@ export const flatMapEither: { (self: Option, f: (a: A) => Either) => Option >( 2, - (self: Option, f: (a: A) => Either): Option => - pipe(self, flatMap(liftEither(f))) + (self: Option, f: (a: A) => Either): Option => flatMap(self, liftEither(f)) ) /** @@ -1311,7 +1310,7 @@ export const Traversable: traversable.Traversable = traversabl F extends TypeLambda >(F: applicative.Applicative) => (self: Option, f: (a: A) => Kind): Kind> => - isNone(self) ? F.of>(none()) : pipe(f(self.value), F.map(some)) + isNone(self) ? F.of>(none()) : F.map(f(self.value), some) ) /** diff --git a/src/Predicate.ts b/src/Predicate.ts index d03aae9de..8eba74050 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { constFalse, constTrue, pipe } from "@fp-ts/core/Function" +import { constFalse, constTrue, dual } from "@fp-ts/core/Function" import type { TypeLambda } from "@fp-ts/core/HKT" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" @@ -258,22 +258,26 @@ export const not = (self: Predicate): Predicate => (a) => !self(a) /** * @since 1.0.0 */ -export const or = (that: Predicate) => - (self: Predicate): Predicate => (a) => self(a) || that(a) +export const or: { + (that: Predicate): (self: Predicate) => Predicate + (self: Predicate, that: Predicate): Predicate +} = dual(2, (self: Predicate, that: Predicate): Predicate => (a) => self(a) || that(a)) /** * @since 1.0.0 */ -export const and = (that: Predicate) => - (self: Predicate): Predicate => (a) => self(a) && that(a) +export const and: { + (that: Predicate): (self: Predicate) => Predicate + (self: Predicate, that: Predicate): Predicate +} = dual(2, (self: Predicate, that: Predicate): Predicate => (a) => self(a) && that(a)) /** * @category instances * @since 1.0.0 */ export const getSemigroupAny = (): Semigroup> => - semigroup.make( - (self, that) => pipe(self, or(that)), + semigroup.make>( + or, (self, collection) => a => { if (self(a)) { @@ -300,8 +304,8 @@ export const getMonoidAny = (): monoid.Monoid> => * @since 1.0.0 */ export const getSemigroupAll = (): Semigroup> => - semigroup.make( - (self, that) => pipe(self, and(that)), + semigroup.make>( + and, (self, collection) => a => { if (!self(a)) { diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 5778133cf..308cee2a7 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -5,7 +5,7 @@ */ import type { Either } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" -import { dual, identity, pipe } from "@fp-ts/core/Function" +import { dual, identity } from "@fp-ts/core/Function" import type { LazyArg } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" @@ -157,9 +157,10 @@ export const matchRight = ( * * @since 1.0.0 */ -export const prepend = ( - head: B -) => (self: Iterable): NonEmptyArray => [head, ...self] +export const prepend: { + (head: B): (self: Iterable) => NonEmptyArray + (self: Iterable, head: B): NonEmptyArray +} = dual(2, (self: Iterable, head: B): NonEmptyArray => [head, ...self]) /** * @since 1.0.0 @@ -187,9 +188,10 @@ export function prependAllNonEmpty( * * @since 1.0.0 */ -export const append = ( - last: B -) => (self: Iterable): NonEmptyArray => [...self, last] as any +export const append: { + (last: B): (self: Iterable) => NonEmptyArray + (self: Iterable, last: B): NonEmptyArray +} = dual(2, (self: Iterable, last: B): NonEmptyArray => [...self, last] as any) /** * @since 1.0.0 @@ -658,8 +660,7 @@ export const replaceOption = ( * @since 1.0.0 */ export const modify = (i: number, f: (a: A) => B) => - (self: Iterable): Array => - pipe(modifyOption(i, f)(self), O.getOrElse(() => Array.from(self))) + (self: Iterable): Array => O.getOrElse(modifyOption(self, i, f), () => Array.from(self)) /** * Apply a function to the element at the specified index, creating a new `Array`, @@ -667,17 +668,19 @@ export const modify = (i: number, f: (a: A) => B) => * * @since 1.0.0 */ -export const modifyOption = (i: number, f: (a: A) => B) => - (self: Iterable): Option> => { - const out = Array.from(self) - if (isOutOfBound(i, out)) { - return O.none() - } - const next = f(out[i]) - // @ts-expect-error - out[i] = next - return O.some(out) +export const modifyOption: { + (i: number, f: (a: A) => B): (self: Iterable) => Option> + (self: Iterable, i: number, f: (a: A) => B): Option> +} = dual(3, (self: Iterable, i: number, f: (a: A) => B): Option> => { + const out = Array.from(self) + if (isOutOfBound(i, out)) { + return O.none() } + const next = f(out[i]) + // @ts-expect-error + out[i] = next + return O.some(out) +}) /** * Delete the element at the specified index, creating a new `Array`, @@ -815,20 +818,33 @@ export const zipWith = (that: Iterable, f: (a: A, b: B) => C) => */ export const zipNonEmpty = (that: NonEmptyReadonlyArray) => (self: NonEmptyReadonlyArray): NonEmptyArray<[A, B]> => - pipe(self, zipNonEmptyWith(that, (a, b) => [a, b])) + zipNonEmptyWith(self, that, (a, b) => [a, b]) /** * @since 1.0.0 */ -export const zipNonEmptyWith = (that: NonEmptyReadonlyArray, f: (a: A, b: B) => C) => - (self: NonEmptyReadonlyArray): NonEmptyArray => { - const cs: NonEmptyArray = [f(headNonEmpty(self), headNonEmpty(that))] - const len = Math.min(self.length, that.length) - for (let i = 1; i < len; i++) { - cs[i] = f(self[i], that[i]) - } - return cs +export const zipNonEmptyWith: { + ( + that: NonEmptyReadonlyArray, + f: (a: A, b: B) => C + ): (self: NonEmptyReadonlyArray) => NonEmptyArray + ( + self: NonEmptyReadonlyArray, + that: NonEmptyReadonlyArray, + f: (a: A, b: B) => C + ): NonEmptyArray +} = dual(3, ( + self: NonEmptyReadonlyArray, + that: NonEmptyReadonlyArray, + f: (a: A, b: B) => C +): NonEmptyArray => { + const cs: NonEmptyArray = [f(headNonEmpty(self), headNonEmpty(that))] + const len = Math.min(self.length, that.length) + for (let i = 1; i < len; i++) { + cs[i] = f(self[i], that[i]) } + return cs +}) /** * This function is the inverse of `zip`. Takes an `Iterable` of pairs and return two corresponding `Array`s. @@ -910,7 +926,7 @@ export const setNonEmptyHead = ( */ export const modifyNonEmptyLast = (f: (a: A) => B) => (self: NonEmptyReadonlyArray): NonEmptyArray => - pipe(initNonEmpty(self), append(f(lastNonEmpty(self)))) + append(initNonEmpty(self), f(lastNonEmpty(self))) /** * Change the last element, creating a new `NonEmptyReadonlyArray`. @@ -1019,20 +1035,28 @@ export const chop = ( * * @since 1.0.0 */ -export const chopNonEmpty = ( +export const chopNonEmpty: { + ( + f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] + ): (self: NonEmptyReadonlyArray) => NonEmptyArray + ( + self: NonEmptyReadonlyArray, + f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] + ): NonEmptyArray +} = dual(2, ( + self: NonEmptyReadonlyArray, f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] -) => - (self: NonEmptyReadonlyArray): NonEmptyArray => { - const [b, rest] = f(self) - const out: NonEmptyArray = [b] - let next: ReadonlyArray = rest - while (readonlyArray.isNonEmpty(next)) { - const [b, rest] = f(next) - out.push(b) - next = rest - } - return out +): NonEmptyArray => { + const [b, rest] = f(self) + const out: NonEmptyArray = [b] + let next: ReadonlyArray = rest + while (readonlyArray.isNonEmpty(next)) { + const [b, rest] = f(next) + out.push(b) + next = rest } + return out +}) /** * Splits an `Iterable` into two pieces, the first piece has max `n` elements. @@ -1070,7 +1094,7 @@ export const splitNonEmptyAt = (n: number) => const m = Math.max(1, n) return m >= self.length ? [copy(self), []] : - [pipe(self.slice(1, m), prepend(headNonEmpty(self))), self.slice(m)] + [prepend(self.slice(1, m), headNonEmpty(self)), self.slice(m)] } /** @@ -1113,23 +1137,20 @@ export const chunksOfNonEmpty = ( */ export const group = (equivalence: Equivalence) => (self: NonEmptyReadonlyArray): NonEmptyArray> => - pipe( - self, - chopNonEmpty((as) => { - const h = headNonEmpty(as) - const out: NonEmptyArray = [h] - let i = 1 - for (; i < as.length; i++) { - const a = as[i] - if (equivalence(a, h)) { - out.push(a) - } else { - break - } + chopNonEmpty(self, (as) => { + const h = headNonEmpty(as) + const out: NonEmptyArray = [h] + let i = 1 + for (; i < as.length; i++) { + const a = as[i] + if (equivalence(a, h)) { + out.push(a) + } else { + break } - return [out, as.slice(i)] - }) - ) + } + return [out, as.slice(i)] + }) /** * Splits an `Iterable` into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning @@ -1155,17 +1176,19 @@ export const groupBy = (f: (a: A) => string) => /** * @since 1.0.0 */ -export const union = (equivalence: Equivalence) => - (that: ReadonlyArray) => - (self: ReadonlyArray): Array => { - const a = Array.from(self) - const b = Array.from(that) - return isNonEmpty(a) && isNonEmpty(b) ? - unionNonEmpty(equivalence)(b)(a) : - isNonEmpty(a) ? - a : - b - } +export const union = (equivalence: Equivalence): { + (that: ReadonlyArray): (self: ReadonlyArray) => Array + (self: ReadonlyArray, that: ReadonlyArray): Array +} => + dual(2, (self: ReadonlyArray, that: ReadonlyArray): Array => { + const a = Array.from(self) + const b = Array.from(that) + return isNonEmpty(a) && isNonEmpty(b) ? + unionNonEmpty(equivalence)(b)(a) : + isNonEmpty(a) ? + a : + b + }) /** * @since 1.0.0 @@ -1185,10 +1208,15 @@ export const unionNonEmpty = (equivalence: Equivalence): { * * @since 1.0.0 */ -export const intersection = (equivalence: Equivalence) => - (that: Iterable) => - (self: Iterable): Array => +export const intersection = (equivalence: Equivalence): { + (that: Iterable): (self: Iterable) => Array + (self: Iterable, that: Iterable): Array +} => + dual( + 2, + (self: Iterable, that: Iterable): Array => fromIterable(self).filter((a) => contains(equivalence)(a)(that)) + ) /** * Creates a `Array` of values not included in the other given `Iterable`. @@ -1220,15 +1248,10 @@ export const empty: () => Array = () => [] export const mapNonEmpty: { (f: (a: A) => B): (self: readonly [A, ...Array]) => [B, ...Array] (self: readonly [A, ...Array], f: (a: A) => B): [B, ...Array] -} = dual< - ( - f: (a: A) => B - ) => (self: NonEmptyReadonlyArray) => NonEmptyArray, - (self: NonEmptyReadonlyArray, f: (a: A) => B) => NonEmptyArray ->( +} = dual( 2, (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray => - pipe(self, mapNonEmptyWithIndex(f)) + mapNonEmptyWithIndex(self, f) ) /** @@ -1243,16 +1266,16 @@ export const mapWithIndex = ( * @category mapping * @since 1.0.0 */ -export const mapNonEmptyWithIndex = ( - f: (a: A, i: number) => B -) => - (self: NonEmptyReadonlyArray): NonEmptyArray => { - const out: NonEmptyArray = [f(headNonEmpty(self), 0)] - for (let i = 1; i < self.length; i++) { - out.push(f(self[i], i)) - } - return out +export const mapNonEmptyWithIndex: { + (f: (a: A, i: number) => B): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: NonEmptyReadonlyArray, f: (a: A, i: number) => B): NonEmptyArray +} = dual(2, (self: NonEmptyReadonlyArray, f: (a: A, i: number) => B): NonEmptyArray => { + const out: NonEmptyArray = [f(headNonEmpty(self), 0)] + for (let i = 1; i < self.length; i++) { + out.push(f(self[i], i)) } + return out +}) /** * @category instances @@ -1361,17 +1384,19 @@ export const Pointed: pointed.Pointed = { * @category sequencing * @since 1.0.0 */ -export const flatMapWithIndex = (f: (a: A, i: number) => ReadonlyArray) => - (self: ReadonlyArray): Array => { - if (isEmpty(self)) { - return [] - } - const out: Array = [] - for (let i = 0; i < self.length; i++) { - out.push(...f(self[i], i)) - } - return out +export const flatMapWithIndex: { + (f: (a: A, i: number) => ReadonlyArray): (self: ReadonlyArray) => Array + (self: ReadonlyArray, f: (a: A, i: number) => ReadonlyArray): Array +} = dual(2, (self: ReadonlyArray, f: (a: A, i: number) => ReadonlyArray): Array => { + if (isEmpty(self)) { + return [] + } + const out: Array = [] + for (let i = 0; i < self.length; i++) { + out.push(...f(self[i], i)) } + return out +}) /** * @category sequencing @@ -1383,7 +1408,7 @@ export const flatMap: { } = dual( 2, (self: ReadonlyArray, f: (a: A) => ReadonlyArray): Array => - pipe(self, flatMapWithIndex(f)) + flatMapWithIndex(self, f) ) /** @@ -1468,18 +1493,20 @@ export const bind: ( * @category filtering * @since 1.0.0 */ -export const filterMapWithIndex = (f: (a: A, i: number) => Option) => - (self: Iterable): Array => { - const as = fromIterable(self) - const out: Array = [] - for (let i = 0; i < as.length; i++) { - const o = f(as[i], i) - if (O.isSome(o)) { - out.push(o.value) - } +export const filterMapWithIndex: { + (f: (a: A, i: number) => Option): (self: Iterable) => Array + (self: Iterable, f: (a: A, i: number) => Option): Array +} = dual(2, (self: Iterable, f: (a: A, i: number) => Option): Array => { + const as = fromIterable(self) + const out: Array = [] + for (let i = 0; i < as.length; i++) { + const o = f(as[i], i) + if (O.isSome(o)) { + out.push(o.value) } - return out } + return out +}) /** * @category filtering @@ -1509,7 +1536,7 @@ export const filterMap: { (self: Iterable, f: (a: A) => Option): Array } = dual( 2, - (self: Iterable, f: (a: A) => Option): Array => pipe(self, filterMapWithIndex(f)) + (self: Iterable, f: (a: A) => Option): Array => filterMapWithIndex(self, f) ) /** @@ -1532,7 +1559,7 @@ export const Compactable: compactable.Compactable = { compact } -// TODO: input as interables +// TODO: input as iterables /** * @category filtering * @since 1.0.0 @@ -1651,7 +1678,7 @@ export const traverseNonEmptyWithIndex = ( ) => (f: (a: A, i: number) => Kind) => (self: NonEmptyReadonlyArray): Kind> => { - const [head, ...tail] = pipe(self, mapNonEmptyWithIndex(f)) + const [head, ...tail] = mapNonEmptyWithIndex(self, f) return F.productMany(head, tail) } @@ -2140,7 +2167,8 @@ export const unfold = (b: B, f: (b: B) => Option): Array< * @since 1.0.0 */ export const getUnionSemigroup = (equivalence: Equivalence): Semigroup> => - fromCombine((self, that) => pipe(self, union(equivalence)(that))) + // @ts-expect-error + fromCombine(union(equivalence)) /** * @category instances @@ -2163,7 +2191,8 @@ export const getUnionMonoid = (equivalence: Equivalence): Monoid( equivalence: Equivalence ): Semigroup> => - fromCombine((self, that) => pipe(self, intersection(equivalence)(that))) + // @ts-expect-error + fromCombine(intersection(equivalence)) /** * Returns a `Semigroup` for `ReadonlyArray`. diff --git a/src/These.ts b/src/These.ts index 2f0863c62..85d9be685 100644 --- a/src/These.ts +++ b/src/These.ts @@ -5,7 +5,7 @@ import type { Either, Left, Right } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" -import { constNull, constUndefined, dual, pipe } from "@fp-ts/core/Function" +import { constNull, constUndefined, dual } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { proto, structural } from "@fp-ts/core/internal/effect" import * as N from "@fp-ts/core/Number" @@ -395,7 +395,7 @@ export const flatMapOption = ( onNone: (a: A) => E2 ) => (self: Validated): Validated => - pipe(self, flatMap(liftOption(f, (a) => [onNone(a)]))) + flatMap(self, liftOption(f, (a) => [onNone(a)])) /** * @category sequencing @@ -403,7 +403,7 @@ export const flatMapOption = ( */ export const flatMapEither = ( f: (a: A) => Either -) => (self: Validated): Validated => pipe(self, flatMap(liftEither(f))) +) => (self: Validated): Validated => flatMap(self, liftEither(f)) /** * @category sequencing @@ -411,7 +411,7 @@ export const flatMapEither = ( */ export const flatMapThese = ( f: (a: A) => These -) => (self: Validated): Validated => pipe(self, flatMap(liftThese(f))) +) => (self: Validated): Validated => flatMap(self, liftThese(f)) /** * Converts a `These` to an `Option` discarding the error (`Both` included). @@ -701,11 +701,8 @@ export const Traversable: traversable.Traversable = traversable isLeft(self) ? F.of>(self) : isRight(self) - ? pipe(f(self.right), F.map>(right)) - : pipe( - f(self.right), - F.map((b) => both(self.left, b)) - ) + ? F.map>(f(self.right), right) + : F.map(f(self.right), (b) => both(self.left, b)) ) /** @@ -796,8 +793,8 @@ export const orElseEither = ( ) => (self: These): These> => isLeft(self) ? - pipe(that(self.left), map(E.right)) : - pipe(self, map(E.left)) + map(that(self.left), E.right) : + map(self, E.left) /** * Executes this effect and returns its value, if it succeeds, but otherwise @@ -814,19 +811,21 @@ export const orElseFail = ( * @category error handling * @since 1.0.0 */ -export const firstRightOrBothOf = (collection: Iterable>) => - (self: These): These => { - let out = self +export const firstRightOrBothOf: { + (collection: Iterable>): (self: These) => These + (self: These, collection: Iterable>): These +} = dual(2, (self: These, collection: Iterable>): These => { + let out = self + if (isRightOrBoth(out)) { + return out + } + for (out of collection) { if (isRightOrBoth(out)) { return out } - for (out of collection) { - if (isRightOrBoth(out)) { - return out - } - } - return out } + return out +}) /** * @category instances @@ -835,7 +834,7 @@ export const firstRightOrBothOf = (collection: Iterable>) => export const SemiCoproduct: semiCoproduct.SemiCoproduct = semiCoproduct.make( Invariant, (self, that) => isRightOrBoth(self) ? self : that, - (self, collection) => pipe(self, firstRightOrBothOf(collection)) + firstRightOrBothOf ) /** @@ -962,7 +961,7 @@ const productMany = ( self: Validated, collection: Iterable> ): Validated]> => - pipe(product(self, productAll(collection)), map(([a, as]) => [a, ...as])) + map(product(self, productAll(collection)), ([a, as]) => [a, ...as]) /** * @category instances diff --git a/src/typeclass/Chainable.ts b/src/typeclass/Chainable.ts index 62d20c226..2d3fa7e60 100644 --- a/src/typeclass/Chainable.ts +++ b/src/typeclass/Chainable.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { dual, pipe } from "@fp-ts/core/Function" +import { dual } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" import type { FlatMap } from "@fp-ts/core/typeclass/FlatMap" @@ -52,16 +52,7 @@ export const tap = (F: Chainable): { ( self: Kind, f: (a: A) => Kind - ): Kind => - pipe( - self, - F.flatMap(a => - pipe( - f(a), - F.map(() => a) - ) - ) - ) + ): Kind => F.flatMap(self, a => F.map(f(a), () => a)) ) /** @@ -79,10 +70,4 @@ export const bind = (F: Chainable) => O1 | O2, E1 | E2, { [K in keyof A | N]: K extends keyof A ? A[K] : B } - > => - F.flatMap(a => - pipe( - f(a), - F.map(b => Object.assign({}, a, { [name]: b }) as any) - ) - ) + > => F.flatMap(a => F.map(f(a), b => Object.assign({}, a, { [name]: b }) as any)) diff --git a/src/typeclass/Compactable.ts b/src/typeclass/Compactable.ts index 0dd5e5ec1..3b65fa49a 100644 --- a/src/typeclass/Compactable.ts +++ b/src/typeclass/Compactable.ts @@ -4,7 +4,6 @@ * @since 1.0.0 */ import type { Either } from "@fp-ts/core/Either" -import { pipe } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" import * as either from "@fp-ts/core/internal/Either" import type { Option } from "@fp-ts/core/Option" @@ -39,6 +38,6 @@ export const separate = ( ( self: Kind> ): [Kind, Kind] => [ - pipe(self, F.map(either.getLeft), F.compact), - pipe(self, F.map(either.getRight), F.compact) + F.compact(F.map(self, either.getLeft)), + F.compact(F.map(self, either.getRight)) ] diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index c3b278d9f..40c03e8ef 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { dual, pipe } from "@fp-ts/core/Function" +import { dual } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" @@ -61,7 +61,7 @@ export const flap = (F: Covariant): { dual( 2, (a: A, self: Kind B>): Kind => - pipe(self, F.map(f => f(a))) + F.map(self, f => f(a)) ) /** @@ -74,8 +74,7 @@ export const as = (F: Covariant): { } => dual( 2, - (self: Kind, b: B): Kind => - pipe(self, F.map(() => b)) + (self: Kind, b: B): Kind => F.map(self, () => b) ) /** diff --git a/src/typeclass/Product.ts b/src/typeclass/Product.ts index bbbc4b640..495344514 100644 --- a/src/typeclass/Product.ts +++ b/src/typeclass/Product.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { pipe } from "@fp-ts/core/Function" + import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Of } from "@fp-ts/core/typeclass/Of" import type { SemiProduct } from "@fp-ts/core/typeclass/SemiProduct" @@ -40,14 +40,11 @@ export const struct = (F: Product) => { [K in keyof R]: [R[K]] extends [Kind] ? A : never } > => { const keys = Object.keys(fields) - return pipe( - F.productAll(keys.map(k => fields[k])), - F.imap(values => { - const out: any = {} - for (let i = 0; i < values.length; i++) { - out[keys[i]] = values[i] - } - return out - }, (r) => keys.map(k => r[k])) - ) + return F.imap(F.productAll(keys.map(k => fields[k])), values => { + const out: any = {} + for (let i = 0; i < values.length; i++) { + out[keys[i]] = values[i] + } + return out + }, (r) => keys.map(k => r[k])) } diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index 1de85e34e..e55b7b5cf 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { dual, identity, pipe, SK } from "@fp-ts/core/Function" +import { dual, identity, SK } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" @@ -23,12 +23,9 @@ export interface SemiApplicative extends SemiProduct, C export const getSemigroup = (F: SemiApplicative) => (S: Semigroup): Semigroup> => semigroup.make( - (self, that) => pipe(F.product(self, that), F.map(([a1, a2]) => S.combine(a1, a2))), + (self, that) => F.map(F.product(self, that), ([a1, a2]) => S.combine(a1, a2)), (self, collection) => - pipe( - F.productMany(self, collection), - F.map(([head, ...tail]) => S.combineMany(head, tail)) - ) + F.map(F.productMany(self, collection), ([head, ...tail]) => S.combineMany(head, tail)) ) /** @@ -67,8 +64,7 @@ export const zipWith = (F: SemiApplicative): { self: Kind, that: Kind, f: (a: A, b: B) => C - ): Kind => - pipe(F.product(self, that), F.map(([a, b]) => f(a, b))) + ): Kind => F.map(F.product(self, that), ([a, b]) => f(a, b)) ) /** diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index c85a78058..833edf0db 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { dual, pipe } from "@fp-ts/core/Function" +import { dual } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" @@ -113,10 +113,7 @@ export const productManyComposition = >, collection: Iterable>> ): Kind]>> => - pipe( - F.productMany(self, collection), - F.map(([ga, ...gas]) => G.productMany(ga, gas)) - ) + F.map(F.productMany(self, collection), ([ga, ...gas]) => G.productMany(ga, gas)) /** * @category do notation @@ -136,13 +133,9 @@ export const andThenBind = (F: SemiProduct) => E1 | E2, { [K in keyof A | N]: K extends keyof A ? A[K] : B } > => - pipe( - F.product(self, that), - F.imap( - ([a, b]) => Object.assign({}, a, { [name]: b }) as any, - ({ [name]: b, ...rest }) => [rest, b] as any - ) - ) + F.imap(F.product(self, that), ([a, b]) => + Object.assign({}, a, { [name]: b }) as any, ({ [name]: b, ...rest }) => + [rest, b] as any) /** * Appends an element to the end of a tuple. @@ -164,10 +157,8 @@ export const appendElement = (F: SemiProduct): { self: Kind, that: Kind ): Kind => - pipe( - F.product(self, that), - F.imap(([a, b]) => [...a, b], ab => [ab.slice(0, -1), ab[ab.length - 1]] as any) - )) + F.imap(F.product(self, that), ([a, b]) => [...a, b], ab => + [ab.slice(0, -1), ab[ab.length - 1]] as any)) /** * @since 1.0.0 @@ -199,14 +190,15 @@ export const nonEmptyStruct = (F: SemiProduct) => { [K in keyof R]: [R[K]] extends [Kind] ? A : never } > => { const keys = Object.keys(fields) - return pipe( + return F.imap( F.productMany(fields[keys[0]], keys.slice(1).map(k => fields[k])), - F.imap(([value, ...values]) => { + ([value, ...values]) => { const out: any = { [keys[0]]: value } for (let i = 0; i < values.length; i++) { out[keys[i + 1]] = values[i] } return out - }, (r) => keys.map(k => r[k]) as any) + }, + (r) => keys.map(k => r[k]) as any ) } From c9ce88857743eb6b5292aae9038883890f21976c Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 3 Feb 2023 17:36:28 +0100 Subject: [PATCH 172/255] Either: apply dual --- docs/modules/Either.ts.md | 118 +++++++++------ guides/Either.md | 1 + src/Bigint.ts | 10 +- src/Boolean.ts | 5 +- src/Either.ts | 238 ++++++++++++++++++++----------- src/Number.ts | 10 +- src/Option.ts | 66 ++------- src/ReadonlyRecord.ts | 33 +---- src/internal/Either.ts | 5 +- src/typeclass/Order.ts | 46 ++---- src/typeclass/SemiApplicative.ts | 58 +------- 11 files changed, 271 insertions(+), 319 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index c8becacce..7d3dff796 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -62,7 +62,6 @@ Added in v1.0.0 - [getOrElse](#getorelse) - [getOrNull](#getornull) - [getOrUndefined](#getorundefined) - - [merge](#merge) - [guards](#guards) - [isEither](#iseither) - [isLeft](#isleft) @@ -90,6 +89,7 @@ Added in v1.0.0 - [getOrThrow](#getorthrow) - [liftNullable](#liftnullable) - [liftThrowable](#liftthrowable) + - [merge](#merge) - [lifting](#lifting) - [lift2](#lift2) - [liftOption](#liftoption) @@ -320,7 +320,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromIterable: (onEmpty: LazyArg) => (collection: Iterable) => Either +export declare const fromIterable: { + (onEmpty: LazyArg): (collection: Iterable) => Either + (collection: Iterable, onEmpty: LazyArg): Either +} ``` Added in v1.0.0 @@ -465,7 +468,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const inspectLeft: (onLeft: (e: E) => void) => (self: Either) => Either +export declare const inspectLeft: { + (onLeft: (e: E) => void): (self: Either) => Either + (self: Either, onLeft: (e: E) => void): Either +} ``` Added in v1.0.0 @@ -475,7 +481,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const inspectRight: (onRight: (a: A) => void) => (self: Either) => Either +export declare const inspectRight: { + (onRight: (a: A) => void): (self: Either) => Either + (self: Either, onRight: (a: A) => void): Either +} ``` Added in v1.0.0 @@ -593,9 +602,10 @@ executes the specified effect. **Signature** ```ts -export declare const orElse: ( - that: (e1: E1) => Either -) => (self: Either) => Either +export declare const orElse: { + (that: (e1: E1) => Either): (self: Either) => Either + (self: Either, that: (e1: E1) => Either): Either +} ``` Added in v1.0.0 @@ -608,9 +618,10 @@ fails, in which case, it will produce the value of the specified effect. **Signature** ```ts -export declare const orElseEither: ( - that: (e1: E1) => Either -) => (self: Either) => Either> +export declare const orElseEither: { + (that: (e1: E1) => Either): (self: Either) => Either> + (self: Either, that: (e1: E1) => Either): Either> +} ``` Added in v1.0.0 @@ -623,7 +634,10 @@ fails with the specified error. **Signature** ```ts -export declare const orElseFail: (onLeft: LazyArg) => (self: Either) => Either +export declare const orElseFail: { + (onLeft: LazyArg): (self: Either) => Either + (self: Either, onLeft: LazyArg): Either +} ``` Added in v1.0.0 @@ -635,9 +649,10 @@ Returns an effect that effectfully "peeks" at the failure of this effect. **Signature** ```ts -export declare const tapError: ( - onLeft: (e: E1) => Either -) => (self: Either) => Either +export declare const tapError: { + (onLeft: (e: E1) => Either): (self: Either) => Either + (self: Either, onLeft: (e: E1) => Either): Either +} ``` Added in v1.0.0 @@ -649,7 +664,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const compact: (onNone: LazyArg) => (self: Either>) => Either +export declare const compact: { + (onNone: LazyArg): (self: Either>) => Either + (self: Either>, onNone: LazyArg): Either +} ``` Added in v1.0.0 @@ -666,6 +684,12 @@ export declare const filter: { (predicate: Predicate, onFalse: LazyArg): ( self: Either ) => Either + ( + self: Either, + refinement: Refinement, + onFalse: LazyArg + ): Either + (self: Either, predicate: Predicate, onFalse: LazyArg): Either } ``` @@ -676,10 +700,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const filterMap: ( - f: (a: A) => Option, - onNone: LazyArg -) => (self: Either) => Either +export declare const filterMap: { + (f: (a: A) => Option, onNone: LazyArg): (self: Either) => Either + (self: Either, f: (a: A) => Option, onNone: LazyArg): Either +} ``` Added in v1.0.0 @@ -737,16 +761,6 @@ export declare const getOrUndefined: (self: Either) => A | undefined Added in v1.0.0 -## merge - -**Signature** - -```ts -export declare const merge: (self: Either) => E | A -``` - -Added in v1.0.0 - # guards ## isEither @@ -1028,6 +1042,16 @@ export declare const liftThrowable: ( Added in v1.0.0 +## merge + +**Signature** + +```ts +export declare const merge: (self: Either) => E | A +``` + +Added in v1.0.0 + # lifting ## lift2 @@ -1229,7 +1253,10 @@ if the value is a `Right` the inner value is applied to the second function. **Signature** ```ts -export declare const match: (onLeft: (e: E) => B, onRight: (a: A) => C) => (self: Either) => B | C +export declare const match: { + (onLeft: (e: E) => B, onRight: (a: A) => C): (self: Either) => B | C + (self: Either, onLeft: (e: E) => B, onRight: (a: A) => C): B | C +} ``` **Example** @@ -1284,10 +1311,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapNullable: ( - f: (a: A) => B | null | undefined, - onNullable: (a: A) => E2 -) => (self: Either) => Either> +export declare const flatMapNullable: { + (f: (a: A) => B | null | undefined, onNullable: (a: A) => E2): ( + self: Either + ) => Either> + (self: Either, f: (a: A) => B | null | undefined, onNullable: (a: A) => E2): Either< + E1 | E2, + NonNullable + > +} ``` Added in v1.0.0 @@ -1297,10 +1329,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapOption: ( - f: (a: A) => Option, - onNone: (a: A) => E2 -) => (self: Either) => Either +export declare const flatMapOption: { + (f: (a: A) => Option, onNone: (a: A) => E2): (self: Either) => Either + (self: Either, f: (a: A) => Option, onNone: (a: A) => E2): Either +} ``` Added in v1.0.0 @@ -1426,7 +1458,10 @@ Returns a function that checks if an `Either` contains a given value using a pro **Signature** ```ts -export declare const contains: (equivalence: Equivalence) => (a: A) => (self: Either) => boolean +export declare const contains: (equivalence: Equivalence) => { + (a: A): (self: Either) => boolean + (self: Either, a: A): boolean +} ``` Added in v1.0.0 @@ -1438,7 +1473,10 @@ Returns `false` if `Left` or returns the Either of the application of the given **Signature** ```ts -export declare const exists: (predicate: Predicate) => (self: Either) => boolean +export declare const exists: { + (predicate: Predicate): (self: Either) => boolean + (self: Either, predicate: Predicate): boolean +} ``` **Example** diff --git a/guides/Either.md b/guides/Either.md index 926de5601..0ab81f654 100644 --- a/guides/Either.md +++ b/guides/Either.md @@ -487,6 +487,7 @@ console.log(getOrUndefined(left("error message"))); // undefined | `flatMapNullable` | `Either`, `(...a: A) => B \| null \| undefined`, `A => E2` | `Either>` | | `getOrNull` | `Either` | `A \| null` | | `getOrUndefined` | `Either` | `A \| undefined` | +| `merge` | `Either` | `E \| A` | Now let's see the other case, that is when we need to interoperate with code that throws exceptions. diff --git a/src/Bigint.ts b/src/Bigint.ts index 030eac00d..c1dbd8321 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -44,10 +44,7 @@ export const multiply: { export const subtract: { (that: bigint): (self: bigint) => bigint (self: bigint, that: bigint): bigint -} = dual< - (that: bigint) => (self: bigint) => bigint, - (self: bigint, that: bigint) => bigint ->(2, (self: bigint, that: bigint): bigint => self - that) +} = dual(2, (self: bigint, that: bigint): bigint => self - that) /** * @category algebraic operations @@ -56,10 +53,7 @@ export const subtract: { export const divide: { (that: bigint): (self: bigint) => bigint (self: bigint, that: bigint): bigint -} = dual< - (that: bigint) => (self: bigint) => bigint, - (self: bigint, that: bigint) => bigint ->(2, (self: bigint, that: bigint): bigint => self / that) +} = dual(2, (self: bigint, that: bigint): bigint => self / that) /** * @since 1.0.0 diff --git a/src/Boolean.ts b/src/Boolean.ts index 83410c8f2..01e537fb2 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -44,10 +44,7 @@ export const isBoolean: Refinement = predicate.isBoolean export const match: { (onFalse: LazyArg, onTrue: LazyArg): (value: boolean) => A | B (value: boolean, onFalse: LazyArg, onTrue: LazyArg): A | B -} = dual< - (onFalse: LazyArg, onTrue: LazyArg) => (value: boolean) => A | B, - (value: boolean, onFalse: LazyArg, onTrue: LazyArg) => A | B ->( +} = dual( 3, (value: boolean, onFalse: LazyArg, onTrue: LazyArg): A | B => value ? onTrue() : onFalse() diff --git a/src/Either.ts b/src/Either.ts index 231f65d08..12042bf7d 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -148,13 +148,15 @@ export const toRefinement = (f: (a: A) => Either): Refi * @category conversions * @since 1.0.0 */ -export const fromIterable = (onEmpty: LazyArg) => - (collection: Iterable): Either => { - for (const a of collection) { - return right(a) - } - return left(onEmpty()) +export const fromIterable: { + (onEmpty: LazyArg): (collection: Iterable) => Either + (collection: Iterable, onEmpty: LazyArg): Either +} = dual(2, (collection: Iterable, onEmpty: LazyArg): Either => { + for (const a of collection) { + return right(a) } + return left(onEmpty()) +}) /** * Converts a `Either` to an `Option` discarding the error. @@ -521,8 +523,7 @@ export const tuple: >>( ) => Either< [T[number]] extends [Either] ? E : never, { [I in keyof T]: [T[I]] extends [Either] ? A : never } -> = product_ - .tuple(Product) +> = product_.tuple(Product) /** * @since 1.0.0 @@ -532,8 +533,7 @@ export const struct: >>( ) => Either< [R[keyof R]] extends [Either] ? E : never, { [K in keyof R]: [R[K]] extends [Either] ? A : never } -> = product_ - .struct(Product) +> = product_.struct(Product) /** * @category instances @@ -561,8 +561,7 @@ export const SemiApplicative: semiApplicative.SemiApplicative * @since 1.0.0 */ export const getFirstLeftSemigroup: (S: Semigroup) => Semigroup> = - semiApplicative - .getSemigroup(SemiApplicative) + semiApplicative.getSemigroup(SemiApplicative) /** * Lifts a binary function into `Either`. @@ -624,9 +623,7 @@ export const Applicative: applicative.Applicative = { * @since 1.0.0 */ export const getFirstLeftMonoid: (M: Monoid) => Monoid> = applicative - .getMonoid( - Applicative - ) + .getMonoid(Applicative) /** * @category error handling @@ -696,10 +693,7 @@ export const getFirstRightSemigroup: () => Semigroup> = semiC export const getOrElse: { (onLeft: (e: E) => B): (self: Either) => B | A (self: Either, onLeft: (e: E) => B): A | B -} = dual< - (onLeft: (e: E) => B) => (self: Either) => A | B, - (self: Either, onLeft: (e: E) => B) => A | B ->( +} = dual( 2, (self: Either, onLeft: (e: E) => B): A | B => isLeft(self) ? onLeft(self.left) : self.right @@ -712,9 +706,14 @@ export const getOrElse: { * @category error handling * @since 1.0.0 */ -export const orElse = ( - that: (e1: E1) => Either -) => (self: Either): Either => isLeft(self) ? that(self.left) : self +export const orElse: { + (that: (e1: E1) => Either): (self: Either) => Either + (self: Either, that: (e1: E1) => Either): Either +} = dual( + 2, + (self: Either, that: (e1: E1) => Either): Either => + isLeft(self) ? that(self.left) : self +) /** * Returns an effect that will produce the value of this effect, unless it @@ -723,13 +722,16 @@ export const orElse = ( * @category error handling * @since 1.0.0 */ -export const orElseEither = ( - that: (e1: E1) => Either -) => - (self: Either): Either> => +export const orElseEither: { + (that: (e1: E1) => Either): (self: Either) => Either> + (self: Either, that: (e1: E1) => Either): Either> +} = dual( + 2, + (self: Either, that: (e1: E1) => Either): Either> => isLeft(self) ? map(that(self.left), right) : map(self, left) +) /** * Executes this effect and returns its value, if it succeeds, but otherwise @@ -738,9 +740,14 @@ export const orElseEither = ( * @category error handling * @since 1.0.0 */ -export const orElseFail = ( - onLeft: LazyArg -): (self: Either) => Either => orElse(() => left(onLeft())) +export const orElseFail: { + (onLeft: LazyArg): (self: Either) => Either + (self: Either, onLeft: LazyArg): Either +} = dual( + 2, + (self: Either, onLeft: LazyArg): Either => + orElse(self, () => left(onLeft())) +) /** * @category instances @@ -809,8 +816,14 @@ export const toArray: (self: Either) => Array = foldable.toArray( * @category pattern matching * @since 1.0.0 */ -export const match = (onLeft: (e: E) => B, onRight: (a: A) => C) => - (self: Either): B | C => isLeft(self) ? onLeft(self.left) : onRight(self.right) +export const match: { + (onLeft: (e: E) => B, onRight: (a: A) => C): (self: Either) => B | C + (self: Either, onLeft: (e: E) => B, onRight: (a: A) => C): B | C +} = dual( + 3, + (self: Either, onLeft: (e: E) => B, onRight: (a: A) => C): B | C => + isLeft(self) ? onLeft(self.left) : onRight(self.right) +) // ------------------------------------------------------------------------------------- // interop @@ -834,10 +847,7 @@ export const match = (onLeft: (e: E) => B, onRight: (a: A) => C) export const fromNullable: { (onNullable: (a: A) => E): (a: A) => Either> (a: A, onNullable: (a: A) => E): Either> -} = dual< - (onNullable: (a: A) => E) => (a: A) => Either>, - (a: A, onNullable: (a: A) => E) => Either> ->( +} = dual( 2, (a: A, onNullable: (a: A) => E): Either> => a == null ? left(onNullable(a)) : right(a as NonNullable) @@ -852,15 +862,31 @@ export const liftNullable = , B, E>( onNullable: (...a: A) => E ) => (...a: A): Either> => fromNullable(f(...a), () => onNullable(...a)) +/** + * @category interop + * @since 1.0.0 + */ +export const merge: (self: Either) => E | A = match(identity, identity) + /** * @category sequencing * @since 1.0.0 */ -export const flatMapNullable = ( +export const flatMapNullable: { + ( + f: (a: A) => B | null | undefined, + onNullable: (a: A) => E2 + ): (self: Either) => Either> + ( + self: Either, + f: (a: A) => B | null | undefined, + onNullable: (a: A) => E2 + ): Either> +} = dual(3, ( + self: Either, f: (a: A) => B | null | undefined, onNullable: (a: A) => E2 -): ((self: Either) => Either>) => - flatMap(liftNullable(f, onNullable)) +): Either> => flatMap(self, liftNullable(f, onNullable))) /** * @category interop @@ -891,12 +917,6 @@ export const liftThrowable = , B, E>( } } -/** - * @category getters - * @since 1.0.0 - */ -export const merge: (self: Either) => E | A = match(identity, identity) - /** * @since 1.0.0 */ @@ -907,9 +927,14 @@ export const reverse = (self: Either): Either => * @category filtering * @since 1.0.0 */ -export const compact = (onNone: LazyArg) => - (self: Either>): Either => +export const compact: { + (onNone: LazyArg): (self: Either>) => Either + (self: Either>, onNone: LazyArg): Either +} = dual( + 2, + (self: Either>, onNone: LazyArg): Either => isLeft(self) ? self : option.isNone(self.right) ? left(onNone()) : right(self.right.value) +) /** * @category filtering @@ -923,26 +948,45 @@ export const filter: { predicate: Predicate, onFalse: LazyArg ): (self: Either) => Either -} = ( + ( + self: Either, + refinement: Refinement, + onFalse: LazyArg + ): Either + ( + self: Either, + predicate: Predicate, + onFalse: LazyArg + ): Either +} = dual(3, ( + self: Either, predicate: Predicate, - onFalse: LazyArg -) => - (self: Either): Either => - isLeft(self) ? self : predicate(self.right) ? self : left(onFalse()) + onFalse: LazyArg +): Either => isLeft(self) ? self : predicate(self.right) ? self : left(onFalse())) /** * @category filtering * @since 1.0.0 */ -export const filterMap = ( +export const filterMap: { + ( + f: (a: A) => Option, + onNone: LazyArg + ): (self: Either) => Either + ( + self: Either, + f: (a: A) => Option, + onNone: LazyArg + ): Either +} = dual(3, ( + self: Either, f: (a: A) => Option, onNone: LazyArg -) => - (self: Either): Either => - flatMap(self, (a) => { - const ob = f(a) - return option.isNone(ob) ? left(onNone()) : right(ob.value) - }) +): Either => + flatMap(self, (a) => { + const ob = f(a) + return option.isNone(ob) ? left(onNone()) : right(ob.value) + })) /** * @category instances @@ -1021,29 +1065,29 @@ export const tap: { * @category debugging * @since 1.0.0 */ -export const inspectRight = ( - onRight: (a: A) => void -) => - (self: Either): Either => { - if (isRight(self)) { - onRight(self.right) - } - return self +export const inspectRight: { + (onRight: (a: A) => void): (self: Either) => Either + (self: Either, onRight: (a: A) => void): Either +} = dual(2, (self: Either, onRight: (a: A) => void): Either => { + if (isRight(self)) { + onRight(self.right) } + return self +}) /** * @category debugging * @since 1.0.0 */ -export const inspectLeft = ( - onLeft: (e: E) => void -) => - (self: Either): Either => { - if (isLeft(self)) { - onLeft(self.left) - } - return self +export const inspectLeft: { + (onLeft: (e: E) => void): (self: Either) => Either + (self: Either, onLeft: (e: E) => void): Either +} = dual(2, (self: Either, onLeft: (e: E) => void): Either => { + if (isLeft(self)) { + onLeft(self.left) } + return self +}) /** * Returns an effect that effectfully "peeks" at the failure of this effect. @@ -1051,16 +1095,19 @@ export const inspectLeft = ( * @category error handling * @since 1.0.0 */ -export const tapError = ( - onLeft: (e: E1) => Either -) => - (self: Either): Either => { +export const tapError: { + (onLeft: (e: E1) => Either): (self: Either) => Either + (self: Either, onLeft: (e: E1) => Either): Either +} = dual( + 2, + (self: Either, onLeft: (e: E1) => Either): Either => { if (isRight(self)) { return self } const out = onLeft(self.left) return isLeft(out) ? out : self } +) /** * @category getters @@ -1119,18 +1166,35 @@ export const liftOption = , B, E>( * @category sequencing * @since 1.0.0 */ -export const flatMapOption = ( +export const flatMapOption: { + ( + f: (a: A) => Option, + onNone: (a: A) => E2 + ): (self: Either) => Either + ( + self: Either, + f: (a: A) => Option, + onNone: (a: A) => E2 + ): Either +} = dual(3, ( + self: Either, f: (a: A) => Option, onNone: (a: A) => E2 -) => (self: Either): Either => flatMap(self, liftOption(f, onNone)) +): Either => flatMap(self, liftOption(f, onNone))) /** * Returns a function that checks if an `Either` contains a given value using a provided `equivalence` function. * * @since 1.0.0 */ -export const contains = (equivalence: Equivalence) => - (a: A) => (self: Either): boolean => isLeft(self) ? false : equivalence(self.right, a) +export const contains = (equivalence: Equivalence): { + (a: A): (self: Either) => boolean + (self: Either, a: A): boolean +} => + dual( + 2, + (self: Either, a: A): boolean => isLeft(self) ? false : equivalence(self.right, a) + ) /** * Returns `false` if `Left` or returns the Either of the application of the given predicate to the `Right` value. @@ -1146,8 +1210,14 @@ export const contains = (equivalence: Equivalence) => * * @since 1.0.0 */ -export const exists = (predicate: Predicate) => - (self: Either): boolean => isLeft(self) ? false : predicate(self.right) +export const exists: { + (predicate: Predicate): (self: Either) => boolean + (self: Either, predicate: Predicate): boolean +} = dual( + 2, + (self: Either, predicate: Predicate): boolean => + isLeft(self) ? false : predicate(self.right) +) /** * Semigroup that models the combination of values that may be absent, elements that are `Left` are ignored diff --git a/src/Number.ts b/src/Number.ts index e78620163..2ff7d5b35 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -63,10 +63,7 @@ export const multiply: { export const subtract: { (that: number): (self: number) => number (self: number, that: number): number -} = dual< - (that: number) => (self: number) => number, - (self: number, that: number) => number ->(2, (self: number, that: number): number => self - that) +} = dual(2, (self: number, that: number): number => self - that) /** * @example @@ -81,10 +78,7 @@ export const subtract: { export const divide: { (that: number): (self: number) => number (self: number, that: number): number -} = dual< - (that: number) => (self: number) => number, - (self: number, that: number) => number ->(2, (self: number, that: number): number => self / that) +} = dual(2, (self: number, that: number): number => self / that) /** * @example diff --git a/src/Option.ts b/src/Option.ts index 2c3b0f42d..d48cfe561 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -201,10 +201,7 @@ export const isSome: (self: Option) => self is Some = option.isSome export const match: { (onNone: LazyArg, onSome: (a: A) => C): (self: Option) => B | C (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C -} = dual< - (onNone: LazyArg, onSome: (a: A) => C) => (self: Option) => B | C, - (self: Option, onNone: LazyArg, onSome: (a: A) => C) => B | C ->( +} = dual( 3, (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C => isNone(self) ? onNone() : onSome(self.value) @@ -342,10 +339,7 @@ export const toEither: { export const getOrElse: { (onNone: LazyArg): (self: Option) => B | A (self: Option, onNone: LazyArg): A | B -} = dual< - (onNone: LazyArg) => (self: Option) => A | B, - (self: Option, onNone: LazyArg) => A | B ->( +} = dual( 2, (self: Option, onNone: LazyArg): A | B => isNone(self) ? onNone() : self.value ) @@ -395,10 +389,7 @@ export const getOrElse: { export const orElse: { (that: LazyArg>): (self: Option) => Option (self: Option, that: LazyArg>): Option -} = dual< - (that: LazyArg>) => (self: Option) => Option, - (self: Option, that: LazyArg>) => Option ->( +} = dual( 2, (self: Option, that: LazyArg>): Option => isNone(self) ? that() : self ) @@ -418,10 +409,7 @@ export const orElse: { export const orElseEither: { (that: LazyArg>): (self: Option) => Option> (self: Option, that: LazyArg>): Option> -} = dual< - (that: LazyArg>) => (self: Option) => Option>, - (self: Option, that: LazyArg>) => Option> ->( +} = dual( 2, (self: Option, that: LazyArg>): Option> => isNone(self) ? map(that(), either.right) : map(self, either.left) @@ -688,10 +676,7 @@ export const Pointed: pointed.Pointed = { export const flatMap: { (f: (a: A) => Option): (self: Option) => Option (self: Option, f: (a: A) => Option): Option -} = dual< - (f: (a: A) => Option) => (self: Option) => Option, - (self: Option, f: (a: A) => Option) => Option ->( +} = dual( 2, (self: Option, f: (a: A) => Option): Option => isNone(self) ? none() : f(self.value) @@ -719,10 +704,7 @@ export const flatMap: { export const flatMapEither: { (f: (a: A) => Either): (self: Option) => Option (self: Option, f: (a: A) => Either): Option -} = dual< - (f: (a: A) => Either) => (self: Option) => Option, - (self: Option, f: (a: A) => Either) => Option ->( +} = dual( 2, (self: Option, f: (a: A) => Either): Option => flatMap(self, liftEither(f)) ) @@ -770,10 +752,7 @@ export const flatMapEither: { export const flatMapNullable: { (f: (a: A) => B | null | undefined): (self: Option) => Option> (self: Option, f: (a: A) => B | null | undefined): Option> -} = dual< - (f: (a: A) => B | null | undefined) => (self: Option) => Option>, - (self: Option, f: (a: A) => B | null | undefined) => Option> ->( +} = dual( 2, (self: Option, f: (a: A) => B | null | undefined): Option> => isNone(self) ? none() : fromNullable(f(self.value)) @@ -871,10 +850,7 @@ export const tap: { export const inspectSome: { (onSome: (a: A) => void): (self: Option) => Option (self: Option, onSome: (a: A) => void): Option -} = dual< - (onSome: (a: A) => void) => (self: Option) => Option, - (self: Option, onSome: (a: A) => void) => Option ->(2, (self: Option, onSome: (a: A) => void): Option => { +} = dual(2, (self: Option, onSome: (a: A) => void): Option => { if (isSome(self)) { onSome(self.value) } @@ -893,10 +869,7 @@ export const inspectSome: { export const inspectNone: { (onNone: () => void): (self: Option) => Option (self: Option, onNone: () => void): Option -} = dual< - (onNone: () => void) => (self: Option) => Option, - (self: Option, onNone: () => void) => Option ->(2, (self: Option, onNone: () => void): Option => { +} = dual(2, (self: Option, onNone: () => void): Option => { if (isNone(self)) { onNone() } @@ -1188,10 +1161,7 @@ export const Alternative: alternative.Alternative = { export const reduceCompact: { (b: B, f: (b: B, a: A) => B): (self: Iterable>) => B (self: Iterable>, b: B, f: (b: B, a: A) => B): B -} = dual< - (b: B, f: (b: B, a: A) => B) => (self: Iterable>) => B, - (self: Iterable>, b: B, f: (b: B, a: A) => B) => B ->( +} = dual( 3, (self: Iterable>, b: B, f: (b: B, a: A) => B): B => { let out: B = b @@ -1263,10 +1233,7 @@ export const separate: (self: Option>) => [Option, Option< export const filterMap: { (f: (a: A) => Option): (self: Option) => Option (self: Option, f: (a: A) => Option): Option -} = dual< - (f: (a: A) => Option) => (self: Option) => Option, - (self: Option, f: (a: A) => Option) => Option ->( +} = dual( 2, (self: Option, f: (a: A) => Option): Option => isNone(self) ? none() : f(self.value) @@ -1497,11 +1464,7 @@ export const liftEither = , E, B>( export const contains = (equivalence: Equivalence): { (a: A): (self: Option) => boolean (self: Option, a: A): boolean -} => - dual< - (a: A) => (self: Option) => boolean, - (self: Option, a: A) => boolean - >(2, (self: Option, a: A): boolean => isNone(self) ? false : equivalence(self.value, a)) +} => dual(2, (self: Option, a: A): boolean => isNone(self) ? false : equivalence(self.value, a)) /** * Check if a value in an `Option` type meets a certain predicate. @@ -1524,10 +1487,7 @@ export const contains = (equivalence: Equivalence): { export const exists: { (predicate: Predicate): (self: Option) => boolean (self: Option, predicate: Predicate): boolean -} = dual< - (predicate: Predicate) => (self: Option) => boolean, - (self: Option, predicate: Predicate) => boolean ->( +} = dual( 2, (self: Option, predicate: Predicate): boolean => isNone(self) ? false : predicate(self.value) diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index e9896666c..8c80c6bdb 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -39,13 +39,7 @@ export interface ReadonlyRecord { export const fromIterable: { (f: (a: A) => readonly [string, B]): (self: Iterable) => Record (self: Iterable, f: (a: A) => readonly [string, B]): Record -} = dual< - (f: (a: A) => readonly [string, B]) => (self: Iterable) => Record, - (self: Iterable, f: (a: A) => readonly [string, B]) => Record ->(2, ( - self: Iterable, - f: (a: A) => readonly [string, B] -): Record => { +} = dual(2, (self: Iterable, f: (a: A) => readonly [string, B]): Record => { const out: Record = {} for (const a of self) { const [k, b] = f(a) @@ -75,10 +69,7 @@ export const fromIterable: { export const get: { (key: string): (self: ReadonlyRecord) => Option (self: ReadonlyRecord, key: string): Option -} = dual< - (key: string) => (self: ReadonlyRecord) => Option, - (self: ReadonlyRecord, key: string) => Option ->( +} = dual( 2, (self: ReadonlyRecord, key: string): Option => Object.prototype.hasOwnProperty.call(self, key) ? O.some(self[key]) : O.none() @@ -112,10 +103,7 @@ export const get: { export const modifyOption: { (key: string, f: (a: A) => B): (self: ReadonlyRecord) => Option> (self: ReadonlyRecord, key: string, f: (a: A) => B): Option> -} = dual< - (key: string, f: (a: A) => B) => (self: ReadonlyRecord) => Option>, - (self: ReadonlyRecord, key: string, f: (a: A) => B) => Option> ->( +} = dual( 3, (self: ReadonlyRecord, key: string, f: (a: A) => B): Option> => { if (!Object.prototype.hasOwnProperty.call(self, key)) { @@ -149,10 +137,7 @@ export const modifyOption: { export const replaceOption: { (key: string, b: B): (self: ReadonlyRecord) => Option> (self: ReadonlyRecord, key: string, b: B): Option> -} = dual< - (key: string, b: B) => (self: ReadonlyRecord) => Option>, - (self: ReadonlyRecord, key: string, b: B) => Option> ->( +} = dual( 3, (self: ReadonlyRecord, key: string, b: B): Option> => modifyOption(self, key, () => b) @@ -177,10 +162,7 @@ export const replaceOption: { export const mapWithKey: { (f: (k: string, a: A) => B): (self: ReadonlyRecord) => Record (self: ReadonlyRecord, f: (k: string, a: A) => B): Record -} = dual< - (f: (k: string, a: A) => B) => (self: ReadonlyRecord) => Record, - (self: ReadonlyRecord, f: (k: string, a: A) => B) => Record ->( +} = dual( 2, (self: ReadonlyRecord, f: (k: string, a: A) => B): Record => { const out: Record = {} @@ -212,10 +194,7 @@ export const mapWithKey: { export const map: { (f: (a: A) => B): (self: ReadonlyRecord) => Record (self: ReadonlyRecord, f: (a: A) => B): Record -} = dual< - (f: (a: A) => B) => (self: ReadonlyRecord) => Record, - (self: ReadonlyRecord, f: (a: A) => B) => Record ->( +} = dual( 2, (self: ReadonlyRecord, f: (a: A) => B): Record => mapWithKey(self, (_, a) => f(a)) diff --git a/src/internal/Either.ts b/src/internal/Either.ts index 5e5b4e25d..94335436a 100644 --- a/src/internal/Either.ts +++ b/src/internal/Either.ts @@ -33,10 +33,7 @@ export const getRight = ( ): Option => (isLeft(self) ? option.none : option.some(self.right)) /** @internal */ -export const fromOption = dual< - (onNone: () => E) => (self: Option) => Either, - (self: Option, onNone: () => E) => Either ->( +export const fromOption = dual( 2, (self: Option, onNone: () => E): Either => option.isNone(self) ? left(onNone()) : right(self.value) diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 461224411..87bdeac6f 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -232,11 +232,7 @@ export const Product: product.Product = { export const lessThan = (O: Order): { (that: A): (self: A) => boolean (self: A, that: A): boolean -} => - dual< - (that: A) => (self: A) => boolean, - (self: A, that: A) => boolean - >(2, (self: A, that: A) => O.compare(self, that) === -1) +} => dual(2, (self: A, that: A) => O.compare(self, that) === -1) /** * Test whether one value is _strictly greater than_ another. @@ -246,11 +242,7 @@ export const lessThan = (O: Order): { export const greaterThan = (O: Order): { (that: A): (self: A) => boolean (self: A, that: A): boolean -} => - dual< - (that: A) => (self: A) => boolean, - (self: A, that: A) => boolean - >(2, (self: A, that: A) => O.compare(self, that) === 1) +} => dual(2, (self: A, that: A) => O.compare(self, that) === 1) /** * Test whether one value is _non-strictly less than_ another. @@ -260,11 +252,7 @@ export const greaterThan = (O: Order): { export const lessThanOrEqualTo = (O: Order): { (that: A): (self: A) => boolean (self: A, that: A): boolean -} => - dual< - (that: A) => (self: A) => boolean, - (self: A, that: A) => boolean - >(2, (self: A, that: A) => O.compare(self, that) !== 1) +} => dual(2, (self: A, that: A) => O.compare(self, that) !== 1) /** * Test whether one value is _non-strictly greater than_ another. @@ -274,11 +262,7 @@ export const lessThanOrEqualTo = (O: Order): { export const greaterThanOrEqualTo = (O: Order): { (that: A): (self: A) => boolean (self: A, that: A): boolean -} => - dual< - (that: A) => (self: A) => boolean, - (self: A, that: A) => boolean - >(2, (self: A, that: A) => O.compare(self, that) !== -1) +} => dual(2, (self: A, that: A) => O.compare(self, that) !== -1) /** * Take the minimum of two values. If they are considered equal, the first argument is chosen. @@ -288,11 +272,7 @@ export const greaterThanOrEqualTo = (O: Order): { export const min = (O: Order): { (that: A): (self: A) => A (self: A, that: A): A -} => - dual< - (that: A) => (self: A) => A, - (self: A, that: A) => A - >(2, (self: A, that: A) => self === that || O.compare(self, that) < 1 ? self : that) +} => dual(2, (self: A, that: A) => self === that || O.compare(self, that) < 1 ? self : that) /** * Take the maximum of two values. If they are considered equal, the first argument is chosen. @@ -302,11 +282,7 @@ export const min = (O: Order): { export const max = (O: Order): { (that: A): (self: A) => A (self: A, that: A): A -} => - dual< - (that: A) => (self: A) => A, - (self: A, that: A) => A - >(2, (self: A, that: A) => self === that || O.compare(self, that) > -1 ? self : that) +} => dual(2, (self: A, that: A) => self === that || O.compare(self, that) > -1 ? self : that) /** * Clamp a value between a minimum and a maximum. @@ -317,10 +293,7 @@ export const clamp = (O: Order): { (minimum: A, maximum: A): (a: A) => A (a: A, minimum: A, maximum: A): A } => - dual< - (minimum: A, maximum: A) => (a: A) => A, - (a: A, minimum: A, maximum: A) => A - >( + dual( 3, (a: A, minimum: A, maximum: A): A => min(O)(maximum, max(O)(minimum, a)) ) @@ -334,10 +307,7 @@ export const between = (O: Order): { (minimum: A, maximum: A): (a: A) => boolean (a: A, minimum: A, maximum: A): boolean } => - dual< - (minimum: A, maximum: A) => (a: A) => boolean, - (a: A, minimum: A, maximum: A) => boolean - >( + dual( 3, (a: A, minimum: A, maximum: A): boolean => !lessThan(O)(a, minimum) && !greaterThan(O)(a, maximum) diff --git a/src/typeclass/SemiApplicative.ts b/src/typeclass/SemiApplicative.ts index e55b7b5cf..1a9bfb969 100644 --- a/src/typeclass/SemiApplicative.ts +++ b/src/typeclass/SemiApplicative.ts @@ -48,17 +48,7 @@ export const zipWith = (F: SemiApplicative): { f: (a: A, b: B) => C ): Kind } => - dual< - ( - that: Kind, - f: (a: A, b: B) => C - ) => (self: Kind) => Kind, - ( - self: Kind, - that: Kind, - f: (a: A, b: B) => C - ) => Kind - >( + dual( 3, ( self: Kind, @@ -81,17 +71,7 @@ export const ap = (F: SemiApplicative): { that: Kind ): Kind } => - dual< - ( - that: Kind - ) => ( - self: Kind B> - ) => Kind, - ( - self: Kind B>, - that: Kind - ) => Kind - >(2, ( + dual(2, ( self: Kind B>, that: Kind ): Kind => zipWith(F)(self, that, (f, a) => f(a))) @@ -108,17 +88,7 @@ export const andThenDiscard = (F: SemiApplicative): { that: Kind ): Kind } => - dual< - ( - that: Kind - ) => ( - self: Kind - ) => Kind, - ( - self: Kind, - that: Kind - ) => Kind - >(2, ( + dual(2, ( self: Kind, that: Kind ): Kind => zipWith(F)(self, that, identity)) @@ -135,17 +105,7 @@ export const andThen = (F: SemiApplicative): { that: Kind ): Kind } => - dual< - ( - that: Kind - ) => ( - self: Kind - ) => Kind, - ( - self: Kind, - that: Kind - ) => Kind - >(2, ( + dual(2, ( self: Kind, that: Kind ): Kind => zipWith(F)(self, that, SK)) @@ -168,15 +128,7 @@ export const lift2 = (F: SemiApplicative) => that: Kind ): Kind } => - dual< - ( - that: Kind - ) => (self: Kind) => Kind, - ( - self: Kind, - that: Kind - ) => Kind - >(2, ( + dual(2, ( self: Kind, that: Kind ): Kind => zipWith(F)(self, that, f)) From 8aa26ceb4125e7cf970c4fd24944bba78737efb5 Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 3 Feb 2023 18:18:33 +0100 Subject: [PATCH 173/255] more duality --- docs/modules/Identity.ts.md | 16 ++++++ docs/modules/Ordering.ts.md | 9 ++- docs/modules/Predicate.ts.md | 59 ++++++++++---------- docs/modules/String.ts.md | 21 +++++-- docs/modules/Tuple.ts.md | 5 +- src/Identity.ts | 104 ++++++++++++++++++++--------------- src/Number.ts | 25 +++++---- src/Option.ts | 8 +-- src/Ordering.ts | 18 +++++- src/Predicate.ts | 77 +++++++++++++++----------- src/String.ts | 47 ++++++++++++---- src/Struct.ts | 17 ++++-- src/Tuple.ts | 15 +++-- 13 files changed, 267 insertions(+), 154 deletions(-) diff --git a/docs/modules/Identity.ts.md b/docs/modules/Identity.ts.md index 7b291c535..d2edfd2ac 100644 --- a/docs/modules/Identity.ts.md +++ b/docs/modules/Identity.ts.md @@ -14,6 +14,7 @@ Added in v1.0.0 - [do notation](#do-notation) - [Do](#do) + - [andThenBind](#andthenbind) - [bind](#bind) - [bindTo](#bindto) - [let](#let) @@ -53,6 +54,21 @@ export declare const Do: {} Added in v1.0.0 +## andThenBind + +A variant of `bind` that sequentially ignores the scope. + +**Signature** + +```ts +export declare const andThenBind: ( + name: Exclude, + that: B +) => (self: A) => { [K in N | keyof A]: K extends keyof A ? A[K] : B } +``` + +Added in v1.0.0 + ## bind **Signature** diff --git a/docs/modules/Ordering.ts.md b/docs/modules/Ordering.ts.md index 7bc126fdf..6690675d6 100644 --- a/docs/modules/Ordering.ts.md +++ b/docs/modules/Ordering.ts.md @@ -65,11 +65,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const match: ( - onLessThan: LazyArg, - onEqual: LazyArg, - onGreaterThan: LazyArg -) => (o: Ordering) => A | B | C +export declare const match: { + (onLessThan: LazyArg, onEqual: LazyArg, onGreaterThan: LazyArg): (o: Ordering) => A | B | C + (o: Ordering, onLessThan: LazyArg, onEqual: LazyArg, onGreaterThan: LazyArg): A | B | C +} ``` Added in v1.0.0 diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index 754e0c363..ea77a9011 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -17,6 +17,8 @@ Added in v1.0.0 - [constructors](#constructors) - [id](#id) - [do notation](#do-notation) + - [Do](#do) + - [andThenBind](#andthenbind) - [bindTo](#bindto) - [guards](#guards) - [isBigInt](#isbigint) @@ -39,11 +41,9 @@ Added in v1.0.0 - [type lambdas](#type-lambdas) - [PredicateTypeLambda (interface)](#predicatetypelambda-interface) - [utils](#utils) - - [Do](#do) - [Refinement (interface)](#refinement-interface) - [all](#all) - [and](#and) - - [andThenBind](#andthenbind) - [any](#any) - [appendElement](#appendelement) - [compose](#compose) @@ -86,6 +86,31 @@ Added in v1.0.0 # do notation +## Do + +**Signature** + +```ts +export declare const Do: Predicate<{}> +``` + +Added in v1.0.0 + +## andThenBind + +A variant of `bind` that sequentially ignores the scope. + +**Signature** + +```ts +export declare const andThenBind: ( + name: Exclude, + that: Predicate +) => (self: Predicate) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> +``` + +Added in v1.0.0 + ## bindTo **Signature** @@ -272,16 +297,6 @@ Added in v1.0.0 # utils -## Do - -**Signature** - -```ts -export declare const Do: Predicate<{}> -``` - -Added in v1.0.0 - ## Refinement (interface) **Signature** @@ -317,19 +332,6 @@ export declare const and: { Added in v1.0.0 -## andThenBind - -**Signature** - -```ts -export declare const andThenBind: ( - name: Exclude, - that: Predicate -) => (self: Predicate) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> -``` - -Added in v1.0.0 - ## any **Signature** @@ -360,9 +362,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const compose: ( - bc: Refinement -) => (ab: Refinement) => Refinement +export declare const compose: { + (bc: Refinement): (ab: Refinement) => Refinement + (ab: Refinement, bc: Refinement): Refinement +} ``` Added in v1.0.0 diff --git a/docs/modules/String.ts.md b/docs/modules/String.ts.md index 9d72ddbb4..0b5833dcb 100644 --- a/docs/modules/String.ts.md +++ b/docs/modules/String.ts.md @@ -112,7 +112,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const concat: (that: string) => (self: string) => string +export declare const concat: { (that: string): (self: string) => string; (self: string, that: string): string } ``` Added in v1.0.0 @@ -227,7 +227,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const replace: (searchValue: string | RegExp, replaceValue: string) => (s: string) => string +export declare const replace: { + (searchValue: string | RegExp, replaceValue: string): (s: string) => string + (s: string, searchValue: string | RegExp, replaceValue: string): string +} ``` **Example** @@ -246,7 +249,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const slice: (start: number, end: number) => (s: string) => string +export declare const slice: { + (start: number, end: number): (s: string) => string + (s: string, start: number, end: number): string +} ``` **Example** @@ -265,7 +271,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const split: (separator: string | RegExp) => (s: string) => readonly [string, ...string[]] +export declare const split: { + (separator: string | RegExp): (s: string) => readonly [string, ...string[]] + (s: string, separator: string | RegExp): readonly [string, ...string[]] +} ``` **Example** @@ -314,7 +323,7 @@ If `n` is a float, it will be rounded down to the nearest integer. **Signature** ```ts -export declare const takeLeft: (n: number) => (self: string) => string +export declare const takeLeft: { (n: number): (self: string) => string; (self: string, n: number): string } ``` Added in v1.0.0 @@ -333,7 +342,7 @@ If `n` is a float, it will be rounded down to the nearest integer. **Signature** ```ts -export declare const takeRight: (n: number) => (s: string) => string +export declare const takeRight: { (n: number): (s: string) => string; (s: string, n: number): string } ``` Added in v1.0.0 diff --git a/docs/modules/Tuple.ts.md b/docs/modules/Tuple.ts.md index a592b416a..7992f7396 100644 --- a/docs/modules/Tuple.ts.md +++ b/docs/modules/Tuple.ts.md @@ -117,7 +117,10 @@ Appends an element to the end of a tuple. **Signature** ```ts -export declare const appendElement: (that: B) => (self: A) => [...A, B] +export declare const appendElement: { + (that: B): (self: A) => [...A, B] + (self: A, that: B): [...A, B] +} ``` Added in v1.0.0 diff --git a/src/Identity.ts b/src/Identity.ts index 3573e1807..19bbfceb6 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -59,31 +59,6 @@ export const Invariant: invariant.Invariant = { imap: Covariant.imap } -/** - * @category do notation - * @since 1.0.0 - */ -export const bindTo: ( - name: N -) => (self: Identity) => Identity<{ [K in N]: A }> = invariant.bindTo(Invariant) - -const let_: ( - name: Exclude, - f: (a: A) => B -) => ( - self: Identity -) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant.let( - Covariant -) - -export { - /** - * @category do notation - * @since 1.0.0 - */ - let_ as let -} - /** * @category instances * @since 1.0.0 @@ -92,12 +67,6 @@ export const Of: of_.Of = { of: identity } -/** - * @category do notation - * @since 1.0.0 - */ -export const Do: Identity<{}> = of_.Do(Of) - /** * @category instances * @since 1.0.0 @@ -127,19 +96,6 @@ export const Chainable: chainable.Chainable = { flatMap: FlatMap.flatMap } -/** - * @category do notation - * @since 1.0.0 - */ -export const bind: ( - name: Exclude, - f: (a: A) => Identity -) => ( - self: Identity -) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable.bind( - Chainable -) - /** * @category instances * @since 1.0.0 @@ -239,3 +195,63 @@ export const Traversable: traversable.Traversable = traversa f: (a: A) => Kind ): Kind> => f(self) ) + +// ------------------------------------------------------------------------------------- +// do notation +// ------------------------------------------------------------------------------------- + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindTo: ( + name: N +) => (self: Identity) => Identity<{ [K in N]: A }> = invariant.bindTo(Invariant) + +const let_: ( + name: Exclude, + f: (a: A) => B +) => ( + self: Identity +) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant.let( + Covariant +) + +export { + /** + * @category do notation + * @since 1.0.0 + */ + let_ as let +} + +/** + * @category do notation + * @since 1.0.0 + */ +export const Do: Identity<{}> = of_.Do(Of) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bind: ( + name: Exclude, + f: (a: A) => Identity +) => ( + self: Identity +) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable.bind( + Chainable +) + +/** + * A variant of `bind` that sequentially ignores the scope. + * + * @category do notation + * @since 1.0.0 + */ +export const andThenBind: ( + name: Exclude, + that: Identity +) => (self: Identity) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = + semiProduct.andThenBind(SemiProduct) diff --git a/src/Number.ts b/src/Number.ts index 2ff7d5b35..89b081e1a 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -8,6 +8,7 @@ import { dual } from "@fp-ts/core/Function" import type { Ordering } from "@fp-ts/core/Ordering" import * as predicate from "@fp-ts/core/Predicate" +import type { Refinement } from "@fp-ts/core/Predicate" import * as bounded from "@fp-ts/core/typeclass/Bounded" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" @@ -18,7 +19,7 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" * @category guards * @since 1.0.0 */ -export const isNumber = predicate.isNumber +export const isNumber: Refinement = predicate.isNumber /** * @example @@ -106,19 +107,19 @@ export const decrement = (n: number): number => n - 1 * @category instances * @since 1.0.0 */ -export const Equivalence = equivalence.number +export const Equivalence: equivalence.Equivalence = equivalence.number /** * @category instances * @since 1.0.0 */ -export const Order = order.number +export const Order: order.Order = order.number /** * @category instances * @since 1.0.0 */ -export const Bounded = bounded.number +export const Bounded: bounded.Bounded = bounded.number /** * `number` semigroup under addition. @@ -132,19 +133,19 @@ export const Bounded = bounded.number * @category instances * @since 1.0.0 */ -export const SemigroupSum = semigroup.numberSum +export const SemigroupSum: semigroup.Semigroup = semigroup.numberSum /** * @category instances * @since 1.0.0 */ -export const SemigroupMax = semigroup.max(Order) +export const SemigroupMax: semigroup.Semigroup = semigroup.max(Order) /** * @category instances * @since 1.0.0 */ -export const SemigroupMin = semigroup.min(Order) +export const SemigroupMin: semigroup.Semigroup = semigroup.min(Order) /** * `number` semigroup under multiplication. @@ -158,7 +159,7 @@ export const SemigroupMin = semigroup.min(Order) * @category instances * @since 1.0.0 */ -export const SemigroupMultiply = semigroup.numberMultiply +export const SemigroupMultiply: semigroup.Semigroup = semigroup.numberMultiply /** * `number` monoid under addition. @@ -168,7 +169,7 @@ export const SemigroupMultiply = semigroup.numberMultiply * @category instances * @since 1.0.0 */ -export const MonoidSum = monoid.numberSum +export const MonoidSum: monoid.Monoid = monoid.numberSum /** * `number` monoid under multiplication. @@ -178,19 +179,19 @@ export const MonoidSum = monoid.numberSum * @category instances * @since 1.0.0 */ -export const MonoidMultiply = monoid.numberMultiply +export const MonoidMultiply: monoid.Monoid = monoid.numberMultiply /** * @category instances * @since 1.0.0 */ -export const MonoidMax = bounded.max(Bounded) +export const MonoidMax: monoid.Monoid = bounded.max(Bounded) /** * @category instances * @since 1.0.0 */ -export const MonoidMin = bounded.min(Bounded) +export const MonoidMin: monoid.Monoid = bounded.min(Bounded) /** * @since 1.0.0 diff --git a/src/Option.ts b/src/Option.ts index d48cfe561..c03ca486a 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -770,8 +770,7 @@ export const FlatMap: flatMap_.FlatMap = { * @category sequencing * @since 1.0.0 */ -export const flatten: (self: Option>) => Option = flatMap_ - .flatten(FlatMap) +export const flatten: (self: Option>) => Option = flatMap_.flatten(FlatMap) /** * @category sequencing @@ -959,8 +958,9 @@ export const tuple: >>( */ export const struct: >>( r: R -) => Option<{ [K in keyof R]: [R[K]] extends [Option] ? A : never }> = product_ - .struct(Product) +) => Option<{ [K in keyof R]: [R[K]] extends [Option] ? A : never }> = product_.struct( + Product +) /** * @category instances diff --git a/src/Ordering.ts b/src/Ordering.ts index 2e95676ea..60164d78e 100644 --- a/src/Ordering.ts +++ b/src/Ordering.ts @@ -2,6 +2,7 @@ * @since 1.0.0 */ import type { LazyArg } from "@fp-ts/core/Function" +import { dual } from "@fp-ts/core/Function" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" @@ -20,11 +21,24 @@ export const reverse = (o: Ordering): Ordering => (o === -1 ? 1 : o === 1 ? -1 : * @category pattern matching * @since 1.0.0 */ -export const match = ( +export const match: { + ( + onLessThan: LazyArg, + onEqual: LazyArg, + onGreaterThan: LazyArg + ): (o: Ordering) => A | B | C + ( + o: Ordering, + onLessThan: LazyArg, + onEqual: LazyArg, + onGreaterThan: LazyArg + ): A | B | C +} = dual(4, ( + o: Ordering, onLessThan: LazyArg, onEqual: LazyArg, onGreaterThan: LazyArg -) => (o: Ordering): A | B | C => o === -1 ? onLessThan() : o === 0 ? onEqual() : onGreaterThan() +): A | B | C => o === -1 ? onLessThan() : o === 0 ? onEqual() : onGreaterThan()) /** * @category instances diff --git a/src/Predicate.ts b/src/Predicate.ts index 8eba74050..ba949d694 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -78,8 +78,14 @@ export const id = (): Refinement => (_): _ is A => true /** * @since 1.0.0 */ -export const compose = (bc: Refinement) => - (ab: Refinement): Refinement => (i): i is C => ab(i) && bc(i) +export const compose: { + (bc: Refinement): (ab: Refinement) => Refinement + (ab: Refinement, bc: Refinement): Refinement +} = dual( + 2, + (ab: Refinement, bc: Refinement): Refinement => + (a): a is C => ab(a) && bc(a) +) /** * @category instances @@ -115,20 +121,9 @@ export const Invariant: invariant.Invariant = { /** * @since 1.0.0 */ -// @ts-expect-error export const tupled: (self: Predicate) => Predicate = invariant.tupled( Invariant -) - -/** - * @category do notation - * @since 1.0.0 - */ -export const bindTo: ( - name: N -) => (self: Predicate) => Predicate<{ readonly [K in N]: A }> = invariant.bindTo( - Invariant -) +) as any /** * @since 1.0.0 @@ -143,11 +138,6 @@ export const Of: of_.Of = { of } -/** - * @since 1.0.0 - */ -export const Do: Predicate<{}> = of_.Do(Of) - /** * @since 1.0.0 */ @@ -206,19 +196,6 @@ export const Product: product_.Product = { productAll } -/** - * @since 1.0.0 - */ -export const andThenBind: ( - name: Exclude, - that: Predicate -) => ( - self: Predicate -) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct - .andThenBind( - SemiProduct - ) - /** * Appends an element to the end of a tuple. * @@ -338,3 +315,39 @@ export const all = (collection: Iterable>): Predicate => */ export const any = (collection: Iterable>): Predicate => getMonoidAny().combineAll(collection) + +// ------------------------------------------------------------------------------------- +// do notation +// ------------------------------------------------------------------------------------- + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindTo: ( + name: N +) => (self: Predicate) => Predicate<{ readonly [K in N]: A }> = invariant.bindTo( + Invariant +) + +/** + * @category do notation + * @since 1.0.0 + */ +export const Do: Predicate<{}> = of_.Do(Of) + +/** + * A variant of `bind` that sequentially ignores the scope. + * + * @category do notation + * @since 1.0.0 + */ +export const andThenBind: ( + name: Exclude, + that: Predicate +) => ( + self: Predicate +) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct + .andThenBind( + SemiProduct + ) diff --git a/src/String.ts b/src/String.ts index ce49115e1..26380da36 100644 --- a/src/String.ts +++ b/src/String.ts @@ -6,6 +6,7 @@ * @since 1.0.0 */ +import { dual } from "@fp-ts/core/Function" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type { Refinement } from "@fp-ts/core/Predicate" import * as predicate from "@fp-ts/core/Predicate" @@ -59,7 +60,10 @@ export const empty: "" = "" as const /** * @since 1.0.0 */ -export const concat = (that: string) => (self: string): string => Semigroup.combine(self, that) +export const concat: { + (that: string): (self: string) => string + (self: string, that: string): string +} = Semigroup.combine /** * @example @@ -92,8 +96,14 @@ export const toLowerCase = (s: string): string => s.toLowerCase() * * @since 1.0.0 */ -export const replace = (searchValue: string | RegExp, replaceValue: string) => - (s: string): string => s.replace(searchValue, replaceValue) +export const replace: { + (searchValue: string | RegExp, replaceValue: string): (s: string) => string + (s: string, searchValue: string | RegExp, replaceValue: string): string +} = dual( + 3, + (s: string, searchValue: string | RegExp, replaceValue: string): string => + s.replace(searchValue, replaceValue) +) /** * @example @@ -137,7 +147,10 @@ export const trimEnd = (s: string): string => s.trimEnd() * * @since 1.0.0 */ -export const slice = (start: number, end: number) => (s: string): string => s.slice(start, end) +export const slice: { + (start: number, end: number): (s: string) => string + (s: string, start: number, end: number): string +} = dual(3, (s: string, start: number, end: number): string => s.slice(start, end)) /** * Test whether a `string` is empty. @@ -183,11 +196,13 @@ export const length = (s: string): number => s.length * * @since 1.0.0 */ -export const split = (separator: string | RegExp) => - (s: string): NonEmptyReadonlyArray => { - const out = s.split(separator) - return readonlyArray.isNonEmpty(out) ? out : [s] - } +export const split: { + (separator: string | RegExp): (s: string) => NonEmptyReadonlyArray + (s: string, separator: string | RegExp): NonEmptyReadonlyArray +} = dual(2, (s: string, separator: string | RegExp): NonEmptyReadonlyArray => { + const out = s.split(separator) + return readonlyArray.isNonEmpty(out) ? out : [s] +}) /** * @example @@ -240,7 +255,10 @@ export const endsWith = (searchString: string, position?: number) => * * @since 1.0.0 */ -export const takeLeft = (n: number) => (self: string): string => self.slice(0, Math.max(n, 0)) +export const takeLeft: { + (n: number): (self: string) => string + (self: string, n: number): string +} = dual(2, (self: string, n: number): string => self.slice(0, Math.max(n, 0))) /** * Keep the specified number of characters from the end of a string. @@ -254,8 +272,13 @@ export const takeLeft = (n: number) => (self: string): string => self.slice(0, M * * @since 1.0.0 */ -export const takeRight = (n: number) => - (s: string): string => s.slice(Math.max(0, s.length - Math.floor(n)), Infinity) +export const takeRight: { + (n: number): (s: string) => string + (s: string, n: number): string +} = dual( + 2, + (s: string, n: number): string => s.slice(Math.max(0, s.length - Math.floor(n)), Infinity) +) /* diff --git a/src/Struct.ts b/src/Struct.ts index bc320799a..289b13328 100644 --- a/src/Struct.ts +++ b/src/Struct.ts @@ -3,6 +3,7 @@ * * @since 1.0.0 */ + import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as order from "@fp-ts/core/typeclass/Order" @@ -47,7 +48,9 @@ export const omit = ]>( * @category combinators * @since 1.0.0 */ -export const getEquivalence = equivalence.struct +export const getEquivalence: ( + equivalences: { [K in keyof A]: equivalence.Equivalence } +) => equivalence.Equivalence<{ readonly [K in keyof A]: A[K] }> = equivalence.struct /** * This function creates and returns a new `Order` for a struct of values based on the given `Order`s @@ -56,7 +59,9 @@ export const getEquivalence = equivalence.struct * @category combinators * @since 1.0.0 */ -export const getOrder = order.struct +export const getOrder: ( + orders: { readonly [K in keyof A]: order.Order } +) => order.Order<{ readonly [K in keyof A]: A[K] }> = order.struct /** * This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. @@ -67,7 +72,9 @@ export const getOrder = order.struct * @category combinators * @since 1.0.0 */ -export const getSemigroup = semigroup.struct +export const getSemigroup: ( + semigroups: { readonly [K in keyof A]: semigroup.Semigroup } +) => semigroup.Semigroup<{ readonly [K in keyof A]: A[K] }> = semigroup.struct /** * This function creates and returns a new `Monoid` for a struct of values based on the given `Monoid`s for each property in the struct. @@ -80,7 +87,9 @@ export const getSemigroup = semigroup.struct * @category combinators * @since 1.0.0 */ -export const getMonoid = monoid.struct +export const getMonoid: ( + monoids: { readonly [K in keyof A]: monoid.Monoid } +) => monoid.Monoid<{ readonly [K in keyof A]: A[K] }> = monoid.struct /* diff --git a/src/Tuple.ts b/src/Tuple.ts index 017fc108a..0725bcf65 100644 --- a/src/Tuple.ts +++ b/src/Tuple.ts @@ -3,6 +3,7 @@ * * @since 1.0.0 */ +import { dual } from "@fp-ts/core/Function" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as order from "@fp-ts/core/typeclass/Order" @@ -21,7 +22,9 @@ export const tuple = >(...elements: A): A => elemen * @category combinators * @since 1.0.0 */ -export const getEquivalence = equivalence.tuple +export const getEquivalence: >( + ...equivalences: { readonly [K in keyof A]: equivalence.Equivalence } +) => equivalence.Equivalence> = equivalence.tuple /** * This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. @@ -32,7 +35,9 @@ export const getEquivalence = equivalence.tuple * @category combinators * @since 1.0.0 */ -export const getOrder = order.tuple +export const getOrder: >( + ...orders: { readonly [K in keyof A]: order.Order } +) => order.Order> = order.tuple /** * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. @@ -63,8 +68,10 @@ export const getMonoid = monoid.tuple * * @since 1.0.0 */ -export const appendElement = (that: B) => - >(self: A): [...A, B] => [...self, that] +export const appendElement: { + (that: B): >(self: A) => [...A, B] + , B>(self: A, that: B): [...A, B] +} = dual(2, , B>(self: A, that: B): [...A, B] => [...self, that]) /* From b96fd8fb3bae7802f6d2a25f7fd3d873314fb21d Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 3 Feb 2023 19:05:44 +0100 Subject: [PATCH 174/255] These: apply dual --- docs/modules/These.ts.md | 173 +++++++++++---- src/These.ts | 463 +++++++++++++++++++++++++-------------- 2 files changed, 421 insertions(+), 215 deletions(-) diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 29fe790d0..d9f0fa2a7 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -340,7 +340,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const leftOrBoth: (onSome: LazyArg) => (self: O.Option) => These +export declare const leftOrBoth: { + (onSome: LazyArg): (self: O.Option) => These + (self: O.Option, onSome: LazyArg): These +} ``` Added in v1.0.0 @@ -372,7 +375,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const rightOrBoth: (onNone: LazyArg) => (self: O.Option) => These +export declare const rightOrBoth: { + (onNone: LazyArg): (self: O.Option) => These + (self: O.Option, onNone: LazyArg): These +} ``` Added in v1.0.0 @@ -424,7 +430,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromIterable: (onEmpty: LazyArg) => (collection: Iterable) => These +export declare const fromIterable: { + (onEmpty: LazyArg): (collection: Iterable) => These + (collection: Iterable, onEmpty: LazyArg): These +} ``` Added in v1.0.0 @@ -434,7 +443,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromNullable: (onNullable: LazyArg) => (a: A) => These> +export declare const fromNullable: { + (onNullable: LazyArg): (a: A) => These> + (a: A, onNullable: LazyArg): These> +} ``` Added in v1.0.0 @@ -444,7 +456,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const fromOption: (onNone: LazyArg) => (self: O.Option) => These +export declare const fromOption: { + (onNone: LazyArg): (self: O.Option) => These + (self: O.Option, onNone: LazyArg): These +} ``` Added in v1.0.0 @@ -464,7 +479,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const toEither: (onBoth: (e: E, a: A) => Either) => (self: These) => Either +export declare const toEither: { + (onBoth: (e: E, a: A) => Either): (self: These) => Either + (self: These, onBoth: (e: E, a: A) => Either): Either +} ``` Added in v1.0.0 @@ -486,7 +504,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const inspectBoth: (onBoth: (e: E, a: A) => void) => (self: These) => These +export declare const inspectBoth: { + (onBoth: (e: E, a: A) => void): (self: These) => These + (self: These, onBoth: (e: E, a: A) => void): These +} ``` Added in v1.0.0 @@ -496,7 +517,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const inspectLeft: (onLeft: (e: E) => void) => (self: These) => These +export declare const inspectLeft: { + (onLeft: (e: E) => void): (self: These) => These + (self: These, onLeft: (e: E) => void): These +} ``` Added in v1.0.0 @@ -506,7 +530,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const inspectRight: (onRight: (a: A) => void) => (self: These) => These +export declare const inspectRight: { + (onRight: (a: A) => void): (self: These) => These + (self: These, onRight: (a: A) => void): These +} ``` Added in v1.0.0 @@ -516,7 +543,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const inspectRightOrBoth: (onRightOrBoth: (a: A) => void) => (self: These) => These +export declare const inspectRightOrBoth: { + (onRightOrBoth: (a: A) => void): (self: These) => These + (self: These, onRightOrBoth: (a: A) => void): These +} ``` Added in v1.0.0 @@ -666,9 +696,10 @@ executes the specified effect. **Signature** ```ts -export declare const orElse: ( - that: (e1: E1) => These -) => (self: These) => These +export declare const orElse: { + (that: (e1: E1) => These): (self: These) => These + (self: These, that: (e1: E1) => These): These +} ``` Added in v1.0.0 @@ -681,9 +712,10 @@ fails, in which case, it will produce the value of the specified effect. **Signature** ```ts -export declare const orElseEither: ( - that: (e1: E1) => These -) => (self: These) => These> +export declare const orElseEither: { + (that: (e1: E1) => These): (self: These) => These> + (self: These, that: (e1: E1) => These): These> +} ``` Added in v1.0.0 @@ -696,7 +728,10 @@ fails with the specified error. **Signature** ```ts -export declare const orElseFail: (onLeft: LazyArg) => (self: These) => These +export declare const orElseFail: { + (onLeft: LazyArg): (self: These) => These + (self: These, onLeft: LazyArg): These +} ``` Added in v1.0.0 @@ -708,7 +743,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const compact: (onNone: LazyArg) => (self: These>) => These +export declare const compact: { + (onNone: LazyArg): (self: These>) => These + (self: These>, onNone: LazyArg): These +} ``` Added in v1.0.0 @@ -723,6 +761,12 @@ export declare const filter: { self: These ) => These (predicate: Predicate, onFalse: LazyArg): (self: These) => These + ( + self: These, + refinement: Refinement, + onFalse: LazyArg + ): These + (self: These, predicate: Predicate, onFalse: LazyArg): These } ``` @@ -733,10 +777,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const filterMap: ( - f: (a: A) => O.Option, - onNone: LazyArg -) => (self: These) => These +export declare const filterMap: { + (f: (a: A) => O.Option, onNone: LazyArg): (self: These) => These + (self: These, f: (a: A) => O.Option, onNone: LazyArg): These +} ``` Added in v1.0.0 @@ -758,7 +802,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const getBothOrElse: (e: LazyArg, a: LazyArg) => (self: These) => readonly [E, A] +export declare const getBothOrElse: { + (e: LazyArg, a: LazyArg): (self: These) => [E, A] + (self: These, e: LazyArg, a: LazyArg): [E, A] +} ``` Added in v1.0.0 @@ -792,7 +839,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const getOrElse: (onLeft: LazyArg) => (self: These) => B | A +export declare const getOrElse: { + (onLeft: LazyArg): (self: These) => B | A + (self: These, onLeft: LazyArg): A | B +} ``` Added in v1.0.0 @@ -1321,11 +1371,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const match: ( - onLeft: (e: E) => B, - onRight: (a: A) => C, - onBoth: (e: E, a: A) => D -) => (self: These) => B | C | D +export declare const match: { + (onLeft: (e: E) => B, onRight: (a: A) => C, onBoth: (e: E, a: A) => D): ( + self: These + ) => B | C | D + (self: These, onLeft: (e: E) => B, onRight: (a: A) => C, onBoth: (e: E, a: A) => D): + | B + | C + | D +} ``` Added in v1.0.0 @@ -1337,7 +1391,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const exists: (predicate: Predicate) => (self: These) => boolean +export declare const exists: { + (predicate: Predicate): (self: These) => boolean + (self: These, predicate: Predicate): boolean +} ``` Added in v1.0.0 @@ -1388,9 +1445,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapEither: ( - f: (a: A) => Either -) => (self: These) => These +export declare const flatMapEither: { + (f: (a: A) => Either): ( + self: These + ) => These + (self: These, f: (a: A) => Either): These< + readonly [E1 | E2, ...(E1 | E2)[]], + B + > +} ``` Added in v1.0.0 @@ -1400,10 +1463,16 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapNullable: ( - f: (a: A) => B | null | undefined, - onNullable: (a: A) => E2 -) => (self: These) => These> +export declare const flatMapNullable: { + (f: (a: A) => B | null | undefined, onNullable: (a: A) => E2): ( + self: These + ) => These> + ( + self: These, + f: (a: A) => B | null | undefined, + onNullable: (a: A) => E2 + ): These> +} ``` Added in v1.0.0 @@ -1413,10 +1482,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapOption: ( - f: (a: A) => O.Option, - onNone: (a: A) => E2 -) => (self: These) => These +export declare const flatMapOption: { + (f: (a: A) => O.Option, onNone: (a: A) => E2): ( + self: These + ) => These + (self: These, f: (a: A) => O.Option, onNone: (a: A) => E2): These< + readonly [E1 | E2, ...(E1 | E2)[]], + B + > +} ``` Added in v1.0.0 @@ -1426,9 +1500,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapThese: ( - f: (a: A) => These -) => (self: These) => These +export declare const flatMapThese: { + (f: (a: A) => These): ( + self: These + ) => These + (self: These, f: (a: A) => These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + B + > +} ``` Added in v1.0.0 @@ -1585,7 +1665,10 @@ Returns a function that checks if a `These` contains a given value using a provi **Signature** ```ts -export declare const contains: (equivalence: Equivalence) => (a: A) => (self: These) => boolean +export declare const contains: (equivalence: Equivalence) => { + (a: A): (self: These) => boolean + (self: These, a: A): boolean +} ``` Added in v1.0.0 diff --git a/src/These.ts b/src/These.ts index 85d9be685..014507f9a 100644 --- a/src/These.ts +++ b/src/These.ts @@ -104,15 +104,27 @@ export const both = (left: E, right: A): These => * @category constructors * @since 1.0.0 */ -export const leftOrBoth = (onSome: LazyArg) => - (self: Option): These => O.isNone(self) ? left(onSome()) : both(onSome(), self.value) +export const leftOrBoth: { + (onSome: LazyArg): (self: Option) => These + (self: Option, onSome: LazyArg): These +} = dual( + 2, + (self: Option, onSome: LazyArg): These => + O.isNone(self) ? left(onSome()) : both(onSome(), self.value) +) /** * @category constructors * @since 1.0.0 */ -export const rightOrBoth = (onNone: LazyArg) => - (self: Option): These => O.isNone(self) ? right(onNone()) : both(self.value, onNone()) +export const rightOrBoth: { + (onNone: LazyArg): (self: Option) => These + (self: Option, onNone: LazyArg): These +} = dual( + 2, + (self: Option, onNone: LazyArg): These => + O.isNone(self) ? right(onNone()) : both(self.value, onNone()) +) /** * @category constructors @@ -150,21 +162,33 @@ export const getEquivalence = ( * @category pattern matching * @since 1.0.0 */ -export const match = ( +export const match: { + ( + onLeft: (e: E) => B, + onRight: (a: A) => C, + onBoth: (e: E, a: A) => D + ): (self: These) => B | C | D + ( + self: These, + onLeft: (e: E) => B, + onRight: (a: A) => C, + onBoth: (e: E, a: A) => D + ): B | C | D +} = dual(4, ( + self: These, onLeft: (e: E) => B, onRight: (a: A) => C, onBoth: (e: E, a: A) => D -) => - (self: These): B | C | D => { - switch (self._tag) { - case "Left": - return onLeft(self.left) - case "Right": - return onRight(self.right) - case "Both": - return onBoth(self.left, self.right) - } +): B | C | D => { + switch (self._tag) { + case "Left": + return onLeft(self.left) + case "Right": + return onRight(self.right) + case "Both": + return onBoth(self.left, self.right) } +}) /** * @since 1.0.0 @@ -268,8 +292,14 @@ export const getRightOnlyOrThrow = (self: These): A => { * @category conversions * @since 1.0.0 */ -export const fromNullable = (onNullable: LazyArg) => - (a: A): These> => a == null ? left(onNullable()) : right(a as NonNullable) +export const fromNullable: { + (onNullable: LazyArg): (a: A) => These> + (a: A, onNullable: LazyArg): These> +} = dual( + 2, + (a: A, onNullable: LazyArg): These> => + a == null ? left(onNullable()) : right(a as NonNullable) +) /** * @category conversions @@ -282,9 +312,14 @@ export const fromEither = (self: Either): Validated => * @category conversions * @since 1.0.0 */ -export const toEither = ( - onBoth: (e: E, a: A) => Either -) => (self: These): Either => isBoth(self) ? onBoth(self.left, self.right) : self +export const toEither: { + (onBoth: (e: E, a: A) => Either): (self: These) => Either + (self: These, onBoth: (e: E, a: A) => Either): Either +} = dual( + 2, + (self: These, onBoth: (e: E, a: A) => Either): Either => + isBoth(self) ? onBoth(self.left, self.right) : self +) /** * @category conversions @@ -317,11 +352,21 @@ export const liftNullable = , B, E>( * @category sequencing * @since 1.0.0 */ -export const flatMapNullable = ( +export const flatMapNullable: { + ( + f: (a: A) => B | null | undefined, + onNullable: (a: A) => E2 + ): (self: Validated) => Validated> + ( + self: Validated, + f: (a: A) => B | null | undefined, + onNullable: (a: A) => E2 + ): Validated> +} = dual(3, ( + self: Validated, f: (a: A) => B | null | undefined, onNullable: (a: A) => E2 -): ((self: Validated) => Validated>) => - flatMap(liftNullable(f, (a) => [onNullable(a)])) +): Validated> => flatMap(self, liftNullable(f, (a) => [onNullable(a)]))) /** * @category lifting @@ -340,20 +385,28 @@ export const liftPredicate: { * @category conversions * @since 1.0.0 */ -export const fromIterable = (onEmpty: LazyArg) => - (collection: Iterable): These => { - for (const a of collection) { - return right(a) - } - return left(onEmpty()) +export const fromIterable: { + (onEmpty: LazyArg): (collection: Iterable) => These + (collection: Iterable, onEmpty: LazyArg): These +} = dual(2, (collection: Iterable, onEmpty: LazyArg): These => { + for (const a of collection) { + return right(a) } + return left(onEmpty()) +}) /** * @category conversions * @since 1.0.0 */ -export const fromOption = (onNone: LazyArg) => - (self: Option): These => O.isNone(self) ? left(onNone()) : right(self.value) +export const fromOption: { + (onNone: LazyArg): (self: Option) => These + (self: Option, onNone: LazyArg): These +} = dual( + 2, + (self: Option, onNone: LazyArg): These => + O.isNone(self) ? left(onNone()) : right(self.value) +) /** * @category conversions @@ -390,28 +443,47 @@ export const liftThese = , E, B>( * @category sequencing * @since 1.0.0 */ -export const flatMapOption = ( +export const flatMapOption: { + ( + f: (a: A) => Option, + onNone: (a: A) => E2 + ): (self: Validated) => Validated + ( + self: Validated, + f: (a: A) => Option, + onNone: (a: A) => E2 + ): Validated +} = dual(3, ( + self: Validated, f: (a: A) => Option, onNone: (a: A) => E2 -) => - (self: Validated): Validated => - flatMap(self, liftOption(f, (a) => [onNone(a)])) +): Validated => flatMap(self, liftOption(f, (a) => [onNone(a)]))) /** * @category sequencing * @since 1.0.0 */ -export const flatMapEither = ( - f: (a: A) => Either -) => (self: Validated): Validated => flatMap(self, liftEither(f)) +export const flatMapEither: { + (f: (a: A) => Either): (self: Validated) => Validated + (self: Validated, f: (a: A) => Either): Validated +} = dual( + 2, + (self: Validated, f: (a: A) => Either): Validated => + flatMap(self, liftEither(f)) +) /** * @category sequencing * @since 1.0.0 */ -export const flatMapThese = ( - f: (a: A) => These -) => (self: Validated): Validated => flatMap(self, liftThese(f)) +export const flatMapThese: { + (f: (a: A) => These): (self: Validated) => Validated + (self: Validated, f: (a: A) => These): Validated +} = dual( + 2, + (self: Validated, f: (a: A) => These): Validated => + flatMap(self, liftThese(f)) +) /** * Converts a `These` to an `Option` discarding the error (`Both` included). @@ -465,22 +537,27 @@ export const getBoth = ( * @category getters * @since 1.0.0 */ -export const getBothOrElse = (e: LazyArg, a: LazyArg) => - ( - self: These - ): readonly [E, A] => - isLeft(self) ? - [self.left, a()] : - isRight(self) ? - [e(), self.right] : - [self.left, self.right] +export const getBothOrElse: { + (e: LazyArg, a: LazyArg): (self: These) => [E, A] + (self: These, e: LazyArg, a: LazyArg): [E, A] +} = dual(3, (self: These, e: LazyArg, a: LazyArg): [E, A] => + isLeft(self) ? + [self.left, a()] : + isRight(self) ? + [e(), self.right] : + [self.left, self.right]) /** * @category getters * @since 1.0.0 */ -export const getOrElse = (onLeft: LazyArg) => - (self: These): A | B => isLeft(self) ? onLeft() : self.right +export const getOrElse: { + (onLeft: LazyArg): (self: These) => A | B + (self: These, onLeft: LazyArg): A | B +} = dual( + 2, + (self: These, onLeft: LazyArg): A | B => isLeft(self) ? onLeft() : self.right +) /** * @category getters @@ -498,57 +575,57 @@ export const getOrUndefined: (self: These) => A | undefined = getOrE * @category debugging * @since 1.0.0 */ -export const inspectRight = ( - onRight: (a: A) => void -) => - (self: These): These => { - if (isRight(self)) { - onRight(self.right) - } - return self +export const inspectRight: { + (onRight: (a: A) => void): (self: These) => These + (self: These, onRight: (a: A) => void): These +} = dual(2, (self: These, onRight: (a: A) => void): These => { + if (isRight(self)) { + onRight(self.right) } + return self +}) /** * @category debugging * @since 1.0.0 */ -export const inspectRightOrBoth = ( - onRightOrBoth: (a: A) => void -) => - (self: These): These => { - if (isRightOrBoth(self)) { - onRightOrBoth(self.right) - } - return self +export const inspectRightOrBoth: { + (onRightOrBoth: (a: A) => void): (self: These) => These + (self: These, onRightOrBoth: (a: A) => void): These +} = dual(2, (self: These, onRightOrBoth: (a: A) => void): These => { + if (isRightOrBoth(self)) { + onRightOrBoth(self.right) } + return self +}) /** * @category debugging * @since 1.0.0 */ -export const inspectLeft = ( - onLeft: (e: E) => void -) => - (self: These): These => { - if (isLeft(self)) { - onLeft(self.left) - } - return self +export const inspectLeft: { + (onLeft: (e: E) => void): (self: These) => These + (self: These, onLeft: (e: E) => void): These +} = dual(2, (self: These, onLeft: (e: E) => void): These => { + if (isLeft(self)) { + onLeft(self.left) } + return self +}) /** * @category debugging * @since 1.0.0 */ -export const inspectBoth = ( - onBoth: (e: E, a: A) => void -) => - (self: These): These => { - if (isBoth(self)) { - onBoth(self.left, self.right) - } - return self +export const inspectBoth: { + (onBoth: (e: E, a: A) => void): (self: These) => These + (self: These, onBoth: (e: E, a: A) => void): These +} = dual(2, (self: These, onBoth: (e: E, a: A) => void): These => { + if (isBoth(self)) { + onBoth(self.left, self.right) } + return self +}) /** * @category instances @@ -752,15 +829,27 @@ export const traverseTap: ( * * @since 1.0.0 */ -export const contains = (equivalence: Equivalence) => - (a: A) => (self: These): boolean => isLeft(self) ? false : equivalence(self.right, a) +export const contains = (equivalence: Equivalence): { + (a: A): (self: These) => boolean + (self: These, a: A): boolean +} => + dual( + 2, + (self: These, a: A): boolean => isLeft(self) ? false : equivalence(self.right, a) + ) /** * @category predicates * @since 1.0.0 */ -export const exists = (predicate: Predicate) => - (self: These): boolean => isLeft(self) ? false : predicate(self.right) +export const exists: { + (predicate: Predicate): (self: These) => boolean + (self: These, predicate: Predicate): boolean +} = dual( + 2, + (self: These, predicate: Predicate): boolean => + isLeft(self) ? false : predicate(self.right) +) /** * @category instances @@ -777,9 +866,14 @@ export const Foldable: foldable.Foldable = foldable.make((self, * @category error handling * @since 1.0.0 */ -export const orElse = ( - that: (e1: E1) => These -) => (self: These): These => isLeft(self) ? that(self.left) : self +export const orElse: { + (that: (e1: E1) => These): (self: These) => These + (self: These, that: (e1: E1) => These): These +} = dual( + 2, + (self: These, that: (e1: E1) => These): These => + isLeft(self) ? that(self.left) : self +) /** * Returns an effect that will produce the value of this effect, unless it @@ -788,13 +882,21 @@ export const orElse = ( * @category error handling * @since 1.0.0 */ -export const orElseEither = ( +export const orElseEither: { + ( + that: (e1: E1) => These + ): (self: These) => These> + ( + self: These, + that: (e1: E1) => These + ): These> +} = dual(2, ( + self: These, that: (e1: E1) => These -) => - (self: These): These> => - isLeft(self) ? - map(that(self.left), E.right) : - map(self, E.left) +): These> => + isLeft(self) ? + map(that(self.left), E.right) : + map(self, E.left)) /** * Executes this effect and returns its value, if it succeeds, but otherwise @@ -803,9 +905,14 @@ export const orElseEither = ( * @category error handling * @since 1.0.0 */ -export const orElseFail = ( - onLeft: LazyArg -): (self: These) => These => orElse(() => left(onLeft())) +export const orElseFail: { + (onLeft: LazyArg): (self: These) => These + (self: These, onLeft: LazyArg): These +} = dual( + 2, + (self: These, onLeft: LazyArg): These => + orElse(self, () => left(onLeft())) +) /** * @category error handling @@ -859,15 +966,17 @@ export const SemiAlternative: semiAlternative.SemiAlternative = * @category filtering * @since 1.0.0 */ -export const compact = (onNone: LazyArg) => - (self: These>): These => - isLeft(self) ? - self : - O.isNone(self.right) ? - left(onNone()) : - isBoth(self) ? - both(self.left, self.right.value) : - right(self.right.value) +export const compact: { + (onNone: LazyArg): (self: These>) => These + (self: These>, onNone: LazyArg): These +} = dual(2, (self: These>, onNone: LazyArg): These => + isLeft(self) ? + self : + O.isNone(self.right) ? + left(onNone()) : + isBoth(self) ? + both(self.left, self.right.value) : + right(self.right.value)) /** * @category filtering @@ -881,32 +990,51 @@ export const filter: { predicate: Predicate, onFalse: LazyArg ): (self: These) => These -} = ( + ( + self: These, + refinement: Refinement, + onFalse: LazyArg + ): These + ( + self: These, + predicate: Predicate, + onFalse: LazyArg + ): These +} = dual(3, ( + self: These, predicate: Predicate, - onFalse: LazyArg -) => - (self: These): These => - isLeft(self) ? self : predicate(self.right) ? self : left(onFalse()) + onFalse: LazyArg +): These => isLeft(self) ? self : predicate(self.right) ? self : left(onFalse())) /** * @category filtering * @since 1.0.0 */ -export const filterMap = ( +export const filterMap: { + ( + f: (a: A) => Option, + onNone: LazyArg + ): (self: These) => These + ( + self: These, + f: (a: A) => Option, + onNone: LazyArg + ): These +} = dual(3, ( + self: These, f: (a: A) => Option, onNone: LazyArg -) => - (self: These): These => { - if (isLeft(self)) { - return self - } - if (isRight(self)) { - const ob = f(self.right) - return O.isNone(ob) ? left(onNone()) : right(ob.value) - } +): These => { + if (isLeft(self)) { + return self + } + if (isRight(self)) { const ob = f(self.right) - return O.isNone(ob) ? left(onNone()) : both(self.left, ob.value) + return O.isNone(ob) ? left(onNone()) : right(ob.value) } + const ob = f(self.right) + return O.isNone(ob) ? left(onNone()) : both(self.left, ob.value) +}) const product = ( self: Validated, @@ -1011,9 +1139,7 @@ export const zipWith: { that: Validated, f: (a: A, b: B) => C ): (self: Validated) => Validated -} = semiApplicative.zipWith( - SemiApplicative -) +} = semiApplicative.zipWith(SemiApplicative) /** * @since 1.0.0 @@ -1029,10 +1155,8 @@ export const ap: { * @category combining * @since 1.0.0 */ -export const getFirstLeftSemigroup: ( - S: Semigroup -) => Semigroup> = semiApplicative - .getSemigroup(SemiApplicative) +export const getFirstLeftSemigroup: (S: Semigroup) => Semigroup> = + semiApplicative.getSemigroup(SemiApplicative) /** * Appends an element to the end of a tuple. @@ -1142,8 +1266,7 @@ export const FlatMap: flatMap_.FlatMap = { */ export const flatten: ( self: Validated> -) => Validated = flatMap_ - .flatten(FlatMap) +) => Validated = flatMap_.flatten(FlatMap) /** * @since 1.0.0 @@ -1176,42 +1299,6 @@ export const Chainable: chainable.Chainable = { flatMap } -/** - * @category do notation - * @since 1.0.0 - */ -export const bind: ( - name: Exclude, - f: (a: A) => Validated -) => ( - self: Validated -) => Validated = chainable - .bind(Chainable) - -/** - * @category do notation - * @since 1.0.0 - */ -export const bindEither = ( - name: Exclude, - f: (a: A) => Either -): ( - self: Validated -) => Validated => - bind(name, (a) => fromEither(f(a))) - -/** - * @category do notation - * @since 1.0.0 - */ -export const bindThese = ( - name: Exclude, - f: (a: A) => These -): ( - self: Validated -) => Validated => - bind(name, (a) => toValidated(f(a))) - /** * Sequences the specified effect after this effect, but ignores the value * produced by the effect. @@ -1332,3 +1419,39 @@ export const andThenBind: ( self: Validated ) => Validated = semiProduct .andThenBind(SemiProduct) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bind: ( + name: Exclude, + f: (a: A) => Validated +) => ( + self: Validated +) => Validated = chainable + .bind(Chainable) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindEither = ( + name: Exclude, + f: (a: A) => Either +): ( + self: Validated +) => Validated => + bind(name, (a) => fromEither(f(a))) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindThese = ( + name: Exclude, + f: (a: A) => These +): ( + self: Validated +) => Validated => + bind(name, (a) => toValidated(f(a))) From b8f484062a2f625f8f39a73213ff0365b05a1fe9 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 10:18:50 +0100 Subject: [PATCH 175/255] ReadonlyArray: apply dual --- docs/modules/Either.ts.md | 26 + docs/modules/ReadonlyArray.ts.md | 542 ++++++--- docs/modules/String.ts.md | 33 +- docs/modules/typeclass/Semigroup.ts.md | 5 +- src/Either.ts | 36 + src/ReadonlyArray.ts | 1413 +++++++++++++++--------- src/String.ts | 27 +- src/typeclass/Filterable.ts | 1 - src/typeclass/Semigroup.ts | 9 +- test/ReadonlyArray.ts | 27 +- 10 files changed, 1364 insertions(+), 755 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 7d3dff796..494811871 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -62,6 +62,8 @@ Added in v1.0.0 - [getOrElse](#getorelse) - [getOrNull](#getornull) - [getOrUndefined](#getorundefined) + - [lefts](#lefts) + - [rights](#rights) - [guards](#guards) - [isEither](#iseither) - [isLeft](#isleft) @@ -761,6 +763,30 @@ export declare const getOrUndefined: (self: Either) => A | undefined Added in v1.0.0 +## lefts + +Return all the `Left` elements from an `Interable` of `Either`s. + +**Signature** + +```ts +export declare const lefts: (self: Iterable>) => E[] +``` + +Added in v1.0.0 + +## rights + +Return all the `Right` elements from an `Interable` of `Either`s. + +**Signature** + +```ts +export declare const rights: (self: Iterable>) => A[] +``` + +Added in v1.0.0 + # guards ## isEither diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index bc98ea73c..4ea5586a3 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -92,6 +92,9 @@ Added in v1.0.0 - [grouping](#grouping) - [group](#group) - [groupBy](#groupby) +- [guards](#guards) + - [isEmpty](#isempty) + - [isNonEmpty](#isnonempty) - [instances](#instances) - [Applicative](#applicative) - [Chainable](#chainable) @@ -136,11 +139,10 @@ Added in v1.0.0 - [NonEmptyReadonlyArray (type alias)](#nonemptyreadonlyarray-type-alias) - [pattern matching](#pattern-matching) - [match](#match) + - [matchLeft](#matchleft) - [matchRight](#matchright) - [predicates](#predicates) - [contains](#contains) - - [isEmpty](#isempty) - - [isNonEmpty](#isnonempty) - [some](#some) - [sequencing](#sequencing) - [flatMap](#flatmap) @@ -253,7 +255,18 @@ Return a `NonEmptyArray` of length `n` with element `i` initialized with `f(i)`. **Signature** ```ts -export declare const makeBy: (f: (i: number) => A) => (n: number) => [A, ...A[]] +export declare const makeBy: (n: number, f: (i: number) => A) => [A, ...A[]] +``` + +**Example** + +```ts +import { makeBy } from '@fp-ts/core/ReadonlyArray' + +assert.deepStrictEqual( + makeBy(5, (n) => n * 2), + [0, 2, 4, 6, 8] +) ``` Added in v1.0.0 @@ -278,6 +291,14 @@ Return a `NonEmptyArray` containing a range of integers, including both endpoint export declare const range: (start: number, end: number) => [number, ...number[]] ``` +**Example** + +```ts +import { range } from '@fp-ts/core/ReadonlyArray' + +assert.deepStrictEqual(range(1, 3), [1, 2, 3]) +``` + Added in v1.0.0 ## replicate @@ -289,7 +310,15 @@ Return a `NonEmptyArray` containing a value repeated the specified number of tim **Signature** ```ts -export declare const replicate: (a: A) => (n: number) => [A, ...A[]] +export declare const replicate: { (n: number): (a: A) => [A, ...A[]]; (a: A, n: number): [A, ...A[]] } +``` + +**Example** + +```ts +import { replicate } from '@fp-ts/core/ReadonlyArray' + +assert.deepStrictEqual(replicate('a', 3), ['a', 'a', 'a']) ``` Added in v1.0.0 @@ -427,10 +456,9 @@ Added in v1.0.0 ```ts export declare const filter: { - (self: readonly C[], refinement: (a: A) => a is B): B[] - (self: readonly B[], predicate: (a: A) => boolean): B[] - (refinement: (a: A) => a is B): (self: readonly C[]) => B[] - (predicate: (a: A) => boolean): (self: readonly B[]) => B[] + (refinement: (a: A) => a is B): (self: Iterable) => B[] + (predicate: (a: A) => boolean): (self: Iterable) => B[] + (self: Iterable, refinement: (a: A) => a is B): B[] } ``` @@ -468,8 +496,10 @@ Added in v1.0.0 ```ts export declare const filterWithIndex: { - (refinement: (a: A, i: number) => a is B): (self: readonly C[]) => B[] - (predicate: (a: A, i: number) => boolean): (self: readonly B[]) => B[] + (refinement: (a: A, i: number) => a is B): (self: Iterable) => B[] + (predicate: (a: A, i: number) => boolean): (self: Iterable) => B[] + (self: Iterable, refinement: (a: A, i: number) => a is B): B[] + (self: Iterable, predicate: (a: A, i: number) => boolean): B[] } ``` @@ -481,8 +511,10 @@ Added in v1.0.0 ```ts export declare const partition: { - (refinement: Refinement): (self: readonly C[]) => [C[], B[]] - (predicate: Predicate): (self: readonly B[]) => [B[], B[]] + (refinement: Refinement): (self: Iterable) => [C[], B[]] + (predicate: Predicate): (self: Iterable) => [B[], B[]] + (self: Iterable, refinement: Refinement): [C[], B[]] + (self: Iterable, predicate: Predicate): [B[], B[]] } ``` @@ -493,7 +525,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const partitionMap: (f: (a: A) => Either) => (self: readonly A[]) => [B[], C[]] +export declare const partitionMap: { + (f: (a: A) => Either): (self: Iterable) => [B[], C[]] + (self: Iterable, f: (a: A) => Either): [B[], C[]] +} ``` Added in v1.0.0 @@ -503,9 +538,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const partitionMapWithIndex: ( - f: (a: A, i: number) => Either -) => (self: readonly A[]) => [B[], C[]] +export declare const partitionMapWithIndex: { + (f: (a: A, i: number) => Either): (self: Iterable) => [B[], C[]] + (self: Iterable, f: (a: A, i: number) => Either): [B[], C[]] +} ``` Added in v1.0.0 @@ -516,8 +552,10 @@ Added in v1.0.0 ```ts export declare const partitionWithIndex: { - (refinement: (a: A, i: number) => a is B): (self: readonly C[]) => [C[], B[]] - (predicate: (a: A, i: number) => boolean): (self: readonly B[]) => [B[], B[]] + (refinement: (a: A, i: number) => a is B): (self: Iterable) => [C[], B[]] + (predicate: (a: A, i: number) => boolean): (self: Iterable) => [B[], B[]] + (self: Iterable, refinement: (a: A, i: number) => a is B): [C[], B[]] + (self: Iterable, predicate: (a: A, i: number) => boolean): [B[], B[]] } ``` @@ -543,13 +581,12 @@ Split an `Iterable` into two parts: **Signature** ```ts -export declare function span( - refinement: Refinement -): (self: Iterable) => [init: Array, rest: Array] -export declare function span( - predicate: Predicate -): (self: Iterable) => [init: Array, rest: Array] -export declare function span(predicate: Predicate): (self: Iterable) => [init: Array, rest: Array] +export declare const span: { + (refinement: Refinement): (self: Iterable) => [init: B[], rest: A[]] + (predicate: Predicate): (self: Iterable) => [init: B[], rest: B[]] + (self: Iterable, refinement: Refinement): [init: B[], rest: A[]] + (self: Iterable, predicate: Predicate): [init: B[], rest: B[]] +} ``` Added in v1.0.0 @@ -561,7 +598,10 @@ Added in v1.0.0 ```ts export declare const traverseFilterMap: ( F: applicative.Applicative -) => (f: (a: A) => Kind>) => (self: readonly A[]) => Kind +) => { + (f: (a: A) => Kind>): (self: readonly A[]) => Kind + (self: readonly A[], f: (a: A) => Kind>): Kind +} ``` Added in v1.0.0 @@ -573,9 +613,10 @@ Added in v1.0.0 ```ts export declare const traversePartitionMap: ( F: applicative.Applicative -) => ( - f: (a: A) => Kind> -) => (self: readonly A[]) => Kind +) => { + (f: (a: A) => Kind>): (self: readonly A[]) => Kind + (self: readonly A[], f: (a: A) => Kind>): Kind +} ``` Added in v1.0.0 @@ -587,7 +628,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const combineMap: (M: Monoid) => (f: (a: A) => M) => (self: readonly A[]) => M +export declare const combineMap: (M: Monoid) => { + (f: (a: A) => M): (self: Iterable) => M + (self: Iterable, f: (a: A) => M): M +} ``` Added in v1.0.0 @@ -597,9 +641,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const combineMapNonEmpty: ( - S: Semigroup -) => (f: (a: A) => S) => (self: readonly [A, ...A[]]) => S +export declare const combineMapNonEmpty: (S: Semigroup) => { + (f: (a: A) => S): (self: readonly [A, ...A[]]) => S + (self: readonly [A, ...A[]], f: (a: A) => S): S +} ``` Added in v1.0.0 @@ -609,9 +654,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const combineMapNonEmptyWithIndex: ( - S: Semigroup -) => (f: (a: A, i: number) => S) => (self: readonly [A, ...A[]]) => S +export declare const combineMapNonEmptyWithIndex: (S: Semigroup) => { + (f: (a: A, i: number) => S): (self: readonly [A, ...A[]]) => S + (self: readonly [A, ...A[]], f: (a: A, i: number) => S): S +} ``` Added in v1.0.0 @@ -621,9 +667,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const combineMapWithIndex: ( - Monoid: Monoid -) => (f: (a: A, i: number) => M) => (self: readonly A[]) => M +export declare const combineMapWithIndex: (Monoid: Monoid) => { + (f: (a: A, i: number) => M): (self: Iterable) => M + (self: Iterable, f: (a: A, i: number) => M): M +} ``` Added in v1.0.0 @@ -633,9 +680,12 @@ Added in v1.0.0 **Signature** ```ts -export declare const coproductMapKind: ( - F: Coproduct -) => (f: (a: A) => Kind) => (self: readonly A[]) => Kind +export declare const coproductMapKind: ( + G: Coproduct +) => { + (f: (a: A) => Kind): (self: readonly A[]) => Kind + (self: readonly A[], f: (a: A) => Kind): Kind +} ``` Added in v1.0.0 @@ -646,8 +696,8 @@ Added in v1.0.0 ```ts export declare const reduce: { - (b: B, f: (b: B, a: A) => B): (self: readonly A[]) => B - (self: readonly A[], b: B, f: (b: B, a: A) => B): B + (b: B, f: (b: B, a: A) => B): (self: Iterable) => B + (self: Iterable, b: B, f: (b: B, a: A) => B): B } ``` @@ -658,9 +708,12 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduceKind: ( - F: monad.Monad -) => (b: B, f: (b: B, a: A) => Kind) => (self: readonly A[]) => Kind +export declare const reduceKind: ( + G: monad.Monad +) => { + (b: B, f: (b: B, a: A) => Kind): (self: readonly A[]) => Kind + (self: readonly A[], b: B, f: (b: B, a: A) => Kind): Kind +} ``` Added in v1.0.0 @@ -670,7 +723,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduceRight: (b: B, f: (b: B, a: A) => B) => (self: readonly A[]) => B +export declare const reduceRight: { + (b: B, f: (b: B, a: A) => B): (self: Iterable) => B + (self: Iterable, b: B, f: (b: B, a: A) => B): B +} ``` Added in v1.0.0 @@ -680,7 +736,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduceRightWithIndex: (b: B, f: (b: B, a: A, i: number) => B) => (self: readonly A[]) => B +export declare const reduceRightWithIndex: { + (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B +} ``` Added in v1.0.0 @@ -690,31 +749,40 @@ Added in v1.0.0 **Signature** ```ts -export declare const reduceWithIndex: (b: B, f: (b: B, a: A, i: number) => B) => (self: readonly A[]) => B +export declare const reduceWithIndex: { + (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B +} ``` Added in v1.0.0 ## scan -Fold an `Iterable` from the left, keeping all intermediate results instead of only the final result. +Reduce an `Iterable` from the left, keeping all intermediate results instead of only the final result. **Signature** ```ts -export declare const scan: (b: B, f: (b: B, a: A) => B) => (self: Iterable) => [B, ...B[]] +export declare const scan: { + (b: B, f: (b: B, a: A) => B): (self: Iterable) => [B, ...B[]] + (self: Iterable, b: B, f: (b: B, a: A) => B): [B, ...B[]] +} ``` Added in v1.0.0 ## scanRight -Fold an `Iterable` from the right, keeping all intermediate results instead of only the final result. +Reduce an `Iterable` from the right, keeping all intermediate results instead of only the final result. **Signature** ```ts -export declare const scanRight: (b: B, f: (b: B, a: A) => B) => (self: Iterable) => [B, ...B[]] +export declare const scanRight: { + (b: B, f: (b: B, a: A) => B): (self: Iterable) => [B, ...B[]] + (self: Iterable, b: B, f: (b: B, a: A) => B): [B, ...B[]] +} ``` Added in v1.0.0 @@ -736,7 +804,10 @@ whenever `n` evenly divides the length of `self`. **Signature** ```ts -export declare const chunksOf: (n: number) => (self: Iterable) => [A, ...A[]][] +export declare const chunksOf: { + (n: number): (self: Iterable) => [A, ...A[]][] + (self: Iterable, n: number): [A, ...A[]][] +} ``` Added in v1.0.0 @@ -749,7 +820,10 @@ the `NonEmptyReadonlyArray`. **Signature** ```ts -export declare const chunksOfNonEmpty: (n: number) => (self: readonly [A, ...A[]]) => [[A, ...A[]], ...[A, ...A[]][]] +export declare const chunksOfNonEmpty: { + (n: number): (self: readonly [A, ...A[]]) => [[A, ...A[]], ...[A, ...A[]][]] + (self: readonly [A, ...A[]], n: number): [[A, ...A[]], ...[A, ...A[]][]] +} ``` Added in v1.0.0 @@ -763,7 +837,7 @@ Drop a max number of elements from the start of an `Iterable`, creating a new `A **Signature** ```ts -export declare const drop: (n: number) => (self: Iterable) => A[] +export declare const drop: { (n: number): (self: Iterable) => A[]; (self: Iterable, n: number): A[] } ``` Added in v1.0.0 @@ -777,7 +851,7 @@ Drop a max number of elements from the end of an `Iterable`, creating a new `Arr **Signature** ```ts -export declare const dropRight: (n: number) => (self: Iterable) => A[] +export declare const dropRight: { (n: number): (self: Iterable) => A[]; (self: Iterable, n: number): A[] } ``` Added in v1.0.0 @@ -789,9 +863,12 @@ Remove the longest initial subarray for which all element satisfy the specified **Signature** ```ts -export declare function dropWhile(refinement: Refinement): (self: Iterable) => Array -export declare function dropWhile(predicate: Predicate): (self: Iterable) => Array -export declare function dropWhile(predicate: Predicate): (self: Iterable) => Array +export declare const dropWhile: { + (refinement: Refinement): (self: Iterable) => B[] + (predicate: Predicate): (self: Iterable) => B[] + (self: Iterable, refinement: Refinement): B[] + (self: Iterable, predicate: Predicate): B[] +} ``` Added in v1.0.0 @@ -803,9 +880,12 @@ Find the first element for which a predicate holds. **Signature** ```ts -export declare function findFirst(refinement: Refinement): (self: Iterable) => Option -export declare function findFirst(predicate: Predicate): (self: Iterable) => Option -export declare function findFirst(predicate: Predicate): (self: Iterable) => Option +export declare const findFirst: { + (refinement: Refinement): (self: Iterable) => Option + (predicate: Predicate): (self: Iterable) => Option + (self: Iterable, refinement: Refinement): Option + (self: Iterable, predicate: Predicate): Option +} ``` Added in v1.0.0 @@ -817,7 +897,10 @@ Return the first index for which a predicate holds. **Signature** ```ts -export declare const findFirstIndex: (predicate: Predicate) => (self: Iterable) => Option +export declare const findFirstIndex: { + (predicate: Predicate): (self: Iterable) => Option + (self: Iterable, predicate: Predicate): Option +} ``` Added in v1.0.0 @@ -829,9 +912,12 @@ Find the last element for which a predicate holds. **Signature** ```ts -export declare function findLast(refinement: Refinement): (self: Iterable) => Option -export declare function findLast(predicate: Predicate): (self: Iterable) => Option -export declare function findLast(predicate: Predicate): (self: Iterable) => Option +export declare const findLast: { + (refinement: Refinement): (self: Iterable) => Option + (predicate: Predicate): (self: Iterable) => Option + (self: Iterable, refinement: Refinement): Option + (self: Iterable, predicate: Predicate): Option +} ``` Added in v1.0.0 @@ -843,7 +929,10 @@ Return the last index for which a predicate holds. **Signature** ```ts -export declare const findLastIndex: (predicate: Predicate) => (self: Iterable) => Option +export declare const findLastIndex: { + (predicate: Predicate): (self: Iterable) => Option + (self: Iterable, predicate: Predicate): Option +} ``` Added in v1.0.0 @@ -855,7 +944,10 @@ This function provides a safe way to read a value at a particular index from a ` **Signature** ```ts -export declare const get: (index: number) => (self: readonly A[]) => Option +export declare const get: { + (index: number): (self: readonly A[]) => Option + (self: readonly A[], index: number): Option +} ``` Added in v1.0.0 @@ -923,7 +1015,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const lastNonEmpty: (as: readonly [A, ...A[]]) => A +export declare const lastNonEmpty: (self: readonly [A, ...A[]]) => A ``` Added in v1.0.0 @@ -971,7 +1063,10 @@ Splits an `Iterable` into two pieces, the first piece has max `n` elements. **Signature** ```ts -export declare const splitAt: (n: number) => (self: Iterable) => [A[], A[]] +export declare const splitAt: { + (n: number): (self: Iterable) => [A[], A[]] + (self: Iterable, n: number): [A[], A[]] +} ``` Added in v1.0.0 @@ -983,7 +1078,10 @@ Splits a `NonEmptyReadonlyArray` into two pieces, the first piece has max `n` el **Signature** ```ts -export declare const splitNonEmptyAt: (n: number) => (self: readonly [A, ...A[]]) => [[A, ...A[]], A[]] +export declare const splitNonEmptyAt: { + (n: number): (self: readonly [A, ...A[]]) => [[A, ...A[]], A[]] + (self: readonly [A, ...A[]], n: number): [[A, ...A[]], A[]] +} ``` Added in v1.0.0 @@ -1019,7 +1117,7 @@ Keep only a max number of elements from the start of an `Iterable`, creating a n **Signature** ```ts -export declare const take: (n: number) => (self: Iterable) => A[] +export declare const take: { (n: number): (self: Iterable) => A[]; (self: Iterable, n: number): A[] } ``` Added in v1.0.0 @@ -1033,7 +1131,7 @@ Keep only a max number of elements from the end of an `Iterable`, creating a new **Signature** ```ts -export declare const takeRight: (n: number) => (self: Iterable) => A[] +export declare const takeRight: { (n: number): (self: Iterable) => A[]; (self: Iterable, n: number): A[] } ``` Added in v1.0.0 @@ -1045,8 +1143,12 @@ Calculate the longest initial subarray for which all element satisfy the specifi **Signature** ```ts -export declare function takeWhile(refinement: Refinement): (self: Iterable) => Array -export declare function takeWhile(predicate: Predicate): (self: Iterable) => Array +export declare const takeWhile: { + (refinement: Refinement): (self: Iterable) => B[] + (predicate: Predicate): (self: Iterable) => B[] + (self: Iterable, refinement: Refinement): B[] + (self: Iterable, predicate: Predicate): B[] +} ``` Added in v1.0.0 @@ -1099,7 +1201,36 @@ function on each element, and grouping the results according to values returned **Signature** ```ts -export declare const groupBy: (f: (a: A) => string) => (self: Iterable) => Record +export declare const groupBy: { + (f: (a: A) => string): (self: Iterable) => Record + (self: Iterable, f: (a: A) => string): Record +} +``` + +Added in v1.0.0 + +# guards + +## isEmpty + +Test whether a `ReadonlyArray` is empty narrowing down the type to `[]`. + +**Signature** + +```ts +export declare const isEmpty: (self: readonly A[]) => self is readonly [] +``` + +Added in v1.0.0 + +## isNonEmpty + +Test whether a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyReadonlyArray`. + +**Signature** + +```ts +export declare const isNonEmpty: (self: readonly A[]) => self is readonly [A, ...A[]] ``` Added in v1.0.0 @@ -1492,7 +1623,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const mapWithIndex: (f: (a: A, i: number) => B) => (self: readonly A[]) => B[] +export declare const mapWithIndex: { + (f: (a: A, i: number) => B): (self: readonly A[]) => B[] + (self: readonly A[], f: (a: A, i: number) => B): B[] +} ``` Added in v1.0.0 @@ -1536,61 +1670,53 @@ Added in v1.0.0 **Signature** ```ts -export declare const match: ( - onEmpty: LazyArg, - onNonEmpty: (head: A, tail: A[]) => C -) => (self: readonly A[]) => B | C +export declare const match: { + (onEmpty: LazyArg, onNonEmpty: (self: readonly [A, ...A[]]) => C): (self: readonly A[]) => B | C + (self: readonly A[], onEmpty: LazyArg, onNonEmpty: (self: readonly [A, ...A[]]) => C): B | C +} ``` Added in v1.0.0 -## matchRight +## matchLeft **Signature** ```ts -export declare const matchRight: ( - onEmpty: LazyArg, - onNonEmpty: (init: A[], last: A) => C -) => (self: readonly A[]) => B | C +export declare const matchLeft: { + (onEmpty: LazyArg, onNonEmpty: (head: A, tail: A[]) => C): (self: readonly A[]) => B | C + (self: readonly A[], onEmpty: LazyArg, onNonEmpty: (head: A, tail: A[]) => C): B | C +} ``` Added in v1.0.0 -# predicates - -## contains - -Returns a function that checks if a `ReadonlyArray` contains a given value using a provided `equivalence` function. +## matchRight **Signature** ```ts -export declare const contains: (equivalence: Equivalence) => (a: A) => (self: Iterable) => boolean +export declare const matchRight: { + (onEmpty: LazyArg, onNonEmpty: (init: A[], last: A) => C): (self: readonly A[]) => B | C + (self: readonly A[], onEmpty: LazyArg, onNonEmpty: (init: A[], last: A) => C): B | C +} ``` Added in v1.0.0 -## isEmpty - -Test whether a `ReadonlyArray` is empty narrowing down the type to `[]`. - -**Signature** - -```ts -export declare const isEmpty: (self: readonly A[]) => self is readonly [] -``` - -Added in v1.0.0 +# predicates -## isNonEmpty +## contains -Test whether a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyReadonlyArray`. +Returns a function that checks if a `ReadonlyArray` contains a given value using a provided `equivalence` function. **Signature** ```ts -export declare const isNonEmpty: (self: readonly A[]) => self is readonly [A, ...A[]] +export declare const contains: (equivalence: Equivalence) => { + (a: A): (self: Iterable) => boolean + (self: Iterable, a: A): boolean +} ``` Added in v1.0.0 @@ -1627,9 +1753,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapNonEmpty: ( - f: (a: A) => readonly [B, ...B[]] -) => (self: readonly [A, ...A[]]) => [B, ...B[]] +export declare const flatMapNonEmpty: { + (f: (a: A) => readonly [B, ...B[]]): (self: readonly [A, ...A[]]) => [B, ...B[]] + (self: readonly [A, ...A[]], f: (a: A) => readonly [B, ...B[]]): [B, ...B[]] +} ``` Added in v1.0.0 @@ -1639,9 +1766,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapNonEmptyWithIndex: ( - f: (a: A, i: number) => readonly [B, ...B[]] -) => (self: readonly [A, ...A[]]) => [B, ...B[]] +export declare const flatMapNonEmptyWithIndex: { + (f: (a: A, i: number) => readonly [B, ...B[]]): (self: readonly [A, ...A[]]) => [B, ...B[]] + (self: readonly [A, ...A[]], f: (a: A, i: number) => readonly [B, ...B[]]): [B, ...B[]] +} ``` Added in v1.0.0 @@ -1651,9 +1779,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const flatMapNullable: ( - f: (a: A) => B | null | undefined -) => (self: readonly A[]) => NonNullable[] +export declare const flatMapNullable: { + (f: (a: A) => B | null | undefined): (self: readonly A[]) => NonNullable[] + (self: readonly A[], f: (a: A) => B | null | undefined): NonNullable[] +} ``` Added in v1.0.0 @@ -1792,7 +1921,10 @@ Added in v1.0.0 ```ts export declare const traverseNonEmpty: ( F: semiApplicative.SemiApplicative -) => (f: (a: A) => Kind) => (self: readonly [A, ...A[]]) => Kind +) => { + (f: (a: A) => Kind): (self: readonly [A, ...A[]]) => Kind + (self: readonly [A, ...A[]], f: (a: A) => Kind): Kind +} ``` Added in v1.0.0 @@ -1804,9 +1936,18 @@ Added in v1.0.0 ```ts export declare const traverseNonEmptyWithIndex: ( F: semiApplicative.SemiApplicative -) => ( - f: (a: A, i: number) => Kind -) => (self: readonly [A, ...A[]]) => Kind +) => { + (f: (a: A, i: number) => Kind): ( + self: readonly [A, ...A[]] + ) => Kind + (self: readonly [A, ...A[]], f: (a: A, i: number) => Kind): Kind< + F, + R, + O, + E, + [B, ...B[]] + > +} ``` Added in v1.0.0 @@ -1833,7 +1974,10 @@ Added in v1.0.0 ```ts export declare const traverseWithIndex: ( F: applicative.Applicative -) => (f: (a: A, i: number) => Kind) => (self: readonly A[]) => Kind +) => { + (f: (a: A, i: number) => Kind): (self: Iterable) => Kind + (self: Iterable, f: (a: A, i: number) => Kind): Kind +} ``` Added in v1.0.0 @@ -1861,7 +2005,10 @@ Gets an element unsafely, will throw on out of bounds. **Signature** ```ts -export declare const unsafeGet: (index: number) => (self: readonly A[]) => A +export declare const unsafeGet: { + (index: number): (self: readonly A[]) => A + (self: readonly A[], index: number): A +} ``` Added in v1.0.0 @@ -1901,7 +2048,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const appendAll: (that: Iterable) => (self: Iterable) => (B | A)[] +export declare const appendAll: { + (that: Iterable): (self: Iterable) => (B | A)[] + (self: Iterable, that: Iterable): (A | B)[] +} ``` Added in v1.0.0 @@ -1911,12 +2061,12 @@ Added in v1.0.0 **Signature** ```ts -export declare function appendAllNonEmpty( - that: NonEmptyReadonlyArray -): (self: Iterable) => NonEmptyArray -export declare function appendAllNonEmpty( - that: Iterable -): (self: NonEmptyReadonlyArray) => NonEmptyArray +export declare const appendAllNonEmpty: { + (that: readonly [B, ...B[]]): (self: Iterable) => [B | A, ...(B | A)[]] + (that: Iterable): (self: readonly [A, ...A[]]) => [B | A, ...(B | A)[]] + (self: Iterable, that: readonly [B, ...B[]]): [A | B, ...(A | B)[]] + (self: readonly [A, ...A[]], that: Iterable): [A | B, ...(A | B)[]] +} ``` Added in v1.0.0 @@ -1930,9 +2080,10 @@ value and the rest of the `Array`. **Signature** ```ts -export declare const chop: ( - f: (as: readonly [A, ...A[]]) => readonly [B, readonly A[]] -) => (self: Iterable) => B[] +export declare const chop: { + (f: (as: readonly [A, ...A[]]) => readonly [B, readonly A[]]): (self: Iterable) => B[] + (self: Iterable, f: (as: readonly [A, ...A[]]) => readonly [B, readonly A[]]): B[] +} ``` Added in v1.0.0 @@ -1972,8 +2123,7 @@ Added in v1.0.0 **Signature** ```ts -export declare function copy(self: NonEmptyReadonlyArray): NonEmptyArray -export declare function copy(self: ReadonlyArray): Array +export declare const copy: { (self: readonly [A, ...A[]]): [A, ...A[]]; (self: readonly A[]): A[] } ``` Added in v1.0.0 @@ -1986,7 +2136,10 @@ The order and references of result values are determined by the first `Iterable` **Signature** ```ts -export declare const difference: (equivalence: Equivalence) => (that: Iterable) => (self: Iterable) => A[] +export declare const difference: (equivalence: Equivalence) => { + (that: Iterable): (self: Iterable) => A[] + (self: Iterable, that: Iterable): A[] +} ``` Added in v1.0.0 @@ -1996,7 +2149,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const extend: (f: (as: readonly A[]) => B) => (self: readonly A[]) => B[] +export declare const extend: { + (f: (as: readonly A[]) => B): (self: readonly A[]) => B[] + (self: readonly A[], f: (as: readonly A[]) => B): B[] +} ``` Added in v1.0.0 @@ -2009,20 +2165,26 @@ or return `None` if the index is out of bounds. **Signature** ```ts -export declare const insertAt: (i: number, b: B) => (self: Iterable) => Option<[B | A, ...(B | A)[]]> +export declare const insertAt: { + (i: number, b: B): (self: Iterable) => Option<[B | A, ...(B | A)[]]> + (self: Iterable, i: number, b: B): Option<[A | B, ...(A | B)[]]> +} ``` Added in v1.0.0 ## intercalate -Fold a data structure, accumulating values in some `Monoid`, combining adjacent elements +Fold an `Iterable`, accumulating values in some `Monoid`, combining adjacent elements using the specified separator. **Signature** ```ts -export declare const intercalate: (M: Monoid) => (middle: A) => (self: readonly A[]) => A +export declare const intercalate: (M: Monoid) => { + (middle: A): (self: Iterable) => A + (self: Iterable, middle: A): A +} ``` Added in v1.0.0 @@ -2034,7 +2196,10 @@ Places an element in between members of a `NonEmptyReadonlyArray`, then folds th **Signature** ```ts -export declare const intercalateNonEmpty: (S: Semigroup) => (middle: A) => (self: readonly [A, ...A[]]) => A +export declare const intercalateNonEmpty: (S: Semigroup) => { + (middle: A): (self: readonly [A, ...A[]]) => A + (self: readonly [A, ...A[]], middle: A): A +} ``` Added in v1.0.0 @@ -2062,7 +2227,10 @@ Places an element in between members of an `Iterable` **Signature** ```ts -export declare const intersperse: (middle: B) => (self: Iterable) => (B | A)[] +export declare const intersperse: { + (middle: B): (self: Iterable) => (B | A)[] + (self: Iterable, middle: B): (A | B)[] +} ``` Added in v1.0.0 @@ -2074,7 +2242,10 @@ Places an element in between members of a `NonEmptyReadonlyArray` **Signature** ```ts -export declare const intersperseNonEmpty: (middle: B) => (self: readonly [A, ...A[]]) => [B | A, ...(B | A)[]] +export declare const intersperseNonEmpty: { + (middle: B): (self: readonly [A, ...A[]]) => [B | A, ...(B | A)[]] + (self: readonly [A, ...A[]], middle: B): [A | B, ...(A | B)[]] +} ``` Added in v1.0.0 @@ -2084,7 +2255,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const join: (sep: string) => (self: ReadonlyArray) => string +export declare const join: { + (middle: string): (self: ReadonlyArray) => string + (self: ReadonlyArray, middle: string): string +} ``` Added in v1.0.0 @@ -2117,7 +2291,10 @@ or return a copy of the input if the index is out of bounds. **Signature** ```ts -export declare const modify: (i: number, f: (a: A) => B) => (self: Iterable) => (A | B)[] +export declare const modify: { + (i: number, f: (a: A) => B): (self: Iterable) => (A | B)[] + (self: Iterable, i: number, f: (a: A) => B): (A | B)[] +} ``` Added in v1.0.0 @@ -2129,7 +2306,10 @@ Apply a function to the head, creating a new `NonEmptyReadonlyArray`. **Signature** ```ts -export declare const modifyNonEmptyHead: (f: (a: A) => B) => (self: readonly [A, ...A[]]) => [A | B, ...(A | B)[]] +export declare const modifyNonEmptyHead: { + (f: (a: A) => B): (self: readonly [A, ...A[]]) => [A | B, ...(A | B)[]] + (self: readonly [A, ...A[]], f: (a: A) => B): [A | B, ...(A | B)[]] +} ``` Added in v1.0.0 @@ -2141,7 +2321,10 @@ Apply a function to the last element, creating a new `NonEmptyReadonlyArray`. **Signature** ```ts -export declare const modifyNonEmptyLast: (f: (a: A) => B) => (self: readonly [A, ...A[]]) => [A | B, ...(A | B)[]] +export declare const modifyNonEmptyLast: { + (f: (a: A) => B): (self: readonly [A, ...A[]]) => [A | B, ...(A | B)[]] + (self: readonly [A, ...A[]], f: (a: A) => B): [A | B, ...(A | B)[]] +} ``` Added in v1.0.0 @@ -2182,7 +2365,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const prependAll: (that: Iterable) => (self: Iterable) => (B | A)[] +export declare const prependAll: { + (that: Iterable): (self: Iterable) => (B | A)[] + (self: Iterable, that: Iterable): (A | B)[] +} ``` Added in v1.0.0 @@ -2192,12 +2378,12 @@ Added in v1.0.0 **Signature** ```ts -export declare function prependAllNonEmpty( - that: NonEmptyReadonlyArray -): (self: Iterable) => NonEmptyArray -export declare function prependAllNonEmpty( - that: Iterable -): (self: NonEmptyReadonlyArray) => NonEmptyArray +export declare const prependAllNonEmpty: { + (that: readonly [B, ...B[]]): (self: Iterable) => [B | A, ...(B | A)[]] + (that: Iterable): (self: readonly [A, ...A[]]) => [B | A, ...(B | A)[]] + (self: Iterable, that: readonly [B, ...B[]]): [A | B, ...(A | B)[]] + (self: readonly [A, ...A[]], that: Iterable): [A | B, ...(A | B)[]] +} ``` Added in v1.0.0 @@ -2210,7 +2396,7 @@ or return a copy of the input if the index is out of bounds. **Signature** ```ts -export declare const remove: (i: number) => (self: Iterable) => A[] +export declare const remove: { (i: number): (self: Iterable) => A[]; (self: Iterable, i: number): A[] } ``` Added in v1.0.0 @@ -2223,7 +2409,10 @@ or return a copy of the input if the index is out of bounds. **Signature** ```ts -export declare const replace: (i: number, b: B) => (self: Iterable) => (B | A)[] +export declare const replace: { + (i: number, b: B): (self: Iterable) => (B | A)[] + (self: Iterable, i: number, b: B): (A | B)[] +} ``` Added in v1.0.0 @@ -2233,7 +2422,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const replaceOption: (i: number, b: B) => (self: Iterable) => Option<(B | A)[]> +export declare const replaceOption: { + (i: number, b: B): (self: Iterable) => Option<(B | A)[]> + (self: Iterable, i: number, b: B): Option<(A | B)[]> +} ``` Added in v1.0.0 @@ -2267,7 +2459,7 @@ Rotate an `Iterable` by `n` steps. **Signature** ```ts -export declare const rotate: (n: number) => (self: Iterable) => A[] +export declare const rotate: { (n: number): (self: Iterable) => A[]; (self: Iterable, n: number): A[] } ``` Added in v1.0.0 @@ -2279,7 +2471,10 @@ Rotate a `NonEmptyReadonlyArray` by `n` steps. **Signature** ```ts -export declare const rotateNonEmpty: (n: number) => (self: readonly [A, ...A[]]) => [A, ...A[]] +export declare const rotateNonEmpty: { + (n: number): (self: readonly [A, ...A[]]) => [A, ...A[]] + (self: readonly [A, ...A[]], n: number): [A, ...A[]] +} ``` Added in v1.0.0 @@ -2291,7 +2486,10 @@ Change the head, creating a new `NonEmptyReadonlyArray`. **Signature** ```ts -export declare const setNonEmptyHead: (b: B) => (self: readonly [A, ...A[]]) => [B | A, ...(B | A)[]] +export declare const setNonEmptyHead: { + (b: B): (self: readonly [A, ...A[]]) => [B | A, ...(B | A)[]] + (self: readonly [A, ...A[]], b: B): [A | B, ...(A | B)[]] +} ``` Added in v1.0.0 @@ -2303,7 +2501,10 @@ Change the last element, creating a new `NonEmptyReadonlyArray`. **Signature** ```ts -export declare const setNonEmptyLast: (b: B) => (self: readonly [A, ...A[]]) => [B | A, ...(B | A)[]] +export declare const setNonEmptyLast: { + (b: B): (self: readonly [A, ...A[]]) => [B | A, ...(B | A)[]] + (self: readonly [A, ...A[]], b: B): [A | B, ...(A | B)[]] +} ``` Added in v1.0.0 @@ -2377,6 +2578,8 @@ Added in v1.0.0 export declare const unionNonEmpty: (equivalence: Equivalence) => { (that: readonly [A, ...A[]]): (self: readonly A[]) => [A, ...A[]] (that: readonly A[]): (self: readonly [A, ...A[]]) => [A, ...A[]] + (self: readonly A[], that: readonly [A, ...A[]]): [A, ...A[]] + (self: readonly [A, ...A[]], that: readonly A[]): [A, ...A[]] } ``` @@ -2437,7 +2640,10 @@ longer `Iterable` are discarded. **Signature** ```ts -export declare const zip: (that: Iterable) => (self: Iterable) => [A, B][] +export declare const zip: { + (that: Iterable): (self: Iterable) => [A, B][] + (self: Iterable, that: Iterable): [A, B][] +} ``` Added in v1.0.0 @@ -2447,9 +2653,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const zipNonEmpty: ( - that: readonly [B, ...B[]] -) => (self: readonly [A, ...A[]]) => [[A, B], ...[A, B][]] +export declare const zipNonEmpty: { + (that: readonly [B, ...B[]]): (self: readonly [A, ...A[]]) => [[A, B], ...[A, B][]] + (self: readonly [A, ...A[]], that: readonly [B, ...B[]]): [[A, B], ...[A, B][]] +} ``` Added in v1.0.0 @@ -2475,7 +2682,10 @@ input `Iterable` is short, excess elements of the longer `Iterable` are discarde **Signature** ```ts -export declare const zipWith: (that: Iterable, f: (a: A, b: B) => C) => (self: Iterable) => C[] +export declare const zipWith: { + (that: Iterable, f: (a: A, b: B) => C): (self: Iterable) => C[] + (self: Iterable, that: Iterable, f: (a: A, b: B) => C): C[] +} ``` Added in v1.0.0 diff --git a/docs/modules/String.ts.md b/docs/modules/String.ts.md index 0b5833dcb..f75438948 100644 --- a/docs/modules/String.ts.md +++ b/docs/modules/String.ts.md @@ -181,10 +181,9 @@ export declare const isEmpty: (s: string) => s is '' ```ts import * as S from '@fp-ts/core/String' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe('', S.isEmpty), true) -assert.deepStrictEqual(pipe('a', S.isEmpty), false) +assert.deepStrictEqual(S.isEmpty(''), true) +assert.deepStrictEqual(S.isEmpty('a'), false) ``` Added in v1.0.0 @@ -215,9 +214,8 @@ export declare const length: (s: string) => number ```ts import * as S from '@fp-ts/core/String' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe('abc', S.length), 3) +assert.deepStrictEqual(S.length('abc'), 3) ``` Added in v1.0.0 @@ -326,6 +324,14 @@ If `n` is a float, it will be rounded down to the nearest integer. export declare const takeLeft: { (n: number): (self: string) => string; (self: string, n: number): string } ``` +**Example** + +```ts +import * as S from '@fp-ts/core/String' + +assert.deepStrictEqual(S.takeLeft('Hello World', 5), 'Hello') +``` + Added in v1.0.0 ## takeRight @@ -345,6 +351,14 @@ If `n` is a float, it will be rounded down to the nearest integer. export declare const takeRight: { (n: number): (s: string) => string; (s: string, n: number): string } ``` +**Example** + +```ts +import * as S from '@fp-ts/core/String' + +assert.deepStrictEqual(S.takeRight('Hello World', 5), 'World') +``` + Added in v1.0.0 ## toLowerCase @@ -397,9 +411,8 @@ export declare const trim: (s: string) => string ```ts import * as S from '@fp-ts/core/String' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe(' a ', S.trim), 'a') +assert.deepStrictEqual(S.trim(' a '), 'a') ``` Added in v1.0.0 @@ -416,9 +429,8 @@ export declare const trimEnd: (s: string) => string ```ts import * as S from '@fp-ts/core/String' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe(' a ', S.trimEnd), ' a') +assert.deepStrictEqual(S.trimEnd(' a '), ' a') ``` Added in v1.0.0 @@ -435,9 +447,8 @@ export declare const trimStart: (s: string) => string ```ts import * as S from '@fp-ts/core/String' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe(' a ', S.trimStart), 'a ') +assert.deepStrictEqual(S.trimStart(' a '), 'a ') ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index 54efdb521..17c271e1f 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -363,7 +363,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const intercalate: (separator: A) => (S: Semigroup) => Semigroup +export declare const intercalate: { + (separator: A): (S: Semigroup) => Semigroup + (S: Semigroup, separator: A): Semigroup +} ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index 12042bf7d..55462d8a3 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1272,6 +1272,42 @@ export const divide: { (that: Either): (self: Either) => Either } = lift2(N.divide) +// ------------------------------------------------------------------------------------- +// utils +// ------------------------------------------------------------------------------------- + +/** + * Return all the `Right` elements from an `Interable` of `Either`s. + * + * @category getters + * @since 1.0.0 + */ +export const rights = (self: Iterable>): Array => { + const out: Array = [] + for (const a of self) { + if (isRight(a)) { + out.push(a.right) + } + } + return out +} + +/** + * Return all the `Left` elements from an `Interable` of `Either`s. + * + * @category getters + * @since 1.0.0 + */ +export const lefts = (self: Iterable>): Array => { + const out: Array = [] + for (const a of self) { + if (isLeft(a)) { + out.push(a.left) + } + } + return out +} + // ------------------------------------------------------------------------------------- // do notation // ------------------------------------------------------------------------------------- diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 308cee2a7..e0732413d 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -74,37 +74,54 @@ export const make = >( * * **Note**. `n` is normalized to an integer >= 1. * + * @example + * import { makeBy } from '@fp-ts/core/ReadonlyArray' + * + * assert.deepStrictEqual(makeBy(5, n => n * 2), [0, 2, 4, 6, 8]) + * * @category constructors * @since 1.0.0 */ -export const makeBy = (f: (i: number) => A) => - (n: number): NonEmptyArray => { - const max = Math.max(1, Math.floor(n)) - const out: NonEmptyArray = [f(0)] - for (let i = 1; i < max; i++) { - out.push(f(i)) - } - return out +export const makeBy = (n: number, f: (i: number) => A): NonEmptyArray => { + const max = Math.max(1, Math.floor(n)) + const out: NonEmptyArray = [f(0)] + for (let i = 1; i < max; i++) { + out.push(f(i)) } + return out +} /** * Return a `NonEmptyArray` containing a range of integers, including both endpoints. * + * @example + * import { range } from '@fp-ts/core/ReadonlyArray' + * + * assert.deepStrictEqual(range(1, 3), [1, 2, 3]) + * * @category constructors * @since 1.0.0 */ export const range = (start: number, end: number): NonEmptyArray => - start <= end ? makeBy((i) => start + i)(end - start + 1) : [start] + start <= end ? makeBy(end - start + 1, (i) => start + i) : [start] /** * Return a `NonEmptyArray` containing a value repeated the specified number of times. * * **Note**. `n` is normalized to an integer >= 1. * + * @example + * import { replicate } from '@fp-ts/core/ReadonlyArray' + * + * assert.deepStrictEqual(replicate("a", 3), ["a", "a", "a"]) + * * @category constructors * @since 1.0.0 */ -export const replicate = (a: A): ((n: number) => NonEmptyArray) => makeBy(() => a) +export const replicate: { + (n: number): (a: A) => NonEmptyArray + (a: A, n: number): NonEmptyArray +} = dual(2, (a: A, n: number): NonEmptyArray => makeBy(n, () => a)) /** * @category conversions @@ -116,41 +133,76 @@ export const fromIterable: (collection: Iterable) => Array = readonlyAr * @category conversions * @since 1.0.0 */ -export const fromOption = ( - self: Option -): Array => (O.isNone(self) ? [] : [self.value]) +export const fromOption: (self: Option) => Array = O.toArray /** * @category conversions * @since 1.0.0 */ -export const fromEither = ( - self: Either -): Array => (E.isLeft(self) ? [] : [self.right]) +export const fromEither: (self: Either) => Array = E.toArray /** * @category pattern matching * @since 1.0.0 */ -export const match = ( +export const match: { + ( + onEmpty: LazyArg, + onNonEmpty: (self: NonEmptyReadonlyArray) => C + ): (self: ReadonlyArray) => B | C + ( + self: ReadonlyArray, + onEmpty: LazyArg, + onNonEmpty: (self: NonEmptyReadonlyArray) => C + ): B | C +} = dual(3, ( + self: ReadonlyArray, + onEmpty: LazyArg, + onNonEmpty: (self: NonEmptyReadonlyArray) => C +): B | C => isNonEmpty(self) ? onNonEmpty(self) : onEmpty()) + +/** + * @category pattern matching + * @since 1.0.0 + */ +export const matchLeft: { + ( + onEmpty: LazyArg, + onNonEmpty: (head: A, tail: Array) => C + ): (self: ReadonlyArray) => B | C + ( + self: ReadonlyArray, + onEmpty: LazyArg, + onNonEmpty: (head: A, tail: Array) => C + ): B | C +} = dual(3, ( + self: ReadonlyArray, onEmpty: LazyArg, onNonEmpty: (head: A, tail: Array) => C -) => - (self: ReadonlyArray): B | C => - isNonEmpty(self) ? onNonEmpty(headNonEmpty(self), tailNonEmpty(self)) : onEmpty() +): B | C => isNonEmpty(self) ? onNonEmpty(headNonEmpty(self), tailNonEmpty(self)) : onEmpty()) /** * @category pattern matching * @since 1.0.0 */ -export const matchRight = ( +export const matchRight: { + ( + onEmpty: LazyArg, + onNonEmpty: (init: Array, last: A) => C + ): (self: ReadonlyArray) => B | C + ( + self: ReadonlyArray, + onEmpty: LazyArg, + onNonEmpty: (init: Array, last: A) => C + ): B | C +} = dual(3, ( + self: ReadonlyArray, onEmpty: LazyArg, onNonEmpty: (init: Array, last: A) => C -) => - (self: ReadonlyArray): B | C => - isNonEmpty(self) ? - onNonEmpty(initNonEmpty(self), lastNonEmpty(self)) : - onEmpty() +): B | C => + isNonEmpty(self) ? + onNonEmpty(initNonEmpty(self), lastNonEmpty(self)) : + onEmpty()) /** * Prepend an element to the front of an `Iterable`, creating a new `NonEmptyArray`. @@ -165,23 +217,27 @@ export const prepend: { /** * @since 1.0.0 */ -export const prependAll = (that: Iterable) => - (self: Iterable): Array => fromIterable(that).concat(fromIterable(self)) +export const prependAll: { + (that: Iterable): (self: Iterable) => Array + (self: Iterable, that: Iterable): Array +} = dual( + 2, + (self: Iterable, that: Iterable): Array => + fromIterable(that).concat(fromIterable(self)) +) /** * @since 1.0.0 */ -export function prependAllNonEmpty( - that: NonEmptyReadonlyArray -): (self: Iterable) => NonEmptyArray -export function prependAllNonEmpty( - that: Iterable -): (self: NonEmptyReadonlyArray) => NonEmptyArray -export function prependAllNonEmpty( - that: Iterable -): (self: NonEmptyReadonlyArray) => Array { - return prependAll(that) -} +export const prependAllNonEmpty: { + (that: NonEmptyReadonlyArray): (self: Iterable) => NonEmptyArray + (that: Iterable): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: Iterable, that: NonEmptyReadonlyArray): NonEmptyArray + (self: NonEmptyReadonlyArray, that: Iterable): NonEmptyArray +} = dual( + 2, + (self: Iterable, that: Iterable): Array => prependAll(self, that) +) /** * Append an element to the end of an `Iterable`, creating a new `NonEmptyArray`. @@ -191,67 +247,75 @@ export function prependAllNonEmpty( export const append: { (last: B): (self: Iterable) => NonEmptyArray (self: Iterable, last: B): NonEmptyArray -} = dual(2, (self: Iterable, last: B): NonEmptyArray => [...self, last] as any) +} = dual(2, (self: Iterable, last: B): Array => [...self, last]) /** * @since 1.0.0 */ -export const appendAll = (that: Iterable) => - (self: Iterable): Array => fromIterable(self).concat(fromIterable(that)) +export const appendAll: { + (that: Iterable): (self: Iterable) => Array + (self: Iterable, that: Iterable): Array +} = dual( + 2, + (self: Iterable, that: Iterable): Array => + fromIterable(self).concat(fromIterable(that)) +) /** * @since 1.0.0 */ -export function appendAllNonEmpty( - that: NonEmptyReadonlyArray -): (self: Iterable) => NonEmptyArray -export function appendAllNonEmpty( - that: Iterable -): (self: NonEmptyReadonlyArray) => NonEmptyArray -export function appendAllNonEmpty( - that: Iterable -): (self: NonEmptyReadonlyArray) => Array { - return appendAll(that) -} +export const appendAllNonEmpty: { + (that: NonEmptyReadonlyArray): (self: Iterable) => NonEmptyArray + (that: Iterable): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: Iterable, that: NonEmptyReadonlyArray): NonEmptyArray + (self: NonEmptyReadonlyArray, that: Iterable): NonEmptyArray +} = dual( + 2, + (self: Iterable, that: Iterable): Array => appendAll(self, that) +) /** - * Fold an `Iterable` from the left, keeping all intermediate results instead of only the final result. + * Reduce an `Iterable` from the left, keeping all intermediate results instead of only the final result. * * @category folding * @since 1.0.0 */ -export const scan = (b: B, f: (b: B, a: A) => B) => - (self: Iterable): NonEmptyArray => { - const out: NonEmptyArray = [b] - let i = 0 - for (const a of self) { - out[i + 1] = f(out[i], a) - i++ - } - return out +export const scan: { + (b: B, f: (b: B, a: A) => B): (self: Iterable) => NonEmptyArray + (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray +} = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray => { + const out: NonEmptyArray = [b] + let i = 0 + for (const a of self) { + out[i + 1] = f(out[i], a) + i++ } + return out +}) /** - * Fold an `Iterable` from the right, keeping all intermediate results instead of only the final result. + * Reduce an `Iterable` from the right, keeping all intermediate results instead of only the final result. * * @category folding * @since 1.0.0 */ -export const scanRight = (b: B, f: (b: B, a: A) => B) => - (self: Iterable): NonEmptyArray => { - const input = fromIterable(self) - const out: NonEmptyArray = new Array(input.length + 1) as any - out[input.length] = b - for (let i = input.length - 1; i >= 0; i--) { - out[i] = f(out[i + 1], input[i]) - } - return out +export const scanRight: { + (b: B, f: (b: B, a: A) => B): (self: Iterable) => NonEmptyArray + (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray +} = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): NonEmptyArray => { + const input = fromIterable(self) + const out: NonEmptyArray = new Array(input.length + 1) as any + out[input.length] = b + for (let i = input.length - 1; i >= 0; i--) { + out[i] = f(out[i + 1], input[i]) } + return out +}) /** * Test whether a `ReadonlyArray` is empty narrowing down the type to `[]`. * - * @category predicates + * @category guards * @since 1.0.0 */ export const isEmpty = (self: ReadonlyArray): self is readonly [] => self.length === 0 @@ -259,7 +323,7 @@ export const isEmpty = (self: ReadonlyArray): self is readonly [] => self. /** * Test whether a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyReadonlyArray`. * - * @category predicates + * @category guards * @since 1.0.0 */ export const isNonEmpty: (self: ReadonlyArray) => self is NonEmptyReadonlyArray = @@ -284,11 +348,30 @@ const clamp = (i: number, as: ReadonlyArray): number => * @category getters * @since 1.0.0 */ -export const get = (index: number) => - (self: ReadonlyArray): Option => { - const i = Math.floor(index) - return isOutOfBound(i, self) ? O.none() : O.some(self[i]) +export const get: { + (index: number): (self: ReadonlyArray) => Option + (self: ReadonlyArray, index: number): Option +} = dual(2, (self: ReadonlyArray, index: number): Option => { + const i = Math.floor(index) + return isOutOfBound(i, self) ? O.none() : O.some(self[i]) +}) + +/** + * Gets an element unsafely, will throw on out of bounds. + * + * @since 1.0.0 + * @category unsafe + */ +export const unsafeGet: { + (index: number): (self: ReadonlyArray) => A + (self: ReadonlyArray, index: number): A +} = dual(2, (self: ReadonlyArray, index: number): A => { + const i = Math.floor(index) + if (isOutOfBound(i, self)) { + throw new Error(`Index ${i} out of bounds`) } + return self[i] +}) /** * Return a tuple containing the first element, and a new `Array` of the remaining elements, if any. @@ -318,21 +401,6 @@ export const unappend = ( */ export const head: (self: ReadonlyArray) => Option = get(0) -/** - * Gets an element unsafely, will throw on out of bounds. - * - * @since 1.0.0 - * @category unsafe - */ -export const unsafeGet = (index: number) => - (self: ReadonlyArray): A => { - const i = Math.floor(index) - if (isOutOfBound(i, self)) { - throw new Error(`Index ${i} out of bounds`) - } - return self[i] - } - /** * @category getters * @since 1.0.0 @@ -352,7 +420,7 @@ export const last = (self: ReadonlyArray): Option => * @category getters * @since 1.0.0 */ -export const lastNonEmpty = (as: NonEmptyReadonlyArray): A => as[as.length - 1] +export const lastNonEmpty = (self: NonEmptyReadonlyArray): A => self[self.length - 1] /** * Get all but the first element of an `Iterable`, creating a new `Array`, or `None` if the `Iterable` is empty. @@ -398,11 +466,13 @@ export const initNonEmpty = (self: NonEmptyReadonlyArray): Array => sel * @category getters * @since 1.0.0 */ -export const take = (n: number) => - (self: Iterable): Array => { - const input = fromIterable(self) - return input.slice(0, clamp(n, input)) - } +export const take: { + (n: number): (self: Iterable) => Array + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + return input.slice(0, clamp(n, input)) +}) /** * Keep only a max number of elements from the end of an `Iterable`, creating a new `Array`. @@ -412,12 +482,14 @@ export const take = (n: number) => * @category getters * @since 1.0.0 */ -export const takeRight = (n: number) => - (self: Iterable): Array => { - const input = fromIterable(self) - const i = clamp(n, input) - return i === 0 ? [] : input.slice(-i) - } +export const takeRight: { + (n: number): (self: Iterable) => Array + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + const i = clamp(n, input) + return i === 0 ? [] : input.slice(-i) +}) /** * Calculate the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. @@ -425,26 +497,21 @@ export const takeRight = (n: number) => * @category getters * @since 1.0.0 */ -export function takeWhile( - refinement: Refinement -): (self: Iterable) => Array -export function takeWhile( - predicate: Predicate -): (self: Iterable) => Array -export function takeWhile( - predicate: Predicate -): (self: Iterable) => Array { - return (self: Iterable) => { - const out: Array = [] - for (const a of self) { - if (!predicate(a)) { - break - } - out.push(a) +export const takeWhile: { + (refinement: Refinement): (self: Iterable) => Array + (predicate: Predicate): (self: Iterable) => Array + (self: Iterable, refinement: Refinement): Array + (self: Iterable, predicate: Predicate): Array +} = dual(2, (self: Iterable, predicate: Predicate): Array => { + const out: Array = [] + for (const a of self) { + if (!predicate(a)) { + break } - return out + out.push(a) } -} + return out +}) const spanIndex = (self: Iterable, predicate: Predicate): number => { let i = 0 @@ -466,22 +533,21 @@ const spanIndex = (self: Iterable, predicate: Predicate): number => { * @category filtering * @since 1.0.0 */ -export function span( - refinement: Refinement -): (self: Iterable) => [init: Array, rest: Array] -export function span( - predicate: Predicate -): ( - self: Iterable -) => [init: Array, rest: Array] -export function span( - predicate: Predicate -): (self: Iterable) => [init: Array, rest: Array] -export function span( - predicate: Predicate -): (self: Iterable) => [init: Array, rest: Array] { - return (self) => splitAt(spanIndex(self, predicate))(self) -} +export const span: { + ( + refinement: Refinement + ): (self: Iterable) => [init: Array, rest: Array] + (predicate: Predicate): (self: Iterable) => [init: Array, rest: Array] + ( + self: Iterable, + refinement: Refinement + ): [init: Array, rest: Array] + (self: Iterable, predicate: Predicate): [init: Array, rest: Array] +} = dual( + 2, + (self: Iterable, predicate: Predicate): [init: Array, rest: Array] => + splitAt(self, spanIndex(self, predicate)) +) /** * Drop a max number of elements from the start of an `Iterable`, creating a new `Array`. @@ -491,11 +557,13 @@ export function span( * @category getters * @since 1.0.0 */ -export const drop = (n: number) => - (self: Iterable): Array => { - const input = fromIterable(self) - return input.slice(clamp(n, input), input.length) - } +export const drop: { + (n: number): (self: Iterable) => Array + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + return input.slice(clamp(n, input), input.length) +}) /** * Drop a max number of elements from the end of an `Iterable`, creating a new `Array`. @@ -505,11 +573,13 @@ export const drop = (n: number) => * @category getters * @since 1.0.0 */ -export const dropRight = (n: number) => - (self: Iterable): Array => { - const input = fromIterable(self) - return input.slice(0, input.length - clamp(n, input)) - } +export const dropRight: { + (n: number): (self: Iterable) => Array + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + return input.slice(0, input.length - clamp(n, input)) +}) /** * Remove the longest initial subarray for which all element satisfy the specified predicate, creating a new `Array`. @@ -517,20 +587,16 @@ export const dropRight = (n: number) => * @category getters * @since 1.0.0 */ -export function dropWhile( - refinement: Refinement -): (self: Iterable) => Array -export function dropWhile( - predicate: Predicate -): (self: Iterable) => Array -export function dropWhile( - predicate: Predicate -): (self: Iterable) => Array -export function dropWhile( - predicate: Predicate -): (self: Iterable) => Array { - return (self) => fromIterable(self).slice(spanIndex(self, predicate)) -} +export const dropWhile: { + (refinement: Refinement): (self: Iterable) => Array + (predicate: Predicate): (self: Iterable) => Array + (self: Iterable, refinement: Refinement): Array + (self: Iterable, predicate: Predicate): Array +} = dual( + 2, + (self: Iterable, predicate: Predicate): Array => + fromIterable(self).slice(spanIndex(self, predicate)) +) /** * Return the first index for which a predicate holds. @@ -538,17 +604,19 @@ export function dropWhile( * @category getters * @since 1.0.0 */ -export const findFirstIndex = (predicate: Predicate) => - (self: Iterable): Option => { - let i = 0 - for (const a of self) { - if (predicate(a)) { - return O.some(i) - } - i++ +export const findFirstIndex: { + (predicate: Predicate): (self: Iterable) => Option + (self: Iterable, predicate: Predicate): Option +} = dual(2, (self: Iterable, predicate: Predicate): Option => { + let i = 0 + for (const a of self) { + if (predicate(a)) { + return O.some(i) } - return O.none() + i++ } + return O.none() +}) /** * Return the last index for which a predicate holds. @@ -556,16 +624,18 @@ export const findFirstIndex = (predicate: Predicate) => * @category getters * @since 1.0.0 */ -export const findLastIndex = (predicate: Predicate) => - (self: Iterable): Option => { - const input = fromIterable(self) - for (let i = input.length - 1; i >= 0; i--) { - if (predicate(input[i])) { - return O.some(i) - } +export const findLastIndex: { + (predicate: Predicate): (self: Iterable) => Option + (self: Iterable, predicate: Predicate): Option +} = dual(2, (self: Iterable, predicate: Predicate): Option => { + const input = fromIterable(self) + for (let i = input.length - 1; i >= 0; i--) { + if (predicate(input[i])) { + return O.some(i) } - return O.none() } + return O.none() +}) /** * Find the first element for which a predicate holds. @@ -573,24 +643,20 @@ export const findLastIndex = (predicate: Predicate) => * @category getters * @since 1.0.0 */ -export function findFirst( - refinement: Refinement -): (self: Iterable) => Option -export function findFirst( - predicate: Predicate -): (self: Iterable) => Option -export function findFirst(predicate: Predicate): (self: Iterable) => Option -export function findFirst(predicate: Predicate): (self: Iterable) => Option { - return (self) => { - const input = fromIterable(self) - for (let i = 0; i < input.length; i++) { - if (predicate(input[i])) { - return O.some(input[i]) - } +export const findFirst: { + (refinement: Refinement): (self: Iterable) => Option + (predicate: Predicate): (self: Iterable) => Option + (self: Iterable, refinement: Refinement): Option + (self: Iterable, predicate: Predicate): Option +} = dual(2, (self: Iterable, predicate: Predicate): Option => { + const input = fromIterable(self) + for (let i = 0; i < input.length; i++) { + if (predicate(input[i])) { + return O.some(input[i]) } - return O.none() } -} + return O.none() +}) /** * Find the last element for which a predicate holds. @@ -598,24 +664,20 @@ export function findFirst(predicate: Predicate): (self: Iterable) => Op * @category getters * @since 1.0.0 */ -export function findLast( - refinement: Refinement -): (self: Iterable) => Option -export function findLast( - predicate: Predicate -): (self: Iterable) => Option -export function findLast(predicate: Predicate): (self: Iterable) => Option -export function findLast(predicate: Predicate): (self: Iterable) => Option { - return (self) => { - const input = fromIterable(self) - for (let i = input.length - 1; i >= 0; i--) { - if (predicate(input[i])) { - return O.some(input[i]) - } +export const findLast: { + (refinement: Refinement): (self: Iterable) => Option + (predicate: Predicate): (self: Iterable) => Option + (self: Iterable, refinement: Refinement): Option + (self: Iterable, predicate: Predicate): Option +} = dual(2, (self: Iterable, predicate: Predicate): Option => { + const input = fromIterable(self) + for (let i = input.length - 1; i >= 0; i--) { + if (predicate(input[i])) { + return O.some(input[i]) } - return O.none() } -} + return O.none() +}) /** * Insert an element at the specified index, creating a new `NonEmptyArray`, @@ -623,16 +685,18 @@ export function findLast(predicate: Predicate): (self: Iterable) => Opt * * @since 1.0.0 */ -export const insertAt = (i: number, b: B) => - (self: Iterable): Option> => { - const out: Array = Array.from(self) - // v--- `= self.length` ok, it means inserting in last position - if (i < 0 || i > out.length) { - return O.none() - } - out.splice(i, 0, b) - return O.some(out) as any +export const insertAt: { + (i: number, b: B): (self: Iterable) => Option> + (self: Iterable, i: number, b: B): Option> +} = dual(3, (self: Iterable, i: number, b: B): Option> => { + const out: Array = Array.from(self) + // v--- `= self.length` is ok, it means inserting in last position + if (i < 0 || i > out.length) { + return O.none() } + out.splice(i, 0, b) + return O.some(out) as any +}) /** * Change the element at the specified index, creating a new `Array`, @@ -640,18 +704,21 @@ export const insertAt = (i: number, b: B) => * * @since 1.0.0 */ -export const replace = ( - i: number, - b: B -): ((self: Iterable) => Array) => modify(i, () => b) +export const replace: { + (i: number, b: B): (self: Iterable) => Array + (self: Iterable, i: number, b: B): Array +} = dual(3, (self: Iterable, i: number, b: B): Array => modify(self, i, () => b)) /** * @since 1.0.0 */ -export const replaceOption = ( - i: number, - b: B -): ((self: Iterable) => Option>) => modifyOption(i, () => b) +export const replaceOption: { + (i: number, b: B): (self: Iterable) => Option> + (self: Iterable, i: number, b: B): Option> +} = dual( + 3, + (self: Iterable, i: number, b: B): Option> => modifyOption(self, i, () => b) +) /** * Apply a function to the element at the specified index, creating a new `Array`, @@ -659,8 +726,14 @@ export const replaceOption = ( * * @since 1.0.0 */ -export const modify = (i: number, f: (a: A) => B) => - (self: Iterable): Array => O.getOrElse(modifyOption(self, i, f), () => Array.from(self)) +export const modify: { + (i: number, f: (a: A) => B): (self: Iterable) => Array + (self: Iterable, i: number, f: (a: A) => B): Array +} = dual( + 3, + (self: Iterable, i: number, f: (a: A) => B): Array => + O.getOrElse(modifyOption(self, i, f), () => Array.from(self)) +) /** * Apply a function to the element at the specified index, creating a new `Array`, @@ -688,24 +761,24 @@ export const modifyOption: { * * @since 1.0.0 */ -export const remove = (i: number) => - (self: Iterable): Array => { - const out = Array.from(self) - if (isOutOfBound(i, out)) { - return out - } - out.splice(i, 1) +export const remove: { + (i: number): (self: Iterable) => Array + (self: Iterable, i: number): Array +} = dual(2, (self: Iterable, i: number): Array => { + const out = Array.from(self) + if (isOutOfBound(i, out)) { return out } + out.splice(i, 1) + return out +}) /** * Reverse an `Iterable`, creating a new `Array`. * * @since 1.0.0 */ -export const reverse = ( - self: Iterable -): Array => Array.from(self).reverse() +export const reverse = (self: Iterable): Array => Array.from(self).reverse() /** * @since 1.0.0 @@ -720,15 +793,7 @@ export const reverseNonEmpty = ( * @category getters * @since 1.0.0 */ -export const rights = (self: Iterable>): Array => { - const out: Array = [] - for (const a of self) { - if (E.isRight(a)) { - out.push(a.right) - } - } - return out -} +export const rights: (self: Iterable>) => Array = E.rights /** * Return all the `Left` elements from an `Interable` of `Either`s. @@ -736,15 +801,7 @@ export const rights = (self: Iterable>): Array => { * @category getters * @since 1.0.0 */ -export const lefts = (self: Iterable>): Array => { - const out: Array = [] - for (const a of self) { - if (E.isLeft(a)) { - out.push(a.left) - } - } - return out -} +export const lefts: (self: Iterable>) => Array = E.lefts /** * Sort the elements of an `Iterable` in increasing order, creating a new `Array`. @@ -797,8 +854,14 @@ export const sortByNonEmpty = ( * * @since 1.0.0 */ -export const zip = (that: Iterable): (self: Iterable) => Array<[A, B]> => - zipWith(that, (a, b) => [a, b]) +export const zip: { + (that: Iterable): (self: Iterable) => Array<[A, B]> + (self: Iterable, that: Iterable): Array<[A, B]> +} = dual( + 2, + (self: Iterable, that: Iterable): Array<[A, B]> => + zipWith(self, that, (a, b) => [a, b]) +) /** * Apply a function to pairs of elements at the same index in two `Iterable`s, collecting the results in a new `Array`. If one @@ -806,19 +869,26 @@ export const zip = (that: Iterable): (self: Iterable) => Array<[A, B * * @since 1.0.0 */ -export const zipWith = (that: Iterable, f: (a: A, b: B) => C) => - (self: Iterable): Array => { - const as = fromIterable(self) - const bs = fromIterable(that) - return isNonEmpty(as) && isNonEmpty(bs) ? zipNonEmptyWith(bs, f)(as) : [] - } +export const zipWith: { + (that: Iterable, f: (a: A, b: B) => C): (self: Iterable) => Array + (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Array +} = dual(3, (self: Iterable, that: Iterable, f: (a: A, b: B) => C): Array => { + const as = fromIterable(self) + const bs = fromIterable(that) + return isNonEmpty(as) && isNonEmpty(bs) ? zipNonEmptyWith(bs, f)(as) : [] +}) /** * @since 1.0.0 */ -export const zipNonEmpty = (that: NonEmptyReadonlyArray) => - (self: NonEmptyReadonlyArray): NonEmptyArray<[A, B]> => +export const zipNonEmpty: { + (that: NonEmptyReadonlyArray): (self: NonEmptyReadonlyArray) => NonEmptyArray<[A, B]> + (self: NonEmptyReadonlyArray, that: NonEmptyReadonlyArray): NonEmptyArray<[A, B]> +} = dual( + 2, + (self: NonEmptyReadonlyArray, that: NonEmptyReadonlyArray): NonEmptyArray<[A, B]> => zipNonEmptyWith(self, that, (a, b) => [a, b]) +) /** * @since 1.0.0 @@ -876,97 +946,126 @@ export const unzipNonEmpty = ( * * @since 1.0.0 */ -export const intersperse = (middle: B) => - (self: Iterable): Array => { - const input = fromIterable(self) - return (isNonEmpty(input) ? intersperseNonEmpty(middle)(input) : []) - } +export const intersperse: { + (middle: B): (self: Iterable) => Array + (self: Iterable, middle: B): Array +} = dual(2, (self: Iterable, middle: B): Array => { + const input = fromIterable(self) + return (isNonEmpty(input) ? intersperseNonEmpty(input, middle) : []) +}) /** * Places an element in between members of a `NonEmptyReadonlyArray` * * @since 1.0.0 */ -export const intersperseNonEmpty = (middle: B) => - (self: NonEmptyReadonlyArray): NonEmptyArray => { - const out: NonEmptyArray = [headNonEmpty(self)] - const tail = tailNonEmpty(self) - for (let i = 0; i < tail.length; i++) { - if (i < tail.length) { - out.push(middle) - } - out.push(tail[i]) +export const intersperseNonEmpty: { + (middle: B): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: NonEmptyReadonlyArray, middle: B): NonEmptyArray +} = dual(2, (self: NonEmptyReadonlyArray, middle: B): NonEmptyArray => { + const out: NonEmptyArray = [headNonEmpty(self)] + const tail = tailNonEmpty(self) + for (let i = 0; i < tail.length; i++) { + if (i < tail.length) { + out.push(middle) } - return out + out.push(tail[i]) } + return out +}) /** * Apply a function to the head, creating a new `NonEmptyReadonlyArray`. * * @since 1.0.0 */ -export const modifyNonEmptyHead = (f: (a: A) => B) => - ( - self: NonEmptyReadonlyArray +export const modifyNonEmptyHead: { + (f: (a: A) => B): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray +} = dual( + 2, + ( + self: NonEmptyReadonlyArray, + f: (a: A) => B ): NonEmptyArray => [f(headNonEmpty(self)), ...tailNonEmpty(self)] +) /** * Change the head, creating a new `NonEmptyReadonlyArray`. * * @since 1.0.0 */ -export const setNonEmptyHead = ( - b: B -): ((self: NonEmptyReadonlyArray) => NonEmptyArray) => modifyNonEmptyHead(() => b) +export const setNonEmptyHead: { + (b: B): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: NonEmptyReadonlyArray, b: B): NonEmptyArray +} = dual( + 2, + (self: NonEmptyReadonlyArray, b: B): NonEmptyArray => + modifyNonEmptyHead(self, () => b) +) /** * Apply a function to the last element, creating a new `NonEmptyReadonlyArray`. * * @since 1.0.0 */ -export const modifyNonEmptyLast = (f: (a: A) => B) => - (self: NonEmptyReadonlyArray): NonEmptyArray => +export const modifyNonEmptyLast: { + (f: (a: A) => B): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray +} = dual( + 2, + (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray => append(initNonEmpty(self), f(lastNonEmpty(self))) +) /** * Change the last element, creating a new `NonEmptyReadonlyArray`. * * @since 1.0.0 */ -export const setNonEmptyLast = ( - b: B -): ((self: NonEmptyReadonlyArray) => NonEmptyArray) => modifyNonEmptyLast(() => b) +export const setNonEmptyLast: { + (b: B): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: NonEmptyReadonlyArray, b: B): NonEmptyArray +} = dual( + 2, + (self: NonEmptyReadonlyArray, b: B): NonEmptyArray => + modifyNonEmptyLast(self, () => b) +) /** * Rotate an `Iterable` by `n` steps. * * @since 1.0.0 */ -export const rotate = (n: number) => - (self: Iterable): Array => { - const input = fromIterable(self) - return isNonEmpty(input) ? rotateNonEmpty(n)(input) : [] - } +export const rotate: { + (n: number): (self: Iterable) => Array + (self: Iterable, n: number): Array +} = dual(2, (self: Iterable, n: number): Array => { + const input = fromIterable(self) + return isNonEmpty(input) ? rotateNonEmpty(input, n) : [] +}) /** * Rotate a `NonEmptyReadonlyArray` by `n` steps. * * @since 1.0.0 */ -export const rotateNonEmpty = (n: number) => - (self: NonEmptyReadonlyArray): NonEmptyArray => { - const len = self.length - const m = Math.round(n) % len - if (isOutOfBound(Math.abs(m), self) || m === 0) { - return copy(self) - } - if (m < 0) { - const [f, s] = splitNonEmptyAt(-m)(self) - return appendAllNonEmpty(f)(s) - } else { - return rotateNonEmpty(m - len)(self) - } +export const rotateNonEmpty: { + (n: number): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: NonEmptyReadonlyArray, n: number): NonEmptyArray +} = dual(2, (self: NonEmptyReadonlyArray, n: number): NonEmptyArray => { + const len = self.length + const m = Math.round(n) % len + if (isOutOfBound(Math.abs(m), self) || m === 0) { + return copy(self) + } + if (m < 0) { + const [f, s] = splitNonEmptyAt(self, -m) + return appendAllNonEmpty(s, f) + } else { + return rotateNonEmpty(self, m - len) } +}) /** * Returns a function that checks if a `ReadonlyArray` contains a given value using a provided `equivalence` function. @@ -974,16 +1073,18 @@ export const rotateNonEmpty = (n: number) => * @category predicates * @since 1.0.0 */ -export const contains = (equivalence: Equivalence) => - (a: A) => - (self: Iterable): boolean => { - for (const i of self) { - if (equivalence(a, i)) { - return true - } +export const contains = (equivalence: Equivalence): { + (a: A): (self: Iterable) => boolean + (self: Iterable, a: A): boolean +} => + dual(2, (self: Iterable, a: A): boolean => { + for (const i of self) { + if (equivalence(a, i)) { + return true } - return false } + return false + }) /** * Remove duplicates from am `Iterable`, keeping the first occurrence of an element. @@ -1020,13 +1121,21 @@ export const uniqNonEmpty = (equivalence: Equivalence) => * * @since 1.0.0 */ -export const chop = ( +export const chop: { + ( + f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] + ): (self: Iterable) => Array + ( + self: Iterable, + f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] + ): Array +} = dual(2, ( + self: Iterable, f: (as: NonEmptyReadonlyArray) => readonly [B, ReadonlyArray] -) => - (self: Iterable): Array => { - const input = fromIterable(self) - return isNonEmpty(input) ? chopNonEmpty(f)(input) : [] - } +): Array => { + const input = fromIterable(self) + return isNonEmpty(input) ? chopNonEmpty(input, f) : [] +}) /** * A useful recursion pattern for processing a `NonEmptyReadonlyArray` to produce a new `NonEmptyReadonlyArray`, often used for "chopping" up the input @@ -1064,24 +1173,25 @@ export const chopNonEmpty: { * @category getters * @since 1.0.0 */ -export const splitAt = (n: number) => - (self: Iterable): [Array, Array] => { - const input = Array.from(self) - return n >= 1 && isNonEmpty(input) ? - splitNonEmptyAt(n)(input) : - isEmpty(input) ? - [input, []] : - [[], input] - } +export const splitAt: { + (n: number): (self: Iterable) => [Array, Array] + (self: Iterable, n: number): [Array, Array] +} = dual(2, (self: Iterable, n: number): [Array, Array] => { + const input = Array.from(self) + return n >= 1 && isNonEmpty(input) ? + splitNonEmptyAt(input, n) : + isEmpty(input) ? + [input, []] : + [[], input] +}) /** * @since 1.0.0 */ -export function copy(self: NonEmptyReadonlyArray): NonEmptyArray -export function copy(self: ReadonlyArray): Array -export function copy(self: ReadonlyArray): Array { - return self.slice() -} +export const copy: { + (self: NonEmptyReadonlyArray): NonEmptyArray + (self: ReadonlyArray): Array +} = ((self: ReadonlyArray): Array => self.slice()) as any /** * Splits a `NonEmptyReadonlyArray` into two pieces, the first piece has max `n` elements. @@ -1089,13 +1199,15 @@ export function copy(self: ReadonlyArray): Array { * @category getters * @since 1.0.0 */ -export const splitNonEmptyAt = (n: number) => - (self: NonEmptyReadonlyArray): [NonEmptyArray, Array] => { - const m = Math.max(1, n) - return m >= self.length ? - [copy(self), []] : - [prepend(self.slice(1, m), headNonEmpty(self)), self.slice(m)] - } +export const splitNonEmptyAt: { + (n: number): (self: NonEmptyReadonlyArray) => [NonEmptyArray, Array] + (self: NonEmptyReadonlyArray, n: number): [NonEmptyArray, Array] +} = dual(2, (self: NonEmptyReadonlyArray, n: number): [NonEmptyArray, Array] => { + const m = Math.max(1, n) + return m >= self.length ? + [copy(self), []] : + [prepend(self.slice(1, m), headNonEmpty(self)), self.slice(m)] +}) /** * Splits an `Iterable` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of @@ -1111,11 +1223,13 @@ export const splitNonEmptyAt = (n: number) => * @category getters * @since 1.0.0 */ -export const chunksOf = (n: number) => - (self: Iterable): Array> => { - const input = fromIterable(self) - return isNonEmpty(input) ? chunksOfNonEmpty(n)(input) : [] - } +export const chunksOf: { + (n: number): (self: Iterable) => Array> + (self: Iterable, n: number): Array> +} = dual(2, (self: Iterable, n: number): Array> => { + const input = fromIterable(self) + return isNonEmpty(input) ? chunksOfNonEmpty(input, n) : [] +}) /** * Splits a `NonEmptyReadonlyArray` into length-`n` pieces. The last piece will be shorter if `n` does not evenly divide the length of @@ -1124,10 +1238,14 @@ export const chunksOf = (n: number) => * @category getters * @since 1.0.0 */ -export const chunksOfNonEmpty = ( - n: number -): ((self: NonEmptyReadonlyArray) => NonEmptyArray>) => - chopNonEmpty(splitNonEmptyAt(n)) +export const chunksOfNonEmpty: { + (n: number): (self: NonEmptyReadonlyArray) => NonEmptyArray> + (self: NonEmptyReadonlyArray, n: number): NonEmptyArray> +} = dual( + 2, + (self: NonEmptyReadonlyArray, n: number): NonEmptyArray> => + chopNonEmpty(self, splitNonEmptyAt(n)) +) /** * Group equal, consecutive elements of a `NonEmptyReadonlyArray` into `NonEmptyArray`s. @@ -1159,19 +1277,21 @@ export const group = (equivalence: Equivalence) => * @category grouping * @since 1.0.0 */ -export const groupBy = (f: (a: A) => string) => - (self: Iterable): Record> => { - const out: Record> = {} - for (const a of self) { - const k = f(a) - if (Object.prototype.hasOwnProperty.call(out, k)) { - out[k].push(a) - } else { - out[k] = [a] - } +export const groupBy: { + (f: (a: A) => string): (self: Iterable) => Record> + (self: Iterable, f: (a: A) => string): Record> +} = dual(2, (self: Iterable, f: (a: A) => string): Record> => { + const out: Record> = {} + for (const a of self) { + const k = f(a) + if (Object.prototype.hasOwnProperty.call(out, k)) { + out[k].push(a) + } else { + out[k] = [a] } - return out } + return out +}) /** * @since 1.0.0 @@ -1196,11 +1316,14 @@ export const union = (equivalence: Equivalence): { export const unionNonEmpty = (equivalence: Equivalence): { (that: NonEmptyReadonlyArray): (self: ReadonlyArray) => NonEmptyArray (that: ReadonlyArray): (self: NonEmptyReadonlyArray) => NonEmptyArray + (self: ReadonlyArray, that: NonEmptyReadonlyArray): NonEmptyArray + (self: NonEmptyReadonlyArray, that: ReadonlyArray): NonEmptyArray } => - // @ts-expect-error - (that: ReadonlyArray) => - (self: NonEmptyReadonlyArray): NonEmptyArray => - uniqNonEmpty(equivalence)(appendAllNonEmpty(that)(self)) + dual( + 2, + (self: NonEmptyReadonlyArray, that: ReadonlyArray): NonEmptyArray => + uniqNonEmpty(equivalence)(appendAllNonEmpty(self, that)) + ) /** * Creates an `Array` of unique values that are included in all given `Iterable`s. @@ -1211,12 +1334,14 @@ export const unionNonEmpty = (equivalence: Equivalence): { export const intersection = (equivalence: Equivalence): { (that: Iterable): (self: Iterable) => Array (self: Iterable, that: Iterable): Array -} => - dual( +} => { + const has = contains(equivalence) + return dual( 2, (self: Iterable, that: Iterable): Array => - fromIterable(self).filter((a) => contains(equivalence)(a)(that)) + fromIterable(self).filter((a) => has(that, a)) ) +} /** * Creates a `Array` of values not included in the other given `Iterable`. @@ -1224,10 +1349,17 @@ export const intersection = (equivalence: Equivalence): { * * @since 1.0.0 */ -export const difference = (equivalence: Equivalence) => - (that: Iterable) => - (self: Iterable): Array => - fromIterable(self).filter((a) => !contains(equivalence)(a)(that)) +export const difference = (equivalence: Equivalence): { + (that: Iterable): (self: Iterable) => Array + (self: Iterable, that: Iterable): Array +} => { + const has = contains(equivalence) + return dual( + 2, + (self: Iterable, that: Iterable): Array => + fromIterable(self).filter((a) => !has(that, a)) + ) +} /** * @category constructors @@ -1258,9 +1390,13 @@ export const mapNonEmpty: { * @category mapping * @since 1.0.0 */ -export const mapWithIndex = ( - f: (a: A, i: number) => B -) => (self: ReadonlyArray): Array => self.map((a, i) => f(a, i)) +export const mapWithIndex: { + (f: (a: A, i: number) => B): (self: ReadonlyArray) => Array + (self: ReadonlyArray, f: (a: A, i: number) => B): Array +} = dual( + 2, + (self: ReadonlyArray, f: (a: A, i: number) => B): Array => self.map((a, i) => f(a, i)) +) /** * @category mapping @@ -1285,12 +1421,6 @@ export const Of: of_.Of = { of } -/** - * @category do notation - * @since 1.0.0 - */ -export const Do: ReadonlyArray<{}> = of_.Do(Of) - /** * @category instances * @since 1.0.0 @@ -1326,30 +1456,6 @@ export const Invariant: invariant.Invariant = { export const tupled: (self: ReadonlyArray) => Array<[A]> = invariant .tupled(Invariant) as any -/** - * @category do notation - * @since 1.0.0 - */ -export const bindTo: ( - name: N -) => (self: ReadonlyArray) => Array<{ [K in N]: A }> = invariant - .bindTo(Invariant) as any - -const let_: ( - name: Exclude, - f: (a: A) => B -) => ( - self: ReadonlyArray -) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant.let(Covariant) as any - -export { - /** - * @category do notation - * @since 1.0.0 - */ - let_ as let -} - /** * @category mapping * @since 1.0.0 @@ -1415,22 +1521,41 @@ export const flatMap: { * @category sequencing * @since 1.0.0 */ -export const flatMapNonEmptyWithIndex = (f: (a: A, i: number) => NonEmptyReadonlyArray) => - (self: NonEmptyReadonlyArray): NonEmptyArray => { - const out: NonEmptyArray = copy(f(headNonEmpty(self), 0)) - for (let i = 1; i < self.length; i++) { - out.push(...f(self[i], i)) - } - return out +export const flatMapNonEmptyWithIndex: { + ( + f: (a: A, i: number) => NonEmptyReadonlyArray + ): (self: NonEmptyReadonlyArray) => NonEmptyArray + ( + self: NonEmptyReadonlyArray, + f: (a: A, i: number) => NonEmptyReadonlyArray + ): NonEmptyArray +} = dual(2, ( + self: NonEmptyReadonlyArray, + f: (a: A, i: number) => NonEmptyReadonlyArray +): NonEmptyArray => { + const out: NonEmptyArray = copy(f(headNonEmpty(self), 0)) + for (let i = 1; i < self.length; i++) { + out.push(...f(self[i], i)) } + return out +}) /** * @category sequencing * @since 1.0.0 */ -export const flatMapNonEmpty: ( +export const flatMapNonEmpty: { + ( + f: (a: A) => NonEmptyReadonlyArray + ): (self: NonEmptyReadonlyArray) => NonEmptyArray + ( + self: NonEmptyReadonlyArray, + f: (a: A) => NonEmptyReadonlyArray + ): NonEmptyArray +} = dual(2, ( + self: NonEmptyReadonlyArray, f: (a: A) => NonEmptyReadonlyArray -) => (self: NonEmptyReadonlyArray) => NonEmptyArray = (f) => flatMapNonEmptyWithIndex(f) +): NonEmptyArray => flatMapNonEmptyWithIndex(self, f)) /** * @category instances @@ -1478,17 +1603,6 @@ export const Chainable: chainable.Chainable = { flatMap } -/** - * @category do notation - * @since 1.0.0 - */ -export const bind: ( - name: Exclude, - f: (a: A) => ReadonlyArray -) => ( - self: ReadonlyArray -) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable.bind(Chainable) as any - /** * @category filtering * @since 1.0.0 @@ -1559,52 +1673,66 @@ export const Compactable: compactable.Compactable = { compact } -// TODO: input as iterables /** * @category filtering * @since 1.0.0 */ -export const filter: { +export const filterWithIndex: { ( - self: ReadonlyArray, - refinement: (a: A) => a is B - ): Array - (self: ReadonlyArray, predicate: (a: A) => boolean): Array + refinement: (a: A, i: number) => a is B + ): (self: Iterable) => Array + (predicate: (a: A, i: number) => boolean): (self: Iterable) => Array ( - refinement: (a: A) => a is B - ): (self: ReadonlyArray) => Array - (predicate: (a: A) => boolean): (self: ReadonlyArray) => Array -} = filterable.filter(Filterable) as any + self: Iterable, + refinement: (a: A, i: number) => a is B + ): Array + (self: Iterable, predicate: (a: A, i: number) => boolean): Array +} = dual( + 2, + (self: Iterable, predicate: (a: A, i: number) => boolean): Array => + filterMapWithIndex(self, (b, i) => (predicate(b, i) ? O.some(b) : O.none())) +) /** * @category filtering * @since 1.0.0 */ -export const filterWithIndex: { +export const filter: { ( - refinement: (a: A, i: number) => a is B - ): (self: ReadonlyArray) => Array - ( - predicate: (a: A, i: number) => boolean - ): (self: ReadonlyArray) => Array -} = ( - predicate: (a: A, i: number) => boolean -): ((self: ReadonlyArray) => Array) => - filterMapWithIndex((b, i) => (predicate(b, i) ? O.some(b) : O.none())) + refinement: (a: A) => a is B + ): (self: Iterable) => Array + (predicate: (a: A) => boolean): (self: Iterable) => Array + ( + self: Iterable, + refinement: (a: A) => a is B + ): Array +} = dual( + 2, + (self: Iterable, predicate: (a: A) => boolean): Array => + filterWithIndex(self, predicate) +) -// TODO: input as iterables /** * @category filtering * @since 1.0.0 */ export const partition: { (refinement: Refinement): ( - self: ReadonlyArray + self: Iterable ) => [Array, Array] ( predicate: Predicate - ): (self: ReadonlyArray) => [Array, Array] -} = filterable.partition(Filterable) as any + ): (self: Iterable) => [Array, Array] + ( + self: Iterable, + refinement: Refinement + ): [Array, Array] + (self: Iterable, predicate: Predicate): [Array, Array] +} = dual( + 2, + (self: Iterable, predicate: Predicate): [Array, Array] => + partitionWithIndex(self, predicate) +) /** * @category filtering @@ -1612,34 +1740,53 @@ export const partition: { */ export const partitionWithIndex: { (refinement: (a: A, i: number) => a is B): ( - self: ReadonlyArray + self: Iterable ) => [Array, Array] (predicate: (a: A, i: number) => boolean): ( - self: ReadonlyArray + self: Iterable ) => [Array, Array] -} = ( + ( + self: Iterable, + refinement: (a: A, i: number) => a is B + ): [Array, Array] + ( + self: Iterable, + predicate: (a: A, i: number) => boolean + ): [Array, Array] +} = dual(2, ( + self: Iterable, predicate: (a: A, i: number) => boolean -): ((self: ReadonlyArray) => [Array, Array]) => - partitionMapWithIndex((b, i) => (predicate(b, i) ? E.right(b) : E.left(b))) +): [Array, Array] => + partitionMapWithIndex(self, (b, i) => (predicate(b, i) ? E.right(b) : E.left(b)))) /** * @category filtering * @since 1.0.0 */ -export const partitionMap: ( - f: (a: A) => Either -) => (self: ReadonlyArray) => [Array, Array] = (f) => partitionMapWithIndex(f) +export const partitionMap: { + (f: (a: A) => Either): (self: Iterable) => [Array, Array] + (self: Iterable, f: (a: A) => Either): [Array, Array] +} = dual( + 2, + (self: Iterable, f: (a: A) => Either): [Array, Array] => + partitionMapWithIndex(self, f) +) /** * @category filtering * @since 1.0.0 */ -export const partitionMapWithIndex = (f: (a: A, i: number) => Either) => - (self: ReadonlyArray): [Array, Array] => { +export const partitionMapWithIndex: { + (f: (a: A, i: number) => Either): (self: Iterable) => [Array, Array] + (self: Iterable, f: (a: A, i: number) => Either): [Array, Array] +} = dual( + 2, + (self: Iterable, f: (a: A, i: number) => Either): [Array, Array] => { const left: Array = [] const right: Array = [] - for (let i = 0; i < self.length; i++) { - const e = f(self[i], i) + const as = fromIterable(self) + for (let i = 0; i < as.length; i++) { + const e = f(as[i], i) if (E.isLeft(e)) { left.push(e.left) } else { @@ -1648,14 +1795,25 @@ export const partitionMapWithIndex = (f: (a: A, i: number) => Either(F: applicative.Applicative) => - (f: (a: A, i: number) => Kind) => - (self: ReadonlyArray): Kind> => F.productAll(self.map(f)) +export const traverseWithIndex = (F: applicative.Applicative): { + ( + f: (a: A, i: number) => Kind + ): (self: Iterable) => Kind> + ( + self: Iterable, + f: (a: A, i: number) => Kind + ): Kind> +} => + dual(2, ( + self: Iterable, + f: (a: A, i: number) => Kind + ): Kind> => F.productAll(fromIterable(self).map(f))) /** * @category traversing @@ -1663,11 +1821,19 @@ export const traverseWithIndex = (F: applicative.Applicati */ export const traverseNonEmpty = ( F: semiApplicative.SemiApplicative -) => +): { + ( + f: (a: A) => Kind + ): (self: NonEmptyReadonlyArray) => Kind> ( + self: NonEmptyReadonlyArray, + f: (a: A) => Kind + ): Kind> +} => + dual(2, ( + self: NonEmptyReadonlyArray, f: (a: A) => Kind - ): ((self: NonEmptyReadonlyArray) => Kind>) => - traverseNonEmptyWithIndex(F)(f) + ): Kind> => traverseNonEmptyWithIndex(F)(self, f)) /** * @category traversing @@ -1675,12 +1841,22 @@ export const traverseNonEmpty = ( */ export const traverseNonEmptyWithIndex = ( F: semiApplicative.SemiApplicative -) => - (f: (a: A, i: number) => Kind) => - (self: NonEmptyReadonlyArray): Kind> => { - const [head, ...tail] = mapNonEmptyWithIndex(self, f) - return F.productMany(head, tail) - } +): { + ( + f: (a: A, i: number) => Kind + ): (self: NonEmptyReadonlyArray) => Kind> + ( + self: NonEmptyReadonlyArray, + f: (a: A, i: number) => Kind + ): Kind> +} => + dual(2, ( + self: NonEmptyReadonlyArray, + f: (a: A, i: number) => Kind + ): Kind> => { + const [head, ...tail] = mapNonEmptyWithIndex(self, f) + return F.productMany(head, tail) + }) /** * @category instances @@ -1768,20 +1944,6 @@ export const SemiProduct: semiProduct.SemiProduct = sem return out }) -/** - * A variant of `bind` that sequentially ignores the scope. - * - * @category do notation - * @since 1.0.0 - */ -export const andThenBind: ( - name: Exclude, - that: ReadonlyArray -) => ( - self: ReadonlyArray -) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct - .andThenBind(SemiProduct) as any - /** * @category instances * @since 1.0.0 @@ -1866,89 +2028,144 @@ export const Monad: monad.Monad = { * @category folding * @since 1.0.0 */ -export const reduceWithIndex = (b: B, f: (b: B, a: A, i: number) => B) => - (self: ReadonlyArray): B => self.reduce((b, a, i) => f(b, a, i), b) +export const reduceWithIndex: { + (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B +} = dual( + 3, + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B => + fromIterable(self).reduce((b, a, i) => f(b, a, i), b) +) /** * @category folding * @since 1.0.0 */ -export const reduceRight = (b: B, f: (b: B, a: A) => B) => - (self: ReadonlyArray): B => self.reduceRight((b, a) => f(b, a), b) +export const reduceRight: { + (b: B, f: (b: B, a: A) => B): (self: Iterable) => B + (self: Iterable, b: B, f: (b: B, a: A) => B): B +} = dual( + 3, + (self: Iterable, b: B, f: (b: B, a: A) => B): B => reduceRightWithIndex(self, b, f) +) /** * @category folding * @since 1.0.0 */ -export const reduceRightWithIndex = (b: B, f: (b: B, a: A, i: number) => B) => - (self: ReadonlyArray): B => self.reduceRight((b, a, i) => f(b, a, i), b) +export const reduceRightWithIndex: { + (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B +} = dual( + 3, + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B => + fromIterable(self).reduceRight((b, a, i) => f(b, a, i), b) +) /** * @category instances * @since 1.0.0 */ -export const Foldable: foldable.Foldable = foldable.make((self, b, f) => - self.reduce((b, a) => f(b, a), b) -) +export const Foldable: foldable.Foldable = foldable.make(reduceWithIndex) /** * @category folding * @since 1.0.0 */ export const reduce: { - (b: B, f: (b: B, a: A) => B): (self: ReadonlyArray) => B - (self: ReadonlyArray, b: B, f: (b: B, a: A) => B): B -} = Foldable.reduce + (b: B, f: (b: B, a: A) => B): (self: Iterable) => B + (self: Iterable, b: B, f: (b: B, a: A) => B): B +} = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): B => reduceWithIndex(self, b, f)) /** * @category folding * @since 1.0.0 */ -export const combineMapWithIndex = (Monoid: Monoid) => - (f: (a: A, i: number) => M) => - (self: ReadonlyArray): M => - self.reduce((m, a, i) => Monoid.combine(m, f(a, i)), Monoid.empty) +export const combineMapWithIndex = (Monoid: Monoid): { + (f: (a: A, i: number) => M): (self: Iterable) => M + (self: Iterable, f: (a: A, i: number) => M): M +} => + dual( + 2, + (self: Iterable, f: (a: A, i: number) => M): M => + fromIterable(self).reduce((m, a, i) => Monoid.combine(m, f(a, i)), Monoid.empty) + ) /** * @category folding * @since 1.0.0 */ -export const combineMap = (M: Monoid) => - (f: (a: A) => M) => - (self: ReadonlyArray): M => self.reduce((m, a) => M.combine(m, f(a)), M.empty) +export const combineMap = (M: Monoid): { + (f: (a: A) => M): (self: Iterable) => M + (self: Iterable, f: (a: A) => M): M +} => + dual( + 2, + (self: Iterable, f: (a: A) => M): M => + fromIterable(self).reduce((m, a) => M.combine(m, f(a)), M.empty) + ) /** * @category folding * @since 1.0.0 */ -export const combineMapNonEmpty = (S: Semigroup) => - (f: (a: A) => S): (self: NonEmptyReadonlyArray) => S => combineMapNonEmptyWithIndex(S)(f) +export const combineMapNonEmpty = (S: Semigroup): { + (f: (a: A) => S): (self: NonEmptyReadonlyArray) => S + (self: NonEmptyReadonlyArray, f: (a: A) => S): S +} => + dual( + 2, + (self: NonEmptyReadonlyArray, f: (a: A) => S): S => + combineMapNonEmptyWithIndex(S)(self, f) + ) /** * @category folding * @since 1.0.0 */ -export const combineMapNonEmptyWithIndex = (S: Semigroup) => - (f: (a: A, i: number) => S) => - (self: NonEmptyReadonlyArray): S => +export const combineMapNonEmptyWithIndex = (S: Semigroup): { + (f: (a: A, i: number) => S): (self: NonEmptyReadonlyArray) => S + (self: NonEmptyReadonlyArray, f: (a: A, i: number) => S): S +} => + dual( + 2, + (self: NonEmptyReadonlyArray, f: (a: A, i: number) => S): S => tailNonEmpty(self).reduce((s, a, i) => S.combine(s, f(a, i + 1)), f(headNonEmpty(self), 0)) + ) /** * @category folding * @since 1.0.0 */ -export const reduceKind: (F: monad.Monad) => ( - b: B, - f: (b: B, a: A) => Kind -) => (self: ReadonlyArray) => Kind = foldable.reduceKind(Foldable) +export const reduceKind: ( + G: monad.Monad +) => { + ( + b: B, + f: (b: B, a: A) => Kind + ): (self: ReadonlyArray) => Kind + ( + self: ReadonlyArray, + b: B, + f: (b: B, a: A) => Kind + ): Kind +} = foldable.reduceKind(Foldable) /** * @category folding * @since 1.0.0 */ -export const coproductMapKind: (F: Coproduct) => ( - f: (a: A) => Kind -) => (self: ReadonlyArray) => Kind = foldable.coproductMapKind(Foldable) +export const coproductMapKind: ( + G: Coproduct +) => { + ( + f: (a: A) => Kind + ): (self: ReadonlyArray) => Kind + ( + self: ReadonlyArray, + f: (a: A) => Kind + ): Kind +} = foldable.coproductMapKind(Foldable) /** * @category instances @@ -1969,10 +2186,15 @@ export const TraversableFilterable: traversableFilterable.TraversableFilterable< */ export const traversePartitionMap: ( F: applicative.Applicative -) => ( - f: (a: A) => Kind> -) => (self: ReadonlyArray) => Kind, Array]> = TraversableFilterable - .traversePartitionMap as any +) => { + ( + f: (a: A) => Kind> + ): (self: ReadonlyArray) => Kind, Array]> + ( + self: ReadonlyArray, + f: (a: A) => Kind> + ): Kind, Array]> +} = TraversableFilterable.traversePartitionMap as any /** * @category filtering @@ -1980,10 +2202,15 @@ export const traversePartitionMap: ( */ export const traverseFilterMap: ( F: applicative.Applicative -) => ( - f: (a: A) => Kind> -) => (self: ReadonlyArray) => Kind> = TraversableFilterable - .traverseFilterMap as any +) => { + ( + f: (a: A) => Kind> + ): (self: ReadonlyArray) => Kind> + ( + self: ReadonlyArray, + f: (a: A) => Kind> + ): Kind> +} = TraversableFilterable.traverseFilterMap as any /** * Filter values inside a context. @@ -2053,11 +2280,14 @@ export const liftNullable = , B>( * @category sequencing * @since 1.0.0 */ -export const flatMapNullable = ( - f: (a: A) => B | null | undefined -) => - (self: ReadonlyArray): Array> => +export const flatMapNullable: { + (f: (a: A) => B | null | undefined): (self: ReadonlyArray) => Array> + (self: ReadonlyArray, f: (a: A) => B | null | undefined): Array> +} = dual( + 2, + (self: ReadonlyArray, f: (a: A) => B | null | undefined): Array> => isNonEmpty(self) ? fromNullable(f(headNonEmpty(self))) : empty() +) /** * @category lifting @@ -2095,14 +2325,22 @@ export const some = (predicate: Predicate) => (self: ReadonlyArray): self is NonEmptyReadonlyArray => self.some(predicate) /** - * Fold a data structure, accumulating values in some `Monoid`, combining adjacent elements + * Fold an `Iterable`, accumulating values in some `Monoid`, combining adjacent elements * using the specified separator. * * @since 1.0.0 */ -export const intercalate = (M: Monoid) => - (middle: A) => - (self: ReadonlyArray): A => isNonEmpty(self) ? intercalateNonEmpty(M)(middle)(self) : M.empty +export const intercalate = (M: Monoid): { + (middle: A): (self: Iterable) => A + (self: Iterable, middle: A): A +} => + dual( + 2, + (self: Iterable, middle: A): A => { + const as = fromIterable(self) + return isNonEmpty(as) ? intercalateNonEmpty(M)(as, middle) : M.empty + } + ) /** * Places an element in between members of a `NonEmptyReadonlyArray`, then folds the results using the provided `Semigroup`. @@ -2111,24 +2349,35 @@ export const intercalate = (M: Monoid) => */ export const intercalateNonEmpty = ( S: Semigroup -) => - (middle: A) => - (self: NonEmptyReadonlyArray): A => - semigroup.intercalate(middle)(S).combineMany(headNonEmpty(self), tailNonEmpty(self)) +): { + (middle: A): (self: NonEmptyReadonlyArray) => A + (self: NonEmptyReadonlyArray, middle: A): A +} => + dual( + 2, + (self: NonEmptyReadonlyArray, middle: A): A => + semigroup.intercalate(S, middle).combineMany(headNonEmpty(self), tailNonEmpty(self)) + ) /** * @since 1.0.0 */ -export const join: (sep: string) => (self: ReadonlyArray) => string = intercalate( - string.Monoid -) +export const join: { + (middle: string): (self: ReadonlyArray) => string + (self: ReadonlyArray, middle: string): string +} = intercalate(string.Monoid) /** * @since 1.0.0 */ -export const extend = ( - f: (as: ReadonlyArray) => B -) => (self: ReadonlyArray): Array => self.map((_, i, as) => f(as.slice(i))) +export const extend: { + (f: (as: ReadonlyArray) => B): (self: ReadonlyArray) => Array + (self: ReadonlyArray, f: (as: ReadonlyArray) => B): Array +} = dual( + 2, + (self: ReadonlyArray, f: (as: ReadonlyArray) => B): Array => + self.map((_, i, as) => f(as.slice(i))) +) /** * @since 1.0.0 @@ -2220,3 +2469,63 @@ export const getMonoid: () => Monoid> = monoid.readonlyArray * @since 1.0.0 */ export const getOrder: (O: Order) => Order> = order.array + +// ------------------------------------------------------------------------------------- +// do notation +// ------------------------------------------------------------------------------------- + +/** + * @category do notation + * @since 1.0.0 + */ +export const bindTo: ( + name: N +) => (self: ReadonlyArray) => Array<{ [K in N]: A }> = invariant + .bindTo(Invariant) as any + +const let_: ( + name: Exclude, + f: (a: A) => B +) => ( + self: ReadonlyArray +) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant.let(Covariant) as any + +export { + /** + * @category do notation + * @since 1.0.0 + */ + let_ as let +} + +/** + * @category do notation + * @since 1.0.0 + */ +export const Do: ReadonlyArray<{}> = of_.Do(Of) + +/** + * @category do notation + * @since 1.0.0 + */ +export const bind: ( + name: Exclude, + f: (a: A) => ReadonlyArray +) => ( + self: ReadonlyArray +) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable.bind(Chainable) as any + +/** + * A variant of `bind` that sequentially ignores the scope. + * + * @category do notation + * @since 1.0.0 + */ +export const andThenBind: ( + name: Exclude, + that: ReadonlyArray +) => ( + self: ReadonlyArray +) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct.andThenBind( + SemiProduct +) as any diff --git a/src/String.ts b/src/String.ts index 26380da36..3e307cfb9 100644 --- a/src/String.ts +++ b/src/String.ts @@ -108,9 +108,8 @@ export const replace: { /** * @example * import * as S from '@fp-ts/core/String' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(' a ', S.trim), 'a') + * assert.deepStrictEqual(S.trim(' a '), 'a') * * @since 1.0.0 */ @@ -119,9 +118,8 @@ export const trim = (s: string): string => s.trim() /** * @example * import * as S from '@fp-ts/core/String' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(' a ', S.trimStart), 'a ') + * assert.deepStrictEqual(S.trimStart(' a '), 'a ') * * @since 1.0.0 */ @@ -130,9 +128,8 @@ export const trimStart = (s: string): string => s.trimStart() /** * @example * import * as S from '@fp-ts/core/String' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(' a ', S.trimEnd), ' a') + * assert.deepStrictEqual(S.trimEnd(' a '), ' a') * * @since 1.0.0 */ @@ -157,10 +154,9 @@ export const slice: { * * @example * import * as S from '@fp-ts/core/String' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe('', S.isEmpty), true) - * assert.deepStrictEqual(pipe('a', S.isEmpty), false) + * assert.deepStrictEqual(S.isEmpty(''), true) + * assert.deepStrictEqual(S.isEmpty('a'), false) * * @since 1.0.0 */ @@ -178,9 +174,8 @@ export const isNonEmpty = (s: string): boolean => s.length > 0 * * @example * import * as S from '@fp-ts/core/String' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe('abc', S.length), 3) + * assert.deepStrictEqual(S.length('abc'), 3) * * @since 1.0.0 */ @@ -253,6 +248,11 @@ export const endsWith = (searchString: string, position?: number) => * * If `n` is a float, it will be rounded down to the nearest integer. * + * @example + * import * as S from '@fp-ts/core/String' + * + * assert.deepStrictEqual(S.takeLeft("Hello World", 5), "Hello") + * * @since 1.0.0 */ export const takeLeft: { @@ -270,6 +270,11 @@ export const takeLeft: { * * If `n` is a float, it will be rounded down to the nearest integer. * + * @example + * import * as S from '@fp-ts/core/String' + * + * assert.deepStrictEqual(S.takeRight("Hello World", 5), "World") + * * @since 1.0.0 */ export const takeRight: { diff --git a/src/typeclass/Filterable.ts b/src/typeclass/Filterable.ts index 7cfee5f51..630d8f430 100644 --- a/src/typeclass/Filterable.ts +++ b/src/typeclass/Filterable.ts @@ -108,7 +108,6 @@ export const partition = ( (predicate: (a: A) => boolean): ( self: Kind ) => [Kind, Kind] - ( self: Kind, refinement: (a: A) => a is B diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 11eff41f1..4739713f7 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -266,9 +266,14 @@ export const reverse = (S: Semigroup): Semigroup => /** * @since 1.0.0 */ -export const intercalate = (separator: A) => - (S: Semigroup): Semigroup => +export const intercalate: { + (separator: A): (S: Semigroup) => Semigroup + (S: Semigroup, separator: A): Semigroup +} = dual( + 2, + (S: Semigroup, separator: A): Semigroup => fromCombine((self, that) => S.combineMany(self, [separator, that])) +) /** * Always return the first argument. diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 5eed2fe61..93bb661d7 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -831,15 +831,12 @@ describe.concurrent("ReadonlyArray", () => { }) it("extend", () => { - const sum = (as: ReadonlyArray) => Number.MonoidSum.combineAll(as) - deepStrictEqual(pipe([1, 2, 3, 4], RA.extend(sum)), [10, 9, 7, 4]) + deepStrictEqual(pipe([1, 2, 3, 4], RA.extend(Number.sumAll)), [10, 9, 7, 4]) deepStrictEqual(pipe([1, 2, 3, 4], RA.extend(identity)), [ [1, 2, 3, 4], [2, 3, 4], [3, 4], - [ - 4 - ] + [4] ]) }) @@ -1250,6 +1247,14 @@ describe.concurrent("ReadonlyArray", () => { it("match", () => { const len: (as: ReadonlyArray) => number = RA.match( + () => 0, + (as) => 1 + len(as.slice(1)) + ) + deepStrictEqual(len([1, 2, 3]), 3) + }) + + it("matchLeft", () => { + const len: (as: ReadonlyArray) => number = RA.matchLeft( () => 0, (_, tail) => 1 + len(tail) ) @@ -1409,15 +1414,15 @@ describe.concurrent("ReadonlyArray", () => { }) it("makeBy", () => { - deepStrictEqual(RA.makeBy(double)(5), [0, 2, 4, 6, 8]) - deepStrictEqual(RA.makeBy(double)(2.2), [0, 2]) + deepStrictEqual(RA.makeBy(5, n => n * 2), [0, 2, 4, 6, 8]) + deepStrictEqual(RA.makeBy(2.2, n => n * 2), [0, 2]) }) it("replicate", () => { - deepStrictEqual(RA.replicate("a")(0), ["a"]) - deepStrictEqual(RA.replicate("a")(-1), ["a"]) - deepStrictEqual(RA.replicate("a")(3), ["a", "a", "a"]) - deepStrictEqual(RA.replicate("a")(2.2), ["a", "a"]) + deepStrictEqual(RA.replicate("a", 0), ["a"]) + deepStrictEqual(RA.replicate("a", -1), ["a"]) + deepStrictEqual(RA.replicate("a", 3), ["a", "a", "a"]) + deepStrictEqual(RA.replicate("a", 2.2), ["a", "a"]) }) it("range", () => { From 0d4255a41f0d0628ee2cb77a999c1a44f49e53c1 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 11:16:44 +0100 Subject: [PATCH 176/255] ReadonlyRecord: refactor map --- docs/modules/ReadonlyRecord.ts.md | 34 ++++---------------- src/ReadonlyRecord.ts | 53 ++++++++++--------------------- test/ReadonlyRecord.ts | 9 ++---- 3 files changed, 25 insertions(+), 71 deletions(-) diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md index 1170b6799..9af32beaf 100644 --- a/docs/modules/ReadonlyRecord.ts.md +++ b/docs/modules/ReadonlyRecord.ts.md @@ -20,7 +20,6 @@ Added in v1.0.0 - [get](#get) - [mapping](#mapping) - [map](#map) - - [mapWithKey](#mapwithkey) - [models](#models) - [ReadonlyRecord (interface)](#readonlyrecord-interface) - [utils](#utils) @@ -99,8 +98,8 @@ Maps a `ReadonlyRecord` into another `Record` by applying a transformation funct ```ts export declare const map: { - (f: (a: A) => B): (self: ReadonlyRecord) => Record - (self: ReadonlyRecord, f: (a: A) => B): Record + (f: (a: A, key: string) => B): (self: ReadonlyRecord) => Record + (self: ReadonlyRecord, f: (a: A, key: string) => B): Record } ``` @@ -109,34 +108,13 @@ export declare const map: { ```ts import { map } from '@fp-ts/core/ReadonlyRecord' -const f = (n: number) => `-${n}-` +const f = (n: number) => `-${n}` -assert.deepStrictEqual(map({ a: 3, b: 5 }, f), { a: '-3-', b: '-5-' }) -``` - -Added in v1.0.0 - -## mapWithKey - -Maps the values of a `ReadonlyRecord` to a new `Record` by applying a transformation function to each of its keys and values. - -**Signature** - -```ts -export declare const mapWithKey: { - (f: (k: string, a: A) => B): (self: ReadonlyRecord) => Record - (self: ReadonlyRecord, f: (k: string, a: A) => B): Record -} -``` - -**Example** - -```ts -import { mapWithKey } from '@fp-ts/core/ReadonlyRecord' +assert.deepStrictEqual(map({ a: 3, b: 5 }, f), { a: '-3', b: '-5' }) -const f = (k: string, n: number) => `${k.toUpperCase()}-${n}` +const g = (n: number, key: string) => `${key.toUpperCase()}-${n}` -assert.deepStrictEqual(mapWithKey({ a: 3, b: 5 }, f), { a: 'A-3', b: 'B-5' }) +assert.deepStrictEqual(map({ a: 3, b: 5 }, g), { a: 'A-3', b: 'B-5' }) ``` Added in v1.0.0 diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index 8c80c6bdb..d5905bc3a 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -144,62 +144,41 @@ export const replaceOption: { ) /** - * Maps the values of a `ReadonlyRecord` to a new `Record` by applying a transformation function to each of its keys and values. + * Maps a `ReadonlyRecord` into another `Record` by applying a transformation function to each of its values. * * @param self - The `ReadonlyRecord` to be mapped. - * @param f - A transformation function that will be applied to each of the key/values in the `ReadonlyRecord`. + * @param f - A transformation function that will be applied to each of the values in the `ReadonlyRecord`. * * @example - * import { mapWithKey } from "@fp-ts/core/ReadonlyRecord" + * import { map } from "@fp-ts/core/ReadonlyRecord" + * + * const f = (n: number) => `-${n}` * - * const f = (k: string, n: number) => `${k.toUpperCase()}-${n}` + * assert.deepStrictEqual(map({ a: 3, b: 5 }, f), { a: "-3", b: "-5" }) * - * assert.deepStrictEqual(mapWithKey({ a: 3, b: 5 }, f), { a: "A-3", b: "B-5" }) + * const g = (n: number, key: string) => `${key.toUpperCase()}-${n}` + * + * assert.deepStrictEqual(map({ a: 3, b: 5 }, g), { a: "A-3", b: "B-5" }) * * @category mapping * @since 1.0.0 */ -export const mapWithKey: { - (f: (k: string, a: A) => B): (self: ReadonlyRecord) => Record - (self: ReadonlyRecord, f: (k: string, a: A) => B): Record +export const map: { + (f: (a: A, key: string) => B): (self: ReadonlyRecord) => Record + (self: ReadonlyRecord, f: (a: A, key: string) => B): Record } = dual( 2, - (self: ReadonlyRecord, f: (k: string, a: A) => B): Record => { + (self: ReadonlyRecord, f: (a: A, key: string) => B): Record => { const out: Record = {} - for (const k in self) { - if (Object.prototype.hasOwnProperty.call(self, k)) { - out[k] = f(k, self[k]) + for (const key in self) { + if (Object.prototype.hasOwnProperty.call(self, key)) { + out[key] = f(self[key], key) } } return out } ) -/** - * Maps a `ReadonlyRecord` into another `Record` by applying a transformation function to each of its values. - * - * @param self - The `ReadonlyRecord` to be mapped. - * @param f - A transformation function that will be applied to each of the values in the `ReadonlyRecord`. - * - * @example - * import { map } from "@fp-ts/core/ReadonlyRecord" - * - * const f = (n: number) => `-${n}-` - * - * assert.deepStrictEqual(map({ a: 3, b: 5 }, f), { a: "-3-", b: "-5-" }) - * - * @category mapping - * @since 1.0.0 - */ -export const map: { - (f: (a: A) => B): (self: ReadonlyRecord) => Record - (self: ReadonlyRecord, f: (a: A) => B): Record -} = dual( - 2, - (self: ReadonlyRecord, f: (a: A) => B): Record => - mapWithKey(self, (_, a) => f(a)) -) - /* TODO: diff --git a/test/ReadonlyRecord.ts b/test/ReadonlyRecord.ts index dd9a3f277..1b50b7b2a 100644 --- a/test/ReadonlyRecord.ts +++ b/test/ReadonlyRecord.ts @@ -22,17 +22,14 @@ describe.concurrent("ReadonlyRecord", () => { ) }) - it("mapWithKey", () => { - expect(pipe({ a: 1, b: 2 }, RR.mapWithKey((k, n) => `${k}-${n}`))).toEqual({ + it("map", () => { + expect(pipe({ a: 1, b: 2 }, RR.map(n => n * 2))).toEqual({ a: 2, b: 4 }) + expect(pipe({ a: 1, b: 2 }, RR.map((n, k) => `${k}-${n}`))).toEqual({ a: "a-1", b: "b-2" }) }) - it("map", () => { - expect(pipe({ a: 1, b: 2 }, RR.map(n => n * 2))).toEqual({ a: 2, b: 4 }) - }) - it("fromIterable", () => { const input = [1, 2, 3, 4] expect(RR.fromIterable(input, a => [String(a), a * 2])).toEqual({ From bcc566033ac6a2572b2fb5613c6efbd74590e9c4 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 11:43:02 +0100 Subject: [PATCH 177/255] String: refactor includes, startsWith, endsWith --- docs/modules/String.ts.md | 139 ++++++++++++++++++++++++++++------- src/String.ts | 147 ++++++++++++++++++++++++++++---------- test/String.ts | 101 +++++++++++++++----------- 3 files changed, 280 insertions(+), 107 deletions(-) diff --git a/docs/modules/String.ts.md b/docs/modules/String.ts.md index f75438948..a4b9ffd14 100644 --- a/docs/modules/String.ts.md +++ b/docs/modules/String.ts.md @@ -27,7 +27,9 @@ Added in v1.0.0 - [concat](#concat) - [empty](#empty) - [endsWith](#endswith) + - [endsWithPosition](#endswithposition) - [includes](#includes) + - [includesWithPosition](#includeswithposition) - [isEmpty](#isempty) - [isNonEmpty](#isnonempty) - [length](#length) @@ -35,6 +37,7 @@ Added in v1.0.0 - [slice](#slice) - [split](#split) - [startsWith](#startswith) + - [startsWithPosition](#startswithposition) - [takeLeft](#takeleft) - [takeRight](#takeright) - [toLowerCase](#tolowercase) @@ -132,37 +135,91 @@ Added in v1.0.0 **Signature** ```ts -export declare const endsWith: (searchString: string, position?: number | undefined) => (s: string) => boolean +export declare const endsWith: { + (searchString: string): (self: string) => boolean + (self: string, searchString: string): boolean +} ``` **Example** ```ts import * as S from '@fp-ts/core/String' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe('abc', S.endsWith('c')), true) -assert.deepStrictEqual(pipe('ab', S.endsWith('c')), false) +assert.deepStrictEqual(S.endsWith('abc', 'c'), true) +assert.deepStrictEqual(S.endsWith('ab', 'c'), false) +``` + +Added in v1.0.0 + +## endsWithPosition + +**Signature** + +```ts +export declare const endsWithPosition: { + (searchString: string, position: number): (self: string) => boolean + (self: string, searchString: string, position: number): boolean +} +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' + +assert.deepStrictEqual(S.endsWithPosition('abc', 'b', 2), true) +assert.deepStrictEqual(S.endsWithPosition('abc', 'c', 2), false) ``` Added in v1.0.0 ## includes +Returns `true` if `searchString` appears as a substring of `self`, at one or more positions that are +greater than or equal to `0`; otherwise, returns `false`. + **Signature** ```ts -export declare const includes: (searchString: string, position?: number | undefined) => (s: string) => boolean +export declare const includes: { + (searchString: string): (self: string) => boolean + (self: string, searchString: string): boolean +} ``` **Example** ```ts import * as S from '@fp-ts/core/String' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe('abc', S.includes('b')), true) -assert.deepStrictEqual(pipe('abc', S.includes('d')), false) +assert.deepStrictEqual(S.includes('abc', 'b'), true) +assert.deepStrictEqual(S.includes('abc', 'd'), false) +``` + +Added in v1.0.0 + +## includesWithPosition + +Returns `true` if `searchString` appears as a substring of `self`, at one or more positions that are +greater than or equal to `position`; otherwise, returns `false`. + +**Signature** + +```ts +export declare const includesWithPosition: { + (searchString: string, position: number): (self: string) => boolean + (self: string, searchString: string, position: number): boolean +} +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' + +assert.deepStrictEqual(S.includesWithPosition('abc', 'b', 1), true) +assert.deepStrictEqual(S.includesWithPosition('abc', 'a', 1), false) ``` Added in v1.0.0 @@ -174,7 +231,7 @@ Test whether a `string` is empty. **Signature** ```ts -export declare const isEmpty: (s: string) => s is '' +export declare const isEmpty: (self: string) => self is '' ``` **Example** @@ -195,7 +252,7 @@ Test whether a `string` is non empty. **Signature** ```ts -export declare const isNonEmpty: (s: string) => boolean +export declare const isNonEmpty: (self: string) => boolean ``` Added in v1.0.0 @@ -207,7 +264,7 @@ Calculate the number of characters in a `string`. **Signature** ```ts -export declare const length: (s: string) => number +export declare const length: (self: string) => number ``` **Example** @@ -226,8 +283,8 @@ Added in v1.0.0 ```ts export declare const replace: { - (searchValue: string | RegExp, replaceValue: string): (s: string) => string - (s: string, searchValue: string | RegExp, replaceValue: string): string + (searchValue: string | RegExp, replaceValue: string): (self: string) => string + (self: string, searchValue: string | RegExp, replaceValue: string): string } ``` @@ -248,8 +305,8 @@ Added in v1.0.0 ```ts export declare const slice: { - (start: number, end: number): (s: string) => string - (s: string, start: number, end: number): string + (start: number, end: number): (self: string) => string + (self: string, start: number, end: number): string } ``` @@ -270,8 +327,8 @@ Added in v1.0.0 ```ts export declare const split: { - (separator: string | RegExp): (s: string) => readonly [string, ...string[]] - (s: string, separator: string | RegExp): readonly [string, ...string[]] + (separator: string | RegExp): (self: string) => readonly [string, ...string[]] + (self: string, separator: string | RegExp): readonly [string, ...string[]] } ``` @@ -289,20 +346,48 @@ Added in v1.0.0 ## startsWith +Returns `true` if the sequence of elements of `searchString` is the +same as the corresponding elements of `s` starting at +position. Otherwise returns false. + **Signature** ```ts -export declare const startsWith: (searchString: string, position?: number | undefined) => (s: string) => boolean +export declare const startsWith: { + (searchString: string): (self: string) => boolean + (self: string, searchString: string): boolean +} +``` + +**Example** + +```ts +import * as S from '@fp-ts/core/String' + +assert.deepStrictEqual(S.startsWith('abc', 'a'), true) +assert.deepStrictEqual(S.startsWith('bc', 'a'), false) +``` + +Added in v1.0.0 + +## startsWithPosition + +**Signature** + +```ts +export declare const startsWithPosition: { + (searchString: string, position: number): (self: string) => boolean + (self: string, searchString: string, position: number): boolean +} ``` **Example** ```ts import * as S from '@fp-ts/core/String' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe('abc', S.startsWith('a')), true) -assert.deepStrictEqual(pipe('bc', S.startsWith('a')), false) +assert.deepStrictEqual(S.startsWithPosition('abc', 'b', 1), true) +assert.deepStrictEqual(S.startsWithPosition('bc', 'a', 1), false) ``` Added in v1.0.0 @@ -348,7 +433,7 @@ If `n` is a float, it will be rounded down to the nearest integer. **Signature** ```ts -export declare const takeRight: { (n: number): (s: string) => string; (s: string, n: number): string } +export declare const takeRight: { (n: number): (self: string) => string; (self: string, n: number): string } ``` **Example** @@ -366,7 +451,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const toLowerCase: (s: string) => string +export declare const toLowerCase: (self: string) => string ``` **Example** @@ -385,7 +470,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const toUpperCase: (s: string) => string +export declare const toUpperCase: (self: string) => string ``` **Example** @@ -404,7 +489,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const trim: (s: string) => string +export declare const trim: (self: string) => string ``` **Example** @@ -422,7 +507,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const trimEnd: (s: string) => string +export declare const trimEnd: (self: string) => string ``` **Example** @@ -440,7 +525,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const trimStart: (s: string) => string +export declare const trimStart: (self: string) => string ``` **Example** diff --git a/src/String.ts b/src/String.ts index 3e307cfb9..689445bdf 100644 --- a/src/String.ts +++ b/src/String.ts @@ -74,7 +74,7 @@ export const concat: { * * @since 1.0.0 */ -export const toUpperCase = (s: string): string => s.toUpperCase() +export const toUpperCase = (self: string): string => self.toUpperCase() /** * @example @@ -85,7 +85,7 @@ export const toUpperCase = (s: string): string => s.toUpperCase() * * @since 1.0.0 */ -export const toLowerCase = (s: string): string => s.toLowerCase() +export const toLowerCase = (self: string): string => self.toLowerCase() /** * @example @@ -97,12 +97,12 @@ export const toLowerCase = (s: string): string => s.toLowerCase() * @since 1.0.0 */ export const replace: { - (searchValue: string | RegExp, replaceValue: string): (s: string) => string - (s: string, searchValue: string | RegExp, replaceValue: string): string + (searchValue: string | RegExp, replaceValue: string): (self: string) => string + (self: string, searchValue: string | RegExp, replaceValue: string): string } = dual( 3, - (s: string, searchValue: string | RegExp, replaceValue: string): string => - s.replace(searchValue, replaceValue) + (self: string, searchValue: string | RegExp, replaceValue: string): string => + self.replace(searchValue, replaceValue) ) /** @@ -113,7 +113,7 @@ export const replace: { * * @since 1.0.0 */ -export const trim = (s: string): string => s.trim() +export const trim = (self: string): string => self.trim() /** * @example @@ -123,7 +123,7 @@ export const trim = (s: string): string => s.trim() * * @since 1.0.0 */ -export const trimStart = (s: string): string => s.trimStart() +export const trimStart = (self: string): string => self.trimStart() /** * @example @@ -133,7 +133,7 @@ export const trimStart = (s: string): string => s.trimStart() * * @since 1.0.0 */ -export const trimEnd = (s: string): string => s.trimEnd() +export const trimEnd = (self: string): string => self.trimEnd() /** * @example @@ -145,9 +145,9 @@ export const trimEnd = (s: string): string => s.trimEnd() * @since 1.0.0 */ export const slice: { - (start: number, end: number): (s: string) => string - (s: string, start: number, end: number): string -} = dual(3, (s: string, start: number, end: number): string => s.slice(start, end)) + (start: number, end: number): (self: string) => string + (self: string, start: number, end: number): string +} = dual(3, (self: string, start: number, end: number): string => self.slice(start, end)) /** * Test whether a `string` is empty. @@ -160,14 +160,14 @@ export const slice: { * * @since 1.0.0 */ -export const isEmpty = (s: string): s is "" => s.length === 0 +export const isEmpty = (self: string): self is "" => self.length === 0 /** * Test whether a `string` is non empty. * * @since 1.0.0 */ -export const isNonEmpty = (s: string): boolean => s.length > 0 +export const isNonEmpty = (self: string): boolean => self.length > 0 /** * Calculate the number of characters in a `string`. @@ -179,7 +179,7 @@ export const isNonEmpty = (s: string): boolean => s.length > 0 * * @since 1.0.0 */ -export const length = (s: string): number => s.length +export const length = (self: string): number => self.length /** * @example @@ -192,51 +192,121 @@ export const length = (s: string): number => s.length * @since 1.0.0 */ export const split: { - (separator: string | RegExp): (s: string) => NonEmptyReadonlyArray - (s: string, separator: string | RegExp): NonEmptyReadonlyArray -} = dual(2, (s: string, separator: string | RegExp): NonEmptyReadonlyArray => { - const out = s.split(separator) - return readonlyArray.isNonEmpty(out) ? out : [s] + (separator: string | RegExp): (self: string) => NonEmptyReadonlyArray + (self: string, separator: string | RegExp): NonEmptyReadonlyArray +} = dual(2, (self: string, separator: string | RegExp): NonEmptyReadonlyArray => { + const out = self.split(separator) + return readonlyArray.isNonEmpty(out) ? out : [self] }) /** + * Returns `true` if `searchString` appears as a substring of `self`, at one or more positions that are + * greater than or equal to `0`; otherwise, returns `false`. + * * @example * import * as S from '@fp-ts/core/String' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe('abc', S.includes('b')), true) - * assert.deepStrictEqual(pipe('abc', S.includes('d')), false) + * assert.deepStrictEqual(S.includes("abc", "b"), true) + * assert.deepStrictEqual(S.includes("abc", "d"), false) * * @since 1.0.0 */ -export const includes = (searchString: string, position?: number) => - (s: string): boolean => s.includes(searchString, position) +export const includes: { + (searchString: string): (self: string) => boolean + (self: string, searchString: string): boolean +} = dual(2, (self: string, searchString: string): boolean => self.includes(searchString)) /** + * Returns `true` if `searchString` appears as a substring of `self`, at one or more positions that are + * greater than or equal to `position`; otherwise, returns `false`. + * * @example * import * as S from '@fp-ts/core/String' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe('abc', S.startsWith('a')), true) - * assert.deepStrictEqual(pipe('bc', S.startsWith('a')), false) + * assert.deepStrictEqual(S.includesWithPosition("abc", "b", 1), true) + * assert.deepStrictEqual(S.includesWithPosition("abc", "a", 1), false) * * @since 1.0.0 */ -export const startsWith = (searchString: string, position?: number) => - (s: string): boolean => s.startsWith(searchString, position) +export const includesWithPosition: { + (searchString: string, position: number): (self: string) => boolean + (self: string, searchString: string, position: number): boolean +} = dual( + 3, + (self: string, searchString: string, position: number): boolean => + self.includes(searchString, position) +) + +/** + * Returns `true` if the sequence of elements of `searchString` is the + * same as the corresponding elements of `s` starting at + * position. Otherwise returns false. + * + * @example + * import * as S from '@fp-ts/core/String' + * + * assert.deepStrictEqual(S.startsWith("abc", "a"), true) + * assert.deepStrictEqual(S.startsWith("bc", "a"), false) + * + * @since 1.0.0 + */ +export const startsWith: { + (searchString: string): (self: string) => boolean + (self: string, searchString: string): boolean +} = dual( + 2, + (self: string, searchString: string): boolean => self.startsWith(searchString) +) + +/** + * @example + * import * as S from '@fp-ts/core/String' + * + * assert.deepStrictEqual(S.startsWithPosition("abc", "b", 1), true) + * assert.deepStrictEqual(S.startsWithPosition("bc", "a", 1), false) + * + * @since 1.0.0 + */ +export const startsWithPosition: { + (searchString: string, position: number): (self: string) => boolean + (self: string, searchString: string, position: number): boolean +} = dual( + 3, + (self: string, searchString: string, position: number): boolean => + self.startsWith(searchString, position) +) + +/** + * @example + * import * as S from '@fp-ts/core/String' + * + * assert.deepStrictEqual(S.endsWith("abc", "c"), true) + * assert.deepStrictEqual(S.endsWith("ab", "c"), false) + * + * @since 1.0.0 + */ +export const endsWith: { + (searchString: string): (self: string) => boolean + (self: string, searchString: string): boolean +} = dual(2, (self: string, searchString: string): boolean => self.endsWith(searchString)) /** * @example * import * as S from '@fp-ts/core/String' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe('abc', S.endsWith('c')), true) - * assert.deepStrictEqual(pipe('ab', S.endsWith('c')), false) + * assert.deepStrictEqual(S.endsWithPosition("abc", "b", 2), true) + * assert.deepStrictEqual(S.endsWithPosition("abc", "c", 2), false) * * @since 1.0.0 */ -export const endsWith = (searchString: string, position?: number) => - (s: string): boolean => s.endsWith(searchString, position) +export const endsWithPosition: { + (searchString: string, position: number): (self: string) => boolean + (self: string, searchString: string, position: number): boolean +} = dual( + 3, + (self: string, searchString: string, position: number): boolean => + self.endsWith(searchString, position) +) /** * Keep the specified number of characters from the start of a string. @@ -278,11 +348,12 @@ export const takeLeft: { * @since 1.0.0 */ export const takeRight: { - (n: number): (s: string) => string - (s: string, n: number): string + (n: number): (self: string) => string + (self: string, n: number): string } = dual( 2, - (s: string, n: number): string => s.slice(Math.max(0, s.length - Math.floor(n)), Infinity) + (self: string, n: number): string => + self.slice(Math.max(0, self.length - Math.floor(n)), Infinity) ) /* diff --git a/test/String.ts b/test/String.ts index 76c514f5a..8aa07bba0 100644 --- a/test/String.ts +++ b/test/String.ts @@ -1,37 +1,37 @@ import { pipe } from "@fp-ts/core/Function" -import * as String from "@fp-ts/core/String" +import * as S from "@fp-ts/core/String" import { deepStrictEqual } from "@fp-ts/core/test/util" import * as Order from "@fp-ts/core/typeclass/Order" describe.concurrent("String", () => { it("isString", () => { - expect(String.isString("a")).toEqual(true) - expect(String.isString(1)).toEqual(false) - expect(String.isString(true)).toEqual(false) + expect(S.isString("a")).toEqual(true) + expect(S.isString(1)).toEqual(false) + expect(S.isString(true)).toEqual(false) }) it("empty", () => { - expect(String.empty).toEqual("") + expect(S.empty).toEqual("") }) it("Semigroup", () => { - expect(String.Semigroup.combine("a", "b")).toEqual("ab") - expect(String.Semigroup.combineMany("a", ["b", "c"])).toEqual("abc") - expect(String.Semigroup.combineMany("a", [])).toEqual("a") + expect(S.Semigroup.combine("a", "b")).toEqual("ab") + expect(S.Semigroup.combineMany("a", ["b", "c"])).toEqual("abc") + expect(S.Semigroup.combineMany("a", [])).toEqual("a") }) it("Monoid", () => { - expect(String.Monoid.combineAll([])).toEqual("") + expect(S.Monoid.combineAll([])).toEqual("") }) it("Equivalence", () => { - expect(String.Equivalence("a", "a")).toBe(true) - expect(String.Equivalence("a", "b")).toBe(false) + expect(S.Equivalence("a", "a")).toBe(true) + expect(S.Equivalence("a", "b")).toBe(false) }) it("Order", () => { - const lessThan = Order.lessThan(String.Order) - const lessThanOrEqualTo = Order.lessThanOrEqualTo(String.Order) + const lessThan = Order.lessThan(S.Order) + const lessThanOrEqualTo = Order.lessThanOrEqualTo(S.Order) expect(pipe("a", lessThan("b"))).toEqual(true) expect(pipe("a", lessThan("a"))).toEqual(false) expect(pipe("a", lessThanOrEqualTo("a"))).toEqual(true) @@ -40,76 +40,93 @@ describe.concurrent("String", () => { }) it("concat", () => { - deepStrictEqual(pipe("a", String.concat("b")), "ab") + deepStrictEqual(pipe("a", S.concat("b")), "ab") }) it("isEmpty", () => { - deepStrictEqual(String.isEmpty(""), true) - deepStrictEqual(String.isEmpty("a"), false) + deepStrictEqual(S.isEmpty(""), true) + deepStrictEqual(S.isEmpty("a"), false) }) it("isNonEmpty", () => { - deepStrictEqual(String.isNonEmpty(""), false) - deepStrictEqual(String.isNonEmpty("a"), true) + deepStrictEqual(S.isNonEmpty(""), false) + deepStrictEqual(S.isNonEmpty("a"), true) }) it("length", () => { - deepStrictEqual(String.length(""), 0) - deepStrictEqual(String.length("a"), 1) - deepStrictEqual(String.length("aaa"), 3) + deepStrictEqual(S.length(""), 0) + deepStrictEqual(S.length("a"), 1) + deepStrictEqual(S.length("aaa"), 3) }) it("toUpperCase", () => { - deepStrictEqual(String.toUpperCase("a"), "A") + deepStrictEqual(S.toUpperCase("a"), "A") }) it("toLowerCase", () => { - deepStrictEqual(String.toLowerCase("A"), "a") + deepStrictEqual(S.toLowerCase("A"), "a") }) it("replace", () => { - deepStrictEqual(pipe("abc", String.replace("b", "d")), "adc") + deepStrictEqual(pipe("abc", S.replace("b", "d")), "adc") }) it("split", () => { - deepStrictEqual(pipe("abc", String.split("")), ["a", "b", "c"]) - deepStrictEqual(pipe("", String.split("")), [""]) + deepStrictEqual(pipe("abc", S.split("")), ["a", "b", "c"]) + deepStrictEqual(pipe("", S.split("")), [""]) }) it("trim", () => { - deepStrictEqual(pipe(" a ", String.trim), "a") + deepStrictEqual(pipe(" a ", S.trim), "a") }) it("trimStart", () => { - deepStrictEqual(pipe(" a ", String.trimStart), "a ") + deepStrictEqual(pipe(" a ", S.trimStart), "a ") }) it("trimEnd", () => { - deepStrictEqual(pipe(" a ", String.trimEnd), " a") + deepStrictEqual(pipe(" a ", S.trimEnd), " a") }) it("includes", () => { - deepStrictEqual(pipe("abc", String.includes("b")), true) - deepStrictEqual(pipe("abc", String.includes("b", 2)), false) + assert.deepStrictEqual(S.includes("abc", "b"), true) + assert.deepStrictEqual(S.includes("abc", "d"), false) + }) + + it("includesWithPosition", () => { + assert.deepStrictEqual(S.includesWithPosition("abc", "b", 1), true) + assert.deepStrictEqual(S.includesWithPosition("abc", "a", 1), false) }) it("startsWith", () => { - deepStrictEqual(pipe("abc", String.startsWith("a")), true) + assert.deepStrictEqual(S.startsWith("abc", "a"), true) + assert.deepStrictEqual(S.startsWith("bc", "a"), false) + }) + + it("startsWithPosition", () => { + assert.deepStrictEqual(S.startsWithPosition("abc", "b", 1), true) + assert.deepStrictEqual(S.startsWithPosition("bc", "a", 1), false) }) it("endsWith", () => { - deepStrictEqual(pipe("abc", String.endsWith("c")), true) + assert.deepStrictEqual(S.endsWith("abc", "c"), true) + assert.deepStrictEqual(S.endsWith("ab", "c"), false) + }) + + it("endsWithPosition", () => { + assert.deepStrictEqual(S.endsWithPosition("abc", "b", 2), true) + assert.deepStrictEqual(S.endsWithPosition("abc", "c", 2), false) }) it("slice", () => { - deepStrictEqual(pipe("abcd", String.slice(1, 3)), "bc") + deepStrictEqual(pipe("abcd", S.slice(1, 3)), "bc") }) describe.concurrent("takeLeft", () => { it("should take the specified number of characters from the left side of a string", () => { const string = "Hello, World!" - const result = pipe(string, String.takeLeft(7)) + const result = pipe(string, S.takeLeft(7)) assert.strictEqual(result, "Hello, ") }) @@ -117,7 +134,7 @@ describe.concurrent("String", () => { it("should return the string for `n` larger than the string length", () => { const string = "Hello, World!" - const result = pipe(string, String.takeLeft(100)) + const result = pipe(string, S.takeLeft(100)) assert.strictEqual(result, string) }) @@ -125,7 +142,7 @@ describe.concurrent("String", () => { it("should return the empty string for a negative `n`", () => { const string = "Hello, World!" - const result = pipe(string, String.takeLeft(-1)) + const result = pipe(string, S.takeLeft(-1)) assert.strictEqual(result, "") }) @@ -133,7 +150,7 @@ describe.concurrent("String", () => { it("should round down if `n` is a float", () => { const string = "Hello, World!" - const result = pipe(string, String.takeLeft(5.5)) + const result = pipe(string, S.takeLeft(5.5)) assert.strictEqual(result, "Hello") }) @@ -143,7 +160,7 @@ describe.concurrent("String", () => { it("should take the specified number of characters from the right side of a string", () => { const string = "Hello, World!" - const result = pipe(string, String.takeRight(7)) + const result = pipe(string, S.takeRight(7)) assert.strictEqual(result, " World!") }) @@ -151,7 +168,7 @@ describe.concurrent("String", () => { it("should return the string for `n` larger than the string length", () => { const string = "Hello, World!" - const result = pipe(string, String.takeRight(100)) + const result = pipe(string, S.takeRight(100)) assert.strictEqual(result, string) }) @@ -159,7 +176,7 @@ describe.concurrent("String", () => { it("should return the empty string for a negative `n`", () => { const string = "Hello, World!" - const result = pipe(string, String.takeRight(-1)) + const result = pipe(string, S.takeRight(-1)) assert.strictEqual(result, "") }) @@ -167,7 +184,7 @@ describe.concurrent("String", () => { it("should round down if `n` is a float", () => { const string = "Hello, World!" - const result = pipe(string, String.takeRight(6.5)) + const result = pipe(string, S.takeRight(6.5)) assert.strictEqual(result, "World!") }) From dd123364cd7b2f7b76ee83864878883edd86a123 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 14:12:01 +0100 Subject: [PATCH 178/255] do notation: apply dual --- docs/modules/Either.ts.md | 46 ++++++--- docs/modules/Identity.ts.md | 41 +++++--- docs/modules/Option.ts.md | 41 +++++--- docs/modules/Predicate.ts.md | 21 +++-- docs/modules/ReadonlyArray.ts.md | 41 +++++--- docs/modules/These.ts.md | 85 +++++++++++------ docs/modules/typeclass/Chainable.ts.md | 47 ++++++---- docs/modules/typeclass/Covariant.ts.md | 14 ++- docs/modules/typeclass/Invariant.ts.md | 34 ++++--- docs/modules/typeclass/Of.ts.md | 21 +++-- docs/modules/typeclass/SemiProduct.ts.md | 20 ++-- src/Either.ts | 72 ++++++++------ src/Identity.ts | 61 +++++++----- src/Option.ts | 57 ++++++++---- src/Predicate.ts | 31 +++--- src/ReadonlyArray.ts | 63 ++++++++----- src/These.ts | 114 +++++++++++++++-------- src/typeclass/Chainable.ts | 23 +++-- src/typeclass/Covariant.ts | 26 ++++-- src/typeclass/Invariant.ts | 18 +++- src/typeclass/Of.ts | 1 + src/typeclass/SemiProduct.ts | 34 ++++--- 22 files changed, 591 insertions(+), 320 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 494811871..b51f22dac 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -510,10 +510,16 @@ A variant of `bind` that sequentially ignores the scope. **Signature** ```ts -export declare const andThenBind: ( - name: Exclude, - that: Either -) => (self: Either) => Either +export declare const andThenBind: { + (name: Exclude, that: Either): ( + self: Either + ) => Either + ( + self: Either, + name: Exclude, + that: Either + ): Either +} ``` Added in v1.0.0 @@ -523,10 +529,16 @@ Added in v1.0.0 **Signature** ```ts -export declare const bind: ( - name: Exclude, - f: (a: A) => Either -) => (self: Either) => Either +export declare const bind: { + (name: Exclude, f: (a: A) => Either): ( + self: Either + ) => Either + ( + self: Either, + name: Exclude, + f: (a: A) => Either + ): Either +} ``` Added in v1.0.0 @@ -536,7 +548,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const bindTo: (name: N) => (self: Either) => Either +export declare const bindTo: { + (name: N): (self: Either) => Either + (self: Either, name: N): Either +} ``` Added in v1.0.0 @@ -546,10 +561,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const let: ( - name: Exclude, - f: (a: A) => B -) => (self: Either) => Either +export declare const let: { + (name: Exclude, f: (a: A) => B): ( + self: Either + ) => Either + (self: Either, name: Exclude, f: (a: A) => B): Either< + E, + { [K in N | keyof A]: K extends keyof A ? A[K] : B } + > +} ``` Added in v1.0.0 diff --git a/docs/modules/Identity.ts.md b/docs/modules/Identity.ts.md index d2edfd2ac..14f6af868 100644 --- a/docs/modules/Identity.ts.md +++ b/docs/modules/Identity.ts.md @@ -61,10 +61,14 @@ A variant of `bind` that sequentially ignores the scope. **Signature** ```ts -export declare const andThenBind: ( - name: Exclude, - that: B -) => (self: A) => { [K in N | keyof A]: K extends keyof A ? A[K] : B } +export declare const andThenBind: { + (name: Exclude, that: B): (self: A) => { + [K in N | keyof A]: K extends keyof A ? A[K] : B + } + (self: A, name: Exclude, that: B): { + [K in N | keyof A]: K extends keyof A ? A[K] : B + } +} ``` Added in v1.0.0 @@ -74,10 +78,14 @@ Added in v1.0.0 **Signature** ```ts -export declare const bind: ( - name: Exclude, - f: (a: A) => B -) => (self: A) => { [K in N | keyof A]: K extends keyof A ? A[K] : B } +export declare const bind: { + (name: Exclude, f: (a: A) => B): (self: A) => { + [K in N | keyof A]: K extends keyof A ? A[K] : B + } + (self: A, name: Exclude, f: (a: A) => B): { + [K in N | keyof A]: K extends keyof A ? A[K] : B + } +} ``` Added in v1.0.0 @@ -87,7 +95,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const bindTo: (name: N) => (self: A) => { [K in N]: A } +export declare const bindTo: { + (name: N): (self: A) => { [K in N]: A } + (self: A, name: N): { [K in N]: A } +} ``` Added in v1.0.0 @@ -97,10 +108,14 @@ Added in v1.0.0 **Signature** ```ts -export declare const let: ( - name: Exclude, - f: (a: A) => B -) => (self: A) => { [K in N | keyof A]: K extends keyof A ? A[K] : B } +export declare const let: { + (name: Exclude, f: (a: A) => B): (self: A) => { + [K in N | keyof A]: K extends keyof A ? A[K] : B + } + (self: A, name: Exclude, f: (a: A) => B): { + [K in N | keyof A]: K extends keyof A ? A[K] : B + } +} ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 1f4ae767f..9f522fd86 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -556,10 +556,14 @@ A variant of `bind` that sequentially ignores the scope. **Signature** ```ts -export declare const andThenBind: ( - name: Exclude, - that: Option -) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +export declare const andThenBind: { + (name: Exclude, that: Option): ( + self: Option + ) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + (self: Option, name: Exclude, that: Option): Option<{ + [K in N | keyof A]: K extends keyof A ? A[K] : B + }> +} ``` Added in v1.0.0 @@ -569,10 +573,14 @@ Added in v1.0.0 **Signature** ```ts -export declare const bind: ( - name: Exclude, - f: (a: A) => Option -) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +export declare const bind: { + (name: Exclude, f: (a: A) => Option): ( + self: Option + ) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + (self: Option, name: Exclude, f: (a: A) => Option): Option<{ + [K in N | keyof A]: K extends keyof A ? A[K] : B + }> +} ``` Added in v1.0.0 @@ -582,7 +590,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const bindTo: (name: N) => (self: Option) => Option<{ [K in N]: A }> +export declare const bindTo: { + (name: N): (self: Option) => Option<{ [K in N]: A }> + (self: Option, name: N): Option<{ [K in N]: A }> +} ``` Added in v1.0.0 @@ -592,10 +603,14 @@ Added in v1.0.0 **Signature** ```ts -export declare const let: ( - name: Exclude, - f: (a: A) => B -) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +export declare const let: { + (name: Exclude, f: (a: A) => B): ( + self: Option + ) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + (self: Option, name: Exclude, f: (a: A) => B): Option<{ + [K in N | keyof A]: K extends keyof A ? A[K] : B + }> +} ``` Added in v1.0.0 diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index ea77a9011..0a5475ad1 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -103,10 +103,16 @@ A variant of `bind` that sequentially ignores the scope. **Signature** ```ts -export declare const andThenBind: ( - name: Exclude, - that: Predicate -) => (self: Predicate) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> +export declare const andThenBind: { + (name: Exclude, that: Predicate): ( + self: Predicate + ) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: Predicate, + name: Exclude, + that: Predicate + ): Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} ``` Added in v1.0.0 @@ -116,9 +122,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const bindTo: ( - name: N -) => (self: Predicate) => Predicate<{ readonly [K in N]: A }> +export declare const bindTo: { + (name: N): (self: Predicate) => Predicate<{ readonly [K in N]: A }> + (self: Predicate, name: N): Predicate<{ readonly [K in N]: A }> +} ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 4ea5586a3..c1e029356 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -394,10 +394,14 @@ A variant of `bind` that sequentially ignores the scope. **Signature** ```ts -export declare const andThenBind: ( - name: Exclude, - that: readonly B[] -) => (self: readonly A[]) => { [K in N | keyof A]: K extends keyof A ? A[K] : B }[] +export declare const andThenBind: { + (name: Exclude, that: readonly B[]): ( + self: readonly A[] + ) => { [K in N | keyof A]: K extends keyof A ? A[K] : B }[] + (self: readonly A[], name: Exclude, that: readonly B[]): { + [K in N | keyof A]: K extends keyof A ? A[K] : B + }[] +} ``` Added in v1.0.0 @@ -407,10 +411,14 @@ Added in v1.0.0 **Signature** ```ts -export declare const bind: ( - name: Exclude, - f: (a: A) => readonly B[] -) => (self: readonly A[]) => { [K in N | keyof A]: K extends keyof A ? A[K] : B }[] +export declare const bind: { + (name: Exclude, f: (a: A) => readonly B[]): ( + self: readonly A[] + ) => { [K in N | keyof A]: K extends keyof A ? A[K] : B }[] + (self: readonly A[], name: Exclude, f: (a: A) => readonly B[]): { + [K in N | keyof A]: K extends keyof A ? A[K] : B + }[] +} ``` Added in v1.0.0 @@ -420,7 +428,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const bindTo: (name: N) => (self: readonly A[]) => { [K in N]: A }[] +export declare const bindTo: { + (name: N): (self: readonly A[]) => { [K in N]: A }[] + (self: readonly A[], name: N): { [K in N]: A }[] +} ``` Added in v1.0.0 @@ -430,10 +441,14 @@ Added in v1.0.0 **Signature** ```ts -export declare const let: ( - name: Exclude, - f: (a: A) => B -) => (self: readonly A[]) => { [K in N | keyof A]: K extends keyof A ? A[K] : B }[] +export declare const let: { + (name: Exclude, f: (a: A) => B): ( + self: readonly A[] + ) => { [K in N | keyof A]: K extends keyof A ? A[K] : B }[] + (self: readonly A[], name: Exclude, f: (a: A) => B): { + [K in N | keyof A]: K extends keyof A ? A[K] : B + }[] +} ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index d9f0fa2a7..aa580d692 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -568,12 +568,16 @@ Added in v1.0.0 **Signature** ```ts -export declare const andThenBind: ( - name: Exclude, - that: These -) => ( - self: These -) => These +export declare const andThenBind: { + (name: Exclude, that: These): ( + self: These + ) => These + ( + self: These, + name: Exclude, + that: These + ): These +} ``` Added in v1.0.0 @@ -583,12 +587,19 @@ Added in v1.0.0 **Signature** ```ts -export declare const bind: ( - name: Exclude, - f: (a: A) => These -) => ( - self: These -) => These +export declare const bind: { + ( + name: Exclude, + f: (a: A) => These + ): ( + self: These + ) => These + ( + self: These, + name: Exclude, + f: (a: A) => These + ): These +} ``` Added in v1.0.0 @@ -598,12 +609,16 @@ Added in v1.0.0 **Signature** ```ts -export declare const bindEither: ( - name: Exclude, - f: (a: A) => Either -) => ( - self: These -) => These +export declare const bindEither: { + (name: Exclude, f: (a: A) => Either): ( + self: These + ) => These + ( + self: These, + name: Exclude, + f: (a: A) => Either + ): These +} ``` Added in v1.0.0 @@ -613,12 +628,16 @@ Added in v1.0.0 **Signature** ```ts -export declare const bindThese: ( - name: Exclude, - f: (a: A) => These -) => ( - self: These -) => These +export declare const bindThese: { + (name: Exclude, f: (a: A) => These): ( + self: These + ) => These + ( + self: These, + name: Exclude, + f: (a: A) => These + ): These +} ``` Added in v1.0.0 @@ -628,7 +647,10 @@ Added in v1.0.0 **Signature** ```ts -export declare const bindTo: (name: N) => (self: These) => These +export declare const bindTo: { + (name: N): (self: These) => These + (self: These, name: N): These +} ``` Added in v1.0.0 @@ -638,10 +660,15 @@ Added in v1.0.0 **Signature** ```ts -export declare const let: ( - name: Exclude, - f: (a: A) => B -) => (self: These) => These +export declare const let: { + (name: Exclude, f: (a: A) => B): ( + self: These + ) => These + (self: These, name: Exclude, f: (a: A) => B): These< + E, + { [K in N | keyof A]: K extends keyof A ? A[K] : B } + > +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Chainable.ts.md b/docs/modules/typeclass/Chainable.ts.md index aa0ccbf0e..311a635dc 100644 --- a/docs/modules/typeclass/Chainable.ts.md +++ b/docs/modules/typeclass/Chainable.ts.md @@ -12,16 +12,44 @@ Added in v1.0.0

Table of contents

+- [do notation](#do-notation) + - [bind](#bind) - [sequencing](#sequencing) - [andThenDiscard](#andthendiscard) - [type class](#type-class) - [Chainable (interface)](#chainable-interface) - [utils](#utils) - - [bind](#bind) - [tap](#tap) --- +# do notation + +## bind + +**Signature** + +```ts +export declare const bind: ( + F: Chainable +) => { + (name: Exclude, f: (a: A) => Kind): < + R1, + O1, + E1 + >( + self: Kind + ) => Kind + ( + self: Kind, + name: Exclude, + f: (a: A) => Kind + ): Kind +} +``` + +Added in v1.0.0 + # sequencing ## andThenDiscard @@ -64,23 +92,6 @@ Added in v1.0.0 # utils -## bind - -**Signature** - -```ts -export declare const bind: ( - F: Chainable -) => ( - name: Exclude, - f: (a: A) => Kind -) => ( - self: Kind -) => Kind -``` - -Added in v1.0.0 - ## tap Returns an effect that effectfully "peeks" at the success of this effect. diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index ccc229729..787638d5b 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -51,10 +51,16 @@ Added in v1.0.0 ```ts export declare const let: ( F: Covariant -) => ( - name: Exclude, - f: (a: A) => B -) => (self: Kind) => Kind +) => { + (name: Exclude, f: (a: A) => B): ( + self: Kind + ) => Kind + ( + self: Kind, + name: Exclude, + f: (a: A) => B + ): Kind +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Invariant.ts.md b/docs/modules/typeclass/Invariant.ts.md index 0849357ac..fa1d95cf8 100644 --- a/docs/modules/typeclass/Invariant.ts.md +++ b/docs/modules/typeclass/Invariant.ts.md @@ -14,10 +14,11 @@ Added in v1.0.0 - [constructors](#constructors) - [make](#make) +- [do notation](#do-notation) + - [bindTo](#bindto) - [type class](#type-class) - [Invariant (interface)](#invariant-interface) - [utils](#utils) - - [bindTo](#bindto) - [imapComposition](#imapcomposition) - [tupled](#tupled) @@ -37,39 +38,42 @@ export declare const make: ( Added in v1.0.0 -# type class +# do notation -## Invariant (interface) +## bindTo **Signature** ```ts -export interface Invariant extends TypeClass { - readonly imap: { - (to: (a: A) => B, from: (b: B) => A): (self: Kind) => Kind - (self: Kind, to: (a: A) => B, from: (b: B) => A): Kind - } +export declare const bindTo: ( + F: Invariant +) => { + (name: N): (self: Kind) => Kind + (self: Kind, name: N): Kind } ``` Added in v1.0.0 -# utils +# type class -## bindTo +## Invariant (interface) **Signature** ```ts -export declare const bindTo: ( - F: Invariant -) => ( - name: N -) => (self: Kind) => Kind +export interface Invariant extends TypeClass { + readonly imap: { + (to: (a: A) => B, from: (b: B) => A): (self: Kind) => Kind + (self: Kind, to: (a: A) => B, from: (b: B) => A): Kind + } +} ``` Added in v1.0.0 +# utils + ## imapComposition Returns a default ternary `imap` composition. diff --git a/docs/modules/typeclass/Of.ts.md b/docs/modules/typeclass/Of.ts.md index 80975d22d..21ef2619c 100644 --- a/docs/modules/typeclass/Of.ts.md +++ b/docs/modules/typeclass/Of.ts.md @@ -12,41 +12,44 @@ Added in v1.0.0

Table of contents

+- [do notation](#do-notation) + - [Do](#do) - [type class](#type-class) - [Of (interface)](#of-interface) - [utils](#utils) - - [Do](#do) - [ofComposition](#ofcomposition) - [unit](#unit) --- -# type class +# do notation -## Of (interface) +## Do **Signature** ```ts -export interface Of extends TypeClass { - readonly of:
(a: A) => Kind -} +export declare const Do: (F: Of) => Kind ``` Added in v1.0.0 -# utils +# type class -## Do +## Of (interface) **Signature** ```ts -export declare const Do: (F: Of) => Kind +export interface Of extends TypeClass { + readonly of: (a: A) => Kind +} ``` Added in v1.0.0 +# utils + ## ofComposition Returns a default `of` composition. diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index c77222074..d38bc61d2 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -77,12 +77,20 @@ Added in v1.0.0 ```ts export declare const andThenBind: ( F: SemiProduct -) => ( - name: Exclude, - that: Kind -) => ( - self: Kind -) => Kind +) => { + (name: Exclude, that: Kind): < + R1, + O1, + E1 + >( + self: Kind + ) => Kind + ( + self: Kind, + name: Exclude, + that: Kind + ): Kind +} ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index 55462d8a3..0a7910402 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1316,18 +1316,26 @@ export const lefts = (self: Iterable>): Array => { * @category do notation * @since 1.0.0 */ -export const bindTo: ( - name: N -) => (self: Either) => Either = invariant.bindTo(Invariant) - -const let_: ( - name: Exclude, - f: (a: A) => B -) => ( - self: Either -) => Either = covariant.let( - Covariant -) +export const bindTo: { + ( + name: N + ): (self: Either) => Either + (self: Either, name: N): Either +} = invariant.bindTo(Invariant) + +const let_: { + ( + name: Exclude, + f: (a: A) => B + ): ( + self: Either + ) => Either + ( + self: Either, + name: Exclude, + f: (a: A) => B + ): Either +} = covariant.let(Covariant) export { /** @@ -1346,13 +1354,19 @@ export const Do: Either = of_.Do(Of) * @category do notation * @since 1.0.0 */ -export const bind: ( - name: Exclude, - f: (a: A) => Either -) => ( - self: Either -) => Either = chainable - .bind(Chainable) +export const bind: { + ( + name: Exclude, + f: (a: A) => Either + ): ( + self: Either + ) => Either + ( + self: Either, + name: Exclude, + f: (a: A) => Either + ): Either +} = chainable.bind(Chainable) /** * A variant of `bind` that sequentially ignores the scope. @@ -1360,10 +1374,16 @@ export const bind: ( * @category do notation * @since 1.0.0 */ -export const andThenBind: ( - name: Exclude, - that: Either -) => ( - self: Either -) => Either = semiProduct - .andThenBind(SemiProduct) +export const andThenBind: { + ( + name: Exclude, + that: Either + ): ( + self: Either + ) => Either + ( + self: Either, + name: Exclude, + that: Either + ): Either +} = semiProduct.andThenBind(SemiProduct) diff --git a/src/Identity.ts b/src/Identity.ts index 19bbfceb6..878f174d9 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -204,18 +204,22 @@ export const Traversable: traversable.Traversable = traversa * @category do notation * @since 1.0.0 */ -export const bindTo: ( - name: N -) => (self: Identity) => Identity<{ [K in N]: A }> = invariant.bindTo(Invariant) +export const bindTo: { + (name: N): (self: Identity) => Identity<{ [K in N]: A }> + (self: Identity, name: N): Identity<{ [K in N]: A }> +} = invariant.bindTo(Invariant) -const let_: ( - name: Exclude, - f: (a: A) => B -) => ( - self: Identity -) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant.let( - Covariant -) +const let_: { + ( + name: Exclude, + f: (a: A) => B + ): (self: Identity) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: Identity, + name: Exclude, + f: (a: A) => B + ): Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = covariant.let(Covariant) export { /** @@ -235,14 +239,17 @@ export const Do: Identity<{}> = of_.Do(Of) * @category do notation * @since 1.0.0 */ -export const bind: ( - name: Exclude, - f: (a: A) => Identity -) => ( - self: Identity -) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable.bind( - Chainable -) +export const bind: { + ( + name: Exclude, + f: (a: A) => Identity + ): (self: Identity) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: Identity, + name: Exclude, + f: (a: A) => Identity + ): Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = chainable.bind(Chainable) /** * A variant of `bind` that sequentially ignores the scope. @@ -250,8 +257,14 @@ export const bind: ( * @category do notation * @since 1.0.0 */ -export const andThenBind: ( - name: Exclude, - that: Identity -) => (self: Identity) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = - semiProduct.andThenBind(SemiProduct) +export const andThenBind: { + ( + name: Exclude, + that: Identity + ): (self: Identity) => Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: Identity, + name: Exclude, + that: Identity + ): Identity<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = semiProduct.andThenBind(SemiProduct) diff --git a/src/Option.ts b/src/Option.ts index c03ca486a..b2d9b22dc 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1593,15 +1593,22 @@ export const multiplyCompact = (self: Iterable>): number => { * @category do notation * @since 1.0.0 */ -export const bindTo: ( - name: N -) => (self: Option) => Option<{ [K in N]: A }> = invariant.bindTo(Invariant) - -const let_: ( - name: Exclude, - f: (a: A) => B -) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant - .let(Covariant) +export const bindTo: { + (name: N): (self: Option) => Option<{ [K in N]: A }> + (self: Option, name: N): Option<{ [K in N]: A }> +} = invariant.bindTo(Invariant) + +const let_: { + ( + name: Exclude, + f: (a: A) => B + ): (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: Option, + name: Exclude, + f: (a: A) => B + ): Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = covariant.let(Covariant) export { /** @@ -1615,11 +1622,17 @@ export { * @category do notation * @since 1.0.0 */ -export const bind: ( - name: Exclude, - f: (a: A) => Option -) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable - .bind(Chainable) +export const bind: { + ( + name: Exclude, + f: (a: A) => Option + ): (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: Option, + name: Exclude, + f: (a: A) => Option + ): Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = chainable.bind(Chainable) /** * @category do notation @@ -1633,8 +1646,14 @@ export const Do: Option<{}> = of_.Do(Of) * @category do notation * @since 1.0.0 */ -export const andThenBind: ( - name: Exclude, - that: Option -) => (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct - .andThenBind(SemiProduct) +export const andThenBind: { + ( + name: Exclude, + that: Option + ): (self: Option) => Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: Option, + name: Exclude, + that: Option + ): Option<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = semiProduct.andThenBind(SemiProduct) diff --git a/src/Predicate.ts b/src/Predicate.ts index ba949d694..55b47d2b2 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -324,11 +324,10 @@ export const any = (collection: Iterable>): Predicate => * @category do notation * @since 1.0.0 */ -export const bindTo: ( - name: N -) => (self: Predicate) => Predicate<{ readonly [K in N]: A }> = invariant.bindTo( - Invariant -) +export const bindTo: { + (name: N): (self: Predicate) => Predicate<{ readonly [K in N]: A }> + (self: Predicate, name: N): Predicate<{ readonly [K in N]: A }> +} = invariant.bindTo(Invariant) /** * @category do notation @@ -342,12 +341,16 @@ export const Do: Predicate<{}> = of_.Do(Of) * @category do notation * @since 1.0.0 */ -export const andThenBind: ( - name: Exclude, - that: Predicate -) => ( - self: Predicate -) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct - .andThenBind( - SemiProduct - ) +export const andThenBind: { + ( + name: Exclude, + that: Predicate + ): ( + self: Predicate + ) => Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: Predicate, + name: Exclude, + that: Predicate + ): Predicate<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = semiProduct.andThenBind(SemiProduct) diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index e0732413d..8f5d4e1d5 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -2478,17 +2478,22 @@ export const getOrder: (O: Order) => Order> = order.array * @category do notation * @since 1.0.0 */ -export const bindTo: ( - name: N -) => (self: ReadonlyArray) => Array<{ [K in N]: A }> = invariant - .bindTo(Invariant) as any - -const let_: ( - name: Exclude, - f: (a: A) => B -) => ( - self: ReadonlyArray -) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = covariant.let(Covariant) as any +export const bindTo: { + (name: N): (self: ReadonlyArray) => Array<{ [K in N]: A }> + (self: ReadonlyArray, name: N): Array<{ [K in N]: A }> +} = invariant.bindTo(Invariant) as any + +const let_: { + ( + name: Exclude, + f: (a: A) => B + ): (self: ReadonlyArray) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: ReadonlyArray, + name: Exclude, + f: (a: A) => B + ): Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = covariant.let(Covariant) as any export { /** @@ -2508,12 +2513,17 @@ export const Do: ReadonlyArray<{}> = of_.Do(Of) * @category do notation * @since 1.0.0 */ -export const bind: ( - name: Exclude, - f: (a: A) => ReadonlyArray -) => ( - self: ReadonlyArray -) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = chainable.bind(Chainable) as any +export const bind: { + ( + name: Exclude, + f: (a: A) => ReadonlyArray + ): (self: ReadonlyArray) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: ReadonlyArray, + name: Exclude, + f: (a: A) => ReadonlyArray + ): Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = chainable.bind(Chainable) as any /** * A variant of `bind` that sequentially ignores the scope. @@ -2521,11 +2531,14 @@ export const bind: ( * @category do notation * @since 1.0.0 */ -export const andThenBind: ( - name: Exclude, - that: ReadonlyArray -) => ( - self: ReadonlyArray -) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> = semiProduct.andThenBind( - SemiProduct -) as any +export const andThenBind: { + ( + name: Exclude, + that: ReadonlyArray + ): (self: ReadonlyArray) => Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> + ( + self: ReadonlyArray, + name: Exclude, + that: ReadonlyArray + ): Array<{ [K in N | keyof A]: K extends keyof A ? A[K] : B }> +} = semiProduct.andThenBind(SemiProduct) as any diff --git a/src/These.ts b/src/These.ts index 014507f9a..274a6826b 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1381,18 +1381,22 @@ export const divide: { * @category do notation * @since 1.0.0 */ -export const bindTo: ( - name: N -) => (self: These) => These = invariant.bindTo(Invariant) - -const let_: ( - name: Exclude, - f: (a: A) => B -) => ( - self: These -) => These = covariant.let( - Covariant -) +export const bindTo: { + (name: N): (self: These) => These + (self: These, name: N): These +} = invariant.bindTo(Invariant) + +const let_: { + ( + name: Exclude, + f: (a: A) => B + ): (self: These) => These + ( + self: These, + name: Exclude, + f: (a: A) => B + ): These +} = covariant.let(Covariant) export { /** @@ -1412,46 +1416,80 @@ export const Do: These = of_.Do(Of) * @category do notation * @since 1.0.0 */ -export const andThenBind: ( - name: Exclude, - that: Validated -) => ( - self: Validated -) => Validated = semiProduct - .andThenBind(SemiProduct) +export const bind: { + ( + name: Exclude, + f: (a: A) => Validated + ): ( + self: Validated + ) => Validated + ( + self: Validated, + name: Exclude, + f: (a: A) => Validated + ): Validated +} = chainable.bind(Chainable) /** * @category do notation * @since 1.0.0 */ -export const bind: ( +export const bindEither: { + ( + name: Exclude, + f: (a: A) => Either + ): ( + self: Validated + ) => Validated + ( + self: Validated, + name: Exclude, + f: (a: A) => Either + ): Validated +} = dual(3, ( + self: Validated, name: Exclude, - f: (a: A) => Validated -) => ( - self: Validated -) => Validated = chainable - .bind(Chainable) + f: (a: A) => Either +): Validated => + bind(self, name, (a) => fromEither(f(a)))) /** * @category do notation * @since 1.0.0 */ -export const bindEither = ( +export const bindThese: { + ( + name: Exclude, + f: (a: A) => These + ): ( + self: Validated + ) => Validated + ( + self: Validated, + name: Exclude, + f: (a: A) => These + ): Validated +} = dual(3, ( + self: Validated, name: Exclude, - f: (a: A) => Either -): ( - self: Validated -) => Validated => - bind(name, (a) => fromEither(f(a))) + f: (a: A) => These +): Validated => + bind(self, name, (a) => toValidated(f(a)))) /** * @category do notation * @since 1.0.0 */ -export const bindThese = ( - name: Exclude, - f: (a: A) => These -): ( - self: Validated -) => Validated => - bind(name, (a) => toValidated(f(a))) +export const andThenBind: { + ( + name: Exclude, + that: Validated + ): ( + self: Validated + ) => Validated + ( + self: Validated, + name: Exclude, + that: Validated + ): Validated +} = semiProduct.andThenBind(SemiProduct) diff --git a/src/typeclass/Chainable.ts b/src/typeclass/Chainable.ts index 2d3fa7e60..79ee02aee 100644 --- a/src/typeclass/Chainable.ts +++ b/src/typeclass/Chainable.ts @@ -56,18 +56,25 @@ export const tap = (F: Chainable): { ) /** + * @category do notation * @since 1.0.0 */ -export const bind = (F: Chainable) => +export const bind = (F: Chainable): { ( name: Exclude, f: (a: A) => Kind ): ( self: Kind - ) => Kind< - F, - R1 & R2, - O1 | O2, - E1 | E2, - { [K in keyof A | N]: K extends keyof A ? A[K] : B } - > => F.flatMap(a => F.map(f(a), b => Object.assign({}, a, { [name]: b }) as any)) + ) => Kind + ( + self: Kind, + name: Exclude, + f: (a: A) => Kind + ): Kind +} => + dual(3, ( + self: Kind, + name: Exclude, + f: (a: A) => Kind + ): Kind => + F.flatMap(self, a => F.map(f(a), b => Object.assign({}, a, { [name]: b }) as any))) diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index 40c03e8ef..49c9fb5c9 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -87,13 +87,25 @@ export const asUnit = ( const let_ = ( F: Covariant -): (( - name: Exclude, - f: (a: A) => B -) => ( - self: Kind -) => Kind) => - (name, f) => F.map(a => Object.assign({}, a, { [name]: f(a) }) as any) +): { + ( + name: Exclude, + f: (a: A) => B + ): ( + self: Kind + ) => Kind + ( + self: Kind, + name: Exclude, + f: (a: A) => B + ): Kind +} => + dual(3, ( + self: Kind, + name: Exclude, + f: (a: A) => B + ): Kind => + F.map(self, a => Object.assign({}, a, { [name]: f(a) }) as any)) export { /** diff --git a/src/typeclass/Invariant.ts b/src/typeclass/Invariant.ts index 85857b09b..2b6d206a5 100644 --- a/src/typeclass/Invariant.ts +++ b/src/typeclass/Invariant.ts @@ -52,15 +52,23 @@ export const imapComposition = ( ): Kind> => F.imap(self, G.imap(to, from), G.imap(from, to)) /** + * @category do notation * @since 1.0.0 */ -export const bindTo = (F: Invariant) => +export const bindTo = (F: Invariant): { ( name: N - ): (( - self: Kind - ) => Kind) => - F.imap(a => ({ [name]: a } as any), ({ [name]: a }) => a) + ): (self: Kind) => Kind + ( + self: Kind, + name: N + ): Kind +} => + dual(2, ( + self: Kind, + name: N + ): Kind => + F.imap(self, a => ({ [name]: a } as any), ({ [name]: a }) => a)) /** * @since 1.0.0 diff --git a/src/typeclass/Of.ts b/src/typeclass/Of.ts index e749399b3..69ac52b33 100644 --- a/src/typeclass/Of.ts +++ b/src/typeclass/Of.ts @@ -29,6 +29,7 @@ export const unit = ( ): Kind => F.of(undefined) /** + * @category do notation * @since 1.0.0 */ export const Do = ( diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 833edf0db..cceec4187 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -119,23 +119,29 @@ export const productManyComposition = (F: SemiProduct) => +export const andThenBind = (F: SemiProduct): { ( name: Exclude, that: Kind - ) => - ( - self: Kind - ): Kind< - F, - R1 & R2, - O1 | O2, - E1 | E2, - { [K in keyof A | N]: K extends keyof A ? A[K] : B } - > => - F.imap(F.product(self, that), ([a, b]) => - Object.assign({}, a, { [name]: b }) as any, ({ [name]: b, ...rest }) => - [rest, b] as any) + ): ( + self: Kind + ) => Kind + ( + self: Kind, + name: Exclude, + that: Kind + ): Kind +} => + dual(3, ( + self: Kind, + name: Exclude, + that: Kind + ): Kind => + F.imap( + F.product(self, that), + ([a, b]) => Object.assign({}, a, { [name]: b }) as any, + ({ [name]: b, ...rest }) => [rest, b] as any + )) /** * Appends an element to the end of a tuple. From 6fe9b992863527b18aa1cbec77709e044b22decf Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 14:41:45 +0100 Subject: [PATCH 179/255] ReadonlyArray: remove mapWithIndex --- src/ReadonlyArray.ts | 36 +++++++++---------------- test/ReadonlyArray.ts | 13 +-------- test/limbo/CovariantWithIndex.ts | 40 ---------------------------- test/typeclass/CovariantWithIndex.ts | 31 --------------------- 4 files changed, 13 insertions(+), 107 deletions(-) delete mode 100644 test/limbo/CovariantWithIndex.ts delete mode 100644 test/typeclass/CovariantWithIndex.ts diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 8f5d4e1d5..c8a2e6a62 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1386,18 +1386,6 @@ export const mapNonEmpty: { mapNonEmptyWithIndex(self, f) ) -/** - * @category mapping - * @since 1.0.0 - */ -export const mapWithIndex: { - (f: (a: A, i: number) => B): (self: ReadonlyArray) => Array - (self: ReadonlyArray, f: (a: A, i: number) => B): Array -} = dual( - 2, - (self: ReadonlyArray, f: (a: A, i: number) => B): Array => self.map((a, i) => f(a, i)) -) - /** * @category mapping * @since 1.0.0 @@ -1422,24 +1410,24 @@ export const Of: of_.Of = { } /** - * @category instances + * @category mapping * @since 1.0.0 */ -export const Covariant: covariant.Covariant = covariant.make(( - self: ReadonlyArray, - f: (a: A) => B -): ReadonlyArray => self.map(a => f(a))) +export const map: { + (f: (a: A, i: number) => B): (self: ReadonlyArray) => Array + (self: ReadonlyArray, f: (a: A, i: number) => B): Array +} = dual(2, (self: ReadonlyArray, f: (a: A, i: number) => B): Array => self.map(f)) + +const imap = covariant.imap(map) /** - * @category mapping + * @category instances * @since 1.0.0 */ -export const map: { - (f: (a: A) => B): (self: ReadonlyArray) => Array - (self: ReadonlyArray, f: (a: A) => B): Array -} = Covariant.map as any - -const imap = Covariant.imap +export const Covariant: covariant.Covariant = { + imap, + map +} /** * @category instances diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 93bb661d7..4f028783f 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -786,13 +786,10 @@ describe.concurrent("ReadonlyArray", () => { ), [2, 4, 6] ) - }) - - it("mapWithIndex", () => { deepStrictEqual( pipe( ["a", "b"], - RA.mapWithIndex((s, i) => s + i) + RA.map((s, i) => s + i) ), ["a0", "b1"] ) @@ -1497,14 +1494,6 @@ describe.concurrent("ReadonlyArray", () => { deepStrictEqual(S.combine([1, 2], [1, 2]), [1, 2]) }) - it("should be safe when calling map with a binary function", () => { - interface Foo { - readonly bar: () => number - } - const f = (a: number, x?: Foo) => (x !== undefined ? `${a}${x.bar()}` : `${a}`) - deepStrictEqual(pipe([1, 2], RA.map(f)), ["1", "2"]) - }) - it("empty", () => { deepStrictEqual(RA.empty.length, 0) }) diff --git a/test/limbo/CovariantWithIndex.ts b/test/limbo/CovariantWithIndex.ts deleted file mode 100644 index f4a2efa23..000000000 --- a/test/limbo/CovariantWithIndex.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @since 1.0.0 - */ -import { pipe } from "@fp-ts/core/Function" -import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -// import type { Covariant } from "@fp-ts/core/typeclass/Covariant" - -/** - * @category type class - * @since 1.0.0 - */ -export interface CovariantWithIndex extends TypeClass { - readonly mapWithIndex: ( - f: (a: A, i: I) => B - ) => (self: Kind) => Kind -} - -/** - * Returns a default `mapWithIndex` composition. - * - * @since 1.0.0 - */ -export const mapWithIndexComposition = ( - F: CovariantWithIndex, - G: CovariantWithIndex -): (( - f: (a: A, ij: readonly [I, J]) => B -) => ( - self: Kind> -) => Kind>) => - (f) => F.mapWithIndex((ga, i) => pipe(ga, G.mapWithIndex((a, j) => f(a, [i, j])))) - -// /** -// * Returns a default `map` implementation. -// * -// * @since 1.0.0 -// */ -// export const map = ( -// F: CovariantWithIndex -// ): Covariant["map"] => (f) => F.mapWithIndex(f) diff --git a/test/typeclass/CovariantWithIndex.ts b/test/typeclass/CovariantWithIndex.ts deleted file mode 100644 index d038fb7bd..000000000 --- a/test/typeclass/CovariantWithIndex.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { pipe } from "@fp-ts/core/Function" -import * as RA from "@fp-ts/core/ReadonlyArray" -import * as _ from "@fp-ts/core/test/limbo/CovariantWithIndex" -import * as U from "../util" - -const CovariantWithIndex: _.CovariantWithIndex = { - mapWithIndex: RA.mapWithIndex -} - -describe("CovariantWithIndex", () => { - it("mapWithIndexComposition", () => { - const mapWithIndex = _.mapWithIndexComposition(CovariantWithIndex, CovariantWithIndex) - const f = (a: string, [i, j]: readonly [number, number]) => a + i + j - U.deepStrictEqual(pipe([], mapWithIndex(f)), []) - U.deepStrictEqual(pipe([[]], mapWithIndex(f)), [[]]) - U.deepStrictEqual(pipe([["a"]], mapWithIndex(f)), [["a00"]]) - U.deepStrictEqual(pipe([["a"], ["b"]], mapWithIndex(f)), [["a00"], ["b10"]]) - U.deepStrictEqual(pipe([["a", "c"], ["b", "d", "e"]], mapWithIndex(f)), [["a00", "c01"], [ - "b10", - "d11", - "e12" - ]]) - }) - - // it("map", () => { - // const map = _.map(CovariantWithIndex) - // const f = (a: string) => a + "!" - // U.deepStrictEqual(pipe([], map(f)), []) - // U.deepStrictEqual(pipe(["a", "b", "c"], map(f)), ["a!", "b!", "c!"]) - // }) -}) From 08f355a11cd26fca13a9e2791780a3186ad4d663 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 15:04:01 +0100 Subject: [PATCH 180/255] Request an Equivalent instead of an Equivalence in the APIs --- docs/modules/Either.ts.md | 2 +- docs/modules/Option.ts.md | 2 +- docs/modules/ReadonlyArray.ts.md | 44 ++++++++------------- docs/modules/These.ts.md | 2 +- docs/modules/typeclass/Equivalence.ts.md | 2 +- src/Either.ts | 4 +- src/Option.ts | 6 +-- src/ReadonlyArray.ts | 49 +++++++++++++----------- src/These.ts | 4 +- src/typeclass/Equivalence.ts | 5 +-- 10 files changed, 56 insertions(+), 64 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index b51f22dac..d215ffdd3 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -1504,7 +1504,7 @@ Returns a function that checks if an `Either` contains a given value using a pro **Signature** ```ts -export declare const contains: (equivalence: Equivalence) => { +export declare const contains: (isEquivalent: (self: A, that: A) => boolean) => { (a: A): (self: Either) => boolean (self: Either, a: A): boolean } diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 9f522fd86..2351afeb9 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -1778,7 +1778,7 @@ Returns a function that checks if an `Option` contains a given value using a pro **Signature** ```ts -export declare const contains: (equivalence: Equivalence) => { +export declare const contains: (isEquivalent: (self: A, that: A) => boolean) => { (a: A): (self: Option) => boolean (self: Option, a: A): boolean } diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index c1e029356..6cb9b7733 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -132,7 +132,6 @@ Added in v1.0.0 - [map](#map) - [mapNonEmpty](#mapnonempty) - [mapNonEmptyWithIndex](#mapnonemptywithindex) - - [mapWithIndex](#mapwithindex) - [tupled](#tupled) - [models](#models) - [NonEmptyArray (type alias)](#nonemptyarray-type-alias) @@ -1202,7 +1201,7 @@ Group equal, consecutive elements of a `NonEmptyReadonlyArray` into `NonEmptyArr ```ts export declare const group: ( - equivalence: Equivalence + isEquivalent: (self: A, that: A) => boolean ) => (self: readonly [A, ...A[]]) => [[A, ...A[]], ...[A, ...A[]][]] ``` @@ -1417,7 +1416,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const getIntersectionSemigroup: (equivalence: Equivalence) => Semigroup +export declare const getIntersectionSemigroup: ( + isEquivalent: (self: A, that: A) => boolean +) => Semigroup ``` Added in v1.0.0 @@ -1451,7 +1452,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getUnionMonoid: (equivalence: Equivalence) => Monoid +export declare const getUnionMonoid: (isEquivalent: (self: A, that: A) => boolean) => Monoid ``` Added in v1.0.0 @@ -1461,7 +1462,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const getUnionSemigroup: (equivalence: Equivalence) => Semigroup +export declare const getUnionSemigroup: (isEquivalent: (self: A, that: A) => boolean) => Semigroup ``` Added in v1.0.0 @@ -1600,8 +1601,8 @@ Added in v1.0.0 ```ts export declare const map: { - (f: (a: A) => B): (self: readonly A[]) => B[] - (self: readonly A[], f: (a: A) => B): B[] + (f: (a: A, i: number) => B): (self: readonly A[]) => B[] + (self: readonly A[], f: (a: A, i: number) => B): B[] } ``` @@ -1633,19 +1634,6 @@ export declare const mapNonEmptyWithIndex: { Added in v1.0.0 -## mapWithIndex - -**Signature** - -```ts -export declare const mapWithIndex: { - (f: (a: A, i: number) => B): (self: readonly A[]) => B[] - (self: readonly A[], f: (a: A, i: number) => B): B[] -} -``` - -Added in v1.0.0 - ## tupled **Signature** @@ -1728,7 +1716,7 @@ Returns a function that checks if a `ReadonlyArray` contains a given value using **Signature** ```ts -export declare const contains: (equivalence: Equivalence) => { +export declare const contains: (isEquivalent: (self: A, that: A) => boolean) => { (a: A): (self: Iterable) => boolean (self: Iterable, a: A): boolean } @@ -2151,7 +2139,7 @@ The order and references of result values are determined by the first `Iterable` **Signature** ```ts -export declare const difference: (equivalence: Equivalence) => { +export declare const difference: (isEquivalent: (self: A, that: A) => boolean) => { (that: Iterable): (self: Iterable) => A[] (self: Iterable, that: Iterable): A[] } @@ -2227,7 +2215,7 @@ The order and references of result values are determined by the first `Iterable` **Signature** ```ts -export declare const intersection: (equivalence: Equivalence) => { +export declare const intersection: (isEquivalent: (self: A, that: A) => boolean) => { (that: Iterable): (self: Iterable) => A[] (self: Iterable, that: Iterable): A[] } @@ -2577,7 +2565,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const union: (equivalence: Equivalence) => { +export declare const union: (isEquivalent: (self: A, that: A) => boolean) => { (that: readonly A[]): (self: readonly A[]) => A[] (self: readonly A[], that: readonly A[]): A[] } @@ -2590,7 +2578,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const unionNonEmpty: (equivalence: Equivalence) => { +export declare const unionNonEmpty: (isEquivalent: (self: A, that: A) => boolean) => { (that: readonly [A, ...A[]]): (self: readonly A[]) => [A, ...A[]] (that: readonly A[]): (self: readonly [A, ...A[]]) => [A, ...A[]] (self: readonly A[], that: readonly [A, ...A[]]): [A, ...A[]] @@ -2607,7 +2595,7 @@ Remove duplicates from am `Iterable`, keeping the first occurrence of an element **Signature** ```ts -export declare const uniq: (equivalence: Equivalence) => (self: Iterable) => A[] +export declare const uniq: (isEquivalent: (self: A, that: A) => boolean) => (self: Iterable) => A[] ``` Added in v1.0.0 @@ -2619,7 +2607,9 @@ Remove duplicates from a `NonEmptyReadonlyArray`, keeping the first occurrence o **Signature** ```ts -export declare const uniqNonEmpty: (equivalence: Equivalence) => (self: readonly [A, ...A[]]) => [A, ...A[]] +export declare const uniqNonEmpty: ( + isEquivalent: (self: A, that: A) => boolean +) => (self: readonly [A, ...A[]]) => [A, ...A[]] ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index aa580d692..daebd464a 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1692,7 +1692,7 @@ Returns a function that checks if a `These` contains a given value using a provi **Signature** ```ts -export declare const contains: (equivalence: Equivalence) => { +export declare const contains: (isEquivalent: (self: A, that: A) => boolean) => { (a: A): (self: These) => boolean (self: These, a: A): boolean } diff --git a/docs/modules/typeclass/Equivalence.ts.md b/docs/modules/typeclass/Equivalence.ts.md index 8145f9b01..91ee81067 100644 --- a/docs/modules/typeclass/Equivalence.ts.md +++ b/docs/modules/typeclass/Equivalence.ts.md @@ -124,7 +124,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const make: (equivalent: (self: A, that: A) => boolean) => Equivalence +export declare const make: (isEquivalent: (self: A, that: A) => boolean) => Equivalence ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index 0a7910402..eed30bdec 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1187,13 +1187,13 @@ export const flatMapOption: { * * @since 1.0.0 */ -export const contains = (equivalence: Equivalence): { +export const contains = (isEquivalent: (self: A, that: A) => boolean): { (a: A): (self: Either) => boolean (self: Either, a: A): boolean } => dual( 2, - (self: Either, a: A): boolean => isLeft(self) ? false : equivalence(self.right, a) + (self: Either, a: A): boolean => isLeft(self) ? false : isEquivalent(self.right, a) ) /** diff --git a/src/Option.ts b/src/Option.ts index b2d9b22dc..7ccee3330 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1446,7 +1446,7 @@ export const liftEither = , E, B>( /** * Returns a function that checks if an `Option` contains a given value using a provided `Equivalence` instance. * - * @param equivalence - An `Equivalence` instance to compare values of the `Option`. + * @param equivalent - An `Equivalence` instance to compare values of the `Option`. * @param self - The `Option` to apply the comparison to. * @param a - The value to compare against the `Option`. * @@ -1461,10 +1461,10 @@ export const liftEither = , E, B>( * * @since 1.0.0 */ -export const contains = (equivalence: Equivalence): { +export const contains = (isEquivalent: (self: A, that: A) => boolean): { (a: A): (self: Option) => boolean (self: Option, a: A): boolean -} => dual(2, (self: Option, a: A): boolean => isNone(self) ? false : equivalence(self.value, a)) +} => dual(2, (self: Option, a: A): boolean => isNone(self) ? false : isEquivalent(self.value, a)) /** * Check if a value in an `Option` type meets a certain predicate. diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index c8a2e6a62..f57e50f2a 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -18,7 +18,6 @@ import * as chainable from "@fp-ts/core/typeclass/Chainable" import type * as compactable from "@fp-ts/core/typeclass/Compactable" import type { Coproduct } from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" -import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" import * as filterable from "@fp-ts/core/typeclass/Filterable" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" @@ -1073,13 +1072,13 @@ export const rotateNonEmpty: { * @category predicates * @since 1.0.0 */ -export const contains = (equivalence: Equivalence): { +export const contains = (isEquivalent: (self: A, that: A) => boolean): { (a: A): (self: Iterable) => boolean (self: Iterable, a: A): boolean } => dual(2, (self: Iterable, a: A): boolean => { for (const i of self) { - if (equivalence(a, i)) { + if (isEquivalent(a, i)) { return true } } @@ -1091,10 +1090,10 @@ export const contains = (equivalence: Equivalence): { * * @since 1.0.0 */ -export const uniq = (equivalence: Equivalence) => +export const uniq = (isEquivalent: (self: A, that: A) => boolean) => (self: Iterable): Array => { const input = fromIterable(self) - return isNonEmpty(input) ? uniqNonEmpty(equivalence)(input) : [] + return isNonEmpty(input) ? uniqNonEmpty(isEquivalent)(input) : [] } /** @@ -1102,12 +1101,12 @@ export const uniq = (equivalence: Equivalence) => * * @since 1.0.0 */ -export const uniqNonEmpty = (equivalence: Equivalence) => +export const uniqNonEmpty = (isEquivalent: (self: A, that: A) => boolean) => (self: NonEmptyReadonlyArray): NonEmptyArray => { const out: NonEmptyArray = [headNonEmpty(self)] const rest = tailNonEmpty(self) for (const a of rest) { - if (out.every((o) => !equivalence(a, o))) { + if (out.every((o) => !isEquivalent(a, o))) { out.push(a) } } @@ -1253,7 +1252,7 @@ export const chunksOfNonEmpty: { * @category grouping * @since 1.0.0 */ -export const group = (equivalence: Equivalence) => +export const group = (isEquivalent: (self: A, that: A) => boolean) => (self: NonEmptyReadonlyArray): NonEmptyArray> => chopNonEmpty(self, (as) => { const h = headNonEmpty(as) @@ -1261,7 +1260,7 @@ export const group = (equivalence: Equivalence) => let i = 1 for (; i < as.length; i++) { const a = as[i] - if (equivalence(a, h)) { + if (isEquivalent(a, h)) { out.push(a) } else { break @@ -1296,7 +1295,7 @@ export const groupBy: { /** * @since 1.0.0 */ -export const union = (equivalence: Equivalence): { +export const union = (isEquivalent: (self: A, that: A) => boolean): { (that: ReadonlyArray): (self: ReadonlyArray) => Array (self: ReadonlyArray, that: ReadonlyArray): Array } => @@ -1304,7 +1303,7 @@ export const union = (equivalence: Equivalence): { const a = Array.from(self) const b = Array.from(that) return isNonEmpty(a) && isNonEmpty(b) ? - unionNonEmpty(equivalence)(b)(a) : + unionNonEmpty(isEquivalent)(a, b) : isNonEmpty(a) ? a : b @@ -1313,7 +1312,7 @@ export const union = (equivalence: Equivalence): { /** * @since 1.0.0 */ -export const unionNonEmpty = (equivalence: Equivalence): { +export const unionNonEmpty = (isEquivalent: (self: A, that: A) => boolean): { (that: NonEmptyReadonlyArray): (self: ReadonlyArray) => NonEmptyArray (that: ReadonlyArray): (self: NonEmptyReadonlyArray) => NonEmptyArray (self: ReadonlyArray, that: NonEmptyReadonlyArray): NonEmptyArray @@ -1322,7 +1321,7 @@ export const unionNonEmpty = (equivalence: Equivalence): { dual( 2, (self: NonEmptyReadonlyArray, that: ReadonlyArray): NonEmptyArray => - uniqNonEmpty(equivalence)(appendAllNonEmpty(self, that)) + uniqNonEmpty(isEquivalent)(appendAllNonEmpty(self, that)) ) /** @@ -1331,11 +1330,11 @@ export const unionNonEmpty = (equivalence: Equivalence): { * * @since 1.0.0 */ -export const intersection = (equivalence: Equivalence): { +export const intersection = (isEquivalent: (self: A, that: A) => boolean): { (that: Iterable): (self: Iterable) => Array (self: Iterable, that: Iterable): Array } => { - const has = contains(equivalence) + const has = contains(isEquivalent) return dual( 2, (self: Iterable, that: Iterable): Array => @@ -1349,11 +1348,11 @@ export const intersection = (equivalence: Equivalence): { * * @since 1.0.0 */ -export const difference = (equivalence: Equivalence): { +export const difference = (isEquivalent: (self: A, that: A) => boolean): { (that: Iterable): (self: Iterable) => Array (self: Iterable, that: Iterable): Array } => { - const has = contains(equivalence) + const has = contains(isEquivalent) return dual( 2, (self: Iterable, that: Iterable): Array => @@ -2403,16 +2402,20 @@ export const unfold = (b: B, f: (b: B) => Option): Array< * @category instances * @since 1.0.0 */ -export const getUnionSemigroup = (equivalence: Equivalence): Semigroup> => +export const getUnionSemigroup = ( + isEquivalent: (self: A, that: A) => boolean +): Semigroup> => // @ts-expect-error - fromCombine(union(equivalence)) + fromCombine(union(isEquivalent)) /** * @category instances * @since 1.0.0 */ -export const getUnionMonoid = (equivalence: Equivalence): Monoid> => { - const S = getUnionSemigroup(equivalence) +export const getUnionMonoid = ( + isEquivalent: (self: A, that: A) => boolean +): Monoid> => { + const S = getUnionSemigroup(isEquivalent) return ({ combine: S.combine, combineMany: S.combineMany, @@ -2426,10 +2429,10 @@ export const getUnionMonoid = (equivalence: Equivalence): Monoid( - equivalence: Equivalence + isEquivalent: (self: A, that: A) => boolean ): Semigroup> => // @ts-expect-error - fromCombine(intersection(equivalence)) + fromCombine(intersection(isEquivalent)) /** * Returns a `Semigroup` for `ReadonlyArray`. diff --git a/src/These.ts b/src/These.ts index 274a6826b..77f13a801 100644 --- a/src/These.ts +++ b/src/These.ts @@ -829,13 +829,13 @@ export const traverseTap: ( * * @since 1.0.0 */ -export const contains = (equivalence: Equivalence): { +export const contains = (isEquivalent: (self: A, that: A) => boolean): { (a: A): (self: These) => boolean (self: These, a: A): boolean } => dual( 2, - (self: These, a: A): boolean => isLeft(self) ? false : equivalence(self.right, a) + (self: These, a: A): boolean => isLeft(self) ? false : isEquivalent(self.right, a) ) /** diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 1b21b904e..2f6743deb 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -38,9 +38,8 @@ export interface EquivalenceTypeLambda extends TypeLambda { * @category constructors * @since 1.0.0 */ -export const make = ( - equivalent: (self: A, that: A) => boolean -): Equivalence => dual(2, (self, that) => self === that || equivalent(self, that)) +export const make = (isEquivalent: (self: A, that: A) => boolean): Equivalence => + dual(2, (self: A, that: A): boolean => self === that || isEquivalent(self, that)) /** * Return an `Equivalence` that uses strict equality (===) to compare values From fe13b63692c051bfca4fa0346c9d49af5fd0ef24 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 15:57:03 +0100 Subject: [PATCH 181/255] ReadonlyArray: remove mapNonEmptyWithIndex --- docs/modules/ReadonlyArray.ts.md | 14 ------------ dtslint/ts4.7/ReadonlyArray.ts | 39 ++++++++++++++++++++++++++++++++ src/ReadonlyArray.ts | 39 ++++++++------------------------ test/ReadonlyArray.ts | 12 ++++------ 4 files changed, 53 insertions(+), 51 deletions(-) create mode 100644 dtslint/ts4.7/ReadonlyArray.ts diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 6cb9b7733..75c7cd09b 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -131,7 +131,6 @@ Added in v1.0.0 - [flap](#flap) - [map](#map) - [mapNonEmpty](#mapnonempty) - - [mapNonEmptyWithIndex](#mapnonemptywithindex) - [tupled](#tupled) - [models](#models) - [NonEmptyArray (type alias)](#nonemptyarray-type-alias) @@ -1614,19 +1613,6 @@ Added in v1.0.0 ```ts export declare const mapNonEmpty: { - (f: (a: A) => B): (self: readonly [A, ...A[]]) => [B, ...B[]] - (self: readonly [A, ...A[]], f: (a: A) => B): [B, ...B[]] -} -``` - -Added in v1.0.0 - -## mapNonEmptyWithIndex - -**Signature** - -```ts -export declare const mapNonEmptyWithIndex: { (f: (a: A, i: number) => B): (self: readonly [A, ...A[]]) => [B, ...B[]] (self: readonly [A, ...A[]], f: (a: A, i: number) => B): [B, ...B[]] } diff --git a/dtslint/ts4.7/ReadonlyArray.ts b/dtslint/ts4.7/ReadonlyArray.ts new file mode 100644 index 000000000..26b7012ee --- /dev/null +++ b/dtslint/ts4.7/ReadonlyArray.ts @@ -0,0 +1,39 @@ +import { pipe } from '@fp-ts/core/Function' +import * as RA from '@fp-ts/core/ReadonlyArray' + +declare const neras: RA.NonEmptyReadonlyArray +declare const neas: RA.NonEmptyArray +declare const ras: ReadonlyArray +declare const as: Array + +// ------------------------------------------------------------------------------------- +// map +// ------------------------------------------------------------------------------------- + +// $ExpectType number[] +RA.map(ras, n => n + 1) + +// $ExpectType number[] +pipe(ras, RA.map(n => n + 1)) + +// $ExpectType number[] +RA.map(as, n => n + 1) + +// $ExpectType number[] +pipe(as, RA.map(n => n + 1)) + +// ------------------------------------------------------------------------------------- +// mapNonEmpty +// ------------------------------------------------------------------------------------- + +// $ExpectType [number, ...number[]] +RA.mapNonEmpty(neras, n => n + 1) + +// $ExpectType [number, ...number[]] +pipe(neras, RA.mapNonEmpty(n => n + 1)) + +// $ExpectType [number, ...number[]] +RA.mapNonEmpty(neas, n => n + 1) + +// $ExpectType [number, ...number[]] +pipe(neas, RA.mapNonEmpty(n => n + 1)) diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index f57e50f2a..e1dd1b4ff 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1372,34 +1372,6 @@ export const of = (a: A): NonEmptyArray => [a] */ export const empty: () => Array = () => [] -/** - * @category mapping - * @since 1.0.0 - */ -export const mapNonEmpty: { - (f: (a: A) => B): (self: readonly [A, ...Array]) => [B, ...Array] - (self: readonly [A, ...Array], f: (a: A) => B): [B, ...Array] -} = dual( - 2, - (self: NonEmptyReadonlyArray, f: (a: A) => B): NonEmptyArray => - mapNonEmptyWithIndex(self, f) -) - -/** - * @category mapping - * @since 1.0.0 - */ -export const mapNonEmptyWithIndex: { - (f: (a: A, i: number) => B): (self: NonEmptyReadonlyArray) => NonEmptyArray - (self: NonEmptyReadonlyArray, f: (a: A, i: number) => B): NonEmptyArray -} = dual(2, (self: NonEmptyReadonlyArray, f: (a: A, i: number) => B): NonEmptyArray => { - const out: NonEmptyArray = [f(headNonEmpty(self), 0)] - for (let i = 1; i < self.length; i++) { - out.push(f(self[i], i)) - } - return out -}) - /** * @category instances * @since 1.0.0 @@ -1417,6 +1389,15 @@ export const map: { (self: ReadonlyArray, f: (a: A, i: number) => B): Array } = dual(2, (self: ReadonlyArray, f: (a: A, i: number) => B): Array => self.map(f)) +/** + * @category mapping + * @since 1.0.0 + */ +export const mapNonEmpty: { + (f: (a: A, i: number) => B): (self: readonly [A, ...Array]) => [B, ...Array] + (self: readonly [A, ...Array], f: (a: A, i: number) => B): [B, ...Array] +} = map as any + const imap = covariant.imap(map) /** @@ -1841,7 +1822,7 @@ export const traverseNonEmptyWithIndex = ( self: NonEmptyReadonlyArray, f: (a: A, i: number) => Kind ): Kind> => { - const [head, ...tail] = mapNonEmptyWithIndex(self, f) + const [head, ...tail] = mapNonEmpty(self, f) return F.productMany(head, tail) }) diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 4f028783f..66faeae54 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -1164,6 +1164,10 @@ describe.concurrent("ReadonlyArray", () => { ), [1, 2, 3, 4] ) + deepStrictEqual( + pipe(RA.make("a", "b"), RA.mapNonEmpty((s: string, i: number) => s + i)), + ["a0", "b1"] + ) }) it("sequenceNonEmpty", () => { @@ -1185,14 +1189,6 @@ describe.concurrent("ReadonlyArray", () => { ) }) - it("mapNonEmptyWithIndex", () => { - const add = (s: string, i: number) => s + i - deepStrictEqual( - pipe(RA.make("a", "b"), RA.mapNonEmptyWithIndex(add)), - ["a0", "b1"] - ) - }) - it("min", () => { deepStrictEqual(RA.min(Number.Order)([2, 1, 3]), 1) deepStrictEqual(RA.min(Number.Order)([3]), 3) From 747440499f6808a74928eb7d2baa5ac81bd7d988 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 16:02:36 +0100 Subject: [PATCH 182/255] ReadonlyArray: remove flatMapWithIndex --- docs/modules/ReadonlyArray.ts.md | 18 ++-------------- src/ReadonlyArray.ts | 37 +++++++++++--------------------- test/ReadonlyArray.ts | 9 ++------ 3 files changed, 16 insertions(+), 48 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 75c7cd09b..208ba8a5a 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -147,7 +147,6 @@ Added in v1.0.0 - [flatMapNonEmpty](#flatmapnonempty) - [flatMapNonEmptyWithIndex](#flatmapnonemptywithindex) - [flatMapNullable](#flatmapnullable) - - [flatMapWithIndex](#flatmapwithindex) - [flatten](#flatten) - [flattenNonEmpty](#flattennonempty) - [sorting](#sorting) @@ -1730,8 +1729,8 @@ Added in v1.0.0 ```ts export declare const flatMap: { - (f: (a: A) => readonly B[]): (self: readonly A[]) => B[] - (self: readonly A[], f: (a: A) => readonly B[]): B[] + (f: (a: A, i: number) => readonly B[]): (self: readonly A[]) => B[] + (self: readonly A[], f: (a: A, i: number) => readonly B[]): B[] } ``` @@ -1776,19 +1775,6 @@ export declare const flatMapNullable: { Added in v1.0.0 -## flatMapWithIndex - -**Signature** - -```ts -export declare const flatMapWithIndex: { - (f: (a: A, i: number) => readonly B[]): (self: readonly A[]) => B[] - (self: readonly A[], f: (a: A, i: number) => readonly B[]): B[] -} -``` - -Added in v1.0.0 - ## flatten **Signature** diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index e1dd1b4ff..bc488c2c4 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1458,31 +1458,21 @@ export const Pointed: pointed.Pointed = { * @category sequencing * @since 1.0.0 */ -export const flatMapWithIndex: { +export const flatMap: { (f: (a: A, i: number) => ReadonlyArray): (self: ReadonlyArray) => Array (self: ReadonlyArray, f: (a: A, i: number) => ReadonlyArray): Array -} = dual(2, (self: ReadonlyArray, f: (a: A, i: number) => ReadonlyArray): Array => { - if (isEmpty(self)) { - return [] - } - const out: Array = [] - for (let i = 0; i < self.length; i++) { - out.push(...f(self[i], i)) - } - return out -}) - -/** - * @category sequencing - * @since 1.0.0 - */ -export const flatMap: { - (f: (a: A) => ReadonlyArray): (self: ReadonlyArray) => Array - (self: ReadonlyArray, f: (a: A) => ReadonlyArray): Array } = dual( 2, - (self: ReadonlyArray, f: (a: A) => ReadonlyArray): Array => - flatMapWithIndex(self, f) + (self: ReadonlyArray, f: (a: A, i: number) => ReadonlyArray): Array => { + if (isEmpty(self)) { + return [] + } + const out: Array = [] + for (let i = 0; i < self.length; i++) { + out.push(...f(self[i], i)) + } + return out + } ) /** @@ -1520,10 +1510,7 @@ export const flatMapNonEmpty: { self: NonEmptyReadonlyArray, f: (a: A) => NonEmptyReadonlyArray ): NonEmptyArray -} = dual(2, ( - self: NonEmptyReadonlyArray, - f: (a: A) => NonEmptyReadonlyArray -): NonEmptyArray => flatMapNonEmptyWithIndex(self, f)) +} = flatMap as any /** * @category instances diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 66faeae54..b43c6481a 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -817,14 +817,9 @@ describe.concurrent("ReadonlyArray", () => { ), [1, 2, 2, 3, 3, 4] ) - }) - - it("flatMapWithIndex", () => { - const f = RA.flatMapWithIndex((n: number, i) => [n + i]) + const f = RA.flatMap((n: number, i) => [n + i]) + deepStrictEqual(pipe([], f), []) deepStrictEqual(pipe([1, 2, 3], f), [1, 3, 5]) - deepStrictEqual(pipe(RA.empty(), f), RA.empty()) - const empty: ReadonlyArray = [] - deepStrictEqual(pipe(empty, f), RA.empty()) }) it("extend", () => { From c7c65a78c5dbf6e026941f9a7aca37dcb7f45182 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 16:04:42 +0100 Subject: [PATCH 183/255] ReadonlyArray: remove flatMapNonEmptyWithIndex --- docs/modules/ReadonlyArray.ts.md | 14 -------------- src/ReadonlyArray.ts | 25 +------------------------ test/ReadonlyArray.ts | 7 ++----- 3 files changed, 3 insertions(+), 43 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 208ba8a5a..571c414e6 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -145,7 +145,6 @@ Added in v1.0.0 - [sequencing](#sequencing) - [flatMap](#flatmap) - [flatMapNonEmpty](#flatmapnonempty) - - [flatMapNonEmptyWithIndex](#flatmapnonemptywithindex) - [flatMapNullable](#flatmapnullable) - [flatten](#flatten) - [flattenNonEmpty](#flattennonempty) @@ -1742,19 +1741,6 @@ Added in v1.0.0 ```ts export declare const flatMapNonEmpty: { - (f: (a: A) => readonly [B, ...B[]]): (self: readonly [A, ...A[]]) => [B, ...B[]] - (self: readonly [A, ...A[]], f: (a: A) => readonly [B, ...B[]]): [B, ...B[]] -} -``` - -Added in v1.0.0 - -## flatMapNonEmptyWithIndex - -**Signature** - -```ts -export declare const flatMapNonEmptyWithIndex: { (f: (a: A, i: number) => readonly [B, ...B[]]): (self: readonly [A, ...A[]]) => [B, ...B[]] (self: readonly [A, ...A[]], f: (a: A, i: number) => readonly [B, ...B[]]): [B, ...B[]] } diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index bc488c2c4..73b7a4c67 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1479,7 +1479,7 @@ export const flatMap: { * @category sequencing * @since 1.0.0 */ -export const flatMapNonEmptyWithIndex: { +export const flatMapNonEmpty: { ( f: (a: A, i: number) => NonEmptyReadonlyArray ): (self: NonEmptyReadonlyArray) => NonEmptyArray @@ -1487,29 +1487,6 @@ export const flatMapNonEmptyWithIndex: { self: NonEmptyReadonlyArray, f: (a: A, i: number) => NonEmptyReadonlyArray ): NonEmptyArray -} = dual(2, ( - self: NonEmptyReadonlyArray, - f: (a: A, i: number) => NonEmptyReadonlyArray -): NonEmptyArray => { - const out: NonEmptyArray = copy(f(headNonEmpty(self), 0)) - for (let i = 1; i < self.length; i++) { - out.push(...f(self[i], i)) - } - return out -}) - -/** - * @category sequencing - * @since 1.0.0 - */ -export const flatMapNonEmpty: { - ( - f: (a: A) => NonEmptyReadonlyArray - ): (self: NonEmptyReadonlyArray) => NonEmptyArray - ( - self: NonEmptyReadonlyArray, - f: (a: A) => NonEmptyReadonlyArray - ): NonEmptyArray } = flatMap as any /** diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index b43c6481a..61dc3ac6b 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -1113,11 +1113,8 @@ describe.concurrent("ReadonlyArray", () => { it("flatMapNonEmpty", () => { const f = (a: number): RA.NonEmptyReadonlyArray => [a, 4] deepStrictEqual(pipe(RA.make(1, 2), RA.flatMapNonEmpty(f)), [1, 4, 2, 4]) - }) - - it("flatMapNonEmptyWithIndex", () => { - const f = (a: number, i: number): RA.NonEmptyReadonlyArray => [a + i, 4] - deepStrictEqual(pipe(RA.make(1, 2), RA.flatMapNonEmptyWithIndex(f)), [1, 4, 3, 4]) + const g = (a: number, i: number): RA.NonEmptyReadonlyArray => [a + i, 4] + deepStrictEqual(pipe(RA.make(1, 2), RA.flatMapNonEmpty(g)), [1, 4, 3, 4]) }) it("chunksOfNonEmpty", () => { From af45785fed52be427bfe001142cc6ed974e3e04a Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 16:11:01 +0100 Subject: [PATCH 184/255] ReadonlyArray: remove filterMapWithIndex --- docs/modules/ReadonlyArray.ts.md | 14 ---- src/ReadonlyArray.ts | 37 ++++----- test/ReadonlyArray.ts | 9 +-- test/limbo/FilterableWithIndex.ts | 104 ------------------------- test/limbo/FoldableWithIndex.ts | 101 ------------------------ test/limbo/TraversableWithIndex.ts | 48 ------------ test/typeclass/FilterableWithIndex.ts | 73 ----------------- test/typeclass/FoldableWithIndex.ts | 67 ---------------- test/typeclass/TraversableWithIndex.ts | 41 ---------- 9 files changed, 17 insertions(+), 477 deletions(-) delete mode 100644 test/limbo/FilterableWithIndex.ts delete mode 100644 test/limbo/FoldableWithIndex.ts delete mode 100644 test/limbo/TraversableWithIndex.ts delete mode 100644 test/typeclass/FilterableWithIndex.ts delete mode 100644 test/typeclass/FoldableWithIndex.ts delete mode 100644 test/typeclass/TraversableWithIndex.ts diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 571c414e6..06ed40828 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -37,7 +37,6 @@ Added in v1.0.0 - [compact](#compact) - [filter](#filter) - [filterMap](#filtermap) - - [filterMapWithIndex](#filtermapwithindex) - [filterWithIndex](#filterwithindex) - [partition](#partition) - [partitionMap](#partitionmap) @@ -481,19 +480,6 @@ Added in v1.0.0 ```ts export declare const filterMap: { - (f: (a: A) => Option): (self: Iterable) => B[] - (self: Iterable, f: (a: A) => Option): B[] -} -``` - -Added in v1.0.0 - -## filterMapWithIndex - -**Signature** - -```ts -export declare const filterMapWithIndex: { (f: (a: A, i: number) => Option): (self: Iterable) => B[] (self: Iterable, f: (a: A, i: number) => Option): B[] } diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 73b7a4c67..a46d9b843 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1535,25 +1535,6 @@ export const Chainable: chainable.Chainable = { flatMap } -/** - * @category filtering - * @since 1.0.0 - */ -export const filterMapWithIndex: { - (f: (a: A, i: number) => Option): (self: Iterable) => Array - (self: Iterable, f: (a: A, i: number) => Option): Array -} = dual(2, (self: Iterable, f: (a: A, i: number) => Option): Array => { - const as = fromIterable(self) - const out: Array = [] - for (let i = 0; i < as.length; i++) { - const o = f(as[i], i) - if (O.isSome(o)) { - out.push(o.value) - } - } - return out -}) - /** * @category filtering * @since 1.0.0 @@ -1578,11 +1559,21 @@ export const separate = ( * @since 1.0.0 */ export const filterMap: { - (f: (a: A) => Option): (self: Iterable) => Array - (self: Iterable, f: (a: A) => Option): Array + (f: (a: A, i: number) => Option): (self: Iterable) => Array + (self: Iterable, f: (a: A, i: number) => Option): Array } = dual( 2, - (self: Iterable, f: (a: A) => Option): Array => filterMapWithIndex(self, f) + (self: Iterable, f: (a: A, i: number) => Option): Array => { + const as = fromIterable(self) + const out: Array = [] + for (let i = 0; i < as.length; i++) { + const o = f(as[i], i) + if (O.isSome(o)) { + out.push(o.value) + } + } + return out + } ) /** @@ -1622,7 +1613,7 @@ export const filterWithIndex: { } = dual( 2, (self: Iterable, predicate: (a: A, i: number) => boolean): Array => - filterMapWithIndex(self, (b, i) => (predicate(b, i) ? O.some(b) : O.none())) + filterMap(self, (b, i) => (predicate(b, i) ? O.some(b) : O.none())) ) /** diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 61dc3ac6b..8cfa580c5 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -885,6 +885,9 @@ describe.concurrent("ReadonlyArray", () => { const f = (n: number) => (n % 2 === 0 ? O.none() : O.some(n)) deepStrictEqual(pipe([1, 2, 3], RA.filterMap(f)), [1, 3]) deepStrictEqual(pipe([], RA.filterMap(f)), []) + const g = (n: number, i: number) => ((i + n) % 2 === 0 ? O.none() : O.some(n)) + deepStrictEqual(pipe([1, 2, 4], RA.filterMap(g)), [1, 2]) + deepStrictEqual(pipe([], RA.filterMap(g)), []) }) it("combineMapWithIndex", () => { @@ -897,12 +900,6 @@ describe.concurrent("ReadonlyArray", () => { ) }) - it("filterMapWithIndex", () => { - const f = (n: number, i: number) => ((i + n) % 2 === 0 ? O.none() : O.some(n)) - deepStrictEqual(pipe([1, 2, 4], RA.filterMapWithIndex(f)), [1, 2]) - deepStrictEqual(pipe([], RA.filterMapWithIndex(f)), []) - }) - it("partitionMap", () => { deepStrictEqual(pipe([], RA.partitionMap(identity)), [[], []]) deepStrictEqual( diff --git a/test/limbo/FilterableWithIndex.ts b/test/limbo/FilterableWithIndex.ts deleted file mode 100644 index 2db48857e..000000000 --- a/test/limbo/FilterableWithIndex.ts +++ /dev/null @@ -1,104 +0,0 @@ -/** - * @since 1.0.0 - */ -import type { Either } from "@fp-ts/core/Either" -import * as E from "@fp-ts/core/Either" -import { pipe } from "@fp-ts/core/Function" -import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import * as O from "@fp-ts/core/Option" -import type { Option } from "@fp-ts/core/Option" -import type { Covariant } from "@fp-ts/core/typeclass/Covariant" -// import type { Filterable } from "@fp-ts/core/typeclass/Filterable" - -/** - * @category models - * @since 1.0.0 - */ -export interface FilterableWithIndex extends TypeClass { - readonly filterMapWithIndex: ( - f: (a: A, i: I) => Option - ) => (self: Kind) => Kind -} - -/** - * Returns a default `filterMapWithIndex` composition. - * - * @since 1.0.0 - */ -export const filterMapWithIndexComposition = ( - F: Covariant, - G: FilterableWithIndex -) => - ( - f: (a: A, i: I) => Option - ): ( - self: Kind> - ) => Kind> => F.map(G.filterMapWithIndex(f)) - -// /** -// * Returns a default `filterMap` implementation. -// * -// * @since 1.0.0 -// */ -// export const filterMap = ( -// F: FilterableWithIndex -// ): Filterable["filterMap"] => (f) => F.filterMapWithIndex(f) - -/** - * @since 1.0.0 - */ -export const filterWithIndex: ( - F: FilterableWithIndex -) => { - (refinement: (a: A, i: I) => a is B): ( - self: Kind - ) => Kind - ( - predicate: (a: A, i: I) => boolean - ): (self: Kind) => Kind -} = (FilterableWithIndex: FilterableWithIndex) => - ( - predicate: (a: A, i: I) => boolean - ): ((self: Kind) => Kind) => - FilterableWithIndex.filterMapWithIndex(( - b, - i - ) => (predicate(b, i) ? O.some(b) : O.none())) - -/** - * @since 1.0.0 - */ -export const partitionMapWithIndex = ( - F: FilterableWithIndex -) => - (f: (a: A, i: I) => Either) => - ( - self: Kind - ): readonly [Kind, Kind] => { - return [ - pipe(self, F.filterMapWithIndex((a, i) => E.getLeft(f(a, i)))), - pipe(self, F.filterMapWithIndex((a, i) => E.getRight(f(a, i)))) - ] - } - -/** - * @since 1.0.0 - */ -export const partitionWithIndex: ( - F: FilterableWithIndex -) => { - (refinement: (a: A, i: I) => a is B): ( - self: Kind - ) => readonly [Kind, Kind] - (predicate: (a: A, i: I) => boolean): ( - self: Kind - ) => readonly [Kind, Kind] -} = (FilterableWithIndex: FilterableWithIndex) => { - const partitionMapWithIndex_ = partitionMapWithIndex(FilterableWithIndex) - return ( - predicate: (a: A, i: I) => boolean - ): (( - self: Kind - ) => readonly [Kind, Kind]) => - partitionMapWithIndex_((b, i) => (predicate(b, i) ? E.right(b) : E.left(b))) -} diff --git a/test/limbo/FoldableWithIndex.ts b/test/limbo/FoldableWithIndex.ts deleted file mode 100644 index e68f8f629..000000000 --- a/test/limbo/FoldableWithIndex.ts +++ /dev/null @@ -1,101 +0,0 @@ -/** - * @since 1.0.0 - */ - -import { identity, pipe } from "@fp-ts/core/Function" -import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -// import type { Foldable } from "@fp-ts/core/typeclass/Foldable" -import type { Monoid } from "@fp-ts/core/typeclass/Monoid" - -/** - * @category type class - * @since 1.0.0 - */ -export interface FoldableWithIndex extends TypeClass { - readonly reduceWithIndex: ( - b: B, - f: (b: B, a: A, i: I) => B - ) => (self: Kind) => B - - readonly reduceRightWithIndex: ( - b: B, - f: (b: B, a: A, i: I) => B - ) => (self: Kind) => B -} - -/** - * Returns a default `reduceWithIndex` composition. - * - * @since 1.0.0 - */ -export const reduceWithIndexComposition = ( - F: FoldableWithIndex, - G: FoldableWithIndex -) => - (b: B, f: (b: B, a: A, ij: readonly [I, J]) => B) => - ( - self: Kind> - ): B => - pipe( - self, - F.reduceWithIndex(b, (b, ga, i) => - pipe(ga, G.reduceWithIndex(b, (b, a, j) => f(b, a, [i, j])))) - ) - -/** - * Returns a default `reduceRightWithIndex` composition. - * - * @since 1.0.0 - */ -export const reduceRightWithIndexComposition = ( - F: FoldableWithIndex, - G: FoldableWithIndex -) => - (b: B, f: (b: B, a: A, ij: readonly [I, J]) => B) => - ( - self: Kind> - ): B => - pipe( - self, - F.reduceRightWithIndex(b, (b, ga, i) => - pipe(ga, G.reduceRightWithIndex(b, (b, a, j) => f(b, a, [i, j])))) - ) - -// /** -// * Returns a default `reduce` implementation. -// * -// * @since 1.0.0 -// */ -// export const reduce = ( -// F: FoldableWithIndex -// ): Foldable["reduce"] => (b, f) => F.reduceWithIndex(b, f) - -/** - * @since 1.0.0 - */ -export const toArray = ( - F: FoldableWithIndex -): (self: Kind) => Array => toArrayWith(F)(identity) - -/** - * @since 1.0.0 - */ -export const toArrayWith = ( - F: FoldableWithIndex -) => - (f: (a: A, i: I) => B) => - (self: Kind): Array => - F.reduceWithIndex>([], (out, a, i) => { - out.push(f(a, i)) - return out - })(self) - -/** - * @since 1.0.0 - */ -export const combineMapWithIndex = ( - F: FoldableWithIndex -) => - (M: Monoid) => - (f: (a: A, i: I) => M) => - (self: Kind): M => M.combineAll(toArrayWith(F)(f)(self)) diff --git a/test/limbo/TraversableWithIndex.ts b/test/limbo/TraversableWithIndex.ts deleted file mode 100644 index d8b22679a..000000000 --- a/test/limbo/TraversableWithIndex.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @since 1.0.0 - */ -import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import type { Applicative } from "@fp-ts/core/typeclass/Applicative" -// import type { Traversable } from "@fp-ts/core/typeclass/Traversable" - -/** - * @category type class - * @since 1.0.0 - */ -export interface TraversableWithIndex extends TypeClass { - readonly traverseWithIndex: ( - F: Applicative - ) => ( - f: (a: A, i: I) => Kind - ) => ( - self: Kind - ) => Kind> -} - -/** - * Returns a default `traverseWithIndex` composition. - * - * @since 1.0.0 - */ -export const traverseWithIndexComposition = ( - F: TraversableWithIndex, - G: TraversableWithIndex -) => - (H: Applicative) => - ( - f: (a: A, ij: readonly [I, J]) => Kind - ): (( - fga: Kind> - ) => Kind>>) => - F.traverseWithIndex(H)((ga, i) => - G.traverseWithIndex(H)((a, j) => f(a, [i, j]))(ga) - ) - -// /** -// * Returns a default `traverse` implementation. -// * -// * @since 1.0.0 -// */ -// export const traverse = ( -// F: TraversableWithIndex -// ): Traversable["traverse"] => f => F.traverseWithIndex(f) diff --git a/test/typeclass/FilterableWithIndex.ts b/test/typeclass/FilterableWithIndex.ts deleted file mode 100644 index 36103dceb..000000000 --- a/test/typeclass/FilterableWithIndex.ts +++ /dev/null @@ -1,73 +0,0 @@ -import * as E from "@fp-ts/core/Either" -import { pipe } from "@fp-ts/core/Function" -import * as O from "@fp-ts/core/Option" -import * as RA from "@fp-ts/core/ReadonlyArray" -import * as _ from "@fp-ts/core/test/limbo/FilterableWithIndex" -import * as U from "../util" - -const FilterableWithIndex: _.FilterableWithIndex = { - filterMapWithIndex: RA.filterMapWithIndex -} - -describe("FilterableWithIndex", () => { - it("filterMapComposition", () => { - const filterMapWithIndex: ( - f: (a: A, i: number) => O.Option - ) => ( - self: ReadonlyArray> - ) => ReadonlyArray> = _ - .filterMapWithIndexComposition(RA.Covariant, FilterableWithIndex) - const f = filterMapWithIndex((s: string, i: number) => - s.length + i > 1 ? O.some(s.length) : O.none() - ) - U.deepStrictEqual(pipe([], f), []) - U.deepStrictEqual(pipe([[]], f), [[]]) - U.deepStrictEqual(pipe([["a"]], f), [[]]) - U.deepStrictEqual(pipe([["aa", "a"]], f), [[2, 1]]) - }) - - // it("filterMap", () => { - // const filterMap: ( - // f: (a: A) => O.Option - // ) => (self: ReadonlyArray) => ReadonlyArray = _.filterMap(FilterableWithIndex) - // const f = (n: number) => (n % 2 === 0 ? O.none() : O.some(n)) - // U.deepStrictEqual(pipe([1, 2, 3], filterMap(f)), [1, 3]) - // U.deepStrictEqual(pipe([], filterMap(f)), []) - // }) - - it("filterWithIndex", () => { - const filterWithIndex = _.filterWithIndex(FilterableWithIndex) - const f = (n: number) => n % 2 === 0 - U.deepStrictEqual(pipe(["a", "b", "c"], filterWithIndex((_, i) => f(i))), [ - "a", - "c" - ]) - }) - - it("partitionMapWithIndex", () => { - const partitionMapWithIndex = _.partitionMapWithIndex(FilterableWithIndex) - U.deepStrictEqual( - pipe([], partitionMapWithIndex((a) => a)), - [[], []] - ) - U.deepStrictEqual( - pipe( - [E.right(1), E.left("foo"), E.right(2)], - partitionMapWithIndex((a, i) => pipe(a, E.filter((n) => n > i, () => "err"))) - ), - [["foo", "err"], [1]] - ) - }) - - it("partitionWithIndex", () => { - const partitionWithIndex = _.partitionWithIndex(FilterableWithIndex) - U.deepStrictEqual( - pipe([], partitionWithIndex((i, n) => i + n > 2)), - [[], []] - ) - U.deepStrictEqual( - pipe([1, 2], partitionWithIndex((i, n) => i + n > 2)), - [[1], [2]] - ) - }) -}) diff --git a/test/typeclass/FoldableWithIndex.ts b/test/typeclass/FoldableWithIndex.ts deleted file mode 100644 index 3d9551dca..000000000 --- a/test/typeclass/FoldableWithIndex.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { pipe } from "@fp-ts/core/Function" -import * as N from "@fp-ts/core/Number" -import * as O from "@fp-ts/core/Option" -import * as RA from "@fp-ts/core/ReadonlyArray" -import * as _ from "../limbo/FoldableWithIndex" -import * as U from "../util" - -const FoldableWithIndex: _.FoldableWithIndex = { - reduceWithIndex: RA.reduceWithIndex, - reduceRightWithIndex: RA.reduceRightWithIndex -} - -const FoldableWithIndexO: _.FoldableWithIndex = { - reduceWithIndex: (b, f) => (self) => O.isNone(self) ? b : f(b, self.value, 0), - reduceRightWithIndex: (b, f) => (self) => O.isNone(self) ? b : f(b, self.value, 0) -} - -describe("FoldableWithIndex", () => { - it("reduceWithIndexComposition", () => { - const reduceWithIndex = _.reduceWithIndexComposition( - FoldableWithIndex, - FoldableWithIndex - ) - const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j - U.deepStrictEqual(pipe([], reduceWithIndex("-", f)), "-") - U.deepStrictEqual(pipe([[]], reduceWithIndex("-", f)), "-") - U.deepStrictEqual( - pipe([["a", "c"], ["b", "d"]], reduceWithIndex("-", f)), - "-a00c01b10d11" - ) - }) - - it("reduceRightWithIndexComposition", () => { - const reduceRightWithIndex = _.reduceRightWithIndexComposition( - FoldableWithIndex, - FoldableWithIndex - ) - const f = (b: string, a: string, [i, j]: readonly [number, number]) => b + a + i + j - U.deepStrictEqual(pipe([], reduceRightWithIndex("-", f)), "-") - U.deepStrictEqual(pipe([[]], reduceRightWithIndex("-", f)), "-") - U.deepStrictEqual( - pipe([["a", "c"], ["b", "d"]], reduceRightWithIndex("-", f)), - "-d11b10c01a00" - ) - }) - - it("toArray", () => { - const toReadonlyArray = _.toArray(FoldableWithIndexO) - U.deepStrictEqual(toReadonlyArray(O.none()), []) - U.deepStrictEqual(toReadonlyArray(O.some(2)), [2]) - }) - - it("toArrayWith", () => { - const toReadonlyArrayWith = _.toArrayWith(FoldableWithIndexO) - U.deepStrictEqual(pipe(O.none(), toReadonlyArrayWith(U.double)), []) - U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith(U.double)), [4]) - U.deepStrictEqual(pipe(O.some(2), toReadonlyArrayWith((a, i) => U.double(a) * i)), [0]) - }) - - it("combineMapWithIndex", () => { - const combineMapWithIndex = _.combineMapWithIndex(FoldableWithIndex) - U.deepStrictEqual( - pipe([1, 2, 3], combineMapWithIndex(N.MonoidSum)((n, i) => (n * 2) + i)), - 15 - ) - }) -}) diff --git a/test/typeclass/TraversableWithIndex.ts b/test/typeclass/TraversableWithIndex.ts deleted file mode 100644 index d1201f33c..000000000 --- a/test/typeclass/TraversableWithIndex.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { pipe } from "@fp-ts/core/Function" -import * as O from "@fp-ts/core/Option" -import * as RA from "@fp-ts/core/ReadonlyArray" -import * as _ from "@fp-ts/core/test/limbo/TraversableWithIndex" -import * as U from "../util" - -const TraversableWithIndex: _.TraversableWithIndex = { - // @ts-expect-error - traverseWithIndex: RA.traverseWithIndex -} - -describe("TraversableWithIndex", () => { - it("traverseWithIndexComposition", () => { - const traverseWithIndex = _.traverseWithIndexComposition( - TraversableWithIndex, - TraversableWithIndex - )(O.Applicative) - U.deepStrictEqual( - pipe( - [["a"], ["bb"]], - traverseWithIndex((s, [i, j]) => (s.length >= 1 ? O.some(s + i + j) : O.none())) - ), - O.some([["a00"], ["bb10"]]) - ) - U.deepStrictEqual( - pipe( - [["a"], ["bb"]], - traverseWithIndex((s, [i, j]) => (s.length > 1 ? O.some(s + i + j) : O.none())) - ), - O.none() - ) - }) - - // it("traverse", () => { - // const traverse = _.traverse(TraversableWithIndex)(O.Applicative) - // const f = (n: number) => n > 0 ? O.some(n) : O.none() - // U.deepStrictEqual(pipe([], traverse(f)), O.some([])) - // U.deepStrictEqual(pipe([1, 2, 3], traverse(f)), O.some([1, 2, 3])) - // U.deepStrictEqual(pipe([1, -2, 3], traverse(f)), O.none()) - // }) -}) From f4202dfb4af2455299f4af0d05c2f4cde9f78399 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 16:15:10 +0100 Subject: [PATCH 185/255] ReadonlyArray: remove filterWithIndex --- docs/modules/ReadonlyArray.ts.md | 23 ++++------------------- src/ReadonlyArray.ts | 21 +-------------------- test/ReadonlyArray.ts | 4 +--- 3 files changed, 6 insertions(+), 42 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 06ed40828..3c2a1a7ee 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -37,7 +37,6 @@ Added in v1.0.0 - [compact](#compact) - [filter](#filter) - [filterMap](#filtermap) - - [filterWithIndex](#filterwithindex) - [partition](#partition) - [partitionMap](#partitionmap) - [partitionMapWithIndex](#partitionmapwithindex) @@ -466,9 +465,10 @@ Added in v1.0.0 ```ts export declare const filter: { - (refinement: (a: A) => a is B): (self: Iterable) => B[] - (predicate: (a: A) => boolean): (self: Iterable) => B[] - (self: Iterable, refinement: (a: A) => a is B): B[] + (refinement: (a: A, i: number) => a is B): (self: Iterable) => B[] + (predicate: (a: A, i: number) => boolean): (self: Iterable) => B[] + (self: Iterable, refinement: (a: A, i: number) => a is B): B[] + (self: Iterable, predicate: (a: A, i: number) => boolean): B[] } ``` @@ -487,21 +487,6 @@ export declare const filterMap: { Added in v1.0.0 -## filterWithIndex - -**Signature** - -```ts -export declare const filterWithIndex: { - (refinement: (a: A, i: number) => a is B): (self: Iterable) => B[] - (predicate: (a: A, i: number) => boolean): (self: Iterable) => B[] - (self: Iterable, refinement: (a: A, i: number) => a is B): B[] - (self: Iterable, predicate: (a: A, i: number) => boolean): B[] -} -``` - -Added in v1.0.0 - ## partition **Signature** diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index a46d9b843..58656ceea 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1600,7 +1600,7 @@ export const Compactable: compactable.Compactable = { * @category filtering * @since 1.0.0 */ -export const filterWithIndex: { +export const filter: { ( refinement: (a: A, i: number) => a is B ): (self: Iterable) => Array @@ -1616,25 +1616,6 @@ export const filterWithIndex: { filterMap(self, (b, i) => (predicate(b, i) ? O.some(b) : O.none())) ) -/** - * @category filtering - * @since 1.0.0 - */ -export const filter: { - ( - refinement: (a: A) => a is B - ): (self: Iterable) => Array - (predicate: (a: A) => boolean): (self: Iterable) => Array - ( - self: Iterable, - refinement: (a: A) => a is B - ): Array -} = dual( - 2, - (self: Iterable, predicate: (a: A) => boolean): Array => - filterWithIndex(self, predicate) -) - /** * @category filtering * @since 1.0.0 diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 8cfa580c5..89e9d09a4 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -871,11 +871,9 @@ describe.concurrent("ReadonlyArray", () => { RA.filter(O.isSome) ) assert.deepStrictEqual(y, [O.some(3), O.some(1)]) - }) - it("filterWithIndex", () => { const f = (n: number) => n % 2 === 0 - deepStrictEqual(pipe(["a", "b", "c"], RA.filterWithIndex((_, i) => f(i))), [ + deepStrictEqual(pipe(["a", "b", "c"], RA.filter((_, i) => f(i))), [ "a", "c" ]) From bf1703bc08fc29b9231c4b4977fe754d9b9536b7 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 16:20:12 +0100 Subject: [PATCH 186/255] ReadonlyArray: remove partitionMapWithIndex --- docs/modules/ReadonlyArray.ts.md | 14 -------------- src/ReadonlyArray.ts | 16 +--------------- test/ReadonlyArray.ts | 21 +++++++-------------- 3 files changed, 8 insertions(+), 43 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 3c2a1a7ee..b7146e9fe 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -39,7 +39,6 @@ Added in v1.0.0 - [filterMap](#filtermap) - [partition](#partition) - [partitionMap](#partitionmap) - - [partitionMapWithIndex](#partitionmapwithindex) - [partitionWithIndex](#partitionwithindex) - [separate](#separate) - [span](#span) @@ -508,19 +507,6 @@ Added in v1.0.0 ```ts export declare const partitionMap: { - (f: (a: A) => Either): (self: Iterable) => [B[], C[]] - (self: Iterable, f: (a: A) => Either): [B[], C[]] -} -``` - -Added in v1.0.0 - -## partitionMapWithIndex - -**Signature** - -```ts -export declare const partitionMapWithIndex: { (f: (a: A, i: number) => Either): (self: Iterable) => [B[], C[]] (self: Iterable, f: (a: A, i: number) => Either): [B[], C[]] } diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 58656ceea..e7d124259 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1660,27 +1660,13 @@ export const partitionWithIndex: { } = dual(2, ( self: Iterable, predicate: (a: A, i: number) => boolean -): [Array, Array] => - partitionMapWithIndex(self, (b, i) => (predicate(b, i) ? E.right(b) : E.left(b)))) +): [Array, Array] => partitionMap(self, (b, i) => (predicate(b, i) ? E.right(b) : E.left(b)))) /** * @category filtering * @since 1.0.0 */ export const partitionMap: { - (f: (a: A) => Either): (self: Iterable) => [Array, Array] - (self: Iterable, f: (a: A) => Either): [Array, Array] -} = dual( - 2, - (self: Iterable, f: (a: A) => Either): [Array, Array] => - partitionMapWithIndex(self, f) -) - -/** - * @category filtering - * @since 1.0.0 - */ -export const partitionMapWithIndex: { (f: (a: A, i: number) => Either): (self: Iterable) => [Array, Array] (self: Iterable, f: (a: A, i: number) => Either): [Array, Array] } = dual( diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 89e9d09a4..731c54d59 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -907,6 +907,13 @@ describe.concurrent("ReadonlyArray", () => { ), [["foo"], [1, 2]] ) + deepStrictEqual( + pipe( + [E.right(1), E.left("foo"), E.right(2)], + RA.partitionMap((a, i) => pipe(a, E.filter((n) => n > i, () => "err"))) + ), + [["foo", "err"], [1]] + ) }) it("partition", () => { @@ -920,20 +927,6 @@ describe.concurrent("ReadonlyArray", () => { ) }) - it("partitionMapWithIndex", () => { - deepStrictEqual( - pipe([], RA.partitionMapWithIndex((a) => a)), - [[], []] - ) - deepStrictEqual( - pipe( - [E.right(1), E.left("foo"), E.right(2)], - RA.partitionMapWithIndex((a, i) => pipe(a, E.filter((n) => n > i, () => "err"))) - ), - [["foo", "err"], [1]] - ) - }) - it("partitionWithIndex", () => { deepStrictEqual( pipe([], RA.partitionWithIndex((i, n) => i + n > 2)), From 09040f1bc6863e51b1297ea65d69f3299adb1067 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 16:25:23 +0100 Subject: [PATCH 187/255] ReadonlyArray: remove partitionWithIndex --- docs/modules/ReadonlyArray.ts.md | 24 ++++---------------- src/ReadonlyArray.ts | 38 +++++++++----------------------- test/ReadonlyArray.ts | 7 ++---- 3 files changed, 16 insertions(+), 53 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index b7146e9fe..a98be6775 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -39,7 +39,6 @@ Added in v1.0.0 - [filterMap](#filtermap) - [partition](#partition) - [partitionMap](#partitionmap) - - [partitionWithIndex](#partitionwithindex) - [separate](#separate) - [span](#span) - [traverseFilterMap](#traversefiltermap) @@ -492,10 +491,10 @@ Added in v1.0.0 ```ts export declare const partition: { - (refinement: Refinement): (self: Iterable) => [C[], B[]] - (predicate: Predicate): (self: Iterable) => [B[], B[]] - (self: Iterable, refinement: Refinement): [C[], B[]] - (self: Iterable, predicate: Predicate): [B[], B[]] + (refinement: (a: A, i: number) => a is B): (self: Iterable) => [C[], B[]] + (predicate: (a: A, i: number) => boolean): (self: Iterable) => [B[], B[]] + (self: Iterable, refinement: (a: A, i: number) => a is B): [C[], B[]] + (self: Iterable, predicate: (a: A, i: number) => boolean): [B[], B[]] } ``` @@ -514,21 +513,6 @@ export declare const partitionMap: { Added in v1.0.0 -## partitionWithIndex - -**Signature** - -```ts -export declare const partitionWithIndex: { - (refinement: (a: A, i: number) => a is B): (self: Iterable) => [C[], B[]] - (predicate: (a: A, i: number) => boolean): (self: Iterable) => [B[], B[]] - (self: Iterable, refinement: (a: A, i: number) => a is B): [C[], B[]] - (self: Iterable, predicate: (a: A, i: number) => boolean): [B[], B[]] -} -``` - -Added in v1.0.0 - ## separate **Signature** diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index e7d124259..0b63b446b 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1621,34 +1621,12 @@ export const filter: { * @since 1.0.0 */ export const partition: { - (refinement: Refinement): ( + (refinement: (a: A, i: number) => a is B): ( self: Iterable ) => [Array, Array] ( - predicate: Predicate + predicate: (a: A, i: number) => boolean ): (self: Iterable) => [Array, Array] - ( - self: Iterable, - refinement: Refinement - ): [Array, Array] - (self: Iterable, predicate: Predicate): [Array, Array] -} = dual( - 2, - (self: Iterable, predicate: Predicate): [Array, Array] => - partitionWithIndex(self, predicate) -) - -/** - * @category filtering - * @since 1.0.0 - */ -export const partitionWithIndex: { - (refinement: (a: A, i: number) => a is B): ( - self: Iterable - ) => [Array, Array] - (predicate: (a: A, i: number) => boolean): ( - self: Iterable - ) => [Array, Array] ( self: Iterable, refinement: (a: A, i: number) => a is B @@ -1657,10 +1635,14 @@ export const partitionWithIndex: { self: Iterable, predicate: (a: A, i: number) => boolean ): [Array, Array] -} = dual(2, ( - self: Iterable, - predicate: (a: A, i: number) => boolean -): [Array, Array] => partitionMap(self, (b, i) => (predicate(b, i) ? E.right(b) : E.left(b)))) +} = dual( + 2, + ( + self: Iterable, + predicate: (a: A, i: number) => boolean + ): [Array, Array] => + partitionMap(self, (b, i) => (predicate(b, i) ? E.right(b) : E.left(b))) +) /** * @category filtering diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 731c54d59..d3686d84f 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -925,15 +925,12 @@ describe.concurrent("ReadonlyArray", () => { pipe([1, 3], RA.partition((n) => n > 2)), [[1], [3]] ) - }) - - it("partitionWithIndex", () => { deepStrictEqual( - pipe([], RA.partitionWithIndex((i, n) => i + n > 2)), + pipe([], RA.partition((i, n) => i + n > 2)), [[], []] ) deepStrictEqual( - pipe([1, 2], RA.partitionWithIndex((i, n) => i + n > 2)), + pipe([1, 2], RA.partition((i, n) => i + n > 2)), [[1], [2]] ) }) From bce055a67a5394c5ed04a4d6bd9783702e066106 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 16:34:45 +0100 Subject: [PATCH 188/255] ReadonlyArray: remove traverseWithIndex --- docs/modules/ReadonlyArray.ts.md | 20 ++---------- src/ReadonlyArray.ts | 55 ++++++++++---------------------- test/ReadonlyArray.ts | 19 +++++------ 3 files changed, 27 insertions(+), 67 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index a98be6775..a27673b6c 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -156,7 +156,6 @@ Added in v1.0.0 - [traverseNonEmpty](#traversenonempty) - [traverseNonEmptyWithIndex](#traversenonemptywithindex) - [traverseTap](#traversetap) - - [traverseWithIndex](#traversewithindex) - [type lambdas](#type-lambdas) - [ReadonlyArrayTypeLambda (interface)](#readonlyarraytypelambda-interface) - [unsafe](#unsafe) @@ -1809,8 +1808,8 @@ Added in v1.0.0 export declare const traverse: ( F: applicative.Applicative ) => { - (f: (a: A) => Kind): (self: readonly A[]) => Kind - (self: readonly A[], f: (a: A) => Kind): Kind + (f: (a: A, i: number) => Kind): (self: Iterable) => Kind + (self: Iterable, f: (a: A, i: number) => Kind): Kind } ``` @@ -1869,21 +1868,6 @@ export declare const traverseTap: ( Added in v1.0.0 -## traverseWithIndex - -**Signature** - -```ts -export declare const traverseWithIndex: ( - F: applicative.Applicative -) => { - (f: (a: A, i: number) => Kind): (self: Iterable) => Kind - (self: Iterable, f: (a: A, i: number) => Kind): Kind -} -``` - -Added in v1.0.0 - # type lambdas ## ReadonlyArrayTypeLambda (interface) diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 0b63b446b..16dc31842 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1669,24 +1669,6 @@ export const partitionMap: { } ) -/** - * @category traversing - * @since 1.0.0 - */ -export const traverseWithIndex = (F: applicative.Applicative): { - ( - f: (a: A, i: number) => Kind - ): (self: Iterable) => Kind> - ( - self: Iterable, - f: (a: A, i: number) => Kind - ): Kind> -} => - dual(2, ( - self: Iterable, - f: (a: A, i: number) => Kind - ): Kind> => F.productAll(fromIterable(self).map(f))) - /** * @category traversing * @since 1.0.0 @@ -1731,33 +1713,30 @@ export const traverseNonEmptyWithIndex = ( }) /** - * @category instances + * @category traversing * @since 1.0.0 */ -export const Traversable: traversable.Traversable = traversable.make(< - F extends TypeLambda ->(F: applicative.Applicative) => +export const traverse = (F: applicative.Applicative): { ( - self: ReadonlyArray, - f: (a: A) => Kind - ): Kind> => traverseWithIndex(F)(f)(self) as any -) + f: (a: A, i: number) => Kind + ): (self: Iterable) => Kind> + ( + self: Iterable, + f: (a: A, i: number) => Kind + ): Kind> +} => + dual(2, ( + self: Iterable, + f: (a: A, i: number) => Kind + ): Kind> => F.productAll(fromIterable(self).map(f))) /** - * @category traversing + * @category instances * @since 1.0.0 */ -export const traverse: ( - F: applicative.Applicative -) => { - ( - f: (a: A) => Kind - ): (self: ReadonlyArray) => Kind> - ( - self: ReadonlyArray, - f: (a: A) => Kind - ): Kind> -} = Traversable.traverse as any +export const Traversable: traversable.Traversable = { + traverse: traverse as any +} /** * @category traversing diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index d3686d84f..fae020895 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -737,19 +737,10 @@ describe.concurrent("ReadonlyArray", () => { ): O.Option => (n % 2 === 0 ? O.none() : O.some(n))) deepStrictEqual(traverse([1, 2]), O.none()) deepStrictEqual(traverse([1, 3]), O.some([1, 3])) - }) - - it("sequence", () => { - const sequence = RA.sequence(O.Applicative) - deepStrictEqual(sequence([O.some(1), O.some(3)]), O.some([1, 3])) - deepStrictEqual(sequence([O.some(1), O.none()]), O.none()) - }) - - it("traverseWithIndex", () => { deepStrictEqual( pipe( ["a", "bb"], - RA.traverseWithIndex(O.Applicative)(( + RA.traverse(O.Applicative)(( s, i ) => (s.length >= 1 ? O.some(s + i) : O.none())) @@ -759,7 +750,7 @@ describe.concurrent("ReadonlyArray", () => { deepStrictEqual( pipe( ["a", "bb"], - RA.traverseWithIndex(O.Applicative)(( + RA.traverse(O.Applicative)(( s, i ) => (s.length > 1 ? O.some(s + i) : O.none())) @@ -768,6 +759,12 @@ describe.concurrent("ReadonlyArray", () => { ) }) + it("sequence", () => { + const sequence = RA.sequence(O.Applicative) + deepStrictEqual(sequence([O.some(1), O.some(3)]), O.some([1, 3])) + deepStrictEqual(sequence([O.some(1), O.none()]), O.none()) + }) + it("get", () => { deepStrictEqual(pipe([1, 2, 3], RA.get(0)), O.some(1)) deepStrictEqual(pipe([1, 2, 3], RA.get(3)), O.none()) From 1e6b81c8d6b5ba9800fcff18fe2da5c1c07e6564 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 16:47:49 +0100 Subject: [PATCH 189/255] ReadonlyArray: remove traverseNonEmptyWithIndex --- docs/modules/ReadonlyArray.ts.md | 16 ---------------- src/ReadonlyArray.ts | 20 -------------------- test/ReadonlyArray.ts | 13 ++----------- 3 files changed, 2 insertions(+), 47 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index a27673b6c..835b51999 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -154,7 +154,6 @@ Added in v1.0.0 - [sequenceNonEmpty](#sequencenonempty) - [traverse](#traverse) - [traverseNonEmpty](#traversenonempty) - - [traverseNonEmptyWithIndex](#traversenonemptywithindex) - [traverseTap](#traversetap) - [type lambdas](#type-lambdas) - [ReadonlyArrayTypeLambda (interface)](#readonlyarraytypelambda-interface) @@ -1822,21 +1821,6 @@ Added in v1.0.0 ```ts export declare const traverseNonEmpty: ( F: semiApplicative.SemiApplicative -) => { - (f: (a: A) => Kind): (self: readonly [A, ...A[]]) => Kind - (self: readonly [A, ...A[]], f: (a: A) => Kind): Kind -} -``` - -Added in v1.0.0 - -## traverseNonEmptyWithIndex - -**Signature** - -```ts -export declare const traverseNonEmptyWithIndex: ( - F: semiApplicative.SemiApplicative ) => { (f: (a: A, i: number) => Kind): ( self: readonly [A, ...A[]] diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 16dc31842..ea7df8609 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1675,26 +1675,6 @@ export const partitionMap: { */ export const traverseNonEmpty = ( F: semiApplicative.SemiApplicative -): { - ( - f: (a: A) => Kind - ): (self: NonEmptyReadonlyArray) => Kind> - ( - self: NonEmptyReadonlyArray, - f: (a: A) => Kind - ): Kind> -} => - dual(2, ( - self: NonEmptyReadonlyArray, - f: (a: A) => Kind - ): Kind> => traverseNonEmptyWithIndex(F)(self, f)) - -/** - * @category traversing - * @since 1.0.0 - */ -export const traverseNonEmptyWithIndex = ( - F: semiApplicative.SemiApplicative ): { ( f: (a: A, i: number) => Kind diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index fae020895..8e06e1fa4 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -978,26 +978,17 @@ describe.concurrent("ReadonlyArray", () => { ), O.none() ) - }) - - it("traverseNonEmptyWithIndex", () => { deepStrictEqual( pipe( RA.make("a", "bb"), - RA.traverseNonEmptyWithIndex(O.Applicative)(( - s, - i - ) => (s.length >= 1 ? O.some(s + i) : O.none())) + RA.traverseNonEmpty(O.Applicative)((s, i) => (s.length >= 1 ? O.some(s + i) : O.none())) ), O.some(RA.make("a0", "bb1")) ) deepStrictEqual( pipe( RA.make("a", "bb"), - RA.traverseNonEmptyWithIndex(O.Applicative)(( - s, - i - ) => (s.length > 1 ? O.some(s + i) : O.none())) + RA.traverseNonEmpty(O.Applicative)((s, i) => (s.length > 1 ? O.some(s + i) : O.none())) ), O.none() ) From 0946fd84f5dcd94f18cb6be7ed57eabf800c45d0 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 16:52:18 +0100 Subject: [PATCH 190/255] ReadonlyArray: remove reduceWithIndex --- docs/modules/ReadonlyArray.ts.md | 18 ++---------------- src/ReadonlyArray.ts | 13 ++----------- test/ReadonlyArray.ts | 17 +++++++---------- 3 files changed, 11 insertions(+), 37 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 835b51999..cbff29d6d 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -53,7 +53,6 @@ Added in v1.0.0 - [reduceKind](#reducekind) - [reduceRight](#reduceright) - [reduceRightWithIndex](#reducerightwithindex) - - [reduceWithIndex](#reducewithindex) - [scan](#scan) - [scanRight](#scanright) - [getters](#getters) @@ -646,8 +645,8 @@ Added in v1.0.0 ```ts export declare const reduce: { - (b: B, f: (b: B, a: A) => B): (self: Iterable) => B - (self: Iterable, b: B, f: (b: B, a: A) => B): B + (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B + (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B } ``` @@ -694,19 +693,6 @@ export declare const reduceRightWithIndex: { Added in v1.0.0 -## reduceWithIndex - -**Signature** - -```ts -export declare const reduceWithIndex: { - (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B - (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B -} -``` - -Added in v1.0.0 - ## scan Reduce an `Iterable` from the left, keeping all intermediate results instead of only the final result. diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index ea7df8609..3d8e5bfb4 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1859,7 +1859,7 @@ export const Monad: monad.Monad = { * @category folding * @since 1.0.0 */ -export const reduceWithIndex: { +export const reduce: { (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B } = dual( @@ -1897,16 +1897,7 @@ export const reduceRightWithIndex: { * @category instances * @since 1.0.0 */ -export const Foldable: foldable.Foldable = foldable.make(reduceWithIndex) - -/** - * @category folding - * @since 1.0.0 - */ -export const reduce: { - (b: B, f: (b: B, a: A) => B): (self: Iterable) => B - (self: Iterable, b: B, f: (b: B, a: A) => B): B -} = dual(3, (self: Iterable, b: B, f: (b: B, a: A) => B): B => reduceWithIndex(self, b, f)) +export const Foldable: foldable.Foldable = foldable.make(reduce) /** * @category folding diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 8e06e1fa4..62296c49c 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -934,24 +934,21 @@ describe.concurrent("ReadonlyArray", () => { it("reduce", () => { deepStrictEqual(pipe(["a", "b", "c"], RA.reduce("", (b, a) => b + a)), "abc") - }) - - it("reduceRight", () => { - const f = (b: string, a: string) => b + a - deepStrictEqual(pipe(["a", "b", "c"], RA.reduceRight("", f)), "cba") - deepStrictEqual(pipe([], RA.reduceRight("", f)), "") - }) - - it("reduceWithIndex", () => { deepStrictEqual( pipe( ["a", "b"], - RA.reduceWithIndex("", (b, a, i) => b + i + a) + RA.reduce("", (b, a, i) => b + i + a) ), "0a1b" ) }) + it("reduceRight", () => { + const f = (b: string, a: string) => b + a + deepStrictEqual(pipe(["a", "b", "c"], RA.reduceRight("", f)), "cba") + deepStrictEqual(pipe([], RA.reduceRight("", f)), "") + }) + it("reduceRightWithIndex", () => { deepStrictEqual( pipe( From 3d46e17789153738d0b4921e2340142d6bf01a19 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 16:58:21 +0100 Subject: [PATCH 191/255] ReadonlyArray: remove reduceRightWithIndex --- docs/modules/ReadonlyArray.ts.md | 14 -------------- src/ReadonlyArray.ts | 12 ------------ test/ReadonlyArray.ts | 5 +---- 3 files changed, 1 insertion(+), 30 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index cbff29d6d..efadc3ec5 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -52,7 +52,6 @@ Added in v1.0.0 - [reduce](#reduce) - [reduceKind](#reducekind) - [reduceRight](#reduceright) - - [reduceRightWithIndex](#reducerightwithindex) - [scan](#scan) - [scanRight](#scanright) - [getters](#getters) @@ -673,19 +672,6 @@ Added in v1.0.0 ```ts export declare const reduceRight: { - (b: B, f: (b: B, a: A) => B): (self: Iterable) => B - (self: Iterable, b: B, f: (b: B, a: A) => B): B -} -``` - -Added in v1.0.0 - -## reduceRightWithIndex - -**Signature** - -```ts -export declare const reduceRightWithIndex: { (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B } diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 3d8e5bfb4..8f588fac9 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1873,18 +1873,6 @@ export const reduce: { * @since 1.0.0 */ export const reduceRight: { - (b: B, f: (b: B, a: A) => B): (self: Iterable) => B - (self: Iterable, b: B, f: (b: B, a: A) => B): B -} = dual( - 3, - (self: Iterable, b: B, f: (b: B, a: A) => B): B => reduceRightWithIndex(self, b, f) -) - -/** - * @category folding - * @since 1.0.0 - */ -export const reduceRightWithIndex: { (b: B, f: (b: B, a: A, i: number) => B): (self: Iterable) => B (self: Iterable, b: B, f: (b: B, a: A, i: number) => B): B } = dual( diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 62296c49c..2e4d9208b 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -947,13 +947,10 @@ describe.concurrent("ReadonlyArray", () => { const f = (b: string, a: string) => b + a deepStrictEqual(pipe(["a", "b", "c"], RA.reduceRight("", f)), "cba") deepStrictEqual(pipe([], RA.reduceRight("", f)), "") - }) - - it("reduceRightWithIndex", () => { deepStrictEqual( pipe( ["a", "b"], - RA.reduceRightWithIndex("", (b, a, i) => b + i + a) + RA.reduceRight("", (b, a, i) => b + i + a) ), "1b0a" ) From 240bd6f867369f7ed5b80acc7eff63addcc65fab Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 4 Feb 2023 17:04:05 +0100 Subject: [PATCH 192/255] ReadonlyArray: remove combineMapWithIndex, combineMapNonEmptyWithIndex --- docs/modules/ReadonlyArray.ts.md | 34 +++----------------------------- src/ReadonlyArray.ts | 30 +--------------------------- test/ReadonlyArray.ts | 10 +++------- 3 files changed, 7 insertions(+), 67 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index efadc3ec5..ae4bc9a25 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -46,8 +46,6 @@ Added in v1.0.0 - [folding](#folding) - [combineMap](#combinemap) - [combineMapNonEmpty](#combinemapnonempty) - - [combineMapNonEmptyWithIndex](#combinemapnonemptywithindex) - - [combineMapWithIndex](#combinemapwithindex) - [coproductMapKind](#coproductmapkind) - [reduce](#reduce) - [reduceKind](#reducekind) @@ -576,9 +574,9 @@ Added in v1.0.0 **Signature** ```ts -export declare const combineMap: (M: Monoid) => { - (f: (a: A) => M): (self: Iterable) => M - (self: Iterable, f: (a: A) => M): M +export declare const combineMap: (Monoid: Monoid) => { + (f: (a: A, i: number) => M): (self: Iterable) => M + (self: Iterable, f: (a: A, i: number) => M): M } ``` @@ -590,19 +588,6 @@ Added in v1.0.0 ```ts export declare const combineMapNonEmpty: (S: Semigroup) => { - (f: (a: A) => S): (self: readonly [A, ...A[]]) => S - (self: readonly [A, ...A[]], f: (a: A) => S): S -} -``` - -Added in v1.0.0 - -## combineMapNonEmptyWithIndex - -**Signature** - -```ts -export declare const combineMapNonEmptyWithIndex: (S: Semigroup) => { (f: (a: A, i: number) => S): (self: readonly [A, ...A[]]) => S (self: readonly [A, ...A[]], f: (a: A, i: number) => S): S } @@ -610,19 +595,6 @@ export declare const combineMapNonEmptyWithIndex: (S: Semigroup) => { Added in v1.0.0 -## combineMapWithIndex - -**Signature** - -```ts -export declare const combineMapWithIndex: (Monoid: Monoid) => { - (f: (a: A, i: number) => M): (self: Iterable) => M - (self: Iterable, f: (a: A, i: number) => M): M -} -``` - -Added in v1.0.0 - ## coproductMapKind **Signature** diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 8f588fac9..901642e0c 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1891,7 +1891,7 @@ export const Foldable: foldable.Foldable = foldable.mak * @category folding * @since 1.0.0 */ -export const combineMapWithIndex = (Monoid: Monoid): { +export const combineMap = (Monoid: Monoid): { (f: (a: A, i: number) => M): (self: Iterable) => M (self: Iterable, f: (a: A, i: number) => M): M } => @@ -1901,39 +1901,11 @@ export const combineMapWithIndex = (Monoid: Monoid): { fromIterable(self).reduce((m, a, i) => Monoid.combine(m, f(a, i)), Monoid.empty) ) -/** - * @category folding - * @since 1.0.0 - */ -export const combineMap = (M: Monoid): { - (f: (a: A) => M): (self: Iterable) => M - (self: Iterable, f: (a: A) => M): M -} => - dual( - 2, - (self: Iterable, f: (a: A) => M): M => - fromIterable(self).reduce((m, a) => M.combine(m, f(a)), M.empty) - ) - /** * @category folding * @since 1.0.0 */ export const combineMapNonEmpty = (S: Semigroup): { - (f: (a: A) => S): (self: NonEmptyReadonlyArray) => S - (self: NonEmptyReadonlyArray, f: (a: A) => S): S -} => - dual( - 2, - (self: NonEmptyReadonlyArray, f: (a: A) => S): S => - combineMapNonEmptyWithIndex(S)(self, f) - ) - -/** - * @category folding - * @since 1.0.0 - */ -export const combineMapNonEmptyWithIndex = (S: Semigroup): { (f: (a: A, i: number) => S): (self: NonEmptyReadonlyArray) => S (self: NonEmptyReadonlyArray, f: (a: A, i: number) => S): S } => diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 2e4d9208b..c7987244d 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -53,7 +53,6 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.Foldable).exist expect(RA.reduce).exist expect(RA.reduceRight).exist - expect(RA.combineMap).exist expect(RA.reduceKind).exist expect(RA.coproductMapKind).exist @@ -885,11 +884,11 @@ describe.concurrent("ReadonlyArray", () => { deepStrictEqual(pipe([], RA.filterMap(g)), []) }) - it("combineMapWithIndex", () => { + it("combineMap", () => { deepStrictEqual( pipe( ["a", "b"], - RA.combineMapWithIndex(String.Monoid)((a, i) => i + a) + RA.combineMap(String.Monoid)((a, i) => i + a) ), "0a1b" ) @@ -1511,13 +1510,10 @@ describe.concurrent("ReadonlyArray", () => { ), "abc" ) - }) - - it("combineMapNonEmptyWithIndex", () => { deepStrictEqual( pipe( RA.make("a", "b"), - RA.combineMapNonEmptyWithIndex(String.Semigroup)((a, i) => i + a) + RA.combineMapNonEmpty(String.Semigroup)((a, i) => i + a) ), "0a1b" ) From b9e9c25a740b201ab1fea2298a642066cda88848 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 5 Feb 2023 08:28:35 +0100 Subject: [PATCH 193/255] Function: remove compose --- docs/modules/Function.ts.md | 45 +++++++++++++--------- src/Function.ts | 76 +++++++++++++++++++++++-------------- test/Function.ts | 4 -- 3 files changed, 74 insertions(+), 51 deletions(-) diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 634a1510f..58809bb2e 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -20,7 +20,6 @@ Added in v1.0.0 - [SK](#sk) - [absurd](#absurd) - [apply](#apply) - - [compose](#compose) - [constFalse](#constfalse) - [constNull](#constnull) - [constTrue](#consttrue) @@ -91,7 +90,10 @@ Added in v1.0.0 ## SK -`SK` function (SKI combinator calculus). +The SK combinator, also known as the "S-K combinator" or "S-combinator", is a fundamental combinator in the +lambda calculus and the SKI combinator calculus. + +This function is useful for discarding the first argument passed to it and returning the second argument. **Signature** @@ -99,10 +101,24 @@ Added in v1.0.0 export declare const SK: (_: A, b: B) => B ``` +**Example** + +```ts +import { SK } from '@fp-ts/core/Function' + +assert.deepStrictEqual(SK(0, 'hello'), 'hello') +``` + Added in v1.0.0 ## absurd +The `absurd` function is a stub for cases where a value of type `never` is encountered in your code, +meaning that it should be impossible for this code to be executed. + +This function is particularly useful in functional programming, where it's often necessary to specify that certain cases are impossible. +By calling `absurd`, you can ensure that the type system correctly reflects that a certain value should never occur. + **Signature** ```ts @@ -132,16 +148,6 @@ assert.deepStrictEqual(pipe(2, apply(increment)), 3) Added in v1.0.0 -## compose - -**Signature** - -```ts -export declare const compose: (bc: (b: B) => C) => (ab: (a: A) => B) => (a: A) => C -``` - -Added in v1.0.0 - ## constFalse A thunk that returns always `false`. @@ -204,16 +210,23 @@ Added in v1.0.0 ## constant +Creates a constant value that never changes. + +This is useful when you want to pass a value to a higher-order function (a function that takes another function as its argument) +and want that inner function to always use the same value, no matter how many times it is called. + **Signature** ```ts -export declare const constant: (a: A) => LazyArg +export declare const constant: (value: A) => LazyArg ``` Added in v1.0.0 ## dual +Creates a function that is both data-last and data-first. + **Signature** ```ts @@ -230,7 +243,7 @@ Added in v1.0.0 ## flip -Flips the arguments of a curried function. +Reverses the order of arguments for a curried function. **Signature** @@ -606,10 +619,6 @@ import { pipe } from '@fp-ts/core/Function' const len = (s: string): number => s.length const double = (n: number): number => n * 2 -// without pipe -assert.deepStrictEqual(double(len('aaa')), 6) - -// with pipe assert.deepStrictEqual(pipe('aaa', len, double), 6) ``` diff --git a/src/Function.ts b/src/Function.ts index 6b38742b1..717cb84fb 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -16,10 +16,26 @@ export interface FunctionTypeLambda extends TypeLambda { } /** + * Creates a function that is both data-last and data-first. + * * @since 1.0.0 */ -export const compose: (bc: (b: B) => C) => (ab: (a: A) => B) => (a: A) => C = (bc) => - (ab) => flow(ab, bc) +export const dual = < + DataLast extends (...args: Array) => any, + DataFirst extends (...args: Array) => any +>( + dataFirstArity: Parameters["length"], + body: DataFirst +): DataLast & DataFirst => { + // @ts-expect-error + return function() { + if (arguments.length >= dataFirstArity) { + // @ts-expect-error + return body.apply(this, arguments) + } + return ((self: any) => body(self, ...arguments)) as any + } +} /** * Apply a function to a given value. @@ -66,9 +82,16 @@ export const identity = (a: A): A => a export const unsafeCoerce: (a: A) => B = identity as any /** + * Creates a constant value that never changes. + * + * This is useful when you want to pass a value to a higher-order function (a function that takes another function as its argument) + * and want that inner function to always use the same value, no matter how many times it is called. + * + * @param value - The constant value to be returned + * * @since 1.0.0 */ -export const constant = (a: A): LazyArg => () => a +export const constant = (value: A): LazyArg => () => value /** * A thunk that returns always `true`. @@ -106,7 +129,9 @@ export const constUndefined: LazyArg = constant(undefined) export const constVoid: LazyArg = constUndefined /** - * Flips the arguments of a curried function. + * Reverses the order of arguments for a curried function. + * + * @param f -A curried function that takes multiple arguments. * * @example * import { flip } from '@fp-ts/core/Function' @@ -249,6 +274,12 @@ export function flow( } /** + * The `absurd` function is a stub for cases where a value of type `never` is encountered in your code, + * meaning that it should be impossible for this code to be executed. + * + * This function is particularly useful in functional programming, where it's often necessary to specify that certain cases are impossible. + * By calling `absurd`, you can ensure that the type system correctly reflects that a certain value should never occur. + * * @since 1.0.0 */ export const absurd = (_: never): A => { @@ -287,10 +318,6 @@ export const untupled = , B>(f: (a: A) => B): ( * const len = (s: string): number => s.length * const double = (n: number): number => n * 2 * - * // without pipe - * assert.deepStrictEqual(double(len('aaa')), 6) - * - * // with pipe * assert.deepStrictEqual(pipe('aaa', len, double), 6) * * @see {@link flow} @@ -585,28 +612,19 @@ export function pipe( export const hole: () => T = absurd as any /** - * `SK` function (SKI combinator calculus). + * The SK combinator, also known as the "S-K combinator" or "S-combinator", is a fundamental combinator in the + * lambda calculus and the SKI combinator calculus. + * + * This function is useful for discarding the first argument passed to it and returning the second argument. + * + * @param _ - The first argument to be discarded. + * @param b - The second argument to be returned. + * + * @example + * import { SK } from '@fp-ts/core/Function'; + * + * assert.deepStrictEqual(SK(0, 'hello'), 'hello') * * @since 1.0.0 */ export const SK = (_: A, b: B): B => b - -/** - * @since 1.0.0 - */ -export const dual = < - DataLast extends (...args: Array) => any, - DataFirst extends (...args: Array) => any ->( - dataFirstArity: Parameters["length"], - body: DataFirst -): DataLast & DataFirst => { - // @ts-expect-error - return function() { - if (arguments.length >= dataFirstArity) { - // @ts-expect-error - return body.apply(this, arguments) - } - return ((self: any) => body(self, ...arguments)) as any - } -} diff --git a/test/Function.ts b/test/Function.ts index 264d54ae8..4bb6ffbd3 100644 --- a/test/Function.ts +++ b/test/Function.ts @@ -19,10 +19,6 @@ describe.concurrent("Function", () => { deepStrictEqual(_.flip(g)(2)(2, 1), 5) }) - it("compose", () => { - deepStrictEqual(_.pipe(String.length, _.compose(double))("aaa"), 6) - }) - it("unsafeCoerce", () => { deepStrictEqual(_.unsafeCoerce, _.identity) }) From 15fd0e5f5f917e4df82faf89bc643a5ec0ce4807 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 5 Feb 2023 08:39:12 +0100 Subject: [PATCH 194/255] Predicate: fix isBigint name --- docs/modules/Either.ts.md | 4 ++-- docs/modules/Option.ts.md | 4 ++-- docs/modules/Predicate.ts.md | 6 +++--- docs/modules/These.ts.md | 2 +- src/Bigint.ts | 2 +- src/Either.ts | 4 ++-- src/Option.ts | 4 ++-- src/Predicate.ts | 2 +- src/These.ts | 2 +- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index d215ffdd3..df81779bb 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -292,7 +292,7 @@ Added in v1.0.0 ## of -Alias of `right`. +Alias of {@link right}. **Signature** @@ -385,7 +385,7 @@ Added in v1.0.0 Converts a `Either` to an `Option` discarding the error. -Alias of `toOption`. +Alias of {@link toOption}. **Signature** diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 2351afeb9..41ea42870 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -325,7 +325,7 @@ Added in v1.0.0 ## of -Alias of `some`. +Alias of {@link some}. **Signature** @@ -422,7 +422,7 @@ Added in v1.0.0 Converts a `Either` to an `Option` discarding the error. -Alias of `fromEither`. +Alias of {@link fromEither}. **Signature** diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index 0a5475ad1..5cd48378d 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -21,7 +21,7 @@ Added in v1.0.0 - [andThenBind](#andthenbind) - [bindTo](#bindto) - [guards](#guards) - - [isBigInt](#isbigint) + - [isBigint](#isbigint) - [isBoolean](#isboolean) - [isNumber](#isnumber) - [isString](#isstring) @@ -132,12 +132,12 @@ Added in v1.0.0 # guards -## isBigInt +## isBigint **Signature** ```ts -export declare const isBigInt: (u: unknown) => u is bigint +export declare const isBigint: (u: unknown) => u is bigint ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index daebd464a..b13050772 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -350,7 +350,7 @@ Added in v1.0.0 ## of -Alias of `right`. +Alias of {@link right}. **Signature** diff --git a/src/Bigint.ts b/src/Bigint.ts index c1dbd8321..dd2df7a1f 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -17,7 +17,7 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" * @category guards * @since 1.0.0 */ -export const isBigint: (u: unknown) => u is bigint = predicate.isBigInt +export const isBigint: (u: unknown) => u is bigint = predicate.isBigint /** * @category algebraic operations diff --git a/src/Either.ts b/src/Either.ts index eed30bdec..64bc1ab52 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -92,7 +92,7 @@ export const right: (a: A) => Either = either.right export const left: (e: E) => Either = either.left /** - * Alias of `right`. + * Alias of {@link right}. * * @category constructors * @since 1.0.0 @@ -178,7 +178,7 @@ export const toOption: (self: Either) => Option = either.getRight /** * Converts a `Either` to an `Option` discarding the error. * - * Alias of `toOption`. + * Alias of {@link toOption}. * * @example * import * as O from '@fp-ts/core/Option' diff --git a/src/Option.ts b/src/Option.ts index 7ccee3330..beb94e1f4 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -101,7 +101,7 @@ export const none = (): Option => option.none export const some: (value: A) => Option = option.some /** - * Alias of `some`. + * Alias of {@link some}. * * @category constructors * @since 1.0.0 @@ -264,7 +264,7 @@ export const fromEither: (self: Either) => Option = either.getRig /** * Converts a `Either` to an `Option` discarding the error. * - * Alias of `fromEither`. + * Alias of {@link fromEither}. * * @example * import * as O from '@fp-ts/core/Option' diff --git a/src/Predicate.ts b/src/Predicate.ts index 55b47d2b2..17e1d1f5b 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -61,7 +61,7 @@ export const isBoolean: Refinement = (u: unknown): u is boolea * @category guards * @since 1.0.0 */ -export const isBigInt = (u: unknown): u is bigint => typeof u === "bigint" +export const isBigint = (u: unknown): u is bigint => typeof u === "bigint" /** * @category guards diff --git a/src/These.ts b/src/These.ts index 77f13a801..99800b328 100644 --- a/src/These.ts +++ b/src/These.ts @@ -86,7 +86,7 @@ export const left: (left: E) => These = E.left export const right: (right: A) => These = E.right /** - * Alias of `right`. + * Alias of {@link right}. * * @category constructors * @since 1.0.0 From 7aba57f903aa846c8c5f420d5da9ae184b46dfe5 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 5 Feb 2023 11:52:47 +0100 Subject: [PATCH 195/255] ReadonlyRecord: more APIs --- docs/modules/Either.ts.md | 39 +- docs/modules/ReadonlyArray.ts.md | 2 +- docs/modules/ReadonlyRecord.ts.md | 727 ++++++++++++++++++++++- docs/modules/typeclass/Applicative.ts.md | 5 +- docs/modules/typeclass/Bicovariant.ts.md | 2 + src/Either.ts | 57 +- src/ReadonlyArray.ts | 54 +- src/ReadonlyRecord.ts | 679 +++++++++++++++++++-- src/typeclass/Applicative.ts | 8 +- src/typeclass/Bicovariant.ts | 2 + test/ReadonlyArray.ts | 2 +- test/ReadonlyRecord.ts | 132 ++++ 12 files changed, 1570 insertions(+), 139 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index df81779bb..ec8dd3924 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -210,10 +210,11 @@ Added in v1.0.0 ## getFirstLeftMonoid -Monoid returning the left-most `Left` value. If both operands are `Right`s then the inner values -are concatenated using the provided `Monoid`. +`Monoid` returning the left-most `Left` value. If both operands are `Right`s then the inner values +are combined using the provided `Monoid`. -The `empty` value is `right(M.empty)`. +- `combine` is provided by {@link getFirstLeftSemigroup}. +- `empty` is `right(M.empty)` **Signature** @@ -225,15 +226,17 @@ Added in v1.0.0 ## getFirstLeftSemigroup -Semigroup returning the left-most `Left` value. If both operands are `Right`s then the inner values -are concatenated using the provided `Semigroup`. +`Semigroup` returning the left-most `Left` value. If both operands are `Right`s then the inner values +are combined using the provided `Semigroup`. -| x | y | x | > combine(y) | -| -------- | -------- | ------- | ------------- | -| left(a) | left(b) | left(a) | -| left(a) | right(2) | left(a) | -| right(1) | left(b) | left(b) | -| right(1) | right(2) | right(1 | > combine(2)) | +``` +| self | that | combine(self, that) | +| ---------- | ---------- | ----------------------- | +| left(e1) | left(e2) | left(e1) | +| left(e1) | right(a2) | left(e1) | +| right(a1) | left(e2) | left(e2) | +| right(a1) | right(a2) | right(combine(a1, a2)) | +``` **Signature** @@ -247,12 +250,14 @@ Added in v1.0.0 Semigroup returning the left-most `Right` value. -| x | y | x | > combine(y) | -| -------- | -------- | -------- | ------------ | -| left(a) | left(b) | left(b) | -| left(a) | right(2) | right(2) | -| right(1) | left(b) | right(1) | -| right(1) | right(2) | right(1) | +``` +| self | that | combine(self, that) | +| ---------- | ---------- | ------------------- | +| left(e1) | left(e2) | left(e2) | +| left(e1) | right(a2) | right(a2) | +| right(a1) | left(e2) | right(a1) | +| right(a1) | right(a2) | right(a1) | +``` **Signature** diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index ae4bc9a25..b7c20a1f4 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -512,7 +512,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const separate: (self: readonly Either[]) => [A[], B[]] +export declare const separate: (self: Iterable>) => [A[], B[]] ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md index 9af32beaf..1ec344763 100644 --- a/docs/modules/ReadonlyRecord.ts.md +++ b/docs/modules/ReadonlyRecord.ts.md @@ -15,21 +15,70 @@ Added in v1.0.0

Table of contents

- [constructors](#constructors) + - [empty](#empty) - [fromIterable](#fromiterable) -- [getters](#getters) - - [get](#get) +- [conversions](#conversions) + - [collect](#collect) + - [toArray](#toarray) +- [filtering](#filtering) + - [compact](#compact) + - [filter](#filter) + - [partition](#partition) + - [partitionMap](#partitionmap) + - [separate](#separate) + - [traverseFilterMap](#traversefiltermap) + - [traversePartitionMap](#traversepartitionmap) +- [guards](#guards) + - [isEmpty](#isempty) +- [instances](#instances) + - [Compactable](#compactable) + - [Covariant](#covariant) + - [Filterable](#filterable) + - [Invariant](#invariant) + - [Traversable](#traversable) + - [TraversableFilterable](#traversablefilterable) - [mapping](#mapping) - - [map](#map) + - [as](#as) + - [flap](#flap) + - [tupled](#tupled) - [models](#models) - [ReadonlyRecord (interface)](#readonlyrecord-interface) +- [record](#record) + - [pop](#pop) +- [traversing](#traversing) + - [sequence](#sequence) + - [traverse](#traverse) + - [traverseTap](#traversetap) +- [type lambdas](#type-lambdas) + - [ReadonlyRecordTypeLambda (interface)](#readonlyrecordtypelambda-interface) - [utils](#utils) + - [filterMap](#filtermap) + - [get](#get) + - [has](#has) + - [map](#map) - [modifyOption](#modifyoption) + - [remove](#remove) - [replaceOption](#replaceoption) + - [size](#size) + - [traverseFilter](#traversefilter) + - [traversePartition](#traversepartition) --- # constructors +## empty + +Creates a new, empty record. + +**Signature** + +```ts +export declare const empty:
() => Record +``` + +Added in v1.0.0 + ## fromIterable Takes an iterable and a projection function and returns a record. @@ -59,7 +108,546 @@ assert.deepStrictEqual( Added in v1.0.0 -# getters +# conversions + +## collect + +Transforms the values of a `ReadonlyRecord` into an `Array` with a custom mapping function. + +**Signature** + +```ts +export declare const collect: { + (f: (key: string, a: A) => B): (self: ReadonlyRecord) => B[] + (self: ReadonlyRecord, f: (key: string, a: A) => B): B[] +} +``` + +**Example** + +```ts +import { collect } from '@fp-ts/core/ReadonlyRecord' + +const x = { a: 1, b: 2, c: 3 } +assert.deepStrictEqual( + collect(x, (key, n) => [key, n]), + [ + ['a', 1], + ['b', 2], + ['c', 3], + ] +) +``` + +Added in v1.0.0 + +## toArray + +Converts a `ReadonlyRecord` to an `Array` of key-value pairs. + +**Signature** + +```ts +export declare const toArray: (self: ReadonlyRecord) => [string, A][] +``` + +**Example** + +```ts +import { toArray } from '@fp-ts/core/ReadonlyRecord' + +const x = { a: 1, b: 2 } +assert.deepStrictEqual(toArray(x), [ + ['a', 1], + ['b', 2], +]) +``` + +Added in v1.0.0 + +# filtering + +## compact + +Given a `ReadonlyRecord` with `Option` values, returns a `Record` with only the `Some` values, with the same keys. + +**Signature** + +```ts +export declare const compact: (self: ReadonlyRecord>) => Record +``` + +**Example** + +```ts +import { compact } from '@fp-ts/core/ReadonlyRecord' +import { some, none } from '@fp-ts/core/Option' + +assert.deepStrictEqual(compact({ a: some(1), b: none(), c: some(2) }), { a: 1, c: 2 }) +``` + +Added in v1.0.0 + +## filter + +Selects properties from a record whose values match the given predicate. + +**Signature** + +```ts +export declare const filter: { + (refinement: (a: A, key: string) => a is B): ( + self: ReadonlyRecord + ) => Record + (predicate: (a: A, key: string) => boolean): (self: ReadonlyRecord) => Record + (self: ReadonlyRecord, refinement: (a: A, key: string) => a is B): Record< + string, + B + > + (self: ReadonlyRecord, predicate: (a: A, key: string) => boolean): Record +} +``` + +**Example** + +```ts +import { filter } from '@fp-ts/core/ReadonlyRecord' + +const x = { a: 1, b: 2, c: 3, d: 4 } +assert.deepStrictEqual( + filter(x, (n) => n > 2), + { c: 3, d: 4 } +) +``` + +Added in v1.0.0 + +## partition + +Partitions a `ReadonlyRecord` into two separate `Record`s based on the result of a predicate function. + +**Signature** + +```ts +export declare const partition: { + (refinement: (a: A, key: string) => a is B): ( + self: ReadonlyRecord + ) => [Record, Record] + (predicate: (a: A, key: string) => boolean): ( + self: ReadonlyRecord + ) => [Record, Record] + (self: ReadonlyRecord, refinement: (a: A, key: string) => a is B): [ + Record, + Record + ] + (self: ReadonlyRecord, predicate: (a: A, key: string) => boolean): [ + Record, + Record + ] +} +``` + +**Example** + +```ts +import { partition } from '@fp-ts/core/ReadonlyRecord' + +assert.deepStrictEqual( + partition({ a: 1, b: 3 }, (n) => n > 2), + [{ a: 1 }, { b: 3 }] +) +``` + +Added in v1.0.0 + +## partitionMap + +Partitions the elements of a `ReadonlyRecord` into two groups: those that match a predicate, and those that don't. + +**Signature** + +```ts +export declare const partitionMap: { + (f: (a: A, key: string) => Either): (self: ReadonlyRecord) => [Record, Record] + (self: ReadonlyRecord, f: (a: A, key: string) => Either): [Record, Record] +} +``` + +**Example** + +```ts +import { partitionMap } from '@fp-ts/core/ReadonlyRecord' +import { left, right } from '@fp-ts/core/Either' + +const x = { a: 1, b: 2, c: 3 } +const f = (n: number) => (n % 2 === 0 ? right(n) : left(n)) +assert.deepStrictEqual(partitionMap(x, f), [{ a: 1, c: 3 }, { b: 2 }]) +``` + +Added in v1.0.0 + +## separate + +Partitions a `ReadonlyRecord` of `Either` values into two separate records, +one with the `Left` values and one with the `Right` values. + +**Signature** + +```ts +export declare const separate: (self: ReadonlyRecord>) => [Record, Record] +``` + +**Example** + +```ts +import { separate } from '@fp-ts/core/ReadonlyRecord' +import { left, right } from '@fp-ts/core/Either' + +assert.deepStrictEqual(separate({ a: left('e'), b: right(1) }), [{ a: 'e' }, { b: 1 }]) +``` + +Added in v1.0.0 + +## traverseFilterMap + +**Signature** + +```ts +export declare const traverseFilterMap: ( + F: applicative.Applicative +) => { + (f: (a: A) => Kind>): ( + self: ReadonlyRecord + ) => Kind> + (self: ReadonlyRecord, f: (a: A) => Kind>): Kind< + F, + R, + O, + E, + Record + > +} +``` + +Added in v1.0.0 + +## traversePartitionMap + +**Signature** + +```ts +export declare const traversePartitionMap: ( + F: applicative.Applicative +) => { + (f: (a: A) => Kind>): ( + self: ReadonlyRecord + ) => Kind, Record]> + (self: ReadonlyRecord, f: (a: A) => Kind>): Kind< + F, + R, + O, + E, + [Record, Record] + > +} +``` + +Added in v1.0.0 + +# guards + +## isEmpty + +Determine if a `ReadonlyRecord` is empty. + +**Signature** + +```ts +export declare const isEmpty: (self: ReadonlyRecord) => self is Record +``` + +**Example** + +```ts +import { isEmpty } from '@fp-ts/core/ReadonlyRecord' + +assert.deepStrictEqual(isEmpty({}), true) +assert.deepStrictEqual(isEmpty({ a: 3 }), false) +``` + +Added in v1.0.0 + +# instances + +## Compactable + +**Signature** + +```ts +export declare const Compactable: compactable.Compactable +``` + +Added in v1.0.0 + +## Covariant + +**Signature** + +```ts +export declare const Covariant: covariant.Covariant +``` + +Added in v1.0.0 + +## Filterable + +**Signature** + +```ts +export declare const Filterable: filterable.Filterable +``` + +Added in v1.0.0 + +## Invariant + +**Signature** + +```ts +export declare const Invariant: invariant.Invariant +``` + +Added in v1.0.0 + +## Traversable + +**Signature** + +```ts +export declare const Traversable: traversable.Traversable +``` + +Added in v1.0.0 + +## TraversableFilterable + +**Signature** + +```ts +export declare const TraversableFilterable: traversableFilterable.TraversableFilterable +``` + +Added in v1.0.0 + +# mapping + +## as + +Maps the success value of this effect to the specified constant value. + +**Signature** + +```ts +export declare const as: { + (b: B): <_>(self: ReadonlyRecord<_>) => Record + <_, B>(self: ReadonlyRecord<_>, b: B): Record +} +``` + +Added in v1.0.0 + +## flap + +**Signature** + +```ts +export declare const flap: { + (self: ReadonlyRecord<(a: A) => B>): (a: A) => Record + (a: A, self: ReadonlyRecord<(a: A) => B>): Record +} +``` + +Added in v1.0.0 + +## tupled + +**Signature** + +```ts +export declare const tupled: (self: ReadonlyRecord) => Record +``` + +Added in v1.0.0 + +# models + +## ReadonlyRecord (interface) + +**Signature** + +```ts +export interface ReadonlyRecord { + readonly [x: string]: A +} +``` + +Added in v1.0.0 + +# record + +## pop + +Retrieves the value of the property with the given `key` from a `ReadonlyRecord` and returns an `Option` +of a tuple with the value and the `ReadonlyRecord` with the removed property. +If the key is not present, returns `O.none`. + +**Signature** + +```ts +export declare const pop: { + (key: string): (self: ReadonlyRecord) => Option]> + (self: ReadonlyRecord, key: string): Option]> +} +``` + +**Example** + +```ts +import { pop } from '@fp-ts/core/ReadonlyRecord' +import { some, none } from '@fp-ts/core/Option' + +assert.deepStrictEqual(pop({ a: 1, b: 2 }, 'a'), some([1, { b: 2 }])) +assert.deepStrictEqual(pop({ a: 1, b: 2 }, 'c'), none()) +``` + +Added in v1.0.0 + +# traversing + +## sequence + +Transforms a `ReadonlyRecord` of `Kind` values into a `Kind` of `Record` values. + +**Signature** + +```ts +export declare const sequence: ( + F: applicative.Applicative +) => (self: ReadonlyRecord>) => Kind> +``` + +**Example** + +```ts +import * as RR from '@fp-ts/core/ReadonlyRecord' +import { some, none, Applicative } from '@fp-ts/core/Option' + +const sequence = RR.sequence(Applicative) + +assert.deepStrictEqual(sequence({ a: some(1), b: some(2) }), some({ a: 1, b: 2 })) +assert.deepStrictEqual(sequence({ a: none(), b: some(2) }), none()) +``` + +Added in v1.0.0 + +## traverse + +Maps each entry of a `ReadonlyRecord` to an effect and collects the results into a new record. + +**Signature** + +```ts +export declare const traverse: ( + F: applicative.Applicative +) => { + (f: (a: A, key: string) => Kind): ( + self: ReadonlyRecord + ) => Kind> + (self: ReadonlyRecord, f: (a: A, key: string) => Kind): Kind< + F, + R, + O, + E, + Record + > +} +``` + +**Example** + +```ts +import { traverse } from '@fp-ts/core/ReadonlyRecord' +import { some, none, Applicative } from '@fp-ts/core/Option' + +assert.deepStrictEqual( + traverse(Applicative)({ a: 1, b: 2 }, (n: number) => (n <= 2 ? some(n) : none())), + some({ a: 1, b: 2 }) +) +assert.deepStrictEqual( + traverse(Applicative)({ a: 1, b: 2 }, (n: number) => (n >= 2 ? some(n) : none())), + none() +) +``` + +Added in v1.0.0 + +## traverseTap + +**Signature** + +```ts +export declare const traverseTap: ( + F: applicative.Applicative +) => { + (f: (a: A) => Kind): (self: ReadonlyRecord) => Kind> + (self: ReadonlyRecord, f: (a: A) => Kind): Kind> +} +``` + +Added in v1.0.0 + +# type lambdas + +## ReadonlyRecordTypeLambda (interface) + +**Signature** + +```ts +export interface ReadonlyRecordTypeLambda extends TypeLambda { + readonly type: ReadonlyRecord +} +``` + +Added in v1.0.0 + +# utils + +## filterMap + +Transforms a `ReadonlyRecord` into a `Record` by applying the function `f` to each key and value in the original `ReadonlyRecord`. +If the function returns `Some`, the key-value pair is included in the output `Record`. + +**Signature** + +```ts +export declare const filterMap: { + (f: (a: A, key: string) => Option): (self: ReadonlyRecord) => Record + (self: ReadonlyRecord, f: (a: A, key: string) => Option): Record +} +``` + +**Example** + +```ts +import { filterMap } from '@fp-ts/core/ReadonlyRecord' +import { some, none } from '@fp-ts/core/Option' + +const x = { a: 1, b: 2, c: 3 } +const f = (a: number, key: string) => (a > 2 ? some(a * 2) : none()) +assert.deepStrictEqual(filterMap(x, f), { c: 6 }) +``` + +Added in v1.0.0 ## get @@ -88,7 +676,29 @@ assert.deepStrictEqual(get(person, 'email'), none()) Added in v1.0.0 -# mapping +## has + +Check if a given `key` exists in a `ReadonlyRecord`. + +**Signature** + +```ts +export declare const has: { + (key: string): (self: ReadonlyRecord) => boolean + (self: ReadonlyRecord, key: string): boolean +} +``` + +**Example** + +```ts +import { has } from '@fp-ts/core/ReadonlyRecord' + +assert.deepStrictEqual(has({ a: 1, b: 2 }, 'a'), true) +assert.deepStrictEqual(has({ a: 1, b: 2 }, 'c'), false) +``` + +Added in v1.0.0 ## map @@ -119,22 +729,6 @@ assert.deepStrictEqual(map({ a: 3, b: 5 }, g), { a: 'A-3', b: 'B-5' }) Added in v1.0.0 -# models - -## ReadonlyRecord (interface) - -**Signature** - -```ts -export interface ReadonlyRecord { - readonly [x: string]: A -} -``` - -Added in v1.0.0 - -# utils - ## modifyOption Apply a function to the element at the specified key, creating a new record, @@ -163,6 +757,29 @@ assert.deepStrictEqual(modifyOption({ a: 3 }, 'b', f), none()) Added in v1.0.0 +## remove + +Removes a key from a `ReadonlyRecord` and returns a new `Record` + +**Signature** + +```ts +export declare const remove: { + (key: string): (self: ReadonlyRecord) => Record + (self: ReadonlyRecord, key: string): Record +} +``` + +**Example** + +```ts +import { remove } from '@fp-ts/core/ReadonlyRecord' + +assert.deepStrictEqual(remove({ a: 1, b: 2 }, 'a'), { b: 2 }) +``` + +Added in v1.0.0 + ## replaceOption Replaces a value in the record with the new value passed as parameter. @@ -187,3 +804,71 @@ assert.deepStrictEqual(replaceOption({}, 'a', 10), none()) ``` Added in v1.0.0 + +## size + +Returns the number of key/value pairs in a `ReadonlyRecord`. + +**Signature** + +```ts +export declare const size: (self: ReadonlyRecord) => number +``` + +**Example** + +```ts +import { size } from '@fp-ts/core/ReadonlyRecord' + +assert.deepStrictEqual(size({ a: 'a', b: 1, c: true }), 3) +``` + +Added in v1.0.0 + +## traverseFilter + +Filter values inside a context. + +**Signature** + +```ts +export declare const traverseFilter: ( + F: applicative.Applicative +) => { + (predicate: (a: A) => Kind): ( + self: ReadonlyRecord + ) => Kind> + (self: ReadonlyRecord, predicate: (a: A) => Kind): Kind< + F, + R, + O, + E, + Record + > +} +``` + +Added in v1.0.0 + +## traversePartition + +**Signature** + +```ts +export declare const traversePartition: ( + F: applicative.Applicative +) => { + (predicate: (a: A) => Kind): ( + self: ReadonlyRecord + ) => Kind, Record]> + (self: ReadonlyRecord, predicate: (a: A) => Kind): Kind< + F, + R, + O, + E, + [Record, Record] + > +} +``` + +Added in v1.0.0 diff --git a/docs/modules/typeclass/Applicative.ts.md b/docs/modules/typeclass/Applicative.ts.md index 72fc5328d..cc9f54179 100644 --- a/docs/modules/typeclass/Applicative.ts.md +++ b/docs/modules/typeclass/Applicative.ts.md @@ -35,7 +35,10 @@ Added in v1.0.0 ## getMonoid -Lift a monoid into 'F', the inner values are combined using the provided `Monoid`. +Lift a `Monoid` into `F`, combining the inner values using the provided `Monoid`: + +- `combine` is provided by {@link semiApplicative.getSemigroup}. +- `empty` is `F.of(M.empty)` **Signature** diff --git a/docs/modules/typeclass/Bicovariant.ts.md b/docs/modules/typeclass/Bicovariant.ts.md index 1dfb0cea9..4ce9f2b00 100644 --- a/docs/modules/typeclass/Bicovariant.ts.md +++ b/docs/modules/typeclass/Bicovariant.ts.md @@ -94,6 +94,8 @@ Added in v1.0.0 ## mapLeft +Returns a default `mapLeft` implementation. + **Signature** ```ts diff --git a/src/Either.ts b/src/Either.ts index 64bc1ab52..5100327cd 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -546,23 +546,6 @@ export const SemiApplicative: semiApplicative.SemiApplicative productMany: SemiProduct.productMany } -/** - * Semigroup returning the left-most `Left` value. If both operands are `Right`s then the inner values - * are concatenated using the provided `Semigroup`. - * - * | x | y | x |> combine(y) | - * | ---------| ---------| -----------------------| - * | left(a) | left(b) | left(a) | - * | left(a) | right(2) | left(a) | - * | right(1) | left(b) | left(b) | - * | right(1) | right(2) | right(1 |> combine(2)) | - * - * @category combining - * @since 1.0.0 - */ -export const getFirstLeftSemigroup: (S: Semigroup) => Semigroup> = - semiApplicative.getSemigroup(SemiApplicative) - /** * Lifts a binary function into `Either`. * @@ -614,10 +597,30 @@ export const Applicative: applicative.Applicative = { } /** - * Monoid returning the left-most `Left` value. If both operands are `Right`s then the inner values - * are concatenated using the provided `Monoid`. + * `Semigroup` returning the left-most `Left` value. If both operands are `Right`s then the inner values + * are combined using the provided `Semigroup`. + * + * ``` + * | self | that | combine(self, that) | + * | ---------- | ---------- | ----------------------- | + * | left(e1) | left(e2) | left(e1) | + * | left(e1) | right(a2) | left(e1) | + * | right(a1) | left(e2) | left(e2) | + * | right(a1) | right(a2) | right(combine(a1, a2)) | + * ``` + * + * @category combining + * @since 1.0.0 + */ +export const getFirstLeftSemigroup: (S: Semigroup) => Semigroup> = + semiApplicative.getSemigroup(SemiApplicative) + +/** + * `Monoid` returning the left-most `Left` value. If both operands are `Right`s then the inner values + * are combined using the provided `Monoid`. * - * The `empty` value is `right(M.empty)`. + * - `combine` is provided by {@link getFirstLeftSemigroup}. + * - `empty` is `right(M.empty)` * * @category combining * @since 1.0.0 @@ -658,12 +661,14 @@ export const SemiCoproduct: semiCoproduct.SemiCoproduct = semi /** * Semigroup returning the left-most `Right` value. * - * | x | y | x |> combine(y) | - * | ---------| ---------| ----------------| - * | left(a) | left(b) | left(b) | - * | left(a) | right(2) | right(2) | - * | right(1) | left(b) | right(1) | - * | right(1) | right(2) | right(1) | + * ``` + * | self | that | combine(self, that) | + * | ---------- | ---------- | ------------------- | + * | left(e1) | left(e2) | left(e2) | + * | left(e1) | right(a2) | right(a2) | + * | right(a1) | left(e2) | right(a1) | + * | right(a1) | right(a2) | right(a1) | + * ``` * * @category combining * @since 1.0.0 diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 901642e0c..6059ca81c 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -3,6 +3,7 @@ * * @since 1.0.0 */ + import type { Either } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" import { dual, identity } from "@fp-ts/core/Function" @@ -1535,25 +1536,6 @@ export const Chainable: chainable.Chainable = { flatMap } -/** - * @category filtering - * @since 1.0.0 - */ -export const separate = ( - self: ReadonlyArray> -): [Array, Array] => { - const left: Array = [] - const right: Array = [] - for (const e of self) { - if (E.isLeft(e)) { - left.push(e.left) - } else { - right.push(e.right) - } - } - return [left, right] -} - /** * @category filtering * @since 1.0.0 @@ -1669,6 +1651,14 @@ export const partitionMap: { } ) +/** + * @category filtering + * @since 1.0.0 + */ +export const separate: (self: Iterable>) => [Array, Array] = partitionMap( + identity +) + /** * @category traversing * @since 1.0.0 @@ -1711,22 +1701,22 @@ export const traverse = (F: applicative.Applicative): { ): Kind> => F.productAll(fromIterable(self).map(f))) /** - * @category instances + * @category traversing * @since 1.0.0 */ -export const Traversable: traversable.Traversable = { - traverse: traverse as any -} +export const sequence = ( + F: applicative.Applicative +): ( + self: ReadonlyArray> +) => Kind> => traverse(F)(identity) /** - * @category traversing + * @category instances * @since 1.0.0 */ -export const sequence: ( - F: applicative.Applicative -) => ( - self: ReadonlyArray> -) => Kind> = traversable.sequence(Traversable) as any +export const Traversable: traversable.Traversable = { + traverse: traverse as any +} /** * @category traversing @@ -1956,10 +1946,8 @@ export const coproductMapKind: ( export const TraversableFilterable: traversableFilterable.TraversableFilterable< ReadonlyArrayTypeLambda > = traversableFilterable.make( - traversableFilterable - .traversePartitionMap({ ...Traversable, ...Covariant, ...Compactable }), - traversableFilterable - .traverseFilterMap({ ...Traversable, ...Compactable }) + traversableFilterable.traversePartitionMap({ ...Traversable, ...Covariant, ...Compactable }), + traversableFilterable.traverseFilterMap({ ...Traversable, ...Compactable }) ) /** diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index d5905bc3a..e4a1aa06f 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -4,9 +4,23 @@ * @since 1.0.0 */ -import { dual } from "@fp-ts/core/Function" +import type { Either } from "@fp-ts/core/Either" +import * as E from "@fp-ts/core/Either" +import { dual, identity } from "@fp-ts/core/Function" +import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Option } from "@fp-ts/core/Option" import * as O from "@fp-ts/core/Option" +import type * as applicative from "@fp-ts/core/typeclass/Applicative" +import type * as compactable from "@fp-ts/core/typeclass/Compactable" +import * as covariant from "@fp-ts/core/typeclass/Covariant" +import * as filterable from "@fp-ts/core/typeclass/Filterable" +import * as invariant from "@fp-ts/core/typeclass/Invariant" +import * as traversable from "@fp-ts/core/typeclass/Traversable" +import * as traversableFilterable from "@fp-ts/core/typeclass/TraversableFilterable" + +// ------------------------------------------------------------------------------------- +// models +// ------------------------------------------------------------------------------------- /** * @category models @@ -16,6 +30,26 @@ export interface ReadonlyRecord { readonly [x: string]: A } +/** + * @category type lambdas + * @since 1.0.0 + */ +export interface ReadonlyRecordTypeLambda extends TypeLambda { + readonly type: ReadonlyRecord +} + +// ------------------------------------------------------------------------------------- +// constructors +// ------------------------------------------------------------------------------------- + +/** + * Creates a new, empty record. + * + * @category constructors + * @since 1.0.0 + */ +export const empty = (): Record => ({}) + /** * Takes an iterable and a projection function and returns a record. * The projection function maps each value of the iterable to a tuple of a key and a value, which is then added to the resulting record. @@ -48,6 +82,126 @@ export const fromIterable: { return out }) +// ------------------------------------------------------------------------------------- +// guards +// ------------------------------------------------------------------------------------- + +/** + * Determine if a `ReadonlyRecord` is empty. + * + * @param self - `ReadonlyRecord` to test for emptiness. + * + * @example + * import { isEmpty } from "@fp-ts/core/ReadonlyRecord" + * + * assert.deepStrictEqual(isEmpty({}), true); + * assert.deepStrictEqual(isEmpty({ a: 3 }), false); + * + * @category guards + * @since 1.0.0 + */ +export const isEmpty = (self: ReadonlyRecord): self is Record => { + for (const k in self) { + if (has(self, k)) { + return false + } + } + return true +} + +// ------------------------------------------------------------------------------------- +// conversions +// ------------------------------------------------------------------------------------- + +/** + * Transforms the values of a `ReadonlyRecord` into an `Array` with a custom mapping function. + * + * @param self - The `ReadonlyRecord` to transform. + * @param f - The custom mapping function to apply to each key/value of the `ReadonlyRecord`. + * + * @example + * import { collect } from '@fp-ts/core/ReadonlyRecord' + * + * const x = { a: 1, b: 2, c: 3 } + * assert.deepStrictEqual(collect(x, (key, n) => [key, n]), [["a", 1], ["b", 2], ["c", 3]]) + * + * @category conversions + * @since 1.0.0 + */ +export const collect: { + (f: (key: string, a: A) => B): (self: ReadonlyRecord) => Array + (self: ReadonlyRecord, f: (key: string, a: A) => B): Array +} = dual( + 2, + (self: ReadonlyRecord, f: (key: string, a: A) => B): Array => { + const out: Array = [] + for (const key of Object.keys(self)) { + out.push(f(key, self[key])) + } + return out + } +) + +/** + * Converts a `ReadonlyRecord` to an `Array` of key-value pairs. + * + * @param self - A `ReadonlyRecord` to convert to an `Array`. + * + * @example + * import { toArray } from '@fp-ts/core/ReadonlyRecord' + * + * const x = { a: 1, b: 2 } + * assert.deepStrictEqual(toArray(x), [["a", 1], ["b", 2]]) + * + * @category conversions + * @since 1.0.0 + */ +export const toArray: (self: ReadonlyRecord) => Array<[string, A]> = collect(( + key, + a +) => [key, a]) + +// ------------------------------------------------------------------------------------- +// utils +// ------------------------------------------------------------------------------------- + +/** + * Returns the number of key/value pairs in a `ReadonlyRecord`. + * + * @param self - A `ReadonlyRecord` to calculate the number of key/value pairs in. + * + * @example + * import { size } from "@fp-ts/core/ReadonlyRecord"; + * + * assert.deepStrictEqual(size({ a: "a", b: 1, c: true }), 3); + * + * @since 1.0.0 + */ +export const size = (self: ReadonlyRecord): number => Object.keys(self).length + +/** + * Check if a given `key` exists in a `ReadonlyRecord`. + * + * @param self - the `ReadonlyRecord` to look in. + * @param key - the key to look for in the `ReadonlyRecord`. + * + * @example + * import { has } from '@fp-ts/core/ReadonlyRecord' + * + * assert.deepStrictEqual(has({ a: 1, b: 2 }, "a"), true); + * assert.deepStrictEqual(has({ a: 1, b: 2 }, "c"), false); + * + * @since 1.0.0 + */ +export const has: { + (key: string): (self: ReadonlyRecord) => boolean + (self: ReadonlyRecord, key: string): boolean +} = dual( + 2, + (self: ReadonlyRecord, key: string): boolean => + Object.prototype.hasOwnProperty.call(self, key) +) + /** * Retrieve a value at a particular key from a `ReadonlyRecord`, returning it wrapped in an `Option`. * @@ -63,7 +217,6 @@ export const fromIterable: { * assert.deepStrictEqual(get(person, "name"), some("John Doe")) * assert.deepStrictEqual(get(person, "email"), none()) * - * @category getters * @since 1.0.0 */ export const get: { @@ -72,7 +225,7 @@ export const get: { } = dual( 2, (self: ReadonlyRecord, key: string): Option => - Object.prototype.hasOwnProperty.call(self, key) ? O.some(self[key]) : O.none() + has(self, key) ? O.some(self[key]) : O.none() ) /** @@ -106,7 +259,7 @@ export const modifyOption: { } = dual( 3, (self: ReadonlyRecord, key: string, f: (a: A) => B): Option> => { - if (!Object.prototype.hasOwnProperty.call(self, key)) { + if (!has(self, key)) { return O.none() } const out: Record = { ...self } @@ -143,6 +296,55 @@ export const replaceOption: { modifyOption(self, key, () => b) ) +/** + * Removes a key from a `ReadonlyRecord` and returns a new `Record` + * + * @param self - the `ReadonlyRecord` to remove the key from. + * @param key - the key to remove from the `ReadonlyRecord`. + * + * @example + * import { remove } from '@fp-ts/core/ReadonlyRecord' + * + * assert.deepStrictEqual(remove({ a: 1, b: 2 }, "a"), { b: 2 }) + * + * @since 1.0.0 + */ +export const remove: { + (key: string): (self: ReadonlyRecord) => Record + (self: ReadonlyRecord, key: string): Record +} = dual(2, (self: ReadonlyRecord, key: string): Record => { + const out: Record = { ...self } + delete out[key] + return out +}) + +/** + * Retrieves the value of the property with the given `key` from a `ReadonlyRecord` and returns an `Option` + * of a tuple with the value and the `ReadonlyRecord` with the removed property. + * If the key is not present, returns `O.none`. + * + * @param self - The input `ReadonlyRecord`. + * @param key - The key of the property to retrieve. + * + * @example + * import { pop } from '@fp-ts/core/ReadonlyRecord' + * import { some, none } from '@fp-ts/core/Option' + * + * assert.deepStrictEqual(pop({ a: 1, b: 2 }, "a"), some([1, { b: 2 }])) + * assert.deepStrictEqual(pop({ a: 1, b: 2 }, "c"), none()) + * + * @category record + * @since 1.0.0 + */ +export const pop: { + (key: string): (self: ReadonlyRecord) => Option]> + (self: ReadonlyRecord, key: string): Option]> +} = dual(2, ( + self: ReadonlyRecord, + key: string +): Option]> => + has(self, key) ? O.some([self[key], remove(self, key)]) : O.none()) + /** * Maps a `ReadonlyRecord` into another `Record` by applying a transformation function to each of its values. * @@ -160,7 +362,6 @@ export const replaceOption: { * * assert.deepStrictEqual(map({ a: 3, b: 5 }, g), { a: "A-3", b: "B-5" }) * - * @category mapping * @since 1.0.0 */ export const map: { @@ -170,41 +371,443 @@ export const map: { 2, (self: ReadonlyRecord, f: (a: A, key: string) => B): Record => { const out: Record = {} - for (const key in self) { - if (Object.prototype.hasOwnProperty.call(self, key)) { - out[key] = f(self[key], key) - } + for (const key of Object.keys(self)) { + out[key] = f(self[key], key) } return out } ) -/* - - TODO: - - - size - - isEmpty - - collect - - toArray - - has - - remove - - pop - - empty - - filterMapWithIndex - - filterMap - - filterWithIndex - - filter - - partition - - partitionWithIndex - - partitionMap - - partitionMapWithIndex - - traverseWithKey - - traverse - - sequence - - compact - - separate - - traverseFilterMap - - traversePartitionMap - -*/ +/** + * Transforms a `ReadonlyRecord` into a `Record` by applying the function `f` to each key and value in the original `ReadonlyRecord`. + * If the function returns `Some`, the key-value pair is included in the output `Record`. + * + * @param self - The input `ReadonlyRecord`. + * @param f - The transformation function. + * + * @example + * import { filterMap } from '@fp-ts/core/ReadonlyRecord' + * import { some, none } from '@fp-ts/core/Option' + * + * const x = { a: 1, b: 2, c: 3 } + * const f = (a: number, key: string) => a > 2 ? some(a * 2) : none() + * assert.deepStrictEqual(filterMap(x, f), { c: 6 }) + * + * @since 1.0.0 + */ +export const filterMap: { + (f: (a: A, key: string) => Option): (self: ReadonlyRecord) => Record + (self: ReadonlyRecord, f: (a: A, key: string) => Option): Record +} = dual(2, ( + self: ReadonlyRecord, + f: (a: A, key: string) => Option +): Record => { + const out: Record = {} + for (const key of Object.keys(self)) { + const o = f(self[key], key) + if (O.isSome(o)) { + out[key] = o.value + } + } + return out +}) + +/** + * Selects properties from a record whose values match the given predicate. + * + * @param self - The `ReadonlyRecord` to filter. + * @param predicate - A function that returns a `boolean` value to determine if the entry should be included in the new record. + * + * @example + * import { filter } from '@fp-ts/core/ReadonlyRecord' + * + * const x = { a: 1, b: 2, c: 3, d: 4 } + * assert.deepStrictEqual(filter(x, (n) => n > 2), { c: 3, d: 4 }) + * + * @category filtering + * @since 1.0.0 + */ +export const filter: { + ( + refinement: (a: A, key: string) => a is B + ): (self: ReadonlyRecord) => Record + ( + predicate: (a: A, key: string) => boolean + ): (self: ReadonlyRecord) => Record + ( + self: ReadonlyRecord, + refinement: (a: A, key: string) => a is B + ): Record + ( + self: ReadonlyRecord, + predicate: (a: A, key: string) => boolean + ): Record +} = dual( + 2, + ( + self: ReadonlyRecord, + predicate: (a: A, key: string) => boolean + ): Record => filterMap(self, (b, key) => (predicate(b, key) ? O.some(b) : O.none())) +) + +/** + * Given a `ReadonlyRecord` with `Option` values, returns a `Record` with only the `Some` values, with the same keys. + * + * @param self - A `ReadonlyRecord` with `Option` values. + * + * @example + * import { compact } from '@fp-ts/core/ReadonlyRecord' + * import { some, none } from '@fp-ts/core/Option' + * + * assert.deepStrictEqual( + * compact({ a: some(1), b: none(), c: some(2) }), + * { a: 1, c: 2 } + * ) + * + * @category filtering + * @since 1.0.0 + */ +export const compact: (self: ReadonlyRecord>) => Record = filterMap( + identity +) + +/** + * Partitions the elements of a `ReadonlyRecord` into two groups: those that match a predicate, and those that don't. + * + * @param self - The `ReadonlyRecord` to partition. + * @param f - The predicate function to apply to each element. + * + * @example + * import { partitionMap } from '@fp-ts/core/ReadonlyRecord' + * import { left, right } from '@fp-ts/core/Either' + * + * const x = { a: 1, b: 2, c: 3 } + * const f = (n: number) => (n % 2 === 0 ? right(n) : left(n)) + * assert.deepStrictEqual(partitionMap(x, f), [{ a: 1, c: 3 }, { b: 2}]) + * + * @category filtering + * @since 1.0.0 + */ +export const partitionMap: { + ( + f: (a: A, key: string) => Either + ): (self: ReadonlyRecord) => [Record, Record] + ( + self: ReadonlyRecord, + f: (a: A, key: string) => Either + ): [Record, Record] +} = dual( + 2, + ( + self: ReadonlyRecord, + f: (a: A, key: string) => Either + ): [Record, Record] => { + const left: Record = {} + const right: Record = {} + for (const key of Object.keys(self)) { + const e = f(self[key], key) + if (E.isLeft(e)) { + left[key] = e.left + } else { + right[key] = e.right + } + } + return [left, right] + } +) + +/** + * Partitions a `ReadonlyRecord` of `Either` values into two separate records, + * one with the `Left` values and one with the `Right` values. + * + * @param self - the `ReadonlyRecord` to partition. + * + * @example + * import { separate } from '@fp-ts/core/ReadonlyRecord' + * import { left, right } from '@fp-ts/core/Either' + * + * assert.deepStrictEqual( + * separate({ a: left("e"), b: right(1) }), + * [{ a: "e" }, { b: 1 }] + * ) + * + * @category filtering + * @since 1.0.0 + */ +export const separate: ( + self: ReadonlyRecord> +) => [Record, Record] = partitionMap(identity) + +/** + * Partitions a `ReadonlyRecord` into two separate `Record`s based on the result of a predicate function. + * + * @param self - The input `ReadonlyRecord` to partition. + * @param predicate - The partitioning function to determine the partitioning of each value of the `ReadonlyRecord`. + * + * @example + * import { partition } from '@fp-ts/core/ReadonlyRecord' + * + * assert.deepStrictEqual( + * partition({ a: 1, b: 3 }, (n) => n > 2), + * [{ a: 1 }, { b: 3 }] + * ) + * + * @category filtering + * @since 1.0.0 + */ +export const partition: { + (refinement: (a: A, key: string) => a is B): ( + self: ReadonlyRecord + ) => [Record, Record] + ( + predicate: (a: A, key: string) => boolean + ): (self: ReadonlyRecord) => [Record, Record] + ( + self: ReadonlyRecord, + refinement: (a: A, key: string) => a is B + ): [Record, Record] + ( + self: ReadonlyRecord, + predicate: (a: A, key: string) => boolean + ): [Record, Record] +} = dual( + 2, + ( + self: ReadonlyRecord, + predicate: (a: A, key: string) => boolean + ): [Record, Record] => + partitionMap(self, (b, i) => (predicate(b, i) ? E.right(b) : E.left(b))) +) + +/** + * Maps each entry of a `ReadonlyRecord` to an effect and collects the results into a new record. + * + * @param F - an {@link applicative.Applicative Applicative} instance. + * @param self - a `ReadonlyRecord` to map over. + * @param f - the mapping function, which maps an entry `a` and its corresponding `key` to an effect. + * + * @example + * import { traverse } from '@fp-ts/core/ReadonlyRecord' + * import { some, none, Applicative } from '@fp-ts/core/Option' + * + * assert.deepStrictEqual( + * traverse(Applicative)({ a: 1, b: 2 }, (n: number) => (n <= 2 ? some(n) : none())), + * some({ a: 1, b: 2 }) + * ) + * assert.deepStrictEqual( + * traverse(Applicative)({ a: 1, b: 2 }, (n: number) => (n >= 2 ? some(n) : none())), + * none() + * ) + * + * @category traversing + * @since 1.0.0 + */ +export const traverse = (F: applicative.Applicative): { + ( + f: (a: A, key: string) => Kind + ): (self: ReadonlyRecord) => Kind> + ( + self: ReadonlyRecord, + f: (a: A, key: string) => Kind + ): Kind> +} => + dual(2, ( + self: ReadonlyRecord, + f: (a: A, key: string) => Kind + ): Kind> => + F.map( + F.productAll( + Object.entries(self).map(([key, a]) => F.map(f(a, key), b => [key, b] as const)) + ), + Object.fromEntries + )) + +/** + * Transforms a `ReadonlyRecord` of `Kind` values into a `Kind` of `Record` values. + * + * @param F - an {@link applicative.Applicative Applicative} instance. + * @param self - the `ReadonlyRecord` of `Kind` values. + * + * @example + * import * as RR from '@fp-ts/core/ReadonlyRecord' + * import { some, none, Applicative } from '@fp-ts/core/Option' + * + * const sequence = RR.sequence(Applicative) + * + * assert.deepStrictEqual(sequence({ a: some(1), b: some(2) }), some({ a: 1, b: 2 })) + * assert.deepStrictEqual(sequence({ a: none(), b: some(2) }), none()) + * + * @category traversing + * @since 1.0.0 + */ +export const sequence = ( + F: applicative.Applicative +): ( + self: ReadonlyRecord> +) => Kind> => traverse(F)(identity) + +const imap = covariant.imap(map) + +/** + * @category instances + * @since 1.0.0 + */ +export const Covariant: covariant.Covariant = { + imap, + map +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Invariant: invariant.Invariant = { + imap +} + +/** + * @category mapping + * @since 1.0.0 + */ +export const tupled: (self: ReadonlyRecord) => Record = invariant.tupled( + Invariant +) + +/** + * @category mapping + * @since 1.0.0 + */ +export const flap: { + (self: ReadonlyRecord<(a: A) => B>): (a: A) => Record + (a: A, self: ReadonlyRecord<(a: A) => B>): Record +} = covariant.flap(Covariant) + +/** + * Maps the success value of this effect to the specified constant value. + * + * @category mapping + * @since 1.0.0 + */ +export const as: { + (b: B): <_>(self: ReadonlyRecord<_>) => Record + <_, B>(self: ReadonlyRecord<_>, b: B): Record +} = covariant.as(Covariant) + +/** + * @category instances + * @since 1.0.0 + */ +export const Filterable: filterable.Filterable = filterable.make( + filterMap +) + +/** + * @category instances + * @since 1.0.0 + */ +export const Compactable: compactable.Compactable = { + compact +} + +/** + * @category instances + * @since 1.0.0 + */ +export const Traversable: traversable.Traversable = { + traverse +} + +/** + * @category traversing + * @since 1.0.0 + */ +export const traverseTap: ( + F: applicative.Applicative +) => { + ( + f: (a: A) => Kind + ): (self: ReadonlyRecord) => Kind> + ( + self: ReadonlyRecord, + f: (a: A) => Kind + ): Kind> +} = traversable.traverseTap(Traversable) + +/** + * @category instances + * @since 1.0.0 + */ +export const TraversableFilterable: traversableFilterable.TraversableFilterable< + ReadonlyRecordTypeLambda +> = traversableFilterable.make( + traversableFilterable.traversePartitionMap({ ...Traversable, ...Covariant, ...Compactable }), + traversableFilterable.traverseFilterMap({ ...Traversable, ...Compactable }) +) + +/** + * @category filtering + * @since 1.0.0 + */ +export const traversePartitionMap: ( + F: applicative.Applicative +) => { + ( + f: (a: A) => Kind> + ): ( + self: ReadonlyRecord + ) => Kind, Record]> + ( + self: ReadonlyRecord, + f: (a: A) => Kind> + ): Kind, Record]> +} = TraversableFilterable.traversePartitionMap + +/** + * @category filtering + * @since 1.0.0 + */ +export const traverseFilterMap: ( + F: applicative.Applicative +) => { + ( + f: (a: A) => Kind> + ): (self: ReadonlyRecord) => Kind> + ( + self: ReadonlyRecord, + f: (a: A) => Kind> + ): Kind> +} = TraversableFilterable.traverseFilterMap + +/** + * Filter values inside a context. + * + * @since 1.0.0 + */ +export const traverseFilter: ( + F: applicative.Applicative +) => { + ( + predicate: (a: A) => Kind + ): (self: ReadonlyRecord) => Kind> + ( + self: ReadonlyRecord, + predicate: (a: A) => Kind + ): Kind> +} = traversableFilterable.traverseFilter(TraversableFilterable) + +/** + * @since 1.0.0 + */ +export const traversePartition: ( + F: applicative.Applicative +) => { + ( + predicate: (a: A) => Kind + ): ( + self: ReadonlyRecord + ) => Kind, Record]> + ( + self: ReadonlyRecord, + predicate: (a: A) => Kind + ): Kind, Record]> +} = traversableFilterable.traversePartition(TraversableFilterable) diff --git a/src/typeclass/Applicative.ts b/src/typeclass/Applicative.ts index 84deeb68a..0c370b53f 100644 --- a/src/typeclass/Applicative.ts +++ b/src/typeclass/Applicative.ts @@ -15,7 +15,13 @@ import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" export interface Applicative extends SemiApplicative, Product {} /** - * Lift a monoid into 'F', the inner values are combined using the provided `Monoid`. + * Lift a `Monoid` into `F`, combining the inner values using the provided `Monoid`: + * + * - `combine` is provided by {@link semiApplicative.getSemigroup}. + * - `empty` is `F.of(M.empty)` + * + * @param F - The `Applicative` instance for `F`. + * @param M - The `Monoid` instance for `A`. * * @since 1.0.0 */ diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index ef31a8d68..3fcff67ef 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -53,6 +53,8 @@ export const bimapComposition = ( ): Kind> => CovariantF.map(self, BicovariantG.bimap(f, g)) /** + * Returns a default `mapLeft` implementation. + * * @since 1.0.0 */ export const mapLeft = ( diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index c7987244d..ef34ba5e5 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -11,7 +11,7 @@ import * as assert from "assert" import * as fc from "fast-check" describe.concurrent("ReadonlyArray", () => { - it("instances and derived exports", () => { + it("exports", () => { expect(RA.Invariant).exist expect(RA.tupled).exist expect(RA.bindTo).exist diff --git a/test/ReadonlyRecord.ts b/test/ReadonlyRecord.ts index 1b50b7b2a..c00e2f099 100644 --- a/test/ReadonlyRecord.ts +++ b/test/ReadonlyRecord.ts @@ -1,8 +1,26 @@ +import * as E from "@fp-ts/core/Either" import { pipe } from "@fp-ts/core/Function" import * as O from "@fp-ts/core/Option" import * as RR from "@fp-ts/core/ReadonlyRecord" describe.concurrent("ReadonlyRecord", () => { + it("exports", () => { + expect(RR.Invariant).exist + expect(RR.tupled).exist + expect(RR.Covariant).exist + expect(RR.flap).exist + expect(RR.as).exist + expect(RR.Compactable).exist + expect(RR.Filterable).exist + expect(RR.Traversable).exist + expect(RR.traverseTap).exist + expect(RR.TraversableFilterable).exist + expect(RR.traversePartitionMap).exist + expect(RR.traverseFilterMap).exist + expect(RR.traverseFilter).exist + expect(RR.traversePartition).exist + }) + it("get", () => { expect(pipe({}, RR.get("a"))).toEqual(O.none()) expect(pipe({ a: 1 }, RR.get("a"))).toEqual(O.some(1)) @@ -39,4 +57,118 @@ describe.concurrent("ReadonlyRecord", () => { "4": 8 }) }) + + it("collect", () => { + const x = { a: 1, b: 2, c: 3 } + assert.deepStrictEqual(RR.collect(x, (key, n) => [key, n]), [["a", 1], ["b", 2], ["c", 3]]) + }) + + it("toArray", () => { + const x = { a: 1, b: 2 } + assert.deepStrictEqual(RR.toArray(x), [["a", 1], ["b", 2]]) + }) + + it("remove", () => { + assert.deepStrictEqual(RR.remove({ a: 1, b: 2 }, "a"), { b: 2 }) + assert.deepStrictEqual(RR.remove({ a: 1, b: 2 }, "c"), { a: 1, b: 2 }) + }) + + describe("pop", () => { + it("should return the value associated with the given key, if the key is present in the record", () => { + const record = { a: 1, b: 2 } + const result = RR.pop("a")(record) + + assert.deepStrictEqual(result, O.some([1, { b: 2 }])) + }) + + it("should return none if the key is not present in the record", () => { + const record = { a: 1, b: 2 } + const result = RR.pop("c")(record) + + assert.deepStrictEqual(result, O.none()) + }) + }) + + describe("filterMap", () => { + it("should filter the properties of an object", () => { + const obj = { a: 1, b: 2, c: 3 } + const filtered = RR.filterMap(obj, (value, key) => (value > 2 ? O.some(key) : O.none())) + expect(filtered).toEqual({ c: "c" }) + }) + }) + + it("compact", () => { + const x = { a: O.some(1), b: O.none(), c: O.some(2) } + assert.deepStrictEqual(RR.compact(x), { a: 1, c: 2 }) + }) + + it("filter", () => { + const x = { a: 1, b: 2, c: 3, d: 4 } + assert.deepStrictEqual(RR.filter(x, (value) => value > 2), { c: 3, d: 4 }) + }) + + it("partitionMap", () => { + const f = (n: number) => (n > 2 ? E.right(n + 1) : E.left(n - 1)) + assert.deepStrictEqual(RR.partitionMap({}, f), [{}, {}]) + assert.deepStrictEqual(RR.partitionMap({ a: 1, b: 3 }, f), [{ a: 0 }, { b: 4 }]) + }) + + it("partition", () => { + const f = (n: number) => n > 2 + assert.deepStrictEqual(RR.partition({}, f), [{}, {}]) + assert.deepStrictEqual(RR.partition({ a: 1, b: 3 }, f), [{ a: 1 }, { b: 3 }]) + }) + + it("separate", () => { + assert.deepStrictEqual( + RR.separate({ a: E.left("e"), b: E.right(1) }), + [{ a: "e" }, { b: 1 }] + ) + // should ignore non own properties + const o: RR.ReadonlyRecord> = Object.create({ a: 1 }) + assert.deepStrictEqual(pipe(o, RR.separate), [{}, {}]) + }) + + it("traverse", () => { + assert.deepStrictEqual( + RR.traverse(O.Applicative)({ a: 1, b: 2 }, (n: number) => (n <= 2 ? O.some(n) : O.none())), + O.some({ a: 1, b: 2 }) + ) + assert.deepStrictEqual( + RR.traverse(O.Applicative)((n: number) => (n <= 2 ? O.some(n) : O.none()))({ a: 1, b: 2 }), + O.some({ a: 1, b: 2 }) + ) + assert.deepStrictEqual( + RR.traverse(O.Applicative)({ a: 1, b: 2 }, (n: number) => (n >= 2 ? O.some(n) : O.none())), + O.none() + ) + assert.deepStrictEqual( + RR.traverse(O.Applicative)((n: number) => (n >= 2 ? O.some(n) : O.none()))({ a: 1, b: 2 }), + O.none() + ) + }) + + it("sequence", () => { + const sequence = RR.sequence(O.Applicative) + assert.deepStrictEqual(sequence({ a: O.some(1), b: O.some(2) }), O.some({ a: 1, b: 2 })) + assert.deepStrictEqual(sequence({ a: O.none(), b: O.some(2) }), O.none()) + }) + + it("empty", () => { + expect(RR.empty()).toEqual({}) + }) + + it("isEmpty", () => { + assert.deepStrictEqual(RR.isEmpty({}), true) + assert.deepStrictEqual(RR.isEmpty({ a: 3 }), false) + }) + + it("size", () => { + assert.deepStrictEqual(RR.size({ a: "a", b: 1, c: true }), 3) + }) + + it("has", () => { + assert.deepStrictEqual(RR.has({ a: 1, b: 2 }, "a"), true) + assert.deepStrictEqual(RR.has({ a: 1, b: 2 }, "c"), false) + }) }) From b163dcb341d37a6f00096f599d27157930f97d92 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 5 Feb 2023 18:24:08 +0100 Subject: [PATCH 196/255] Filterable: add `partitionMap` operation to typeclass --- docs/modules/Option.ts.md | 14 +++++++ docs/modules/typeclass/Filterable.ts.md | 32 +++++++++----- guides/typeclass.md | 15 +++---- src/Option.ts | 23 ++++++++++- src/ReadonlyArray.ts | 55 +++++++++++++------------ src/ReadonlyRecord.ts | 1 + src/typeclass/Filterable.ts | 54 ++++++++++++++---------- test/Option.ts | 7 ++++ test/typeclass/Filterable.ts | 18 ++++---- 9 files changed, 144 insertions(+), 75 deletions(-) diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 41ea42870..45a1eccfa 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -56,6 +56,7 @@ Added in v1.0.0 - [filtering](#filtering) - [filter](#filter) - [filterMap](#filtermap) + - [partitionMap](#partitionmap) - [separate](#separate) - [folding](#folding) - [Foldable](#foldable) @@ -799,6 +800,19 @@ export declare const filterMap: { Added in v1.0.0 +## partitionMap + +**Signature** + +```ts +export declare const partitionMap: { + (f: (a: A) => Either): (self: Option) => [Option, Option] + (self: Option, f: (a: A) => Either): [Option, Option] +} +``` + +Added in v1.0.0 + ## separate **Signature** diff --git a/docs/modules/typeclass/Filterable.ts.md b/docs/modules/typeclass/Filterable.ts.md index 20bf8d7e7..7ee335d05 100644 --- a/docs/modules/typeclass/Filterable.ts.md +++ b/docs/modules/typeclass/Filterable.ts.md @@ -22,7 +22,7 @@ Added in v1.0.0 - [filter](#filter) - [filterMapComposition](#filtermapcomposition) - [partition](#partition) - - [partitionMap](#partitionmap) + - [partitionMapComposition](#partitionmapcomposition) --- @@ -34,6 +34,10 @@ Added in v1.0.0 ```ts export declare const make: ( + partitionMap: ( + self: Kind, + f: (a: A) => Either + ) => [Kind, Kind], filterMap: (self: Kind, f: (a: A) => Option) => Kind ) => Filterable ``` @@ -48,6 +52,13 @@ Added in v1.0.0 ```ts export interface Filterable extends TypeClass { + readonly partitionMap: { + (f: (a: A) => Either): ( + self: Kind + ) => [Kind, Kind] + (self: Kind, f: (a: A) => Either): [Kind, Kind] + } + readonly filterMap: { (f: (a: A) => Option): (self: Kind) => Kind (self: Kind, f: (a: A) => Option): Kind @@ -129,19 +140,20 @@ export declare const partition: ( Added in v1.0.0 -## partitionMap +## partitionMapComposition + +Returns a default binary `partitionMap` composition. **Signature** ```ts -export declare const partitionMap: ( - F: Filterable -) => { - (f: (a: A) => Either): ( - self: Kind - ) => [Kind, Kind] - (self: Kind, f: (a: A) => Either): [Kind, Kind] -} +export declare const partitionMapComposition: ( + F: Covariant, + G: Filterable +) => ( + self: Kind>, + f: (a: A) => Either +) => [Kind>, Kind>] ``` Added in v1.0.0 diff --git a/guides/typeclass.md b/guides/typeclass.md index 51a39b7f9..57cc126bc 100644 --- a/guides/typeclass.md +++ b/guides/typeclass.md @@ -269,13 +269,14 @@ Extends: `Filterable` allows you to `map` and filter out elements simultaneously. -| Name | Given | To | -| -------------------- | --------------------------- | -------------- | -| **filterMap** | `F`, `A => Option` | `F` | -| filterMapComposition | `F>`, `A => Option` | `F>` | -| filter | `F`, `A => boolean` | `F` | -| partitionMap | `F`, `A => Either` | `[F, F]` | -| partition | `F`, `A => boolean` | `[F, F]` | +| Name | Given | To | +| ----------------------- | ------------------------------ | -------------------- | +| **partitionMap** | `F`, `A => Either` | `[F, F]` | +| **filterMap** | `F`, `A => Option` | `F` | +| filter | `F`, `A => boolean` | `F` | +| partition | `F`, `A => boolean` | `[F, F]` | +| partitionMapComposition | `F>`, `A => Either` | `[F>, F>]` | +| filterMapComposition | `F>`, `A => Option` | `F>` | ### FlatMap diff --git a/src/Option.ts b/src/Option.ts index beb94e1f4..5692c7d01 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1243,9 +1243,28 @@ export const filterMap: { * @category instances * @since 1.0.0 */ -export const Filterable: filterable.Filterable = { +export const Filterable: filterable.Filterable = filterable.make( + ( + self: Option, + f: (a: A) => Either + ): [Option, Option] => { + if (isNone(self)) { + return [none(), none()] + } + const e = f(self.value) + return either.isLeft(e) ? [some(e.left), none()] : [none(), some(e.right)] + }, filterMap -} +) + +/** + * @category filtering + * @since 1.0.0 + */ +export const partitionMap: { + (f: (a: A) => Either): (self: Option) => [Option, Option] + (self: Option, f: (a: A) => Either): [Option, Option] +} = Filterable.partitionMap /** * Filters an `Option` using a predicate. If the predicate is not satisfied or the `Option` is `None` returns `None`. diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 6059ca81c..4ae14d762 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1558,11 +1558,39 @@ export const filterMap: { } ) +/** + * @category filtering + * @since 1.0.0 + */ +export const partitionMap: { + (f: (a: A, i: number) => Either): (self: Iterable) => [Array, Array] + (self: Iterable, f: (a: A, i: number) => Either): [Array, Array] +} = dual( + 2, + (self: Iterable, f: (a: A, i: number) => Either): [Array, Array] => { + const left: Array = [] + const right: Array = [] + const as = fromIterable(self) + for (let i = 0; i < as.length; i++) { + const e = f(as[i], i) + if (E.isLeft(e)) { + left.push(e.left) + } else { + right.push(e.right) + } + } + return [left, right] + } +) + /** * @category instances * @since 1.0.0 */ -export const Filterable: filterable.Filterable = filterable.make(filterMap) +export const Filterable: filterable.Filterable = filterable.make( + partitionMap, + filterMap +) /** * @category filtering @@ -1626,31 +1654,6 @@ export const partition: { partitionMap(self, (b, i) => (predicate(b, i) ? E.right(b) : E.left(b))) ) -/** - * @category filtering - * @since 1.0.0 - */ -export const partitionMap: { - (f: (a: A, i: number) => Either): (self: Iterable) => [Array, Array] - (self: Iterable, f: (a: A, i: number) => Either): [Array, Array] -} = dual( - 2, - (self: Iterable, f: (a: A, i: number) => Either): [Array, Array] => { - const left: Array = [] - const right: Array = [] - const as = fromIterable(self) - for (let i = 0; i < as.length; i++) { - const e = f(as[i], i) - if (E.isLeft(e)) { - left.push(e.left) - } else { - right.push(e.right) - } - } - return [left, right] - } -) - /** * @category filtering * @since 1.0.0 diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index e4a1aa06f..3d8aa122f 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -698,6 +698,7 @@ export const as: { * @since 1.0.0 */ export const Filterable: filterable.Filterable = filterable.make( + partitionMap, filterMap ) diff --git a/src/typeclass/Filterable.ts b/src/typeclass/Filterable.ts index 630d8f430..0960402e5 100644 --- a/src/typeclass/Filterable.ts +++ b/src/typeclass/Filterable.ts @@ -16,6 +16,16 @@ import type { Covariant } from "@fp-ts/core/typeclass/Covariant" * @since 1.0.0 */ export interface Filterable extends TypeClass { + readonly partitionMap: { + ( + f: (a: A) => Either + ): (self: Kind) => [Kind, Kind] + ( + self: Kind, + f: (a: A) => Either + ): [Kind, Kind] + } + readonly filterMap: { (f: (a: A) => Option): (self: Kind) => Kind (self: Kind, f: (a: A) => Option): Kind @@ -27,14 +37,36 @@ export interface Filterable extends TypeClass { * @since 1.0.0 */ export const make = ( + partitionMap: ( + self: Kind, + f: (a: A) => Either + ) => [Kind, Kind], filterMap: ( self: Kind, f: (a: A) => Option ) => Kind ): Filterable => ({ + partitionMap: dual(2, partitionMap), filterMap: dual(2, filterMap) }) +/** + * Returns a default binary `partitionMap` composition. + * + * @since 1.0.0 + */ +export const partitionMapComposition = ( + F: Covariant, + G: Filterable +) => + ( + self: Kind>, + f: (a: A) => Either + ): [Kind>, Kind>] => { + const filterMap = filterMapComposition(F, G) + return [filterMap(self, a => either.getLeft(f(a))), filterMap(self, a => either.getRight(f(a)))] + } + /** * Returns a default binary `filterMap` composition. * @@ -76,26 +108,6 @@ export const filter: ( Filterable.filterMap(self, (b) => (predicate(b) ? option.some(b) : option.none)) ) -/** - * @since 1.0.0 - */ -export const partitionMap = (F: Filterable): { - ( - f: (a: A) => Either - ): (self: Kind) => [Kind, Kind] - ( - self: Kind, - f: (a: A) => Either - ): [Kind, Kind] -} => - dual(2, ( - self: Kind, - f: (a: A) => Either - ): [Kind, Kind] => [ - F.filterMap(self, (a) => either.getLeft(f(a))), - F.filterMap(self, (a) => either.getRight(f(a))) - ]) - /** * @since 1.0.0 */ @@ -123,5 +135,5 @@ export const partition = ( self: Kind, predicate: (a: A) => boolean ): [Kind, Kind] => - partitionMap(F)(self, (b) => (predicate(b) ? either.right(b) : either.left(b))) + F.partitionMap(self, (b) => (predicate(b) ? either.right(b) : either.left(b))) ) diff --git a/test/Option.ts b/test/Option.ts index 1a16a6b67..212064d87 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -293,6 +293,13 @@ describe.concurrent("Option", () => { assertAlt(_.none(), _.none(), _.none()) }) + it("partitionMap", () => { + const f = (n: number) => (p(n) ? E.right(n + 1) : E.left(n - 1)) + assert.deepStrictEqual(pipe(_.none(), _.partitionMap(f)), [_.none(), _.none()]) + assert.deepStrictEqual(pipe(_.some(1), _.partitionMap(f)), [_.some(0), _.none()]) + assert.deepStrictEqual(pipe(_.some(3), _.partitionMap(f)), [_.none(), _.some(4)]) + }) + it("filterMap", () => { const f = (n: number) => (p(n) ? _.some(n + 1) : _.none()) Util.deepStrictEqual(pipe(_.none(), _.filterMap(f)), _.none()) diff --git a/test/typeclass/Filterable.ts b/test/typeclass/Filterable.ts index 24ab1ae46..84e25190d 100644 --- a/test/typeclass/Filterable.ts +++ b/test/typeclass/Filterable.ts @@ -15,6 +15,15 @@ describe("Filterable", () => { U.deepStrictEqual(filterMap([O.some("aa")], f), [O.some(2)]) }) + it("partitionMapComposition", () => { + const partitionMap = _.partitionMapComposition(RA.Covariant, O.Filterable) + const f = (s: string) => s.length > 1 ? E.right(s.length) : E.left(s + "!") + U.deepStrictEqual(partitionMap([], f), [[], []]) + U.deepStrictEqual(partitionMap([O.none()], f), [[O.none()], [O.none()]]) + U.deepStrictEqual(partitionMap([O.some("a")], f), [[O.some("a!")], [O.none()]]) + U.deepStrictEqual(partitionMap([O.some("aa")], f), [[O.none()], [O.some(2)]]) + }) + it("filter", () => { const filter = _.filter(RA.Filterable) const f = filter((n: number) => n > 0) @@ -24,15 +33,6 @@ describe("Filterable", () => { U.deepStrictEqual(pipe([1, -1], f), [1]) }) - it("partitionMap", () => { - const partitionMap = _.partitionMap(RA.Filterable) - const f = partitionMap((s: string) => s.length > 1 ? E.right(s.length) : E.left(s)) - U.deepStrictEqual(pipe([], f), [[], []]) - U.deepStrictEqual(pipe(["a"], f), [["a"], []]) - U.deepStrictEqual(pipe(["aa"], f), [[], [2]]) - U.deepStrictEqual(pipe(["aa", "a"], f), [["a"], [2]]) - }) - it("partition", () => { const partition = _.partition(RA.Filterable) const f = partition((n: number) => n > 0) From 3cb86e865fc0f5e34d8bb10361c0c903e4d8e22d Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 5 Feb 2023 19:21:17 +0100 Subject: [PATCH 197/255] Filterable: remove make --- docs/modules/typeclass/Filterable.ts.md | 20 ------------ src/Option.ts | 42 ++++++++++++------------- src/ReadonlyArray.ts | 33 ++++++++++++++----- src/ReadonlyRecord.ts | 30 ++++++++++++++---- src/typeclass/Filterable.ts | 18 ----------- 5 files changed, 71 insertions(+), 72 deletions(-) diff --git a/docs/modules/typeclass/Filterable.ts.md b/docs/modules/typeclass/Filterable.ts.md index 7ee335d05..0a12ce95a 100644 --- a/docs/modules/typeclass/Filterable.ts.md +++ b/docs/modules/typeclass/Filterable.ts.md @@ -14,8 +14,6 @@ Added in v1.0.0

Table of contents

-- [constructors](#constructors) - - [make](#make) - [models](#models) - [Filterable (interface)](#filterable-interface) - [utils](#utils) @@ -26,24 +24,6 @@ Added in v1.0.0 --- -# constructors - -## make - -**Signature** - -```ts -export declare const make: ( - partitionMap: ( - self: Kind, - f: (a: A) => Either - ) => [Kind, Kind], - filterMap: (self: Kind, f: (a: A) => Option) => Kind -) => Filterable -``` - -Added in v1.0.0 - # models ## Filterable (interface) diff --git a/src/Option.ts b/src/Option.ts index 5692c7d01..57c02654a 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1219,6 +1219,24 @@ export const Compactable: compactable.Compactable = { export const separate: (self: Option>) => [Option
, Option] = compactable .separate({ ...Covariant, ...Compactable }) +/** + * @category filtering + * @since 1.0.0 + */ +export const partitionMap: { + (f: (a: A) => Either): (self: Option) => [Option, Option] + (self: Option, f: (a: A) => Either): [Option, Option] +} = dual(2, ( + self: Option, + f: (a: A) => Either +): [Option, Option] => { + if (isNone(self)) { + return [none(), none()] + } + const e = f(self.value) + return either.isLeft(e) ? [some(e.left), none()] : [none(), some(e.right)] +}) + /** * Maps over the value of an `Option` and filters out `None`s. * @@ -1243,28 +1261,10 @@ export const filterMap: { * @category instances * @since 1.0.0 */ -export const Filterable: filterable.Filterable = filterable.make( - ( - self: Option, - f: (a: A) => Either - ): [Option, Option] => { - if (isNone(self)) { - return [none(), none()] - } - const e = f(self.value) - return either.isLeft(e) ? [some(e.left), none()] : [none(), some(e.right)] - }, +export const Filterable: filterable.Filterable = { + partitionMap, filterMap -) - -/** - * @category filtering - * @since 1.0.0 - */ -export const partitionMap: { - (f: (a: A) => Either): (self: Option) => [Option, Option] - (self: Option, f: (a: A) => Either): [Option, Option] -} = Filterable.partitionMap +} /** * Filters an `Option` using a predicate. If the predicate is not satisfied or the `Option` is `None` returns `None`. diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 4ae14d762..30978232d 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -19,7 +19,7 @@ import * as chainable from "@fp-ts/core/typeclass/Chainable" import type * as compactable from "@fp-ts/core/typeclass/Compactable" import type { Coproduct } from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" -import * as filterable from "@fp-ts/core/typeclass/Filterable" +import type * as filterable from "@fp-ts/core/typeclass/Filterable" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" @@ -1587,10 +1587,10 @@ export const partitionMap: { * @category instances * @since 1.0.0 */ -export const Filterable: filterable.Filterable = filterable.make( +export const Filterable: filterable.Filterable = { partitionMap, filterMap -) +} /** * @category filtering @@ -1622,8 +1622,16 @@ export const filter: { (self: Iterable, predicate: (a: A, i: number) => boolean): Array } = dual( 2, - (self: Iterable, predicate: (a: A, i: number) => boolean): Array => - filterMap(self, (b, i) => (predicate(b, i) ? O.some(b) : O.none())) + (self: Iterable, predicate: (a: A, i: number) => boolean): Array => { + const as = fromIterable(self) + const out: Array = [] + for (let i = 0; i < as.length; i++) { + if (predicate(as[i], i)) { + out.push(as[i]) + } + } + return out + } ) /** @@ -1650,8 +1658,19 @@ export const partition: { ( self: Iterable, predicate: (a: A, i: number) => boolean - ): [Array, Array] => - partitionMap(self, (b, i) => (predicate(b, i) ? E.right(b) : E.left(b))) + ): [Array, Array] => { + const left: Array = [] + const right: Array = [] + const as = fromIterable(self) + for (let i = 0; i < as.length; i++) { + if (predicate(as[i], i)) { + right.push(as[i]) + } else { + left.push(as[i]) + } + } + return [left, right] + } ) /** diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index 3d8aa122f..cf1b32089 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -13,7 +13,7 @@ import * as O from "@fp-ts/core/Option" import type * as applicative from "@fp-ts/core/typeclass/Applicative" import type * as compactable from "@fp-ts/core/typeclass/Compactable" import * as covariant from "@fp-ts/core/typeclass/Covariant" -import * as filterable from "@fp-ts/core/typeclass/Filterable" +import type * as filterable from "@fp-ts/core/typeclass/Filterable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import * as traversable from "@fp-ts/core/typeclass/Traversable" import * as traversableFilterable from "@fp-ts/core/typeclass/TraversableFilterable" @@ -447,7 +447,15 @@ export const filter: { ( self: ReadonlyRecord, predicate: (a: A, key: string) => boolean - ): Record => filterMap(self, (b, key) => (predicate(b, key) ? O.some(b) : O.none())) + ): Record => { + const out: Record = {} + for (const key of Object.keys(self)) { + if (predicate(self[key], key)) { + out[key] = self[key] + } + } + return out + } ) /** @@ -575,8 +583,18 @@ export const partition: { ( self: ReadonlyRecord, predicate: (a: A, key: string) => boolean - ): [Record, Record] => - partitionMap(self, (b, i) => (predicate(b, i) ? E.right(b) : E.left(b))) + ): [Record, Record] => { + const left: Record = {} + const right: Record = {} + for (const key of Object.keys(self)) { + if (predicate(self[key], key)) { + right[key] = self[key] + } else { + left[key] = self[key] + } + } + return [left, right] + } ) /** @@ -697,10 +715,10 @@ export const as: { * @category instances * @since 1.0.0 */ -export const Filterable: filterable.Filterable = filterable.make( +export const Filterable: filterable.Filterable = { partitionMap, filterMap -) +} /** * @category instances diff --git a/src/typeclass/Filterable.ts b/src/typeclass/Filterable.ts index 0960402e5..018158ba9 100644 --- a/src/typeclass/Filterable.ts +++ b/src/typeclass/Filterable.ts @@ -32,24 +32,6 @@ export interface Filterable extends TypeClass { } } -/** - * @category constructors - * @since 1.0.0 - */ -export const make = ( - partitionMap: ( - self: Kind, - f: (a: A) => Either - ) => [Kind, Kind], - filterMap: ( - self: Kind, - f: (a: A) => Option - ) => Kind -): Filterable => ({ - partitionMap: dual(2, partitionMap), - filterMap: dual(2, filterMap) -}) - /** * Returns a default binary `partitionMap` composition. * From 029fb5cff4b9856f6676ad0ce23d23fa2dede283 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 5 Feb 2023 19:32:50 +0100 Subject: [PATCH 198/255] Covariant: remove make --- docs/modules/typeclass/Covariant.ts.md | 16 ---------------- src/Either.ts | 26 +++++++++++++++----------- src/Identity.ts | 18 +++++++++++++----- src/Option.ts | 25 ++++++++++++++----------- src/typeclass/Covariant.ts | 11 ----------- test/typeclass/NonEmptyTraversable.ts | 8 ++++++-- 6 files changed, 48 insertions(+), 56 deletions(-) diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index 787638d5b..bfb88b528 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -12,8 +12,6 @@ Added in v1.0.0

Table of contents

-- [constructors](#constructors) - - [make](#make) - [do notation](#do-notation) - [let](#let) - [mapping](#mapping) @@ -28,20 +26,6 @@ Added in v1.0.0 --- -# constructors - -## make - -**Signature** - -```ts -export declare const make: ( - map: (self: Kind, f: (a: A) => B) => Kind -) => Covariant -``` - -Added in v1.0.0 - # do notation ## let diff --git a/src/Either.ts b/src/Either.ts index 5100327cd..96ef9d5a4 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -275,15 +275,6 @@ export const mapLeft: { (self: Either, f: (e: E) => G): Either } = bicovariant.mapLeft(Bicovariant) -/** - * @category instances - * @since 1.0.0 - */ -export const Covariant: covariant.Covariant = covariant.make(( - self: Either, - f: (a: A) => B -): Either => isRight(self) ? right(f(self.right)) : self) - /** * Maps the `Right` side of an `Either` value to a new `Either` value. * @@ -296,9 +287,22 @@ export const Covariant: covariant.Covariant = covariant.make(< export const map: { (f: (a: A) => B): (self: Either) => Either (self: Either, f: (a: A) => B): Either -} = Covariant.map +} = dual( + 2, + (self: Either, f: (a: A) => B): Either => + isRight(self) ? right(f(self.right)) : self +) -const imap = Covariant.imap +const imap = covariant.imap(map) + +/** + * @category instances + * @since 1.0.0 + */ +export const Covariant: covariant.Covariant = { + imap, + map +} /** * @category instances diff --git a/src/Identity.ts b/src/Identity.ts index 878f174d9..82f362736 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { identity } from "@fp-ts/core/Function" +import { dual, identity } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type * as applicative from "@fp-ts/core/typeclass/Applicative" @@ -43,20 +43,28 @@ export interface IdentityTypeLambdaFix
extends TypeLambda { readonly type: Identity } +const map: { + (f: (a: A) => B): (self: Identity) => Identity + (self: Identity, f: (a: A) => B): Identity +} = dual(2, (self: Identity, f: (a: A) => B): Identity => f(self)) + +const imap = covariant.imap(map) + /** * @category instances * @since 1.0.0 */ -export const Covariant: covariant.Covariant = covariant.make< - IdentityTypeLambda ->((self, f) => f(self)) +export const Covariant: covariant.Covariant = { + imap, + map +} /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap: Covariant.imap + imap } /** diff --git a/src/Option.ts b/src/Option.ts index 57c02654a..f0ad45313 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -573,15 +573,6 @@ export const getOrThrow = (self: Option): A => { // mapping // ------------------------------------------------------------------------------------- -/** - * @category mapping - * @since 1.0.0 - */ -export const Covariant: covariant.Covariant = covariant.make(( - self: Option, - f: (a: A) => B -): Option => isNone(self) ? none() : some(f(self.value))) - /** * Maps the `Some` side of an `Option` value to a new `Option` value. * @@ -594,9 +585,21 @@ export const Covariant: covariant.Covariant = covariant.make(< export const map: { (f: (a: A) => B): (self: Option) => Option (self: Option, f: (a: A) => B): Option -} = Covariant.map +} = dual( + 2, + (self: Option, f: (a: A) => B): Option => isNone(self) ? none() : some(f(self.value)) +) -const imap = Covariant.imap +const imap = covariant.imap(map) + +/** + * @category mapping + * @since 1.0.0 + */ +export const Covariant: covariant.Covariant = { + imap, + map +} /** * @category mapping diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index 49c9fb5c9..a0e0eed67 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -16,17 +16,6 @@ export interface Covariant extends Invariant { } } -/** - * @category constructors - * @since 1.0.0 - */ -export const make = ( - map: (self: Kind, f: (a: A) => B) => Kind -): Covariant => ({ - map: dual(2, map), - imap: imap(map) -}) - /** * Returns a default `map` composition. * diff --git a/test/typeclass/NonEmptyTraversable.ts b/test/typeclass/NonEmptyTraversable.ts index 050a96db9..9470d1c40 100644 --- a/test/typeclass/NonEmptyTraversable.ts +++ b/test/typeclass/NonEmptyTraversable.ts @@ -21,12 +21,16 @@ export interface NonEmptyReadonlyArrayTypeLambda extends TypeLambda { readonly type: RA.NonEmptyReadonlyArray } +const imap = covariant.imap(RA.mapNonEmpty) + /** * @category instances * @since 1.0.0 */ -export const NonEmptyCovariant: covariant.Covariant = covariant - .make(RA.mapNonEmpty) +export const NonEmptyCovariant: covariant.Covariant = { + imap, + map: RA.mapNonEmpty +} describe("NonEmptyTraversable", () => { it("traverseNonEmptyComposition", () => { From 2313f2495e5f4c3237e1ea5f633902acb9119f03 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 5 Feb 2023 19:39:14 +0100 Subject: [PATCH 199/255] Bicovariant: remove make --- docs/modules/typeclass/Bicovariant.ts.md | 16 ------------ src/Either.ts | 24 ++++++++++-------- src/These.ts | 32 ++++++++++++------------ src/typeclass/Bicovariant.ts | 14 ----------- 4 files changed, 29 insertions(+), 57 deletions(-) diff --git a/docs/modules/typeclass/Bicovariant.ts.md b/docs/modules/typeclass/Bicovariant.ts.md index 4ce9f2b00..bd1d571fa 100644 --- a/docs/modules/typeclass/Bicovariant.ts.md +++ b/docs/modules/typeclass/Bicovariant.ts.md @@ -12,8 +12,6 @@ Added in v1.0.0

Table of contents

-- [constructors](#constructors) - - [make](#make) - [type class](#type-class) - [Bicovariant (interface)](#bicovariant-interface) - [utils](#utils) @@ -23,20 +21,6 @@ Added in v1.0.0 --- -# constructors - -## make - -**Signature** - -```ts -export declare const make: ( - bimap: (self: Kind, f: (e: E1) => E2, g: (a: A) => B) => Kind -) => Bicovariant -``` - -Added in v1.0.0 - # type class ## Bicovariant (interface) diff --git a/src/Either.ts b/src/Either.ts index 96ef9d5a4..412c313d0 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -242,16 +242,6 @@ export const getEquivalence = ( isRight(y) && EA(x.right, y.right)) ) -/** - * @category instances - * @since 1.0.0 - */ -export const Bicovariant: bicovariant.Bicovariant = bicovariant.make(( - self, - f, - g -) => isLeft(self) ? left(f(self.left)) : right(g(self.right))) - /** * @category mapping * @since 1.0.0 @@ -259,7 +249,19 @@ export const Bicovariant: bicovariant.Bicovariant = bicovarian export const bimap: { (f: (e: E1) => E2, g: (a: A) => B): (self: Either) => Either (self: Either, f: (e: E1) => E2, g: (a: A) => B): Either -} = Bicovariant.bimap +} = dual( + 3, + (self: Either, f: (e: E1) => E2, g: (a: A) => B): Either => + isLeft(self) ? left(f(self.left)) : right(g(self.right)) +) + +/** + * @category instances + * @since 1.0.0 + */ +export const Bicovariant: bicovariant.Bicovariant = { + bimap +} /** * Maps the `Left` side of an `Either` value to a new `Either` value. diff --git a/src/These.ts b/src/These.ts index 99800b328..ab35a711f 100644 --- a/src/These.ts +++ b/src/These.ts @@ -628,29 +628,29 @@ export const inspectBoth: { }) /** - * @category instances + * @category mapping * @since 1.0.0 */ -export const Bicovariant: bicovariant.Bicovariant = bicovariant.make(( - self, - f, - g -) => - isLeft(self) ? - left(f(self.left)) : - isRight(self) ? - right(g(self.right)) : - both(f(self.left), g(self.right)) +export const bimap: { + (f: (e: E1) => E2, g: (a: A) => B): (self: These) => These + (self: These, f: (e: E1) => E2, g: (a: A) => B): These +} = dual( + 3, + (self: These, f: (e: E1) => E2, g: (a: A) => B): These => + isLeft(self) ? + left(f(self.left)) : + isRight(self) ? + right(g(self.right)) : + both(f(self.left), g(self.right)) ) /** - * @category mapping + * @category instances * @since 1.0.0 */ -export const bimap: { - (f: (e: E1) => E2, g: (a: A) => B): (self: These) => These - (self: These, f: (e: E1) => E2, g: (a: A) => B): These -} = Bicovariant.bimap +export const Bicovariant: bicovariant.Bicovariant = { + bimap +} /** * Maps the `Left` side of an `These` value to a new `These` value. diff --git a/src/typeclass/Bicovariant.ts b/src/typeclass/Bicovariant.ts index 3fcff67ef..1f1a67c20 100644 --- a/src/typeclass/Bicovariant.ts +++ b/src/typeclass/Bicovariant.ts @@ -23,20 +23,6 @@ export interface Bicovariant extends TypeClass { } } -/** - * @category constructors - * @since 1.0.0 - */ -export const make = ( - bimap: ( - self: Kind, - f: (e: E1) => E2, - g: (a: A) => B - ) => Kind -): Bicovariant => ({ - bimap: dual(3, bimap) -}) - /** * Returns a default ternary `bimap` composition. * From 1deb4530adea4f2bc1ed25c45afa35facec21aea Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 5 Feb 2023 19:45:44 +0100 Subject: [PATCH 200/255] Contravariant: remove make --- docs/modules/typeclass/Contravariant.ts.md | 16 -------------- src/Predicate.ts | 25 ++++++++++------------ src/typeclass/Contravariant.ts | 14 ------------ src/typeclass/Equivalence.ts | 22 ++++++++++++------- src/typeclass/Order.ts | 25 ++++++++++++---------- 5 files changed, 39 insertions(+), 63 deletions(-) diff --git a/docs/modules/typeclass/Contravariant.ts.md b/docs/modules/typeclass/Contravariant.ts.md index 914928d08..2f0411e5f 100644 --- a/docs/modules/typeclass/Contravariant.ts.md +++ b/docs/modules/typeclass/Contravariant.ts.md @@ -12,8 +12,6 @@ Added in v1.0.0

Table of contents

-- [constructors](#constructors) - - [make](#make) - [type class](#type-class) - [Contravariant (interface)](#contravariant-interface) - [utils](#utils) @@ -22,20 +20,6 @@ Added in v1.0.0 --- -# constructors - -## make - -**Signature** - -```ts -export declare const make: ( - contramap: (self: Kind, f: (b: B) => A) => Kind -) => Contravariant -``` - -Added in v1.0.0 - # type class ## Contravariant (interface) diff --git a/src/Predicate.ts b/src/Predicate.ts index 17e1d1f5b..a5a1823c1 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -87,18 +87,6 @@ export const compose: { (a): a is C => ab(a) && bc(a) ) -/** - * @category instances - * @since 1.0.0 - */ -export const Contravariant: contravariant.Contravariant = contravariant.make(< - A, - B ->( - self: Predicate
, - f: (b: B) => A -): Predicate => (b) => self(f(b))) - /** * @category combinators * @since 1.0.0 @@ -106,9 +94,18 @@ export const Contravariant: contravariant.Contravariant = c export const contramap: { (f: (b: B) => A): (self: Predicate) => Predicate (self: Predicate, f: (b: B) => A): Predicate -} = Contravariant.contramap +} = dual(2, (self: Predicate, f: (b: B) => A): Predicate => (b) => self(f(b))) + +const imap = contravariant.imap(contramap) -const imap = Contravariant.imap +/** + * @category instances + * @since 1.0.0 + */ +export const Contravariant: contravariant.Contravariant = { + imap, + contramap +} /** * @category instances diff --git a/src/typeclass/Contravariant.ts b/src/typeclass/Contravariant.ts index c9677d5a3..6d70cd2c6 100644 --- a/src/typeclass/Contravariant.ts +++ b/src/typeclass/Contravariant.ts @@ -16,20 +16,6 @@ export interface Contravariant extends Invariant { } } -/** - * @category constructors - * @since 1.0.0 - */ -export const make = ( - contramap: ( - self: Kind, - f: (b: B) => A - ) => Kind -): Contravariant => ({ - contramap: dual(2, contramap), - imap: imap(contramap) -}) - /** * Composing two contravariant functors yields a Covariant functor. * diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 2f6743deb..9eed10248 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -178,28 +178,34 @@ export const getMonoid = (): Monoid> => monoid.fromSemigroup(getSemigroup(), empty) /** - * @category instances + * @category combinators * @since 1.0.0 */ -export const Contravariant: contravariant.Contravariant = contravariant.make( +export const contramap: { + (f: (b: B) => A): (self: Equivalence) => Equivalence + (self: Equivalence, f: (b: B) => A): Equivalence +} = dual( + 2, (self: Equivalence, f: (b: B) => A): Equivalence => make((x, y) => self(f(x), f(y))) ) +const imap = contravariant.imap(contramap) + /** - * @category combinators + * @category instances * @since 1.0.0 */ -export const contramap: { - (f: (b: B) => A): (self: Equivalence) => Equivalence - (self: Equivalence, f: (b: B) => A): Equivalence -} = Contravariant.contramap +export const Contravariant: contravariant.Contravariant = { + imap, + contramap +} /** * @category instances * @since 1.0.0 */ export const Invariant: invariant.Invariant = { - imap: Contravariant.imap + imap } /** diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 87bdeac6f..a28839df9 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -174,15 +174,6 @@ const empty: Order = make(() => 0) */ export const getMonoid = (): Monoid> => monoid.fromSemigroup(getSemigroup(), empty) -/** - * @category instances - * @since 1.0.0 - */ -export const Contravariant: contravariant.Contravariant = contravariant.make(< - A, - B ->(self: Order, f: (b: B) => A): Order => make((b1, b2) => self.compare(f(b1), f(b2)))) - /** * @category combinators * @since 1.0.0 @@ -190,9 +181,21 @@ export const Contravariant: contravariant.Contravariant = contr export const contramap: { (f: (b: B) => A): (self: Order) => Order (self: Order, f: (b: B) => A): Order -} = Contravariant.contramap +} = dual( + 2, + (self: Order, f: (b: B) => A): Order => make((b1, b2) => self.compare(f(b1), f(b2))) +) + +const imap = contravariant.imap(contramap) -const imap = Contravariant.imap +/** + * @category instances + * @since 1.0.0 + */ +export const Contravariant: contravariant.Contravariant = { + imap, + contramap +} /** * @category instances From ba24c33c7f4a69ec88b25072f1df97b5e1f7beaa Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 5 Feb 2023 19:49:40 +0100 Subject: [PATCH 201/255] FlatMap: remove make --- docs/modules/typeclass/FlatMap.ts.md | 19 ------------ src/Identity.ts | 44 +++++++++++++++------------- src/typeclass/FlatMap.ts | 13 -------- 3 files changed, 24 insertions(+), 52 deletions(-) diff --git a/docs/modules/typeclass/FlatMap.ts.md b/docs/modules/typeclass/FlatMap.ts.md index 1999ba8ec..302ab0faa 100644 --- a/docs/modules/typeclass/FlatMap.ts.md +++ b/docs/modules/typeclass/FlatMap.ts.md @@ -12,8 +12,6 @@ Added in v1.0.0

Table of contents

-- [constructors](#constructors) - - [make](#make) - [type class](#type-class) - [FlatMap (interface)](#flatmap-interface) - [utils](#utils) @@ -23,23 +21,6 @@ Added in v1.0.0 --- -# constructors - -## make - -**Signature** - -```ts -export declare const make: ( - flatMap: ( - self: Kind, - f: (a: A) => Kind - ) => Kind -) => FlatMap -``` - -Added in v1.0.0 - # type class ## FlatMap (interface) diff --git a/src/Identity.ts b/src/Identity.ts index 82f362736..2a5c69c55 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -7,7 +7,7 @@ import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type * as applicative from "@fp-ts/core/typeclass/Applicative" import * as chainable from "@fp-ts/core/typeclass/Chainable" import * as covariant from "@fp-ts/core/typeclass/Covariant" -import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" +import type * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" import * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" @@ -81,27 +81,31 @@ export const Of: of_.Of = { */ export const Pointed: pointed.Pointed = { of: Of.of, - imap: Invariant.imap, - map: Covariant.map + imap, + map } +const flatMap: { + (f: (a: A) => B): (self: Identity
) => Identity + (self: Identity, f: (a: A) => B): Identity +} = dual(2, (self: Identity, f: (a: A) => B): Identity => f(self)) + /** * @category instances * @since 1.0.0 */ -export const FlatMap: flatMap_.FlatMap = flatMap_.make(( - self: Identity, - f: (a: A) => Identity -): Identity => f(self)) +export const FlatMap: flatMap_.FlatMap = { + flatMap +} /** * @category instances * @since 1.0.0 */ export const Chainable: chainable.Chainable = { - imap: Invariant.imap, - map: Covariant.map, - flatMap: FlatMap.flatMap + imap, + map, + flatMap } /** @@ -109,10 +113,10 @@ export const Chainable: chainable.Chainable = { * @since 1.0.0 */ export const Monad: monad.Monad = { - imap: Invariant.imap, + imap, of: Of.of, - map: Covariant.map, - flatMap: FlatMap.flatMap + map, + flatMap } /** @@ -131,7 +135,7 @@ export const SemiProduct: semiProduct.SemiProduct = semiProd */ export const Product: product_.Product = { of: Of.of, - imap: Invariant.imap, + imap, product: SemiProduct.product, productMany: SemiProduct.productMany, productAll: readonlyArray.fromIterable @@ -142,8 +146,8 @@ export const Product: product_.Product = { * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { - imap: Invariant.imap, - map: Covariant.map, + imap, + map, product: SemiProduct.product, productMany: SemiProduct.productMany } @@ -153,9 +157,9 @@ export const SemiApplicative: semiApplicative.SemiApplicative = { - imap: Invariant.imap, + imap, of: Of.of, - map: Covariant.map, + map, product: SemiProduct.product, productMany: SemiProduct.productMany, productAll: Product.productAll @@ -168,7 +172,7 @@ export const Applicative: applicative.Applicative = { export const getSemiCoproduct = ( S: Semigroup ): semiCoproduct.SemiCoproduct> => ({ - imap: Invariant.imap, + imap, coproduct: S.combine, coproductMany: S.combineMany }) @@ -181,7 +185,7 @@ export const getSemiAlternative = ( S: Semigroup ): semiAlternative.SemiAlternative> => ({ ...getSemiCoproduct(S), - map: Covariant.map + map }) /** diff --git a/src/typeclass/FlatMap.ts b/src/typeclass/FlatMap.ts index e426f8f26..680f15119 100644 --- a/src/typeclass/FlatMap.ts +++ b/src/typeclass/FlatMap.ts @@ -20,19 +20,6 @@ export interface FlatMap extends TypeClass { } } -/** - * @category constructors - * @since 1.0.0 - */ -export const make = ( - flatMap: ( - self: Kind, - f: (a: A) => Kind - ) => Kind -): FlatMap => ({ - flatMap: dual(2, flatMap) -}) - /** * @since 1.0.0 */ From ef49669bffbb06493fef5026d1026dabb44742da Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 5 Feb 2023 19:52:58 +0100 Subject: [PATCH 202/255] Invariant: remove make --- docs/modules/typeclass/Invariant.ts.md | 16 ---------------- src/typeclass/Invariant.ts | 14 -------------- src/typeclass/Semigroup.ts | 23 ++++++++++------------- 3 files changed, 10 insertions(+), 43 deletions(-) diff --git a/docs/modules/typeclass/Invariant.ts.md b/docs/modules/typeclass/Invariant.ts.md index fa1d95cf8..2a7524c1c 100644 --- a/docs/modules/typeclass/Invariant.ts.md +++ b/docs/modules/typeclass/Invariant.ts.md @@ -12,8 +12,6 @@ Added in v1.0.0

Table of contents

-- [constructors](#constructors) - - [make](#make) - [do notation](#do-notation) - [bindTo](#bindto) - [type class](#type-class) @@ -24,20 +22,6 @@ Added in v1.0.0 --- -# constructors - -## make - -**Signature** - -```ts -export declare const make: ( - imap: (self: Kind, to: (a: A) => B, from: (b: B) => A) => Kind -) => Invariant -``` - -Added in v1.0.0 - # do notation ## bindTo diff --git a/src/typeclass/Invariant.ts b/src/typeclass/Invariant.ts index 2b6d206a5..738621cf7 100644 --- a/src/typeclass/Invariant.ts +++ b/src/typeclass/Invariant.ts @@ -22,20 +22,6 @@ export interface Invariant extends TypeClass { } } -/** - * @category constructors - * @since 1.0.0 - */ -export const make = ( - imap: ( - self: Kind, - to: (a: A) => B, - from: (b: B) => A - ) => Kind -): Invariant => ({ - imap: dual(3, imap) -}) - /** * Returns a default ternary `imap` composition. * diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 4739713f7..d82277b3c 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -4,7 +4,7 @@ import { dual } from "@fp-ts/core/Function" import type { TypeLambda } from "@fp-ts/core/HKT" import { fromIterable } from "@fp-ts/core/internal/ReadonlyArray" -import * as invariant from "@fp-ts/core/typeclass/Invariant" +import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Order } from "@fp-ts/core/typeclass/Order" import type * as product from "@fp-ts/core/typeclass/Product" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" @@ -301,27 +301,24 @@ export const last =
(): Semigroup => ) /** - * @category instances * @since 1.0.0 */ -export const Invariant: invariant.Invariant = invariant.make(( - S: Semigroup, - to: (a: A) => B, - from: (b: B) => A -): Semigroup => +export const imap: { + (to: (a: A) => B, from: (b: B) => A): (self: Semigroup) => Semigroup + (self: Semigroup, to: (a: A) => B, from: (b: B) => A): Semigroup +} = dual(3, (S: Semigroup, to: (a: A) => B, from: (b: B) => A): Semigroup => make( (self, that) => to(S.combine(from(self), from(that))), (self, collection) => to(S.combineMany(from(self), (fromIterable(collection)).map(from))) - ) -) + )) /** + * @category instances * @since 1.0.0 */ -export const imap: { - (to: (a: A) => B, from: (b: B) => A): (self: Semigroup) => Semigroup - (self: Semigroup, to: (a: A) => B, from: (b: B) => A): Semigroup -} = Invariant.imap +export const Invariant: invariant.Invariant = { + imap +} /** * @category instances From 944d878073985cc363cf8944d6d643bc2804a72a Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 6 Feb 2023 06:12:50 +0100 Subject: [PATCH 203/255] Foldable: remove make --- docs/modules/typeclass/Foldable.ts.md | 18 +------------ src/Either.ts | 10 +++++--- src/Identity.ts | 20 ++++++++------- src/Option.ts | 9 ++++--- src/ReadonlyArray.ts | 4 ++- src/These.ts | 12 ++++++--- src/typeclass/Foldable.ts | 12 +-------- test/Identity.ts | 37 +++++++++++---------------- 8 files changed, 52 insertions(+), 70 deletions(-) diff --git a/docs/modules/typeclass/Foldable.ts.md b/docs/modules/typeclass/Foldable.ts.md index 81eb7d5d7..7f3a23b45 100644 --- a/docs/modules/typeclass/Foldable.ts.md +++ b/docs/modules/typeclass/Foldable.ts.md @@ -12,8 +12,6 @@ Added in v1.0.0

Table of contents

-- [constructors](#constructors) - - [make](#make) - [type class](#type-class) - [Foldable (interface)](#foldable-interface) - [utils](#utils) @@ -26,20 +24,6 @@ Added in v1.0.0 --- -# constructors - -## make - -**Signature** - -```ts -export declare const make: ( - reduce: (self: Kind, b: B, f: (b: B, a: A) => B) => B -) => Foldable -``` - -Added in v1.0.0 - # type class ## Foldable (interface) @@ -93,7 +77,7 @@ Added in v1.0.0 ## reduceComposition -Returns a default binary `reduce` composition. +Returns a default ternary `reduce` composition. **Signature** diff --git a/src/Either.ts b/src/Either.ts index 412c313d0..63074f519 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -775,9 +775,13 @@ export const SemiAlternative: semiAlternative.SemiAlternative * @category instances * @since 1.0.0 */ -export const Foldable: foldable.Foldable = foldable.make((self, b, f) => - isLeft(self) ? b : f(b, self.right) -) +export const Foldable: foldable.Foldable = { + reduce: dual( + 3, + (self: Either, b: B, f: (b: B, a: A) => B): B => + isLeft(self) ? b : f(b, self.right) + ) +} /** * Transforms an `Either` into an `Array`. diff --git a/src/Identity.ts b/src/Identity.ts index 2a5c69c55..ddd796975 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -8,7 +8,7 @@ import type * as applicative from "@fp-ts/core/typeclass/Applicative" import * as chainable from "@fp-ts/core/typeclass/Chainable" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" -import * as foldable from "@fp-ts/core/typeclass/Foldable" +import type * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" import * as of_ from "@fp-ts/core/typeclass/Of" @@ -67,12 +67,14 @@ export const Invariant: invariant.Invariant = { imap } +const of:
(a: A) => Identity = identity + /** * @category instances * @since 1.0.0 */ export const Of: of_.Of = { - of: identity + of } /** @@ -80,7 +82,7 @@ export const Of: of_.Of = { * @since 1.0.0 */ export const Pointed: pointed.Pointed = { - of: Of.of, + of, imap, map } @@ -114,7 +116,7 @@ export const Chainable: chainable.Chainable = { */ export const Monad: monad.Monad = { imap, - of: Of.of, + of, map, flatMap } @@ -134,7 +136,7 @@ export const SemiProduct: semiProduct.SemiProduct = semiProd * @since 1.0.0 */ export const Product: product_.Product = { - of: Of.of, + of, imap, product: SemiProduct.product, productMany: SemiProduct.productMany, @@ -158,7 +160,7 @@ export const SemiApplicative: semiApplicative.SemiApplicative = { imap, - of: Of.of, + of, map, product: SemiProduct.product, productMany: SemiProduct.productMany, @@ -192,9 +194,9 @@ export const getSemiAlternative = ( * @category instances * @since 1.0.0 */ -export const Foldable: foldable.Foldable = foldable.make((self, b, f) => - f(b, self) -) +export const Foldable: foldable.Foldable = { + reduce: dual(3, (self: Identity, b: B, f: (b: B, a: A) => B): B => f(b, self)) +} /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index f0ad45313..d2fc16bb6 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1181,9 +1181,12 @@ export const reduceCompact: { * @category folding * @since 1.0.0 */ -export const Foldable: foldable.Foldable = foldable.make((self, b, f) => - isNone(self) ? b : f(b, self.value) -) +export const Foldable: foldable.Foldable = { + reduce: dual( + 3, + (self: Option, b: B, f: (b: B, a: A) => B): B => isNone(self) ? b : f(b, self.value) + ) +} /** * Transforms an `Option` into an `Array`. diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 30978232d..5394d5296 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1897,7 +1897,9 @@ export const reduceRight: { * @category instances * @since 1.0.0 */ -export const Foldable: foldable.Foldable = foldable.make(reduce) +export const Foldable: foldable.Foldable = { + reduce +} /** * @category folding diff --git a/src/These.ts b/src/These.ts index ab35a711f..f1f26eedc 100644 --- a/src/These.ts +++ b/src/These.ts @@ -21,7 +21,7 @@ import * as covariant from "@fp-ts/core/typeclass/Covariant" import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as flatMap_ from "@fp-ts/core/typeclass/FlatMap" -import * as foldable from "@fp-ts/core/typeclass/Foldable" +import type * as foldable from "@fp-ts/core/typeclass/Foldable" import * as invariant from "@fp-ts/core/typeclass/Invariant" import type * as monad from "@fp-ts/core/typeclass/Monad" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" @@ -855,9 +855,13 @@ export const exists: { * @category instances * @since 1.0.0 */ -export const Foldable: foldable.Foldable = foldable.make((self, b, f) => - isLeft(self) ? b : f(b, self.right) -) +export const Foldable: foldable.Foldable = { + reduce: dual( + 3, + (self: These, b: B, f: (b: B, a: A) => B): B => + isLeft(self) ? b : f(b, self.right) + ) +} /** * Executes this effect and returns its value, if it succeeds, but otherwise diff --git a/src/typeclass/Foldable.ts b/src/typeclass/Foldable.ts index a3bc5029d..16d49adfb 100644 --- a/src/typeclass/Foldable.ts +++ b/src/typeclass/Foldable.ts @@ -20,17 +20,7 @@ export interface Foldable extends TypeClass { } /** - * @category constructors - * @since 1.0.0 - */ -export const make = ( - reduce: (self: Kind, b: B, f: (b: B, a: A) => B) => B -): Foldable => ({ - reduce: dual(3, reduce) -}) - -/** - * Returns a default binary `reduce` composition. + * Returns a default ternary `reduce` composition. * * @since 1.0.0 */ diff --git a/test/Identity.ts b/test/Identity.ts index 649e89cf5..6d8f7cbd2 100644 --- a/test/Identity.ts +++ b/test/Identity.ts @@ -7,37 +7,26 @@ import * as U from "./util" describe.concurrent("Identity", () => { it("instances and derived exports", () => { expect(_.Invariant).exist - expect(_.bindTo).exist - expect(_.Covariant).exist - expect(_.let).exist - expect(_.Of).exist - expect(_.Do).exist - expect(_.Pointed).exist - expect(_.FlatMap).exist - expect(_.Chainable).exist - expect(_.bind).exist - expect(_.Monad).exist - expect(_.SemiProduct).exist - expect(_.Product).exist - expect(_.SemiApplicative).exist - expect(_.Applicative).exist - expect(_.Foldable).exist - expect(_.Traversable).exist + + expect(_.bindTo).exist + expect(_.let).exist + expect(_.Do).exist + expect(_.bind).exist }) - it("of", () => { + it("Of", () => { U.deepStrictEqual(_.Of.of("a"), "a") }) @@ -50,14 +39,18 @@ describe.concurrent("Identity", () => { U.deepStrictEqual(_.Product.productAll(["a", "b", "c"]), ["a", "b", "c"]) }) - it("flatMap", () => { + it("Covariant", () => { + assert.deepStrictEqual(_.Covariant.map(1, n => n * 2), 2) + }) + + it("FlatMap", () => { U.deepStrictEqual( - pipe("a", _.Chainable.flatMap((a) => a + "b")), + pipe("a", _.FlatMap.flatMap((a) => a + "b")), "ab" ) }) - it("product", () => { + it("SemiProduct", () => { const product = _.SemiProduct.product U.deepStrictEqual(product("a", "b"), ["a", "b"]) }) @@ -74,11 +67,11 @@ describe.concurrent("Identity", () => { U.deepStrictEqual(F.coproductMany("a", ["b", "c"]), "abc") }) - it("reduce", () => { + it("Foldable", () => { U.deepStrictEqual(pipe("b", _.Foldable.reduce("a", (b, a) => b + a)), "ab") }) - it("traverse", () => { + it("Traversable", () => { U.deepStrictEqual(pipe(1, _.Traversable.traverse(O.Applicative)(O.some)), O.some(1)) U.deepStrictEqual(pipe(1, _.Traversable.traverse(O.Applicative)(() => O.none())), O.none()) }) From 0133ae03e2b27ca3d095050f187fff141b25b7a2 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 6 Feb 2023 06:22:47 +0100 Subject: [PATCH 204/255] SemiCoproduct: remove make --- docs/modules/typeclass/SemiCoproduct.ts.md | 24 ---------- src/Either.ts | 23 ++++++--- src/Option.ts | 54 +++++++++++++--------- src/These.ts | 23 ++++++--- src/typeclass/SemiCoproduct.ts | 21 --------- 5 files changed, 64 insertions(+), 81 deletions(-) diff --git a/docs/modules/typeclass/SemiCoproduct.ts.md b/docs/modules/typeclass/SemiCoproduct.ts.md index e8eae9e73..2a635a6c7 100644 --- a/docs/modules/typeclass/SemiCoproduct.ts.md +++ b/docs/modules/typeclass/SemiCoproduct.ts.md @@ -12,8 +12,6 @@ Added in v1.0.0

Table of contents

-- [constructors](#constructors) - - [make](#make) - [type class](#type-class) - [SemiCoproduct (interface)](#semicoproduct-interface) - [utils](#utils) @@ -21,28 +19,6 @@ Added in v1.0.0 --- -# constructors - -## make - -**Signature** - -```ts -export declare const make: ( - Invariant: Invariant, - coproduct: ( - self: Kind, - that: Kind - ) => Kind, - coproductMany: ( - self: Kind, - collection: Iterable> - ) => Kind -) => SemiCoproduct -``` - -Added in v1.0.0 - # type class ## SemiCoproduct (interface) diff --git a/src/Either.ts b/src/Either.ts index 63074f519..ea414fa00 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -654,15 +654,24 @@ export const firstRightOf: { return out }) +const coproduct: { + (that: Either): (self: Either) => Either + (self: Either, that: Either): Either +} = dual( + 2, + (self: Either, that: Either): Either => + isRight(self) ? self : that +) + /** * @category instances * @since 1.0.0 */ -export const SemiCoproduct: semiCoproduct.SemiCoproduct = semiCoproduct.make( - Invariant, - (self, that) => isRight(self) ? self : that, - firstRightOf -) +export const SemiCoproduct: semiCoproduct.SemiCoproduct = { + imap, + coproduct, + coproductMany: firstRightOf +} /** * Semigroup returning the left-most `Right` value. @@ -767,8 +776,8 @@ export const orElseFail: { export const SemiAlternative: semiAlternative.SemiAlternative = { map, imap, - coproduct: SemiCoproduct.coproduct, - coproductMany: SemiCoproduct.coproductMany + coproduct, + coproductMany: firstRightOf } /** diff --git a/src/Option.ts b/src/Option.ts index d2fc16bb6..738f4fa48 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1074,26 +1074,36 @@ export const getFailureMonoid:
(M: Monoid) => Monoid> = applicat Applicative ) -/** - * @category instances - * @since 1.0.0 - */ -export const SemiCoproduct: semiCoproduct.SemiCoproduct = semiCoproduct.make( - Invariant, - (self, that) => isSome(self) ? self : that, - (self, collection) => { - let out = self +const coproduct: { + (that: Option): (self: Option) => Option + (self: Option, that: Option): Option +} = dual(2, (self: Option, that: Option): Option => isSome(self) ? self : that) + +const coproductMany: { + (collection: Iterable>): (self: Option) => Option + (self: Option, collection: Iterable>): Option +} = dual(2, (self: Option, collection: Iterable>): Option => { + let out = self + if (isSome(out)) { + return out + } + for (out of collection) { if (isSome(out)) { return out } - for (out of collection) { - if (isSome(out)) { - return out - } - } - return out } -) + return out +}) + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiCoproduct: semiCoproduct.SemiCoproduct = { + imap, + coproduct, + coproductMany +} /** * Semigroup returning the first `Some` value encountered. @@ -1110,8 +1120,8 @@ export const getFirstSomeSemigroup: () => Semigroup> = semiCoproduc */ export const Coproduct: coproduct_.Coproduct = { imap, - coproduct: SemiCoproduct.coproduct, - coproductMany: SemiCoproduct.coproductMany, + coproduct, + coproductMany, zero: none, coproductAll: firstSomeOf } @@ -1123,8 +1133,8 @@ export const Coproduct: coproduct_.Coproduct = { export const SemiAlternative: semiAlternative.SemiAlternative = { map, imap, - coproduct: SemiCoproduct.coproduct, - coproductMany: SemiCoproduct.coproductMany + coproduct, + coproductMany } /** @@ -1134,8 +1144,8 @@ export const SemiAlternative: semiAlternative.SemiAlternative export const Alternative: alternative.Alternative = { map, imap, - coproduct: SemiCoproduct.coproduct, - coproductMany: SemiCoproduct.coproductMany, + coproduct, + coproductMany, coproductAll: firstSomeOf, zero: none } diff --git a/src/These.ts b/src/These.ts index f1f26eedc..5515b301b 100644 --- a/src/These.ts +++ b/src/These.ts @@ -938,15 +938,24 @@ export const firstRightOrBothOf: { return out }) +const coproduct: { + (that: These): (self: These) => These + (self: These, that: These): These +} = dual( + 2, + (self: These, that: These): These => + isRightOrBoth(self) ? self : that +) + /** * @category instances * @since 1.0.0 */ -export const SemiCoproduct: semiCoproduct.SemiCoproduct = semiCoproduct.make( - Invariant, - (self, that) => isRightOrBoth(self) ? self : that, - firstRightOrBothOf -) +export const SemiCoproduct: semiCoproduct.SemiCoproduct = { + imap, + coproduct, + coproductMany: firstRightOrBothOf +} /** * @category combining @@ -962,8 +971,8 @@ export const getFirstRightOrBothSemigroup: () => Semigroup> = export const SemiAlternative: semiAlternative.SemiAlternative = { map, imap, - coproduct: SemiCoproduct.coproduct, - coproductMany: SemiCoproduct.coproductMany + coproduct, + coproductMany: firstRightOrBothOf } /** diff --git a/src/typeclass/SemiCoproduct.ts b/src/typeclass/SemiCoproduct.ts index 32f6fb189..cee0ba850 100644 --- a/src/typeclass/SemiCoproduct.ts +++ b/src/typeclass/SemiCoproduct.ts @@ -2,7 +2,6 @@ * @since 1.0.0 */ -import { dual } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Invariant } from "@fp-ts/core/typeclass/Invariant" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" @@ -33,26 +32,6 @@ export interface SemiCoproduct extends Invariant { } } -/** - * @category constructors - * @since 1.0.0 - */ -export const make = ( - Invariant: Invariant, - coproduct: ( - self: Kind, - that: Kind - ) => Kind, - coproductMany: ( - self: Kind, - collection: Iterable> - ) => Kind -): SemiCoproduct => ({ - imap: Invariant.imap, - coproduct: dual(2, coproduct), - coproductMany: dual(2, coproductMany) -}) - /** * @since 1.0.0 */ From 3e4909d071c30fed43db760f7c24e5920e8af946 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 6 Feb 2023 06:57:42 +0100 Subject: [PATCH 205/255] SemiProduct: remove make --- docs/modules/typeclass/Equivalence.ts.md | 2 +- docs/modules/typeclass/Order.ts.md | 2 +- docs/modules/typeclass/SemiProduct.ts.md | 53 +++++++--------- docs/modules/typeclass/Semigroup.ts.md | 2 +- src/Either.ts | 48 +++++++++----- src/Identity.ts | 37 +++++++---- src/Option.ts | 63 +++++++++++-------- src/Predicate.ts | 43 ++++++++----- src/ReadonlyArray.ts | 51 ++++++++------- src/These.ts | 80 ++++++++++++++---------- src/typeclass/Equivalence.ts | 47 ++++++++++---- src/typeclass/Order.ts | 42 ++++++++++--- src/typeclass/SemiProduct.ts | 37 +++-------- src/typeclass/Semigroup.ts | 46 ++++++++++---- 14 files changed, 330 insertions(+), 223 deletions(-) diff --git a/docs/modules/typeclass/Equivalence.ts.md b/docs/modules/typeclass/Equivalence.ts.md index 91ee81067..9fd1bc0c3 100644 --- a/docs/modules/typeclass/Equivalence.ts.md +++ b/docs/modules/typeclass/Equivalence.ts.md @@ -168,7 +168,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: product.Product +export declare const Product: product_.Product ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index 513ef68ef..e1007da76 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -148,7 +148,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: product.Product +export declare const Product: product_.Product ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index d38bc61d2..fda458a1b 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -13,8 +13,7 @@ Added in v1.0.0

Table of contents

- [constructors](#constructors) - - [fromProduct](#fromproduct) - - [make](#make) + - [productMany](#productmany) - [do notation](#do-notation) - [andThenBind](#andthenbind) - [type class](#type-class) @@ -30,40 +29,34 @@ Added in v1.0.0 # constructors -## fromProduct +## productMany Useful when `productMany` can't be optimised. **Signature** ```ts -export declare const fromProduct: ( - Covariant: Covariant, - product: ( - self: Kind, - that: Kind - ) => Kind -) => SemiProduct -``` - -Added in v1.0.0 - -## make - -**Signature** - -```ts -export declare const make: ( - Invariant: Invariant, - product: ( - self: Kind, - that: Kind - ) => Kind, - productMany: ( - self: Kind, - collection: Iterable> - ) => Kind -) => SemiProduct +export declare const productMany: ( + map: { + (f: (a: A) => B): (self: Kind) => Kind + (self: Kind, f: (a: A) => B): Kind + }, + product: { + (that: Kind): ( + self: Kind + ) => Kind + (self: Kind, that: Kind): Kind< + F, + R1 & R2, + O1 | O2, + E1 | E2, + [A, B] + > + } +) => { + (collection: Iterable>): (self: Kind) => Kind + (self: Kind, collection: Iterable>): Kind +} ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index 17c271e1f..b3fb5941d 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -187,7 +187,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const Product: product.Product +export declare const Product: product_.Product ``` Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index ea414fa00..04b1f4a27 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -456,17 +456,21 @@ export const Monad: monad.Monad = { flatMap } -/** - * @category instances - * @since 1.0.0 - */ -export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( - Invariant, - (self, that) => isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self, - ( - self: Either, - collection: Iterable> - ): Either]> => { +const product: { + (that: Either): (self: Either) => Either + (self: Either, that: Either): Either +} = dual( + 2, + (self: Either, that: Either): Either => + isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self +) + +const productMany: { + (collection: Iterable>): (self: Either) => Either]> + (self: Either, collection: Iterable>): Either]> +} = dual( + 2, + (self: Either, collection: Iterable>): Either]> => { if (isLeft(self)) { return self } @@ -481,6 +485,16 @@ export const SemiProduct: semiProduct.SemiProduct = semiProduc } ) +/** + * @category instances + * @since 1.0.0 + */ +export const SemiProduct: semiProduct.SemiProduct = { + imap, + product, + productMany +} + /** * Appends an element to the end of a tuple. * @@ -516,8 +530,8 @@ const productAll = ( export const Product: product_.Product = { of, imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll } @@ -548,8 +562,8 @@ export const struct: >>( export const SemiApplicative: semiApplicative.SemiApplicative = { imap, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany + product, + productMany } /** @@ -597,8 +611,8 @@ export const Applicative: applicative.Applicative = { imap, of, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll } diff --git a/src/Identity.ts b/src/Identity.ts index ddd796975..a2f99755c 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -121,15 +121,28 @@ export const Monad: monad.Monad = { flatMap } +const product: { + (that: Identity):
(self: Identity) => Identity<[A, B]> + (self: Identity, that: Identity): Identity<[A, B]> +} = dual(2, (self: Identity, that: Identity): Identity<[A, B]> => [self, that]) + +const productMany: { + (collection: Iterable): (self: Identity) => [A, ...Array] + (self: Identity, collection: Iterable): [A, ...Array] +} = dual( + 2, + (self: Identity, collection: Iterable): [A, ...Array] => [self, ...collection] +) + /** * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( - Invariant, - (self, that) => [self, that], - (self, collection) => [self, ...collection] -) +export const SemiProduct: semiProduct.SemiProduct = { + imap, + product, + productMany +} /** * @category instances @@ -138,8 +151,8 @@ export const SemiProduct: semiProduct.SemiProduct = semiProd export const Product: product_.Product = { of, imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll: readonlyArray.fromIterable } @@ -150,8 +163,8 @@ export const Product: product_.Product = { export const SemiApplicative: semiApplicative.SemiApplicative = { imap, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany + product, + productMany } /** @@ -162,9 +175,9 @@ export const Applicative: applicative.Applicative = { imap, of, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany, - productAll: Product.productAll + product, + productMany, + productAll: readonlyArray.fromIterable } /** diff --git a/src/Option.ts b/src/Option.ts index 738f4fa48..c75a712e5 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -889,30 +889,41 @@ export const Monad: monad.Monad = { flatMap } +const product: { + (that: Option): (self: Option) => Option<[A, B]> + (self: Option, that: Option): Option<[A, B]> +} = dual( + 2, + (self: Option, that: Option): Option<[A, B]> => + isSome(self) && isSome(that) ? some([self.value, that.value]) : none() +) + +const productMany: { + (collection: Iterable>): (self: Option) => Option<[A, ...Array]> + (self: Option, collection: Iterable>): Option<[A, ...Array]> +} = dual(2, (self: Option, collection: Iterable>): Option<[A, ...Array]> => { + if (isNone(self)) { + return none() + } + const out: [A, ...Array] = [self.value] + for (const o of collection) { + if (isNone(o)) { + return none() + } + out.push(o.value) + } + return some(out) +}) + /** * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( - Invariant, - (self, that) => isSome(self) && isSome(that) ? some([self.value, that.value]) : none(), - ( - self: Option, - collection: Iterable> - ): Option<[A, ...Array]> => { - if (isNone(self)) { - return none() - } - const out: [A, ...Array] = [self.value] - for (const o of collection) { - if (isNone(o)) { - return none() - } - out.push(o.value) - } - return some(out) - } -) +export const SemiProduct: semiProduct.SemiProduct = { + imap, + product, + productMany +} /** * Appends an element to the end of a tuple. @@ -942,8 +953,8 @@ const productAll = (collection: Iterable>): Option> => { export const Product: product_.Product = { of, imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll } @@ -972,8 +983,8 @@ export const struct: >>( export const SemiApplicative: semiApplicative.SemiApplicative = { imap, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany + product, + productMany } /** @@ -1053,8 +1064,8 @@ export const Applicative: applicative.Applicative = { imap, of, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll } diff --git a/src/Predicate.ts b/src/Predicate.ts index a5a1823c1..0e7b444ff 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -140,20 +140,21 @@ export const Of: of_.Of = { */ export const unit: Predicate = of_.unit(Of) -/** - * @category instances - * @since 1.0.0 - */ -export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( - Invariant, - ( - self: Predicate, - that: Predicate - ): Predicate<[A, B]> => ([a, b]) => self(a) && that(b), - ( - self: Predicate, - collection: Iterable> - ): Predicate]> => +const product: { + (that: Predicate): (self: Predicate) => Predicate<[A, B]> + (self: Predicate, that: Predicate): Predicate<[A, B]> +} = dual( + 2, + (self: Predicate, that: Predicate): Predicate<[A, B]> => + ([a, b]) => self(a) && that(b) +) + +const productMany: { + (collection: Iterable>): (self: Predicate) => Predicate<[A, ...Array]> + (self: Predicate, collection: Iterable>): Predicate<[A, ...Array]> +} = dual( + 2, + (self: Predicate, collection: Iterable>): Predicate<[A, ...Array]> => ([head, ...tail]) => { if (self(head) === false) { return false @@ -168,6 +169,16 @@ export const SemiProduct: semiProduct.SemiProduct = semiPro } ) +/** + * @category instances + * @since 1.0.0 + */ +export const SemiProduct: semiProduct.SemiProduct = { + imap, + product, + productMany +} + const productAll = ( collection: Iterable> ): Predicate> => @@ -188,8 +199,8 @@ const productAll = ( export const Product: product_.Product = { of, imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll } diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 5394d5296..c2129babd 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1766,26 +1766,33 @@ export const sequenceNonEmpty = ( self: NonEmptyReadonlyArray> ) => Kind>) => traverseNonEmpty(F)(identity) +const product: { + (that: ReadonlyArray): (self: ReadonlyArray) => ReadonlyArray<[A, B]> + (self: ReadonlyArray, that: ReadonlyArray): ReadonlyArray<[A, B]> +} = dual(2, (self: ReadonlyArray, that: ReadonlyArray): ReadonlyArray<[A, B]> => { + if (isEmpty(self) || isEmpty(that)) { + return empty() + } + const out: Array<[A, B]> = [] + for (let i = 0; i < self.length; i++) { + for (let j = 0; j < that.length; j++) { + out.push([self[i], that[j]]) + } + } + return out +}) + +const productMany = semiProduct.productMany(map, product) + /** * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = semiProduct - .fromProduct(Covariant, ( - self: ReadonlyArray, - that: ReadonlyArray - ): Array<[A, B]> => { - if (isEmpty(self) || isEmpty(that)) { - return empty() - } - const out: Array<[A, B]> = [] - for (let i = 0; i < self.length; i++) { - for (let j = 0; j < that.length; j++) { - out.push([self[i], that[j]]) - } - } - return out - }) +export const SemiProduct: semiProduct.SemiProduct = { + imap, + product, + productMany +} /** * @category instances @@ -1794,8 +1801,8 @@ export const SemiProduct: semiProduct.SemiProduct = sem export const SemiApplicative: semiApplicative.SemiApplicative = { imap, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany + product, + productMany } /** @@ -1826,8 +1833,8 @@ export const lift2: (f: (a: A, b: B) => C) => { export const Product: product_.Product = { of, imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll: (collection) => { const arrays = fromIterable(collection) return isEmpty(arrays) ? empty() : SemiProduct.productMany(arrays[0], arrays.slice(1)) @@ -1842,8 +1849,8 @@ export const Applicative: applicative.Applicative = { imap, of, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll: Product.productAll } diff --git a/src/These.ts b/src/These.ts index 5515b301b..4c0c00893 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1049,30 +1049,33 @@ export const filterMap: { return O.isNone(ob) ? left(onNone()) : both(self.left, ob.value) }) -const product = ( - self: Validated, - that: Validated -): Validated => { - if (isLeft(self)) { - return self - } - if (isRight(self)) { +const product: { + (that: Validated): (self: Validated) => Validated + (self: Validated, that: Validated): Validated +} = dual( + 2, + (self: Validated, that: Validated): Validated => { + if (isLeft(self)) { + return self + } + if (isRight(self)) { + if (isLeft(that)) { + return that + } + if (isRight(that)) { + return right([self.right, that.right]) + } + return both(that.left, [self.right, that.right]) + } if (isLeft(that)) { - return that + return left(RA.appendAllNonEmpty(that.left)(self.left)) } if (isRight(that)) { - return right([self.right, that.right]) + return both(self.left, [self.right, that.right]) } - return both(that.left, [self.right, that.right]) - } - if (isLeft(that)) { - return left(RA.appendAllNonEmpty(that.left)(self.left)) + return both(RA.appendAllNonEmpty(that.left)(self.left), [self.right, that.right]) } - if (isRight(that)) { - return both(self.left, [self.right, that.right]) - } - return both(RA.appendAllNonEmpty(that.left)(self.left), [self.right, that.right]) -} +) const productAll = ( collection: Iterable> @@ -1098,21 +1101,32 @@ const productAll = ( return right(rights) } -const productMany = ( - self: Validated, - collection: Iterable> -): Validated]> => - map(product(self, productAll(collection)), ([a, as]) => [a, ...as]) +const productMany: { + ( + collection: Iterable> + ): (self: Validated) => Validated]> + ( + self: Validated, + collection: Iterable> + ): Validated]> +} = dual( + 2, + ( + self: Validated, + collection: Iterable> + ): Validated]> => + map(product(self, productAll(collection)), ([a, as]) => [a, ...as]) +) /** * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( - { imap }, +export const SemiProduct: semiProduct.SemiProduct = { + imap, product, productMany -) +} /** * @category instances @@ -1121,8 +1135,8 @@ export const SemiProduct: semiProduct.SemiProduct = semiPro export const SemiApplicative: semiApplicative.SemiApplicative = { imap, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany + product, + productMany } /** @@ -1193,8 +1207,8 @@ export const appendElement: { export const Product: product_.Product = { of, imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll } @@ -1252,8 +1266,8 @@ export const Applicative: applicative.Applicative = { imap, of, map, - product: SemiProduct.product, - productMany: SemiProduct.productMany, + product, + productMany, productAll } diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 9eed10248..c0bf8995c 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -12,10 +12,10 @@ import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" import * as monoid from "@fp-ts/core/typeclass/Monoid" -import type * as product from "@fp-ts/core/typeclass/Product" +import type * as product_ from "@fp-ts/core/typeclass/Product" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" -import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** * @category type class @@ -208,23 +208,46 @@ export const Invariant: invariant.Invariant = { imap } +const product: { + (that: Equivalence): (self: Equivalence) => Equivalence<[A, B]> + (self: Equivalence, that: Equivalence): Equivalence<[A, B]> +} = dual( + 2, + (self: Equivalence, that: Equivalence): Equivalence<[A, B]> => tuple(self, that) +) + +const productMany: { + (collection: Iterable>): (self: Equivalence) => Equivalence<[A, ...Array]> + (self: Equivalence, collection: Iterable>): Equivalence<[A, ...Array]> +} = dual( + 2, + (self: Equivalence, collection: Iterable>): Equivalence<[A, ...Array]> => + tuple(self, ...collection) +) + /** * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( - Invariant, - tuple, - (self, collection) => tuple(self, ...collection) -) +export const SemiProduct: semiProduct.SemiProduct = { + imap, + product, + productMany +} + +const of: (a: A) => Equivalence = () => empty + +const productAll = (collection: Iterable>): Equivalence> => + tuple>(...collection) + /** * @category instances * @since 1.0.0 */ -export const Product: product.Product = { - of: () => empty, +export const Product: product_.Product = { + of, imap: Invariant.imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, - productAll: (collection: Iterable>) => tuple>(...collection) + product, + productMany, + productAll } diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index a28839df9..09c30cacb 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -7,10 +7,10 @@ import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" import * as monoid from "@fp-ts/core/typeclass/Monoid" -import type * as product from "@fp-ts/core/typeclass/Product" +import type * as product_ from "@fp-ts/core/typeclass/Product" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" -import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** * @category type class @@ -205,26 +205,48 @@ export const Invariant: invariant.Invariant = { imap } +const product: { + (that: Order): (self: Order) => Order<[A, B]> + (self: Order, that: Order): Order<[A, B]> +} = dual( + 2, + (self: Order, that: Order): Order<[A, B]> => tuple(self, that) +) + +const productMany: { + (collection: Iterable>): (self: Order) => Order<[A, ...Array]> + (self: Order, collection: Iterable>): Order<[A, ...Array]> +} = dual( + 2, + (self: Order, collection: Iterable>): Order<[A, ...Array]> => + tuple(self, ...collection) +) + /** * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( - Invariant, - tuple, - (self, collection) => tuple(self, ...collection) -) +export const SemiProduct: semiProduct.SemiProduct = { + imap, + product, + productMany +} + +const of: (a: A) => Order = () => empty + +const productAll = (collection: Iterable>): Order> => + tuple>(...collection) /** * @category instances * @since 1.0.0 */ -export const Product: product.Product = { - of: () => empty, +export const Product: product_.Product = { + of, imap, product: SemiProduct.product, productMany: SemiProduct.productMany, - productAll: (collection: Iterable>): Order> => tuple>(...collection) + productAll } /** diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index cceec4187..70e29a72a 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -33,46 +33,23 @@ export interface SemiProduct extends Invariant { } } -/** - * @category constructors - * @since 1.0.0 - */ -export const make = ( - Invariant: Invariant, - product: ( - self: Kind, - that: Kind - ) => Kind, - productMany: ( - self: Kind, - collection: Iterable> - ) => Kind]> -): SemiProduct => ({ - imap: Invariant.imap, - product: dual(2, product), - productMany: dual(2, productMany) -}) - /** * Useful when `productMany` can't be optimised. * * @category constructors * @since 1.0.0 */ -export const fromProduct = ( - Covariant: Covariant, - product: ( - self: Kind, - that: Kind - ) => Kind -): SemiProduct => - make(Covariant, product, ( +export const productMany = ( + map: Covariant["map"], + product: SemiProduct["product"] +): SemiProduct["productMany"] => + dual(2, ( self: Kind, collection: Iterable> ) => { - let out = Covariant.map(self, (a): [A, ...Array] => [a]) + let out = map(self, (a): [A, ...Array] => [a]) for (const fa of collection) { - out = Covariant.map( + out = map( product(out, fa), ([[head, ...tail], a]): [A, ...Array] => [head, ...tail, a] ) diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index d82277b3c..a028f65ce 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -6,8 +6,8 @@ import type { TypeLambda } from "@fp-ts/core/HKT" import { fromIterable } from "@fp-ts/core/internal/ReadonlyArray" import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Order } from "@fp-ts/core/typeclass/Order" -import type * as product from "@fp-ts/core/typeclass/Product" -import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" +import type * as product_ from "@fp-ts/core/typeclass/Product" +import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** * @category type class @@ -320,24 +320,46 @@ export const Invariant: invariant.Invariant = { imap } +const product: { + (that: Semigroup): (self: Semigroup) => Semigroup<[A, B]> + (self: Semigroup, that: Semigroup): Semigroup<[A, B]> +} = dual( + 2, + (self: Semigroup, that: Semigroup): Semigroup<[A, B]> => tuple(self, that) +) + +const productMany: { + (collection: Iterable>): (self: Semigroup) => Semigroup<[A, ...Array]> + (self: Semigroup, collection: Iterable>): Semigroup<[A, ...Array]> +} = dual( + 2, + (self: Semigroup, collection: Iterable>): Semigroup<[A, ...Array]> => + tuple(self, ...collection) +) + /** * @category instances * @since 1.0.0 */ -export const SemiProduct: semiProduct.SemiProduct = semiProduct.make( - Invariant, - tuple, - (self, collection) => tuple(self, ...collection) -) +export const SemiProduct: semiProduct.SemiProduct = { + imap, + product, + productMany +} + +const of: (a: A) => Semigroup = constant + +const productAll = (collection: Iterable>): Semigroup> => + tuple>(...collection) /** * @category instances * @since 1.0.0 */ -export const Product: product.Product = { - of: constant, +export const Product: product_.Product = { + of, imap: Invariant.imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, - productAll: (collection: Iterable>) => tuple>(...collection) + product, + productMany, + productAll } From 8f5cf6240bae419812c25bd2a27b941c3a37d340 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 6 Feb 2023 07:08:58 +0100 Subject: [PATCH 206/255] Traversable: remove make --- docs/modules/typeclass/Traversable.ts.md | 21 ------------ src/Either.ts | 37 +++++++++++---------- src/Identity.ts | 24 +++++++++----- src/Option.ts | 37 ++++++++++----------- src/These.ts | 41 ++++++++++++------------ src/typeclass/Traversable.ts | 15 --------- 6 files changed, 73 insertions(+), 102 deletions(-) diff --git a/docs/modules/typeclass/Traversable.ts.md b/docs/modules/typeclass/Traversable.ts.md index 9980c9adf..00862c714 100644 --- a/docs/modules/typeclass/Traversable.ts.md +++ b/docs/modules/typeclass/Traversable.ts.md @@ -12,8 +12,6 @@ Added in v1.0.0

Table of contents

-- [constructors](#constructors) - - [make](#make) - [type class](#type-class) - [Traversable (interface)](#traversable-interface) - [utils](#utils) @@ -23,25 +21,6 @@ Added in v1.0.0 --- -# constructors - -## make - -**Signature** - -```ts -export declare const make: ( - traverse: ( - F: Applicative - ) => ( - self: Kind, - f: (a: A) => Kind - ) => Kind> -) => Traversable -``` - -Added in v1.0.0 - # type class ## Traversable (interface) diff --git a/src/Either.ts b/src/Either.ts index 04b1f4a27..e1f424aeb 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1026,29 +1026,13 @@ export const filterMap: { return option.isNone(ob) ? left(onNone()) : right(ob.value) })) -/** - * @category instances - * @since 1.0.0 - */ -export const Traversable: traversable.Traversable = traversable.make(< - F extends TypeLambda ->(F: applicative.Applicative) => - ( - self: Either, - f: (a: A) => Kind - ): Kind> => - isLeft(self) ? - F.of>(self) : - F.map>(f(self.right), right) -) - /** * @category traversing * @since 1.0.0 */ -export const traverse: ( +export const traverse = ( F: applicative.Applicative -) => { +): { ( f: (a: A) => Kind ): (self: Either) => Kind> @@ -1056,7 +1040,22 @@ export const traverse: ( self: Either, f: (a: A) => Kind ): Kind> -} = Traversable.traverse +} => + dual(2, ( + self: Either, + f: (a: A) => Kind + ): Kind> => + isLeft(self) ? + F.of>(self) : + F.map>(f(self.right), right)) + +/** + * @category instances + * @since 1.0.0 + */ +export const Traversable: traversable.Traversable = { + traverse +} /** * @category traversing diff --git a/src/Identity.ts b/src/Identity.ts index a2f99755c..17cc41ec7 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -19,7 +19,7 @@ import type * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import type * as semiCoproduct from "@fp-ts/core/typeclass/SemiCoproduct" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" -import * as traversable from "@fp-ts/core/typeclass/Traversable" +import type * as traversable from "@fp-ts/core/typeclass/Traversable" /** * @category models @@ -211,17 +211,25 @@ export const Foldable: foldable.Foldable = { reduce: dual(3, (self: Identity
, b: B, f: (b: B, a: A) => B): B => f(b, self)) } +const traverse = ( + F: applicative.Applicative +): { + (f: (a: A) => Kind): (self: Identity) => Kind + (self: Identity, f: (a: A) => Kind): Kind +} => + dual( + 2, + (self: Identity, f: (a: A) => Kind): Kind => + f(self) + ) + /** * @category instances * @since 1.0.0 */ -export const Traversable: traversable.Traversable = traversable.make( - (_: applicative.Applicative) => - ( - self: Identity, - f: (a: A) => Kind - ): Kind> => f(self) -) +export const Traversable: traversable.Traversable = { + traverse +} // ------------------------------------------------------------------------------------- // do notation diff --git a/src/Option.ts b/src/Option.ts index c75a712e5..e48d0725b 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1315,32 +1315,33 @@ export const filter: { // traversing // ------------------------------------------------------------------------------------- -/** - * @category instances - * @since 1.0.0 - */ -export const Traversable: traversable.Traversable = traversable.make(< - F extends TypeLambda ->(F: applicative.Applicative) => - (self: Option, f: (a: A) => Kind): Kind> => - isNone(self) ? F.of>(none()) : F.map(f(self.value), some) -) - /** * @category traversing * @since 1.0.0 */ -export const traverse: ( +export const traverse = ( F: applicative.Applicative -) => { +): { ( f: (a: A) => Kind ): (self: Option) => Kind> - ( - self: Option, - f: (a: A) => Kind - ): Kind> -} = Traversable.traverse + (self: Option, f: (a: A) => Kind): Kind> +} => + dual( + 2, + ( + self: Option, + f: (a: A) => Kind + ): Kind> => isNone(self) ? F.of(none()) : F.map(f(self.value), some) + ) + +/** + * @category instances + * @since 1.0.0 + */ +export const Traversable: traversable.Traversable = { + traverse +} /** * @category traversing diff --git a/src/These.ts b/src/These.ts index 4c0c00893..390f3f9f1 100644 --- a/src/These.ts +++ b/src/These.ts @@ -764,31 +764,13 @@ export const Pointed: pointed.Pointed = { map } -/** - * @category instances - * @since 1.0.0 - */ -export const Traversable: traversable.Traversable = traversable.make(< - F extends TypeLambda ->(F: applicative.Applicative) => - ( - self: These, - f: (a: A) => Kind - ): Kind> => - isLeft(self) - ? F.of>(self) - : isRight(self) - ? F.map>(f(self.right), right) - : F.map(f(self.right), (b) => both(self.left, b)) -) - /** * @category traversing * @since 1.0.0 */ -export const traverse: ( +export const traverse = ( F: applicative.Applicative -) => { +): { ( f: (a: A) => Kind ): (self: These) => Kind> @@ -796,7 +778,24 @@ export const traverse: ( self: These, f: (a: A) => Kind ): Kind> -} = Traversable.traverse +} => + dual(2, ( + self: These, + f: (a: A) => Kind + ): Kind> => + isLeft(self) + ? F.of>(self) + : isRight(self) + ? F.map>(f(self.right), right) + : F.map(f(self.right), (b) => both(self.left, b))) + +/** + * @category instances + * @since 1.0.0 + */ +export const Traversable: traversable.Traversable = { + traverse +} /** * @category traversing diff --git a/src/typeclass/Traversable.ts b/src/typeclass/Traversable.ts index 9a5346e8f..442e9d4e4 100644 --- a/src/typeclass/Traversable.ts +++ b/src/typeclass/Traversable.ts @@ -23,21 +23,6 @@ export interface Traversable extends TypeClass { } } -/** - * @category constructors - * @since 1.0.0 - */ -export const make = ( - traverse: ( - F: Applicative - ) => ( - self: Kind, - f: (a: A) => Kind - ) => Kind> -): Traversable => ({ - traverse: F => dual(2, traverse(F)) -}) - /** * Returns a default binary `traverse` composition. * From 7de07dc65d9150f3d9aa83f1aca13a5093b9391b Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 6 Feb 2023 07:45:49 +0100 Subject: [PATCH 207/255] TraversableFilterable: remove make --- .../typeclass/TraversableFilterable.ts.md | 24 ----------- src/ReadonlyArray.ts | 43 ++++++++++++------- src/ReadonlyRecord.ts | 43 ++++++++++++------- src/typeclass/TraversableFilterable.ts | 22 ---------- 4 files changed, 54 insertions(+), 78 deletions(-) diff --git a/docs/modules/typeclass/TraversableFilterable.ts.md b/docs/modules/typeclass/TraversableFilterable.ts.md index 918f924a0..f637d8567 100644 --- a/docs/modules/typeclass/TraversableFilterable.ts.md +++ b/docs/modules/typeclass/TraversableFilterable.ts.md @@ -17,7 +17,6 @@ Added in v1.0.0 - [models](#models) - [TraversableFilterable (interface)](#traversablefilterable-interface) - [utils](#utils) - - [make](#make) - [traverseFilter](#traversefilter) - [traverseFilterMap](#traversefiltermap) - [traversePartition](#traversepartition) @@ -69,29 +68,6 @@ Added in v1.0.0 # utils -## make - -**Signature** - -```ts -export declare const make: ( - traversePartitionMap: ( - F: Applicative - ) => ( - self: Kind, - f: (a: A) => Kind> - ) => Kind, Kind]>, - traverseFilterMap: ( - F: Applicative - ) => ( - self: Kind, - f: (a: A) => Kind> - ) => Kind> -) => TraversableFilterable -``` - -Added in v1.0.0 - ## traverseFilter **Signature** diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index c2129babd..1fb535837 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1970,24 +1970,19 @@ export const coproductMapKind: ( ): Kind } = foldable.coproductMapKind(Foldable) -/** - * @category instances - * @since 1.0.0 - */ -export const TraversableFilterable: traversableFilterable.TraversableFilterable< - ReadonlyArrayTypeLambda -> = traversableFilterable.make( - traversableFilterable.traversePartitionMap({ ...Traversable, ...Covariant, ...Compactable }), - traversableFilterable.traverseFilterMap({ ...Traversable, ...Compactable }) -) +const _traversePartitionMap = traversableFilterable.traversePartitionMap({ + ...Traversable, + ...Covariant, + ...Compactable +}) /** * @category filtering * @since 1.0.0 */ -export const traversePartitionMap: ( +export const traversePartitionMap = ( F: applicative.Applicative -) => { +): { ( f: (a: A) => Kind> ): (self: ReadonlyArray) => Kind, Array]> @@ -1995,15 +1990,20 @@ export const traversePartitionMap: ( self: ReadonlyArray, f: (a: A) => Kind> ): Kind, Array]> -} = TraversableFilterable.traversePartitionMap as any +} => dual(2, _traversePartitionMap(F)) + +const _traverseFilterMap = traversableFilterable.traverseFilterMap({ + ...Traversable, + ...Compactable +}) /** * @category filtering * @since 1.0.0 */ -export const traverseFilterMap: ( +export const traverseFilterMap = ( F: applicative.Applicative -) => { +): { ( f: (a: A) => Kind> ): (self: ReadonlyArray) => Kind> @@ -2011,7 +2011,18 @@ export const traverseFilterMap: ( self: ReadonlyArray, f: (a: A) => Kind> ): Kind> -} = TraversableFilterable.traverseFilterMap as any +} => dual(2, _traverseFilterMap(F)) + +/** + * @category instances + * @since 1.0.0 + */ +export const TraversableFilterable: traversableFilterable.TraversableFilterable< + ReadonlyArrayTypeLambda +> = { + traversePartitionMap: traversePartitionMap as any, + traverseFilterMap: traverseFilterMap as any +} /** * Filter values inside a context. diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index cf1b32089..ff453a590 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -752,24 +752,19 @@ export const traverseTap: ( ): Kind> } = traversable.traverseTap(Traversable) -/** - * @category instances - * @since 1.0.0 - */ -export const TraversableFilterable: traversableFilterable.TraversableFilterable< - ReadonlyRecordTypeLambda -> = traversableFilterable.make( - traversableFilterable.traversePartitionMap({ ...Traversable, ...Covariant, ...Compactable }), - traversableFilterable.traverseFilterMap({ ...Traversable, ...Compactable }) -) +const _traversePartitionMap = traversableFilterable.traversePartitionMap({ + ...Traversable, + ...Covariant, + ...Compactable +}) /** * @category filtering * @since 1.0.0 */ -export const traversePartitionMap: ( +export const traversePartitionMap = ( F: applicative.Applicative -) => { +): { ( f: (a: A) => Kind> ): ( @@ -779,15 +774,20 @@ export const traversePartitionMap: ( self: ReadonlyRecord, f: (a: A) => Kind> ): Kind, Record]> -} = TraversableFilterable.traversePartitionMap +} => dual(2, _traversePartitionMap(F)) + +const _traverseFilterMap = traversableFilterable.traverseFilterMap({ + ...Traversable, + ...Compactable +}) /** * @category filtering * @since 1.0.0 */ -export const traverseFilterMap: ( +export const traverseFilterMap = ( F: applicative.Applicative -) => { +): { ( f: (a: A) => Kind> ): (self: ReadonlyRecord) => Kind> @@ -795,7 +795,18 @@ export const traverseFilterMap: ( self: ReadonlyRecord, f: (a: A) => Kind> ): Kind> -} = TraversableFilterable.traverseFilterMap +} => dual(2, _traverseFilterMap(F)) + +/** + * @category instances + * @since 1.0.0 + */ +export const TraversableFilterable: traversableFilterable.TraversableFilterable< + ReadonlyRecordTypeLambda +> = { + traversePartitionMap, + traverseFilterMap +} /** * Filter values inside a context. diff --git a/src/typeclass/TraversableFilterable.ts b/src/typeclass/TraversableFilterable.ts index 8581cee88..6a799cfcb 100644 --- a/src/typeclass/TraversableFilterable.ts +++ b/src/typeclass/TraversableFilterable.ts @@ -48,28 +48,6 @@ export interface TraversableFilterable extends TypeClass( - traversePartitionMap: ( - F: Applicative - ) => ( - self: Kind, - f: (a: A) => Kind> - ) => Kind, Kind]>, - traverseFilterMap: ( - F: Applicative - ) => ( - self: Kind, - f: (a: A) => Kind> - ) => Kind> -): TraversableFilterable => ({ - traversePartitionMap: (F) => dual(2, traversePartitionMap(F)), - traverseFilterMap: (F) => dual(2, traverseFilterMap(F)) -}) - /** * Returns a default binary `traversePartitionMap` implementation. * From dd686eabce092a97f200b5952fe7e2e1f7a712f4 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 6 Feb 2023 08:35:52 +0100 Subject: [PATCH 208/255] inline traversePartitionMap, traverseFilterMap --- src/ReadonlyArray.ts | 27 +++++++-------- src/ReadonlyRecord.ts | 27 +++++++-------- test/ReadonlyArray.ts | 32 ++++++++++++++++-- test/ReadonlyRecord.ts | 32 ++++++++++++++++-- test/typeclass/TraversableFilterable.ts | 44 +++++++++++++++++++++++++ vitest.config.ts | 1 - 6 files changed, 132 insertions(+), 31 deletions(-) diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 1fb535837..06a0ac726 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1970,12 +1970,6 @@ export const coproductMapKind: ( ): Kind } = foldable.coproductMapKind(Foldable) -const _traversePartitionMap = traversableFilterable.traversePartitionMap({ - ...Traversable, - ...Covariant, - ...Compactable -}) - /** * @category filtering * @since 1.0.0 @@ -1990,12 +1984,13 @@ export const traversePartitionMap = ( self: ReadonlyArray, f: (a: A) => Kind> ): Kind, Array]> -} => dual(2, _traversePartitionMap(F)) - -const _traverseFilterMap = traversableFilterable.traverseFilterMap({ - ...Traversable, - ...Compactable -}) +} => + dual(2, ( + self: ReadonlyArray, + f: (a: A) => Kind> + ): Kind, Array]> => { + return F.map(traverse(F)(self, f), separate) + }) /** * @category filtering @@ -2011,7 +2006,13 @@ export const traverseFilterMap = ( self: ReadonlyArray, f: (a: A) => Kind> ): Kind> -} => dual(2, _traverseFilterMap(F)) +} => + dual(2, ( + self: ReadonlyArray, + f: (a: A) => Kind> + ): Kind> => { + return F.map(traverse(F)(self, f), compact) + }) /** * @category instances diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index ff453a590..a1993f1f9 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -752,12 +752,6 @@ export const traverseTap: ( ): Kind> } = traversable.traverseTap(Traversable) -const _traversePartitionMap = traversableFilterable.traversePartitionMap({ - ...Traversable, - ...Covariant, - ...Compactable -}) - /** * @category filtering * @since 1.0.0 @@ -774,12 +768,13 @@ export const traversePartitionMap = ( self: ReadonlyRecord, f: (a: A) => Kind> ): Kind, Record]> -} => dual(2, _traversePartitionMap(F)) - -const _traverseFilterMap = traversableFilterable.traverseFilterMap({ - ...Traversable, - ...Compactable -}) +} => + dual(2, ( + self: ReadonlyRecord, + f: (a: A) => Kind> + ): Kind, Record]> => { + return F.map(traverse(F)(self, f), separate) + }) /** * @category filtering @@ -795,7 +790,13 @@ export const traverseFilterMap = ( self: ReadonlyRecord, f: (a: A) => Kind> ): Kind> -} => dual(2, _traverseFilterMap(F)) +} => + dual(2, ( + self: ReadonlyRecord, + f: (a: A) => Kind> + ): Kind> => { + return F.map(traverse(F)(self, f), compact) + }) /** * @category instances diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index ef34ba5e5..cbab3dd2e 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -72,8 +72,6 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.partitionMap).exist expect(RA.TraversableFilterable).exist - expect(RA.traverseFilterMap).exist - expect(RA.traversePartitionMap).exist expect(RA.traverseFilter).exist expect(RA.traversePartition).exist @@ -1562,4 +1560,34 @@ describe.concurrent("ReadonlyArray", () => { 5 ]]) }) + + it("traversePartitionMap", () => { + const traversePartitionMap = RA.traversePartitionMap(O.Applicative) + const f = (s: string) => + s.length > 1 ? O.some(E.right(s)) : s.length > 0 ? O.some(E.left(s)) : O.none() + assert.deepStrictEqual(traversePartitionMap([], f), O.some([[], []])) + assert.deepStrictEqual(traversePartitionMap([""], f), O.none()) + assert.deepStrictEqual(traversePartitionMap(["a"], f), O.some([["a"], []])) + assert.deepStrictEqual(traversePartitionMap(["aa"], f), O.some([[], ["aa"]])) + assert.deepStrictEqual(traversePartitionMap(["aa", "a", ""], f), O.none()) + assert.deepStrictEqual( + traversePartitionMap(["aa", "a", "aaa"], f), + O.some([["a"], ["aa", "aaa"]]) + ) + }) + + it("traverseFilterMap", () => { + const traverseFilterMap = RA.traverseFilterMap(O.Applicative) + const f = (s: string) => + s.length > 1 ? O.some(O.some(s)) : s.length > 0 ? O.some(O.none()) : O.none() + assert.deepStrictEqual(traverseFilterMap([], f), O.some([])) + assert.deepStrictEqual(traverseFilterMap([""], f), O.none()) + assert.deepStrictEqual(traverseFilterMap(["a"], f), O.some([])) + assert.deepStrictEqual(traverseFilterMap(["aa"], f), O.some(["aa"])) + assert.deepStrictEqual(traverseFilterMap(["aa", "a", ""], f), O.none()) + assert.deepStrictEqual( + traverseFilterMap(["aa", "a", "aaa"], f), + O.some(["aa", "aaa"]) + ) + }) }) diff --git a/test/ReadonlyRecord.ts b/test/ReadonlyRecord.ts index c00e2f099..79ad4a42e 100644 --- a/test/ReadonlyRecord.ts +++ b/test/ReadonlyRecord.ts @@ -15,8 +15,6 @@ describe.concurrent("ReadonlyRecord", () => { expect(RR.Traversable).exist expect(RR.traverseTap).exist expect(RR.TraversableFilterable).exist - expect(RR.traversePartitionMap).exist - expect(RR.traverseFilterMap).exist expect(RR.traverseFilter).exist expect(RR.traversePartition).exist }) @@ -171,4 +169,34 @@ describe.concurrent("ReadonlyRecord", () => { assert.deepStrictEqual(RR.has({ a: 1, b: 2 }, "a"), true) assert.deepStrictEqual(RR.has({ a: 1, b: 2 }, "c"), false) }) + + it("traversePartitionMap", () => { + const traversePartitionMap = RR.traversePartitionMap(O.Applicative) + const f = (s: string) => + s.length > 1 ? O.some(E.right(s)) : s.length > 0 ? O.some(E.left(s)) : O.none() + assert.deepStrictEqual(traversePartitionMap({}, f), O.some([{}, {}])) + assert.deepStrictEqual(traversePartitionMap({ "": "" }, f), O.none()) + assert.deepStrictEqual(traversePartitionMap({ a: "a" }, f), O.some([{ a: "a" }, {}])) + assert.deepStrictEqual(traversePartitionMap({ aa: "aa" }, f), O.some([{}, { aa: "aa" }])) + assert.deepStrictEqual(traversePartitionMap({ aa: "aa", a: "a", "": "" }, f), O.none()) + assert.deepStrictEqual( + traversePartitionMap({ aa: "aa", a: "a", aaa: "aaa" }, f), + O.some([{ a: "a" }, { aa: "aa", aaa: "aaa" }]) + ) + }) + + it("traverseFilterMap", () => { + const traverseFilterMap = RR.traverseFilterMap(O.Applicative) + const f = (s: string) => + s.length > 1 ? O.some(O.some(s)) : s.length > 0 ? O.some(O.none()) : O.none() + assert.deepStrictEqual(traverseFilterMap({}, f), O.some({})) + assert.deepStrictEqual(traverseFilterMap({ "": "" }, f), O.none()) + assert.deepStrictEqual(traverseFilterMap({ a: "a" }, f), O.some({})) + assert.deepStrictEqual(traverseFilterMap({ aa: "aa" }, f), O.some({ aa: "aa" })) + assert.deepStrictEqual(traverseFilterMap({ aa: "aa", a: "a", "": "" }, f), O.none()) + assert.deepStrictEqual( + traverseFilterMap({ aa: "aa", a: "a", aaa: "aaa" }, f), + O.some({ aa: "aa", aaa: "aaa" }) + ) + }) }) diff --git a/test/typeclass/TraversableFilterable.ts b/test/typeclass/TraversableFilterable.ts index 649bea03d..ee6ac764a 100644 --- a/test/typeclass/TraversableFilterable.ts +++ b/test/typeclass/TraversableFilterable.ts @@ -1,9 +1,53 @@ +import * as E from "@fp-ts/core/Either" import * as O from "@fp-ts/core/Option" import * as RA from "@fp-ts/core/ReadonlyArray" import * as _ from "@fp-ts/core/typeclass/TraversableFilterable" import * as U from "../util" describe("TraversableFilterable", () => { + it("traversePartitionMap", () => { + const traversePartitionMap: ( + self: ReadonlyArray, + f: (a: A) => O.Option> + ) => O.Option<[ReadonlyArray, ReadonlyArray]> = _.traversePartitionMap({ + ...RA.Traversable, + ...RA.Covariant, + ...RA.Compactable + })(O.Applicative) + const f = (s: string) => + s.length > 1 ? O.some(E.right(s)) : s.length > 0 ? O.some(E.left(s)) : O.none() + assert.deepStrictEqual(traversePartitionMap([], f), O.some([[], []])) + assert.deepStrictEqual(traversePartitionMap([""], f), O.none()) + assert.deepStrictEqual(traversePartitionMap(["a"], f), O.some([["a"], []])) + assert.deepStrictEqual(traversePartitionMap(["aa"], f), O.some([[], ["aa"]])) + assert.deepStrictEqual(traversePartitionMap(["aa", "a", ""], f), O.none()) + assert.deepStrictEqual( + traversePartitionMap(["aa", "a", "aaa"], f), + O.some([["a"], ["aa", "aaa"]]) + ) + }) + + it("traverseFilterMap", () => { + const traverseFilterMap: ( + self: ReadonlyArray, + f: (a: A) => O.Option> + ) => O.Option> = _.traverseFilterMap({ + ...RA.Traversable, + ...RA.Compactable + })(O.Applicative) + const f = (s: string) => + s.length > 1 ? O.some(O.some(s)) : s.length > 0 ? O.some(O.none()) : O.none() + assert.deepStrictEqual(traverseFilterMap([], f), O.some([])) + assert.deepStrictEqual(traverseFilterMap([""], f), O.none()) + assert.deepStrictEqual(traverseFilterMap(["a"], f), O.some([])) + assert.deepStrictEqual(traverseFilterMap(["aa"], f), O.some(["aa"])) + assert.deepStrictEqual(traverseFilterMap(["aa", "a", ""], f), O.none()) + assert.deepStrictEqual( + traverseFilterMap(["aa", "a", "aaa"], f), + O.some(["aa", "aaa"]) + ) + }) + it("traverseFilter", () => { const traverseFilter = _.traverseFilter( RA.TraversableFilterable diff --git a/vitest.config.ts b/vitest.config.ts index 9469eb3d4..564ebd3fe 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -7,7 +7,6 @@ export default defineConfig({ include: ["./test/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], exclude: [ "./test/util.ts", - "./test/data/*.ts", "./test/limbo/*.ts" ], globals: true From c3a16b6ff81fba488fd472858f73fc2da39c85e8 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 6 Feb 2023 08:41:03 +0100 Subject: [PATCH 209/255] Option: remove separate --- docs/modules/Option.ts.md | 11 ----------- src/Option.ts | 9 +-------- test/Option.ts | 1 - 3 files changed, 1 insertion(+), 20 deletions(-) diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 45a1eccfa..529ad8e27 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -57,7 +57,6 @@ Added in v1.0.0 - [filter](#filter) - [filterMap](#filtermap) - [partitionMap](#partitionmap) - - [separate](#separate) - [folding](#folding) - [Foldable](#foldable) - [reduceCompact](#reducecompact) @@ -813,16 +812,6 @@ export declare const partitionMap: { Added in v1.0.0 -## separate - -**Signature** - -```ts -export declare const separate: (self: Option>) => [Option, Option] -``` - -Added in v1.0.0 - # folding ## Foldable diff --git a/src/Option.ts b/src/Option.ts index e48d0725b..070b85aed 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -13,7 +13,7 @@ import type { Predicate, Refinement } from "@fp-ts/core/Predicate" import type * as alternative from "@fp-ts/core/typeclass/Alternative" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as chainable from "@fp-ts/core/typeclass/Chainable" -import * as compactable from "@fp-ts/core/typeclass/Compactable" +import type * as compactable from "@fp-ts/core/typeclass/Compactable" import type * as coproduct_ from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" @@ -1239,13 +1239,6 @@ export const Compactable: compactable.Compactable = { compact: flatten } -/** - * @category filtering - * @since 1.0.0 - */ -export const separate: (self: Option>) => [Option, Option] = compactable - .separate({ ...Covariant, ...Compactable }) - /** * @category filtering * @since 1.0.0 diff --git a/test/Option.ts b/test/Option.ts index 212064d87..03bc9ffea 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -81,7 +81,6 @@ describe.concurrent("Option", () => { expect(_.traverseTap).exist expect(_.Compactable).exist - expect(_.separate).exist expect(_.Filterable).exist expect(_.filterMap).exist From ca1e102b7ecf8151297a9b76f6d26e04886f5391 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 6 Feb 2023 09:15:17 +0100 Subject: [PATCH 210/255] chore: derive compact from filterMap --- src/Either.ts | 26 +++++++++++++------------- src/These.ts | 31 ++++++++++++++----------------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/Either.ts b/src/Either.ts index e1f424aeb..d8e3f4d0f 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -961,19 +961,6 @@ export const liftThrowable = , B, E>( export const reverse = (self: Either): Either => isLeft(self) ? right(self.left) : left(self.right) -/** - * @category filtering - * @since 1.0.0 - */ -export const compact: { - (onNone: LazyArg): (self: Either>) => Either - (self: Either>, onNone: LazyArg): Either -} = dual( - 2, - (self: Either>, onNone: LazyArg): Either => - isLeft(self) ? self : option.isNone(self.right) ? left(onNone()) : right(self.right.value) -) - /** * @category filtering * @since 1.0.0 @@ -1026,6 +1013,19 @@ export const filterMap: { return option.isNone(ob) ? left(onNone()) : right(ob.value) })) +/** + * @category filtering + * @since 1.0.0 + */ +export const compact: { + (onNone: LazyArg): (self: Either>) => Either + (self: Either>, onNone: LazyArg): Either +} = dual( + 2, + (self: Either>, onNone: LazyArg): Either => + filterMap(self, identity, onNone) +) + /** * @category traversing * @since 1.0.0 diff --git a/src/These.ts b/src/These.ts index 390f3f9f1..bd1c06b98 100644 --- a/src/These.ts +++ b/src/These.ts @@ -5,7 +5,7 @@ import type { Either, Left, Right } from "@fp-ts/core/Either" import * as E from "@fp-ts/core/Either" import type { LazyArg } from "@fp-ts/core/Function" -import { constNull, constUndefined, dual } from "@fp-ts/core/Function" +import { constNull, constUndefined, dual, identity } from "@fp-ts/core/Function" import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { proto, structural } from "@fp-ts/core/internal/effect" import * as N from "@fp-ts/core/Number" @@ -974,22 +974,6 @@ export const SemiAlternative: semiAlternative.SemiAlternative = coproductMany: firstRightOrBothOf } -/** - * @category filtering - * @since 1.0.0 - */ -export const compact: { - (onNone: LazyArg): (self: These>) => These - (self: These>, onNone: LazyArg): These -} = dual(2, (self: These>, onNone: LazyArg): These => - isLeft(self) ? - self : - O.isNone(self.right) ? - left(onNone()) : - isBoth(self) ? - both(self.left, self.right.value) : - right(self.right.value)) - /** * @category filtering * @since 1.0.0 @@ -1048,6 +1032,19 @@ export const filterMap: { return O.isNone(ob) ? left(onNone()) : both(self.left, ob.value) }) +/** + * @category filtering + * @since 1.0.0 + */ +export const compact: { + (onNone: LazyArg): (self: These>) => These + (self: These>, onNone: LazyArg): These +} = dual( + 2, + (self: These>, onNone: LazyArg): These => + filterMap(self, identity, onNone) +) + const product: { (that: Validated): (self: Validated) => Validated (self: Validated, that: Validated): Validated From 3f7c9e424e555d3dfe692b7074b35fa9f9f3ffa4 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 6 Feb 2023 09:35:29 +0100 Subject: [PATCH 211/255] remove Compactable typeclass --- docs/modules/Option.ts.md | 11 --- docs/modules/ReadonlyArray.ts.md | 11 --- docs/modules/ReadonlyRecord.ts.md | 11 --- docs/modules/index.ts.md | 11 --- docs/modules/typeclass/Compactable.ts.md | 68 ------------------- docs/modules/typeclass/Contravariant.ts.md | 2 +- docs/modules/typeclass/Coproduct.ts.md | 2 +- docs/modules/typeclass/Covariant.ts.md | 2 +- docs/modules/typeclass/Equivalence.ts.md | 2 +- docs/modules/typeclass/Filterable.ts.md | 28 +++++++- docs/modules/typeclass/FlatMap.ts.md | 2 +- docs/modules/typeclass/Foldable.ts.md | 2 +- docs/modules/typeclass/Invariant.ts.md | 2 +- docs/modules/typeclass/Monad.ts.md | 2 +- docs/modules/typeclass/Monoid.ts.md | 2 +- docs/modules/typeclass/Of.ts.md | 2 +- docs/modules/typeclass/Order.ts.md | 2 +- docs/modules/typeclass/Pointed.ts.md | 2 +- docs/modules/typeclass/Product.ts.md | 2 +- docs/modules/typeclass/SemiAlternative.ts.md | 2 +- docs/modules/typeclass/SemiApplicative.ts.md | 2 +- docs/modules/typeclass/SemiCoproduct.ts.md | 2 +- docs/modules/typeclass/SemiProduct.ts.md | 2 +- docs/modules/typeclass/Semigroup.ts.md | 2 +- docs/modules/typeclass/Traversable.ts.md | 2 +- .../typeclass/TraversableFilterable.ts.md | 6 +- guides/typeclass.md | 11 +-- src/Option.ts | 9 --- src/ReadonlyArray.ts | 9 --- src/ReadonlyRecord.ts | 9 --- src/index.ts | 6 -- src/typeclass/Compactable.ts | 43 ------------ src/typeclass/Filterable.ts | 18 ++++- src/typeclass/TraversableFilterable.ts | 12 ++-- test/Option.ts | 2 - test/ReadonlyArray.ts | 18 +++-- test/ReadonlyRecord.ts | 1 - test/typeclass/Compactable.ts | 25 ------- test/typeclass/Filterable.ts | 23 +++++++ test/typeclass/TraversableFilterable.ts | 4 +- 40 files changed, 107 insertions(+), 267 deletions(-) delete mode 100644 docs/modules/typeclass/Compactable.ts.md delete mode 100644 src/typeclass/Compactable.ts delete mode 100644 test/typeclass/Compactable.ts diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 529ad8e27..e826e1013 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -67,7 +67,6 @@ Added in v1.0.0 - [instances](#instances) - [Alternative](#alternative) - [Applicative](#applicative) - - [Compactable](#compactable) - [Coproduct](#coproduct) - [Filterable](#filterable) - [Monad](#monad) @@ -943,16 +942,6 @@ export declare const Applicative: applicative.Applicative Added in v1.0.0 -## Compactable - -**Signature** - -```ts -export declare const Compactable: compactable.Compactable -``` - -Added in v1.0.0 - ## Coproduct **Signature** diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index b7c20a1f4..020c797d9 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -90,7 +90,6 @@ Added in v1.0.0 - [instances](#instances) - [Applicative](#applicative) - [Chainable](#chainable) - - [Compactable](#compactable) - [Covariant](#covariant) - [Filterable](#filterable) - [FlatMap](#flatmap) @@ -1151,16 +1150,6 @@ export declare const Chainable: chainable.Chainable Added in v1.0.0 -## Compactable - -**Signature** - -```ts -export declare const Compactable: compactable.Compactable -``` - -Added in v1.0.0 - ## Covariant **Signature** diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md index 1ec344763..2fecf4825 100644 --- a/docs/modules/ReadonlyRecord.ts.md +++ b/docs/modules/ReadonlyRecord.ts.md @@ -31,7 +31,6 @@ Added in v1.0.0 - [guards](#guards) - [isEmpty](#isempty) - [instances](#instances) - - [Compactable](#compactable) - [Covariant](#covariant) - [Filterable](#filterable) - [Invariant](#invariant) @@ -379,16 +378,6 @@ Added in v1.0.0 # instances -## Compactable - -**Signature** - -```ts -export declare const Compactable: compactable.Compactable -``` - -Added in v1.0.0 - ## Covariant **Signature** diff --git a/docs/modules/index.ts.md b/docs/modules/index.ts.md index 83422b0af..04879ac81 100644 --- a/docs/modules/index.ts.md +++ b/docs/modules/index.ts.md @@ -18,7 +18,6 @@ Added in v1.0.0 - [bicovariant](#bicovariant) - [bounded](#bounded) - [chainable](#chainable) - - [compactable](#compactable) - [contravariant](#contravariant) - [coproduct](#coproduct) - [covariant](#covariant) @@ -113,16 +112,6 @@ export declare const chainable: typeof chainable Added in v1.0.0 -## compactable - -**Signature** - -```ts -export declare const compactable: typeof compactable -``` - -Added in v1.0.0 - ## contravariant **Signature** diff --git a/docs/modules/typeclass/Compactable.ts.md b/docs/modules/typeclass/Compactable.ts.md deleted file mode 100644 index aa4a6e38c..000000000 --- a/docs/modules/typeclass/Compactable.ts.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: typeclass/Compactable.ts -nav_order: 24 -parent: Modules ---- - -## Compactable overview - -`Compactable` represents data structures which can be _compacted_/_separated_. - -Added in v1.0.0 - ---- - -

Table of contents

- -- [models](#models) - - [Compactable (interface)](#compactable-interface) -- [utils](#utils) - - [compactComposition](#compactcomposition) - - [separate](#separate) - ---- - -# models - -## Compactable (interface) - -**Signature** - -```ts -export interface Compactable extends TypeClass { - readonly compact: (self: Kind>) => Kind -} -``` - -Added in v1.0.0 - -# utils - -## compactComposition - -Returns a default `compact` composition. - -**Signature** - -```ts -export declare const compactComposition: ( - F: Covariant, - G: Compactable -) => ( - self: Kind>> -) => Kind> -``` - -Added in v1.0.0 - -## separate - -**Signature** - -```ts -export declare const separate: ( - F: Covariant & Compactable -) => (self: Kind>) => [Kind, Kind] -``` - -Added in v1.0.0 diff --git a/docs/modules/typeclass/Contravariant.ts.md b/docs/modules/typeclass/Contravariant.ts.md index 2f0411e5f..e32cd0c6d 100644 --- a/docs/modules/typeclass/Contravariant.ts.md +++ b/docs/modules/typeclass/Contravariant.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Contravariant.ts -nav_order: 25 +nav_order: 24 parent: Modules --- diff --git a/docs/modules/typeclass/Coproduct.ts.md b/docs/modules/typeclass/Coproduct.ts.md index 2fd0783a0..60abbe45f 100644 --- a/docs/modules/typeclass/Coproduct.ts.md +++ b/docs/modules/typeclass/Coproduct.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Coproduct.ts -nav_order: 26 +nav_order: 25 parent: Modules --- diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index bfb88b528..f0325bc30 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Covariant.ts -nav_order: 27 +nav_order: 26 parent: Modules --- diff --git a/docs/modules/typeclass/Equivalence.ts.md b/docs/modules/typeclass/Equivalence.ts.md index 9fd1bc0c3..84d517f18 100644 --- a/docs/modules/typeclass/Equivalence.ts.md +++ b/docs/modules/typeclass/Equivalence.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Equivalence.ts -nav_order: 28 +nav_order: 27 parent: Modules --- diff --git a/docs/modules/typeclass/Filterable.ts.md b/docs/modules/typeclass/Filterable.ts.md index 0a12ce95a..03c4eab24 100644 --- a/docs/modules/typeclass/Filterable.ts.md +++ b/docs/modules/typeclass/Filterable.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Filterable.ts -nav_order: 29 +nav_order: 28 parent: Modules --- @@ -17,10 +17,12 @@ Added in v1.0.0 - [models](#models) - [Filterable (interface)](#filterable-interface) - [utils](#utils) + - [compact](#compact) - [filter](#filter) - [filterMapComposition](#filtermapcomposition) - [partition](#partition) - [partitionMapComposition](#partitionmapcomposition) + - [separate](#separate) --- @@ -50,6 +52,18 @@ Added in v1.0.0 # utils +## compact + +**Signature** + +```ts +export declare const compact: ( + F: Filterable +) => (self: Kind>) => Kind +``` + +Added in v1.0.0 + ## filter **Signature** @@ -137,3 +151,15 @@ export declare const partitionMapComposition: ( + F: Filterable +) => (self: Kind>) => [Kind, Kind] +``` + +Added in v1.0.0 diff --git a/docs/modules/typeclass/FlatMap.ts.md b/docs/modules/typeclass/FlatMap.ts.md index 302ab0faa..492f0d993 100644 --- a/docs/modules/typeclass/FlatMap.ts.md +++ b/docs/modules/typeclass/FlatMap.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/FlatMap.ts -nav_order: 30 +nav_order: 29 parent: Modules --- diff --git a/docs/modules/typeclass/Foldable.ts.md b/docs/modules/typeclass/Foldable.ts.md index 7f3a23b45..c505ac843 100644 --- a/docs/modules/typeclass/Foldable.ts.md +++ b/docs/modules/typeclass/Foldable.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Foldable.ts -nav_order: 31 +nav_order: 30 parent: Modules --- diff --git a/docs/modules/typeclass/Invariant.ts.md b/docs/modules/typeclass/Invariant.ts.md index 2a7524c1c..914d3ffce 100644 --- a/docs/modules/typeclass/Invariant.ts.md +++ b/docs/modules/typeclass/Invariant.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Invariant.ts -nav_order: 32 +nav_order: 31 parent: Modules --- diff --git a/docs/modules/typeclass/Monad.ts.md b/docs/modules/typeclass/Monad.ts.md index eeb144205..9dea29887 100644 --- a/docs/modules/typeclass/Monad.ts.md +++ b/docs/modules/typeclass/Monad.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Monad.ts -nav_order: 33 +nav_order: 32 parent: Modules --- diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index fab07550d..e4b4ace50 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Monoid.ts -nav_order: 34 +nav_order: 33 parent: Modules --- diff --git a/docs/modules/typeclass/Of.ts.md b/docs/modules/typeclass/Of.ts.md index 21ef2619c..6ad0fd9ae 100644 --- a/docs/modules/typeclass/Of.ts.md +++ b/docs/modules/typeclass/Of.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Of.ts -nav_order: 35 +nav_order: 34 parent: Modules --- diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index e1007da76..3048ec3d4 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Order.ts -nav_order: 36 +nav_order: 35 parent: Modules --- diff --git a/docs/modules/typeclass/Pointed.ts.md b/docs/modules/typeclass/Pointed.ts.md index c1d10a9df..553c202f7 100644 --- a/docs/modules/typeclass/Pointed.ts.md +++ b/docs/modules/typeclass/Pointed.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Pointed.ts -nav_order: 37 +nav_order: 36 parent: Modules --- diff --git a/docs/modules/typeclass/Product.ts.md b/docs/modules/typeclass/Product.ts.md index 951a6fd04..9efdbf291 100644 --- a/docs/modules/typeclass/Product.ts.md +++ b/docs/modules/typeclass/Product.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Product.ts -nav_order: 38 +nav_order: 37 parent: Modules --- diff --git a/docs/modules/typeclass/SemiAlternative.ts.md b/docs/modules/typeclass/SemiAlternative.ts.md index e855eedd0..4c7acbeff 100644 --- a/docs/modules/typeclass/SemiAlternative.ts.md +++ b/docs/modules/typeclass/SemiAlternative.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/SemiAlternative.ts -nav_order: 39 +nav_order: 38 parent: Modules --- diff --git a/docs/modules/typeclass/SemiApplicative.ts.md b/docs/modules/typeclass/SemiApplicative.ts.md index 00765a3da..622a86041 100644 --- a/docs/modules/typeclass/SemiApplicative.ts.md +++ b/docs/modules/typeclass/SemiApplicative.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/SemiApplicative.ts -nav_order: 40 +nav_order: 39 parent: Modules --- diff --git a/docs/modules/typeclass/SemiCoproduct.ts.md b/docs/modules/typeclass/SemiCoproduct.ts.md index 2a635a6c7..7ff611ea7 100644 --- a/docs/modules/typeclass/SemiCoproduct.ts.md +++ b/docs/modules/typeclass/SemiCoproduct.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/SemiCoproduct.ts -nav_order: 41 +nav_order: 40 parent: Modules --- diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index fda458a1b..a4bc96197 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/SemiProduct.ts -nav_order: 43 +nav_order: 42 parent: Modules --- diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index b3fb5941d..294bb8219 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Semigroup.ts -nav_order: 42 +nav_order: 41 parent: Modules --- diff --git a/docs/modules/typeclass/Traversable.ts.md b/docs/modules/typeclass/Traversable.ts.md index 00862c714..9d32ab79e 100644 --- a/docs/modules/typeclass/Traversable.ts.md +++ b/docs/modules/typeclass/Traversable.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/Traversable.ts -nav_order: 44 +nav_order: 43 parent: Modules --- diff --git a/docs/modules/typeclass/TraversableFilterable.ts.md b/docs/modules/typeclass/TraversableFilterable.ts.md index f637d8567..4f67778ab 100644 --- a/docs/modules/typeclass/TraversableFilterable.ts.md +++ b/docs/modules/typeclass/TraversableFilterable.ts.md @@ -1,6 +1,6 @@ --- title: typeclass/TraversableFilterable.ts -nav_order: 45 +nav_order: 44 parent: Modules --- @@ -98,7 +98,7 @@ Returns a default binary `traverseFilterMap` implementation. ```ts export declare const traverseFilterMap: ( - T: Traversable & compactable.Compactable + T: Traversable & filterable.Filterable ) => ( F: Applicative ) => ( @@ -139,7 +139,7 @@ Returns a default binary `traversePartitionMap` implementation. ```ts export declare const traversePartitionMap: ( - T: Traversable & Covariant & compactable.Compactable + T: Traversable & Covariant & filterable.Filterable ) => ( F: Applicative ) => ( diff --git a/guides/typeclass.md b/guides/typeclass.md index 57cc126bc..f6d82343d 100644 --- a/guides/typeclass.md +++ b/guides/typeclass.md @@ -194,15 +194,6 @@ Extends: | andThenDiscard | `F
`, `F` | `F` | | bind | `F`, `name: string`, `A => F` | `F` | -### Compactable - -`Compactable` represents data structures which can be compacted / separated. - -| Name | Given | To | -| ----------- | ----------------- | -------------- | -| **compact** | `F>` | `F` | -| separate | `F>` | `[F, F]` | - ### Contravariant Contravariant functors. @@ -273,6 +264,8 @@ Extends: | ----------------------- | ------------------------------ | -------------------- | | **partitionMap** | `F`, `A => Either` | `[F, F]` | | **filterMap** | `F`, `A => Option` | `F` | +| compact | `F>` | `F` | +| separate | `F>` | `[F, F]` | | filter | `F`, `A => boolean` | `F` | | partition | `F`, `A => boolean` | `[F, F]` | | partitionMapComposition | `F>`, `A => Either` | `[F>, F>]` | diff --git a/src/Option.ts b/src/Option.ts index 070b85aed..3b38f4f78 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -13,7 +13,6 @@ import type { Predicate, Refinement } from "@fp-ts/core/Predicate" import type * as alternative from "@fp-ts/core/typeclass/Alternative" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as chainable from "@fp-ts/core/typeclass/Chainable" -import type * as compactable from "@fp-ts/core/typeclass/Compactable" import type * as coproduct_ from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type { Equivalence } from "@fp-ts/core/typeclass/Equivalence" @@ -1231,14 +1230,6 @@ export const toArray: (self: Option) => Array = foldable.toArray(Foldab // filtering // ------------------------------------------------------------------------------------- -/** - * @category instances - * @since 1.0.0 - */ -export const Compactable: compactable.Compactable = { - compact: flatten -} - /** * @category filtering * @since 1.0.0 diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 06a0ac726..6c9f03ff5 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -16,7 +16,6 @@ import type { Predicate, Refinement } from "@fp-ts/core/Predicate" import * as string from "@fp-ts/core/String" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as chainable from "@fp-ts/core/typeclass/Chainable" -import type * as compactable from "@fp-ts/core/typeclass/Compactable" import type { Coproduct } from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type * as filterable from "@fp-ts/core/typeclass/Filterable" @@ -1598,14 +1597,6 @@ export const Filterable: filterable.Filterable = { */ export const compact: (self: Iterable>) => Array = filterMap(identity) -/** - * @category instances - * @since 1.0.0 - */ -export const Compactable: compactable.Compactable = { - compact -} - /** * @category filtering * @since 1.0.0 diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index a1993f1f9..636abf4db 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -11,7 +11,6 @@ import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import type { Option } from "@fp-ts/core/Option" import * as O from "@fp-ts/core/Option" import type * as applicative from "@fp-ts/core/typeclass/Applicative" -import type * as compactable from "@fp-ts/core/typeclass/Compactable" import * as covariant from "@fp-ts/core/typeclass/Covariant" import type * as filterable from "@fp-ts/core/typeclass/Filterable" import * as invariant from "@fp-ts/core/typeclass/Invariant" @@ -720,14 +719,6 @@ export const Filterable: filterable.Filterable = { filterMap } -/** - * @category instances - * @since 1.0.0 - */ -export const Compactable: compactable.Compactable = { - compact -} - /** * @category instances * @since 1.0.0 diff --git a/src/index.ts b/src/index.ts index 03150d21a..f03ebc373 100644 --- a/src/index.ts +++ b/src/index.ts @@ -38,7 +38,6 @@ import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" import * as bounded from "@fp-ts/core/typeclass/Bounded" import * as chainable from "@fp-ts/core/typeclass/Chainable" -import * as compactable from "@fp-ts/core/typeclass/Compactable" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import * as coproduct from "@fp-ts/core/typeclass/Coproduct" import * as covariant from "@fp-ts/core/typeclass/Covariant" @@ -99,11 +98,6 @@ export { * @since 1.0.0 */ chainable, - /** - * @category typeclass - * @since 1.0.0 - */ - compactable, /** * @category typeclass * @since 1.0.0 diff --git a/src/typeclass/Compactable.ts b/src/typeclass/Compactable.ts deleted file mode 100644 index 3b65fa49a..000000000 --- a/src/typeclass/Compactable.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * `Compactable` represents data structures which can be _compacted_/_separated_. - * - * @since 1.0.0 - */ -import type { Either } from "@fp-ts/core/Either" -import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" -import * as either from "@fp-ts/core/internal/Either" -import type { Option } from "@fp-ts/core/Option" -import type { Covariant } from "@fp-ts/core/typeclass/Covariant" - -/** - * @category models - * @since 1.0.0 - */ -export interface Compactable extends TypeClass { - readonly compact: (self: Kind>) => Kind -} - -/** - * Returns a default `compact` composition. - * - * @since 1.0.0 - */ -export const compactComposition = ( - F: Covariant, - G: Compactable -): (( - self: Kind>> -) => Kind>) => F.map(G.compact) - -/** - * @since 1.0.0 - */ -export const separate = ( - F: Covariant & Compactable -) => - ( - self: Kind> - ): [Kind, Kind] => [ - F.compact(F.map(self, either.getLeft)), - F.compact(F.map(self, either.getRight)) - ] diff --git a/src/typeclass/Filterable.ts b/src/typeclass/Filterable.ts index 018158ba9..1db789e02 100644 --- a/src/typeclass/Filterable.ts +++ b/src/typeclass/Filterable.ts @@ -4,7 +4,7 @@ * @since 1.0.0 */ import type { Either } from "@fp-ts/core/Either" -import { dual } from "@fp-ts/core/Function" +import { dual, identity } from "@fp-ts/core/Function" import type { Kind, TypeClass, TypeLambda } from "@fp-ts/core/HKT" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" @@ -63,6 +63,22 @@ export const filterMapComposition = f: (a: A) => Option ): Kind> => F.map(self, G.filterMap(f)) +/** + * @since 1.0.0 + */ +export const compact = ( + F: Filterable +): (self: Kind>) => Kind => F.filterMap(identity) + +/** + * @since 1.0.0 + */ +export const separate = ( + F: Filterable +): ( + self: Kind> +) => [Kind, Kind] => F.partitionMap(identity) + /** * @since 1.0.0 */ diff --git a/src/typeclass/TraversableFilterable.ts b/src/typeclass/TraversableFilterable.ts index 6a799cfcb..4e93bdb62 100644 --- a/src/typeclass/TraversableFilterable.ts +++ b/src/typeclass/TraversableFilterable.ts @@ -11,9 +11,9 @@ import type { Option } from "@fp-ts/core/Option" import * as O from "@fp-ts/core/Option" import type { TraversableFilterable } from "@fp-ts/core/ReadonlyArray" import type { Applicative } from "@fp-ts/core/typeclass/Applicative" -import * as compactable from "@fp-ts/core/typeclass/Compactable" -import type { Compactable } from "@fp-ts/core/typeclass/Compactable" import type { Covariant } from "@fp-ts/core/typeclass/Covariant" +import * as filterable from "@fp-ts/core/typeclass/Filterable" +import type { Filterable } from "@fp-ts/core/typeclass/Filterable" import type { Traversable } from "@fp-ts/core/typeclass/Traversable" /** @@ -54,14 +54,14 @@ export interface TraversableFilterable extends TypeClass( - T: Traversable & Covariant & Compactable + T: Traversable & Covariant & Filterable ): ( F: Applicative ) => ( self: Kind, f: (a: A) => Kind> ) => Kind, Kind]> => - (F) => (self, f) => F.map(T.traverse(F)(self, f), compactable.separate(T)) + (F) => (self, f) => F.map(T.traverse(F)(self, f), filterable.separate(T)) /** * Returns a default binary `traverseFilterMap` implementation. @@ -69,14 +69,14 @@ export const traversePartitionMap = ( * @since 1.0.0 */ export const traverseFilterMap = ( - T: Traversable & Compactable + T: Traversable & Filterable ): ( F: Applicative ) => ( self: Kind, f: (a: A) => Kind> ) => Kind> => - (F) => (self, f) => F.map(T.traverse(F)(self, f), T.compact) + (F) => (self, f) => F.map(T.traverse(F)(self, f), filterable.compact(T)) /** * @since 1.0.0 diff --git a/test/Option.ts b/test/Option.ts index 03bc9ffea..208598adb 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -80,8 +80,6 @@ describe.concurrent("Option", () => { expect(_.sequence).exist expect(_.traverseTap).exist - expect(_.Compactable).exist - expect(_.Filterable).exist expect(_.filterMap).exist expect(_.filter).exist diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index cbab3dd2e..971c64b82 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -61,9 +61,7 @@ describe.concurrent("ReadonlyArray", () => { expect(RA.sequence).exist expect(RA.traverseTap).exist - expect(RA.Compactable).exist expect(RA.compact).exist - expect(RA.separate).exist expect(RA.Filterable).exist expect(RA.filterMap).exist @@ -832,24 +830,24 @@ describe.concurrent("ReadonlyArray", () => { }) it("compact", () => { - deepStrictEqual(RA.compact([]), []) - deepStrictEqual(RA.compact([O.some(1), O.some(2), O.some(3)]), [ + assert.deepStrictEqual(RA.compact([]), []) + assert.deepStrictEqual(RA.compact([O.some(1), O.some(2), O.some(3)]), [ 1, 2, 3 ]) - deepStrictEqual(RA.compact([O.some(1), O.none(), O.some(3)]), [ + assert.deepStrictEqual(RA.compact([O.some(1), O.none(), O.some(3)]), [ 1, 3 ]) }) it("separate", () => { - deepStrictEqual(RA.separate([]), [[], []]) - deepStrictEqual( - RA.separate([E.left(123), E.right("123")]), - [[123], ["123"]] - ) + assert.deepStrictEqual(RA.separate([]), [[], []]) + assert.deepStrictEqual(pipe([E.right(1), E.left("e"), E.right(2)], RA.separate), [ + ["e"], + [1, 2] + ]) }) it("filter", () => { diff --git a/test/ReadonlyRecord.ts b/test/ReadonlyRecord.ts index 79ad4a42e..5810c5087 100644 --- a/test/ReadonlyRecord.ts +++ b/test/ReadonlyRecord.ts @@ -10,7 +10,6 @@ describe.concurrent("ReadonlyRecord", () => { expect(RR.Covariant).exist expect(RR.flap).exist expect(RR.as).exist - expect(RR.Compactable).exist expect(RR.Filterable).exist expect(RR.Traversable).exist expect(RR.traverseTap).exist diff --git a/test/typeclass/Compactable.ts b/test/typeclass/Compactable.ts deleted file mode 100644 index 50fed2746..000000000 --- a/test/typeclass/Compactable.ts +++ /dev/null @@ -1,25 +0,0 @@ -import * as E from "@fp-ts/core/Either" -import { pipe } from "@fp-ts/core/Function" -import * as O from "@fp-ts/core/Option" -import * as RA from "@fp-ts/core/ReadonlyArray" -import * as _ from "@fp-ts/core/typeclass/Compactable" -import * as U from "../util" - -describe("Compactable", () => { - it("compactComposition", () => { - const compact = _.compactComposition(RA.Covariant, O.Compactable) - U.deepStrictEqual(pipe([], compact), []) - U.deepStrictEqual(pipe([O.none()], compact), [O.none()]) - U.deepStrictEqual(pipe([O.some(O.none())], compact), [O.none()]) - U.deepStrictEqual(pipe([O.some(O.some(1))], compact), [O.some(1)]) - }) - - it("separate", () => { - const separate = _.separate({ ...RA.Covariant, ...RA.Compactable }) - U.deepStrictEqual(pipe([], separate), [[], []]) - U.deepStrictEqual(pipe([E.right(1), E.left("e"), E.right(2)], separate), [ - ["e"], - [1, 2] - ]) - }) -}) diff --git a/test/typeclass/Filterable.ts b/test/typeclass/Filterable.ts index 84e25190d..d0a76c22f 100644 --- a/test/typeclass/Filterable.ts +++ b/test/typeclass/Filterable.ts @@ -41,4 +41,27 @@ describe("Filterable", () => { U.deepStrictEqual(pipe([-1], f), [[-1], []]) U.deepStrictEqual(pipe([1, -1], f), [[-1], [1]]) }) + + it("compact", () => { + const compact = _.compact(RA.Filterable) + assert.deepStrictEqual(compact([]), []) + assert.deepStrictEqual(compact([O.some(1), O.some(2), O.some(3)]), [ + 1, + 2, + 3 + ]) + assert.deepStrictEqual(compact([O.some(1), O.none(), O.some(3)]), [ + 1, + 3 + ]) + }) + + it("separate", () => { + const separate = _.separate(RA.Filterable) + U.deepStrictEqual(pipe([], separate), [[], []]) + U.deepStrictEqual(pipe([E.right(1), E.left("e"), E.right(2)], separate), [ + ["e"], + [1, 2] + ]) + }) }) diff --git a/test/typeclass/TraversableFilterable.ts b/test/typeclass/TraversableFilterable.ts index ee6ac764a..01e48ba8b 100644 --- a/test/typeclass/TraversableFilterable.ts +++ b/test/typeclass/TraversableFilterable.ts @@ -12,7 +12,7 @@ describe("TraversableFilterable", () => { ) => O.Option<[ReadonlyArray, ReadonlyArray]> = _.traversePartitionMap({ ...RA.Traversable, ...RA.Covariant, - ...RA.Compactable + ...RA.Filterable })(O.Applicative) const f = (s: string) => s.length > 1 ? O.some(E.right(s)) : s.length > 0 ? O.some(E.left(s)) : O.none() @@ -33,7 +33,7 @@ describe("TraversableFilterable", () => { f: (a: A) => O.Option> ) => O.Option> = _.traverseFilterMap({ ...RA.Traversable, - ...RA.Compactable + ...RA.Filterable })(O.Applicative) const f = (s: string) => s.length > 1 ? O.some(O.some(s)) : s.length > 0 ? O.some(O.none()) : O.none() From 921841b235e3a0e9bbe8f21c724a475ae9fd6174 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 6 Feb 2023 13:17:35 +0100 Subject: [PATCH 212/255] Function: make compose dual --- docs/modules/Function.ts.md | 28 ++++++++++++++++++++++++++++ src/Function.ts | 22 ++++++++++++++++++++++ test/Function.ts | 5 +++++ 3 files changed, 55 insertions(+) diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 58809bb2e..6d9ffe7c7 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -20,6 +20,7 @@ Added in v1.0.0 - [SK](#sk) - [absurd](#absurd) - [apply](#apply) + - [compose](#compose) - [constFalse](#constfalse) - [constNull](#constnull) - [constTrue](#consttrue) @@ -148,6 +149,33 @@ assert.deepStrictEqual(pipe(2, apply(increment)), 3) Added in v1.0.0 +## compose + +Composes two functions, `ab` and `bc` into a single function that takes in an argument `a` of type `A` and returns a result of type `C`. +The result is obtained by first applying the `ab` function to `a` and then applying the `bc` function to the result of `ab`. + +**Signature** + +```ts +export declare const compose: { + (bc: (b: B) => C): (self: (a: A) => B) => (a: A) => C + (self: (a: A) => B, bc: (b: B) => C): (a: A) => C +} +``` + +**Example** + +```ts +import { compose } from '@fp-ts/core/Function' + +const inc = (n: number) => n + 1 +const square = (n: number) => n * n + +assert.strictEqual(compose(inc, square)(2), 9) +``` + +Added in v1.0.0 + ## constFalse A thunk that returns always `false`. diff --git a/src/Function.ts b/src/Function.ts index 717cb84fb..0b7a5c61a 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -273,6 +273,28 @@ export function flow( return } +/** + * Composes two functions, `ab` and `bc` into a single function that takes in an argument `a` of type `A` and returns a result of type `C`. + * The result is obtained by first applying the `ab` function to `a` and then applying the `bc` function to the result of `ab`. + * + * @param ab - A function that maps from `A` to `B`. + * @param bc - A function that maps from `B` to `C`. + * + * @example + * import { compose } from '@fp-ts/core/Function' + * + * const inc = (n: number) => n + 1; + * const square = (n: number) => n * n; + * + * assert.strictEqual(compose(inc, square)(2), 9); + * + * @since 1.0.0 + */ +export const compose: { + (bc: (b: B) => C): (self: (a: A) => B) => (a: A) => C + (self: (a: A) => B, bc: (b: B) => C): (a: A) => C +} = dual(2, (ab: (a: A) => B, bc: (b: B) => C): (a: A) => C => flow(ab, bc)) + /** * The `absurd` function is a stub for cases where a value of type `never` is encountered in your code, * meaning that it should be impossible for this code to be executed. diff --git a/test/Function.ts b/test/Function.ts index 4bb6ffbd3..b7bba3d8b 100644 --- a/test/Function.ts +++ b/test/Function.ts @@ -11,6 +11,11 @@ describe.concurrent("Function", () => { deepStrictEqual(_.pipe("a", _.apply(String.length)), 1) }) + it("compose", () => { + deepStrictEqual(_.pipe(String.length, _.compose(double))("aaa"), 6) + deepStrictEqual(_.compose(String.length, double)("aaa"), 6) + }) + it("flip", () => { const f = (a: number) => (b: string) => a - b.length const g = (a: number, i = 0) => (b: number) => a ** b + i From e869197594cc1cfba9c0b443820f315c35a34bf5 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 6 Feb 2023 18:02:11 +0100 Subject: [PATCH 213/255] Either: add Validated --- docs/modules/Either.ts.md | 313 +++++++++++- docs/modules/typeclass/Product.ts.md | 2 +- docs/modules/typeclass/SemiProduct.ts.md | 2 +- src/Either.ts | 313 +++++++++++- src/typeclass/Product.ts | 4 +- src/typeclass/SemiProduct.ts | 4 +- test/Either.ts | 612 +++++++++++++---------- 7 files changed, 984 insertions(+), 266 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index ec8dd3924..59de30c1a 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -24,7 +24,9 @@ Added in v1.0.0 - [getFirstLeftSemigroup](#getfirstleftsemigroup) - [getFirstRightSemigroup](#getfirstrightsemigroup) - [zipWith](#zipwith) + - [zipWithValidated](#zipwithvalidated) - [constructors](#constructors) + - [fail](#fail) - [left](#left) - [of](#of) - [right](#right) @@ -36,6 +38,7 @@ Added in v1.0.0 - [toArray](#toarray) - [toOption](#tooption) - [toRefinement](#torefinement) + - [toValidated](#tovalidated) - [debugging](#debugging) - [inspectLeft](#inspectleft) - [inspectRight](#inspectright) @@ -70,6 +73,7 @@ Added in v1.0.0 - [isRight](#isright) - [instances](#instances) - [Applicative](#applicative) + - [ApplicativeValidated](#applicativevalidated) - [Bicovariant](#bicovariant) - [Chainable](#chainable) - [Covariant](#covariant) @@ -80,10 +84,13 @@ Added in v1.0.0 - [Of](#of) - [Pointed](#pointed) - [Product](#product) + - [ProductValidated](#productvalidated) - [SemiAlternative](#semialternative) - [SemiApplicative](#semiapplicative) + - [SemiApplicativeValidated](#semiapplicativevalidated) - [SemiCoproduct](#semicoproduct) - [SemiProduct](#semiproduct) + - [SemiProductValidated](#semiproductvalidated) - [Traversable](#traversable) - [getOptionalSemigroup](#getoptionalsemigroup) - [interop](#interop) @@ -94,6 +101,8 @@ Added in v1.0.0 - [merge](#merge) - [lifting](#lifting) - [lift2](#lift2) + - [lift2Validated](#lift2validated) + - [liftEither](#lifteither) - [liftOption](#liftoption) - [liftPredicate](#liftpredicate) - [mapping](#mapping) @@ -103,6 +112,8 @@ Added in v1.0.0 - [flap](#flap) - [map](#map) - [tupled](#tupled) +- [model](#model) + - [Validated (type alias)](#validated-type-alias) - [models](#models) - [Either (type alias)](#either-type-alias) - [Left (interface)](#left-interface) @@ -120,6 +131,7 @@ Added in v1.0.0 - [traverseTap](#traversetap) - [type lambdas](#type-lambdas) - [EitherTypeLambda (interface)](#eithertypelambda-interface) + - [ValidatedTypeLambda (interface)](#validatedtypelambda-interface) - [utils](#utils) - [andThen](#andthen) - [ap](#ap) @@ -130,7 +142,9 @@ Added in v1.0.0 - [flatten](#flatten) - [reverse](#reverse) - [struct](#struct) + - [structValidated](#structvalidated) - [tuple](#tuple) + - [tupleValidated](#tuplevalidated) - [unit](#unit) --- @@ -280,8 +294,64 @@ export declare const zipWith: { Added in v1.0.0 +## zipWithValidated + +Composes two `Validated` values, using the binary function `f`, in case both `self` and `that` values are right. + +Errors are accumulated. + +**Signature** + +```ts +export declare const zipWithValidated: { + (that: Either, f: (a: A, b: B) => C): ( + self: Either + ) => Either + ( + self: Either, + that: Either, + f: (a: A, b: B) => C + ): Either +} +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' +import * as N from '@fp-ts/core/Number' + +assert.deepStrictEqual(E.zipWithValidated(E.right(1), E.right(2), N.sum), E.right(3)) + +assert.deepStrictEqual(E.zipWithValidated(E.fail('error1'), E.fail('error2'), N.sum), E.left(['error1', 'error2'])) +``` + +Added in v1.0.0 + # constructors +## fail + +Constructs a `Validated` with a `Left` value. + +This is useful when you need to represent an error that occurred during validation. + +**Signature** + +```ts +export declare const fail: (e: E) => Either +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(E.fail('error'), E.left(['error'])) +``` + +Added in v1.0.0 + ## left Constructs a new `Either` holding a `Left` value. This usually represents a failure, due to the right-bias of this @@ -468,6 +538,30 @@ export declare const toRefinement: (f: (a: A) => Either Added in v1.0.0 +## toValidated + +Transforms an `Either` value into a `Validated` value. + +This function is useful for transforming an `Either` with an error value into a `Validated` value that is more suited +for sequential composition and error accumulation. + +**Signature** + +```ts +export declare const toValidated: (self: Either) => Either +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(E.toValidated(E.right(1)), E.right(1)) +assert.deepStrictEqual(E.toValidated(E.left('error')), E.left(['error'])) +``` + +Added in v1.0.0 + # debugging ## inspectLeft @@ -510,7 +604,9 @@ Added in v1.0.0 ## andThenBind -A variant of `bind` that sequentially ignores the scope. +Extends the `Either` value with the value of another `Either` type. + +If both `Either` instances are `Left`, then the result will be the first `Left`. **Signature** @@ -527,6 +623,21 @@ export declare const andThenBind: { } ``` +**Example** + +```ts +import * as E from '@fp-ts/core/Either' +import { pipe } from '@fp-ts/core/Function' + +const result = pipe( + E.Do, + E.bind('a', () => E.left('e1')), + E.andThenBind('b', E.left('e2')) +) + +assert.deepStrictEqual(result, E.left('e1')) +``` + Added in v1.0.0 ## bind @@ -863,6 +974,16 @@ export declare const Applicative: applicative.Applicative Added in v1.0.0 +## ApplicativeValidated + +**Signature** + +```ts +export declare const ApplicativeValidated: applicative.Applicative +``` + +Added in v1.0.0 + ## Bicovariant **Signature** @@ -963,6 +1084,16 @@ export declare const Product: product_.Product Added in v1.0.0 +## ProductValidated + +**Signature** + +```ts +export declare const ProductValidated: product_.Product +``` + +Added in v1.0.0 + ## SemiAlternative **Signature** @@ -983,6 +1114,16 @@ export declare const SemiApplicative: semiApplicative.SemiApplicative +``` + +Added in v1.0.0 + ## SemiCoproduct **Signature** @@ -1003,6 +1144,16 @@ export declare const SemiProduct: semiProduct.SemiProduct Added in v1.0.0 +## SemiProductValidated + +**Signature** + +```ts +export declare const SemiProductValidated: semiProduct.SemiProduct +``` + +Added in v1.0.0 + ## Traversable **Signature** @@ -1122,6 +1273,66 @@ export declare const lift2: ( Added in v1.0.0 +## lift2Validated + +Lifts a binary function into `Validated`. + +**Signature** + +```ts +export declare const lift2Validated: ( + f: (a: A, b: B) => C +) => { + (that: Either): ( + self: Either + ) => Either + (self: Either, that: Either): Either< + readonly [E1 | E2, ...(E1 | E2)[]], + C + > +} +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' +import * as N from '@fp-ts/core/Number' + +const sum = E.lift2Validated(N.sum) + +assert.deepStrictEqual(sum(E.right(1), E.right(2)), E.right(3)) +assert.deepStrictEqual(sum(E.fail('error1'), E.fail('error2')), E.left(['error1', 'error2'])) +``` + +Added in v1.0.0 + +## liftEither + +Lifts an `Either`-returning function into a function that returns a `Validated`. + +**Signature** + +```ts +export declare const liftEither: ( + f: (...a: A) => Either +) => (...a: A) => Either +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' + +const f = (n: number) => (n >= 0 ? E.right(n) : E.left('negative number')) +const g = E.liftEither(f) + +assert.deepStrictEqual(g(1), E.right(1)) +assert.deepStrictEqual(g(-1), E.left(['negative number'])) +``` + +Added in v1.0.0 + ## liftOption **Signature** @@ -1256,6 +1467,18 @@ export declare const tupled: (self: Either) => Either Added in v1.0.0 +# model + +## Validated (type alias) + +**Signature** + +```ts +export type Validated = Either, A> +``` + +Added in v1.0.0 + # models ## Either (type alias) @@ -1446,6 +1669,18 @@ export interface EitherTypeLambda extends TypeLambda { Added in v1.0.0 +## ValidatedTypeLambda (interface) + +**Signature** + +```ts +export interface ValidatedTypeLambda extends TypeLambda { + readonly type: Validated +} +``` + +Added in v3.0.0 + # utils ## andThen @@ -1579,6 +1814,50 @@ export declare const struct: >>( Added in v1.0.0 +## structValidated + +Creates a `Validated` structure by using an object where each property is a `Validated`. + +Errors are accumulated. + +**Signature** + +```ts +export declare const structValidated: }>( + fields: R +) => Either< + readonly [ + [R[keyof R]] extends [Either] ? E : never, + ...([R[keyof R]] extends [Either] ? E : never)[] + ], + { [K in keyof R]: [R[K]] extends [Either] ? A : never } +> +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual( + E.structValidated({ + x: E.right(1), + y: E.right('hello'), + }), + E.right({ x: 1, y: 'hello' }) +) + +assert.deepStrictEqual( + E.structValidated({ + x: E.fail('error1'), + y: E.fail('error2'), + }), + E.left(['error1', 'error2']) +) +``` + +Added in v1.0.0 + ## tuple **Signature** @@ -1594,6 +1873,38 @@ export declare const tuple: []>( Added in v1.0.0 +## tupleValidated + +Creates a `Validated` structure by using a tuple where each element is a `Validated`. + +Errors are accumulated. + +**Signature** + +```ts +export declare const tupleValidated: []>( + ...elements: T +) => Either< + readonly [ + [T[number]] extends [Either] ? E : never, + ...([T[number]] extends [Either] ? E : never)[] + ], + { [I in keyof T]: [T[I]] extends [Either] ? A : never } +> +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(E.tupleValidated(E.right(1), E.right('hello')), E.right([1, 'hello'])) + +assert.deepStrictEqual(E.tupleValidated(E.fail('error1'), E.fail('error2')), E.left(['error1', 'error2'])) +``` + +Added in v1.0.0 + ## unit **Signature** diff --git a/docs/modules/typeclass/Product.ts.md b/docs/modules/typeclass/Product.ts.md index 9efdbf291..e142e70c5 100644 --- a/docs/modules/typeclass/Product.ts.md +++ b/docs/modules/typeclass/Product.ts.md @@ -64,7 +64,7 @@ Added in v1.0.0 export declare const tuple: ( F: Product ) => []>( - ...components: T + ...elements: T ) => Kind< F, [T[number]] extends [Kind] ? R : never, diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index a4bc96197..2811d3cfd 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -178,7 +178,7 @@ Added in v1.0.0 export declare const nonEmptyTuple: ( F: SemiProduct ) => , ...Kind[]]>( - ...components: T + ...elements: T ) => Kind< F, [T[number]] extends [Kind] ? R : never, diff --git a/src/Either.ts b/src/Either.ts index d8e3f4d0f..bb74e1e28 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -8,9 +8,11 @@ import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { structural } from "@fp-ts/core/internal/effect" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" +import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import * as N from "@fp-ts/core/Number" import type { Option } from "@fp-ts/core/Option" import type { Predicate, Refinement } from "@fp-ts/core/Predicate" +import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" import * as chainable from "@fp-ts/core/typeclass/Chainable" @@ -1406,7 +1408,25 @@ export const bind: { } = chainable.bind(Chainable) /** - * A variant of `bind` that sequentially ignores the scope. + * Extends the `Either` value with the value of another `Either` type. + * + * If both `Either` instances are `Left`, then the result will be the first `Left`. + * + * @param self - The original `Either` value. + * @param name - The name of the property that will be added to the original `Either` type. + * @param that - The `Either` value that will be added to the original `Either` type. + * + * @example + * import * as E from '@fp-ts/core/Either' + * import { pipe } from '@fp-ts/core/Function' + * + * const result = pipe( + * E.Do, + * E.bind("a", () => E.left("e1")), + * E.andThenBind("b", E.left("e2")) + * ) + * + * assert.deepStrictEqual(result, E.left("e1")) * * @category do notation * @since 1.0.0 @@ -1424,3 +1444,294 @@ export const andThenBind: { that: Either ): Either } = semiProduct.andThenBind(SemiProduct) + +// ------------------------------------------------------------------------------------- +// Validated +// ------------------------------------------------------------------------------------- + +/** + * @category model + * @since 1.0.0 + */ +export type Validated = Either, A> + +/** + * @category type lambdas + * @since 3.0.0 + */ +export interface ValidatedTypeLambda extends TypeLambda { + readonly type: Validated +} + +/** + * Constructs a `Validated` with a `Left` value. + * + * This is useful when you need to represent an error that occurred during validation. + * + * @param e - The error value to put in the `Left` of the resulting `Validated`. + * + * @example + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(E.fail("error"), E.left(["error"])) + * + * @category constructors + * @since 1.0.0 + */ +export const fail = (e: E): Validated => left([e]) + +/** + * Transforms an `Either` value into a `Validated` value. + * + * This function is useful for transforming an `Either` with an error value into a `Validated` value that is more suited + * for sequential composition and error accumulation. + * + * @param self - The `Either` value to convert. + * + * @example + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(E.toValidated(E.right(1)), E.right(1)) + * assert.deepStrictEqual(E.toValidated(E.left("error")), E.left(["error"])) + * + * @category conversions + * @since 1.0.0 + */ +export const toValidated: (self: Either) => Validated = mapLeft((e) => [e]) + +/** + * Lifts an `Either`-returning function into a function that returns a `Validated`. + * + * @param f - The `Either`-returning function to lift. + * + * @example + * import * as E from '@fp-ts/core/Either' + * + * const f = (n: number) => n >= 0 ? E.right(n) : E.left("negative number") + * const g = E.liftEither(f) + * + * assert.deepStrictEqual(g(1), E.right(1)) + * assert.deepStrictEqual(g(-1), E.left(["negative number"])) + * + * @category lifting + * @since 1.0.0 + */ +export const liftEither = , E, B>( + f: (...a: A) => Either +) => (...a: A): Validated => toValidated(f(...a)) + +const productValidated: { + (that: Validated): (self: Validated) => Validated + (self: Validated, that: Validated): Validated +} = dual(2, ( + self: Validated, + that: Validated +): Validated => + isLeft(self) + ? isLeft(that) + ? left([...self.left, ...that.left]) + : self + : isLeft(that) + ? that + : right([self.right, that.right])) + +const productManyValidated = semiProduct.productMany(map, productValidated) + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiProductValidated: semiProduct.SemiProduct = { + imap, + product: productValidated, + productMany: productManyValidated +} + +const productAllValidated = ( + collection: Iterable> +): Validated> => { + const as = readonlyArray.fromIterable(collection) + return productManyValidated(as[0], as.slice(1)) +} + +/** + * @category instances + * @since 1.0.0 + */ +export const ProductValidated: product_.Product = { + imap, + of, + product: productValidated, + productMany: productManyValidated, + productAll: productAllValidated +} + +/** + * Creates a `Validated` structure by using a tuple where each element is a `Validated`. + * + * Errors are accumulated. + * + * @param elements - A tuple of `Validated` values. + * + * @example + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual( + * E.tupleValidated( + * E.right(1), + * E.right("hello") + * ), + * E.right([1, "hello"]) + * ) + * + * assert.deepStrictEqual( + * E.tupleValidated( + * E.fail("error1"), + * E.fail("error2") + * ), + * E.left(["error1", "error2"]) + * ) + * + * @since 1.0.0 + */ +export const tupleValidated: >>( + ...elements: T +) => Validated< + [T[number]] extends [Validated] ? E : never, + { [I in keyof T]: [T[I]] extends [Validated] ? A : never } +> = product_.tuple(ProductValidated) + +/** + * Creates a `Validated` structure by using an object where each property is a `Validated`. + * + * Errors are accumulated. + * + * @param fields - A struct of `Validated` values. + * + * @example + * import * as E from '@fp-ts/core/Either' + * + * assert.deepStrictEqual( + * E.structValidated({ + * x: E.right(1), + * y: E.right("hello") + * }), + * E.right({ x: 1, y: "hello" }) + * ) + * + * assert.deepStrictEqual( + * E.structValidated({ + * x: E.fail("error1"), + * y: E.fail("error2") + * }), + * E.left(["error1", "error2"]) + * ) + * + * @since 1.0.0 + */ +export const structValidated: }>( + fields: R +) => Validated< + [R[keyof R]] extends [Validated] ? E : never, + { [K in keyof R]: [R[K]] extends [Validated] ? A : never } +> = product_.struct(ProductValidated) + +/** + * @category instances + * @since 1.0.0 + */ +export const SemiApplicativeValidated: semiApplicative.SemiApplicative = { + imap, + map, + product: productValidated, + productMany: productManyValidated +} + +/** + * Composes two `Validated` values, using the binary function `f`, in case both `self` and `that` values are right. + * + * Errors are accumulated. + * + * @param self - first `Validated` value to compose. + * @param that - second `Validated` value to compose. + * @param f - binary function used to compute the `Validated` result from `self` and `that`. + * + * @example + * import * as E from '@fp-ts/core/Either' + * import * as N from '@fp-ts/core/Number' + * + * assert.deepStrictEqual( + * E.zipWithValidated( + * E.right(1), + * E.right(2), + * N.sum + * ), + * E.right(3) + * ) + * + * assert.deepStrictEqual( + * E.zipWithValidated( + * E.fail("error1"), + * E.fail("error2"), + * N.sum + * ), + * E.left(["error1", "error2"]) + * ) + * + * @category combining + * @since 1.0.0 + */ +export const zipWithValidated: { + ( + that: Validated, + f: (a: A, b: B) => C + ): (self: Validated) => Validated + ( + self: Validated, + that: Validated, + f: (a: A, b: B) => C + ): Validated +} = semiApplicative.zipWith(SemiApplicativeValidated) + +/** + * Lifts a binary function into `Validated`. + * + * @param f - The function to lift. + * + * @example + * import * as E from '@fp-ts/core/Either' + * import * as N from '@fp-ts/core/Number' + * + * const sum = E.lift2Validated(N.sum) + * + * assert.deepStrictEqual(sum(E.right(1), E.right(2)), E.right(3)) + * assert.deepStrictEqual( + * sum( + * E.fail("error1"), + * E.fail("error2") + * ), + * E.left(["error1", "error2"]) + * ) + * + * @category lifting + * @since 1.0.0 + */ +export const lift2Validated: ( + f: (a: A, b: B) => C +) => { + (that: Validated): (self: Validated) => Validated + (self: Validated, that: Validated): Validated +} = semiApplicative.lift2(SemiApplicativeValidated) + +/** + * @category instances + * @since 1.0.0 + */ +export const ApplicativeValidated: applicative.Applicative = { + imap, + map, + of, + product: productValidated, + productMany: productManyValidated, + productAll: productAllValidated +} diff --git a/src/typeclass/Product.ts b/src/typeclass/Product.ts index 495344514..0aa9d7c6c 100644 --- a/src/typeclass/Product.ts +++ b/src/typeclass/Product.ts @@ -20,13 +20,13 @@ export interface Product extends SemiProduct, Of { * @since 1.0.0 */ export const tuple = (F: Product) => - >>(...components: T): Kind< + >>(...elements: T): Kind< F, ([T[number]] extends [Kind] ? R : never), ([T[number]] extends [Kind] ? O : never), ([T[number]] extends [Kind] ? E : never), { [I in keyof T]: [T[I]] extends [Kind] ? A : never } - > => F.productAll(components) as any + > => F.productAll(elements) as any /** * @since 1.0.0 diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 70e29a72a..25e70d21a 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -148,14 +148,14 @@ export const appendElement = (F: SemiProduct): { */ export const nonEmptyTuple = (F: SemiProduct) => , ...Array>]>( - ...components: T + ...elements: T ): Kind< F, ([T[number]] extends [Kind] ? R : never), ([T[number]] extends [Kind] ? O : never), ([T[number]] extends [Kind] ? E : never), { [I in keyof T]: [T[I]] extends [Kind] ? A : never } - > => F.productMany(components[0], components.slice(1)) as any + > => F.productMany(elements[0], elements.slice(1)) as any type EnforceNonEmptyRecord = keyof R extends never ? never : R diff --git a/test/Either.ts b/test/Either.ts index a7cd8a83b..ae2c87fdd 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -1,4 +1,4 @@ -import * as _ from "@fp-ts/core/Either" +import * as E from "@fp-ts/core/Either" import { flow, identity, pipe } from "@fp-ts/core/Function" import { structural } from "@fp-ts/core/internal/effect" import * as N from "@fp-ts/core/Number" @@ -8,512 +8,608 @@ import * as Util from "@fp-ts/core/test/util" describe.concurrent("Either", () => { it("exports", () => { - expect(_.toOption).exist - expect(_.getRight).exist - expect(_.getLeft).exist + expect(E.toOption).exist + expect(E.getRight).exist + expect(E.getLeft).exist - expect(_.Invariant).exist - expect(_.tupled).exist - expect(_.bindTo).exist + expect(E.Invariant).exist + expect(E.tupled).exist + expect(E.bindTo).exist - expect(_.Covariant).exist - expect(_.map).exist - expect(_.let).exist - expect(_.flap).exist - expect(_.as).exist - expect(_.asUnit).exist + expect(E.Covariant).exist + expect(E.map).exist + expect(E.let).exist + expect(E.flap).exist + expect(E.as).exist + expect(E.asUnit).exist - expect(_.Bicovariant).exist - expect(_.bimap).exist - expect(_.mapLeft).exist + expect(E.Bicovariant).exist + expect(E.bimap).exist + expect(E.mapLeft).exist - expect(_.Of).exist - expect(_.of).exist - expect(_.unit).exist - expect(_.Do).exist + expect(E.Of).exist + expect(E.of).exist + expect(E.unit).exist + expect(E.Do).exist - expect(_.Pointed).exist + expect(E.Pointed).exist - expect(_.FlatMap).exist - expect(_.flatMap).exist - expect(_.flatten).exist - expect(_.andThen).exist - expect(_.composeKleisliArrow).exist + expect(E.FlatMap).exist + expect(E.flatMap).exist + expect(E.flatten).exist + expect(E.andThen).exist + expect(E.composeKleisliArrow).exist - expect(_.Chainable).exist - expect(_.bind).exist - expect(_.tap).exist - expect(_.andThenDiscard).exist + expect(E.Chainable).exist + expect(E.bind).exist + expect(E.tap).exist + expect(E.andThenDiscard).exist - expect(_.Monad).exist + expect(E.Monad).exist - expect(_.SemiProduct).exist + expect(E.SemiProduct).exist - expect(_.Product).exist - expect(_.tuple).exist - expect(_.struct).exist + expect(E.Product).exist + expect(E.tuple).exist + expect(E.struct).exist - expect(_.SemiApplicative).exist - expect(_.getFirstLeftSemigroup).exist // liftSemigroup - expect(_.lift2).exist - expect(_.ap).exist - expect(_.andThenDiscard).exist - expect(_.andThen).exist + expect(E.SemiApplicative).exist + expect(E.getFirstLeftSemigroup).exist // liftSemigroup + expect(E.lift2).exist + expect(E.ap).exist + expect(E.andThenDiscard).exist + expect(E.andThen).exist - expect(_.Applicative).exist - expect(_.getFirstLeftMonoid).exist // liftMonoid + expect(E.Applicative).exist + expect(E.getFirstLeftMonoid).exist // liftMonoid - expect(_.SemiCoproduct).exist - expect(_.getFirstRightSemigroup).exist // getSemigroup + expect(E.SemiCoproduct).exist + expect(E.getFirstRightSemigroup).exist // getSemigroup - expect(_.SemiAlternative).exist + expect(E.SemiAlternative).exist - expect(_.Foldable).exist + expect(E.Foldable).exist - expect(_.Traversable).exist - expect(_.traverse).exist - expect(_.sequence).exist - expect(_.traverseTap).exist + expect(E.Traversable).exist + expect(E.traverse).exist + expect(E.sequence).exist + expect(E.traverseTap).exist + + expect(E.SemiProductValidated).exist + expect(E.ProductValidated).exist + expect(E.SemiApplicativeValidated).exist + expect(E.ApplicativeValidated).exist }) it("structural tracking", () => { - expect(Util.ownKeys(_.left("a"))).toEqual(["_tag", "left"]) - expect(Util.ownKeys(_.right(1))).toEqual(["_tag", "right"]) + expect(Util.ownKeys(E.left("a"))).toEqual(["_tag", "left"]) + expect(Util.ownKeys(E.right(1))).toEqual(["_tag", "right"]) - expect(Object.prototype.hasOwnProperty.call(_.left("a"), structural)).toEqual(false) - expect(Object.prototype.hasOwnProperty.call(_.right(1), structural)).toEqual(false) + expect(Object.prototype.hasOwnProperty.call(E.left("a"), structural)).toEqual(false) + expect(Object.prototype.hasOwnProperty.call(E.right(1), structural)).toEqual(false) - expect(Util.isStructural(_.left("a"))).toEqual(true) - expect(Util.isStructural(_.right(1))).toEqual(true) + expect(Util.isStructural(E.left("a"))).toEqual(true) + expect(Util.isStructural(E.right(1))).toEqual(true) }) it("toRefinement", () => { - const f = (s: string | number): _.Either => - typeof s === "string" ? _.right(s) : _.left("not a string") - const isString = _.toRefinement(f) + const f = (s: string | number): E.Either => + typeof s === "string" ? E.right(s) : E.left("not a string") + const isString = E.toRefinement(f) Util.deepStrictEqual(isString("s"), true) Util.deepStrictEqual(isString(1), false) type A = { readonly type: "A" } type B = { readonly type: "B" } type C = A | B - const isA = _.toRefinement(( + const isA = E.toRefinement(( c: C - ) => (c.type === "A" ? _.right(c) : _.left("not as A"))) + ) => (c.type === "A" ? E.right(c) : E.left("not as A"))) Util.deepStrictEqual(isA({ type: "A" }), true) Util.deepStrictEqual(isA({ type: "B" }), false) }) it("isEither", () => { - Util.deepStrictEqual(pipe(_.right(1), _.isEither), true) - Util.deepStrictEqual(pipe(_.left("e"), _.isEither), true) - Util.deepStrictEqual(pipe(O.some(1), _.isEither), false) + Util.deepStrictEqual(pipe(E.right(1), E.isEither), true) + Util.deepStrictEqual(pipe(E.left("e"), E.isEither), true) + Util.deepStrictEqual(pipe(O.some(1), E.isEither), false) }) it("orElseFail", () => { - Util.deepStrictEqual(pipe(_.right(1), _.orElseFail(() => "e2")), _.right(1)) - Util.deepStrictEqual(pipe(_.left("e1"), _.orElseFail(() => "e2")), _.left("e2")) + Util.deepStrictEqual(pipe(E.right(1), E.orElseFail(() => "e2")), E.right(1)) + Util.deepStrictEqual(pipe(E.left("e1"), E.orElseFail(() => "e2")), E.left("e2")) }) it("reduce", () => { - Util.deepStrictEqual(pipe(_.right("bar"), _.Foldable.reduce("foo", (b, a) => b + a)), "foobar") - Util.deepStrictEqual(pipe(_.left("bar"), _.Foldable.reduce("foo", (b, a) => b + a)), "foo") + Util.deepStrictEqual(pipe(E.right("bar"), E.Foldable.reduce("foo", (b, a) => b + a)), "foobar") + Util.deepStrictEqual(pipe(E.left("bar"), E.Foldable.reduce("foo", (b, a) => b + a)), "foo") }) it("getRight", () => { - Util.deepStrictEqual(pipe(_.right(1), _.getRight), O.some(1)) - Util.deepStrictEqual(pipe(_.left("a"), _.getRight), O.none()) + Util.deepStrictEqual(pipe(E.right(1), E.getRight), O.some(1)) + Util.deepStrictEqual(pipe(E.left("a"), E.getRight), O.none()) }) it("getLeft", () => { - Util.deepStrictEqual(pipe(_.right(1), _.getLeft), O.none()) - Util.deepStrictEqual(pipe(_.left("e"), _.getLeft), O.some("e")) + Util.deepStrictEqual(pipe(E.right(1), E.getLeft), O.none()) + Util.deepStrictEqual(pipe(E.left("e"), E.getLeft), O.some("e")) }) it("getOrNull", () => { - Util.deepStrictEqual(pipe(_.right(1), _.getOrNull), 1) - Util.deepStrictEqual(pipe(_.left("a"), _.getOrNull), null) + Util.deepStrictEqual(pipe(E.right(1), E.getOrNull), 1) + Util.deepStrictEqual(pipe(E.left("a"), E.getOrNull), null) }) it("getOrUndefined", () => { - Util.deepStrictEqual(pipe(_.right(1), _.getOrUndefined), 1) - Util.deepStrictEqual(pipe(_.left("a"), _.getOrUndefined), undefined) + Util.deepStrictEqual(pipe(E.right(1), E.getOrUndefined), 1) + Util.deepStrictEqual(pipe(E.left("a"), E.getOrUndefined), undefined) }) it("compact", () => { - Util.deepStrictEqual(pipe(_.right(O.some(1)), _.compact(() => "e2")), _.right(1)) - Util.deepStrictEqual(pipe(_.right(O.none()), _.compact(() => "e2")), _.left("e2")) - Util.deepStrictEqual(pipe(_.left("e1"), _.compact(() => "e2")), _.left("e1")) + Util.deepStrictEqual(pipe(E.right(O.some(1)), E.compact(() => "e2")), E.right(1)) + Util.deepStrictEqual(pipe(E.right(O.none()), E.compact(() => "e2")), E.left("e2")) + Util.deepStrictEqual(pipe(E.left("e1"), E.compact(() => "e2")), E.left("e1")) }) it("inspectRight", () => { const log: Array = [] - pipe(_.right(1), _.inspectRight((e) => log.push(e))) - pipe(_.left("e"), _.inspectRight((e) => log.push(e))) + pipe(E.right(1), E.inspectRight((e) => log.push(e))) + pipe(E.left("e"), E.inspectRight((e) => log.push(e))) Util.deepStrictEqual(log, [1]) }) it("tapError", () => { - Util.deepStrictEqual(pipe(_.right(1), _.tapError(() => _.right(2))), _.right(1)) - Util.deepStrictEqual(pipe(_.left("a"), _.tapError(() => _.right(2))), _.left("a")) - Util.deepStrictEqual(pipe(_.left("a"), _.tapError(() => _.left("b"))), _.left("b")) + Util.deepStrictEqual(pipe(E.right(1), E.tapError(() => E.right(2))), E.right(1)) + Util.deepStrictEqual(pipe(E.left("a"), E.tapError(() => E.right(2))), E.left("a")) + Util.deepStrictEqual(pipe(E.left("a"), E.tapError(() => E.left("b"))), E.left("b")) }) it("inspectLeft", () => { const log: Array = [] - pipe(_.right(1), _.inspectLeft((e) => log.push(e))) - pipe(_.left("e"), _.inspectLeft((e) => log.push(e))) + pipe(E.right(1), E.inspectLeft((e) => log.push(e))) + pipe(E.left("e"), E.inspectLeft((e) => log.push(e))) Util.deepStrictEqual(log, ["e"]) }) it("getOrThrow", () => { - expect(pipe(_.right(1), _.getOrThrow)).toEqual(1) - expect(() => pipe(_.left("e"), _.getOrThrow)).toThrowError( + expect(pipe(E.right(1), E.getOrThrow)).toEqual(1) + expect(() => pipe(E.left("e"), E.getOrThrow)).toThrowError( new Error("getOrThrow called on a Left") ) }) it("andThenDiscard", () => { - Util.deepStrictEqual(pipe(_.right(1), _.andThenDiscard(_.right("a"))), _.right(1)) - Util.deepStrictEqual(pipe(_.right(1), _.andThenDiscard(_.left(true))), _.left(true)) - Util.deepStrictEqual(pipe(_.left(1), _.andThenDiscard(_.right("a"))), _.left(1)) - Util.deepStrictEqual(pipe(_.left(1), _.andThenDiscard(_.left(true))), _.left(1)) + Util.deepStrictEqual(pipe(E.right(1), E.andThenDiscard(E.right("a"))), E.right(1)) + Util.deepStrictEqual(pipe(E.right(1), E.andThenDiscard(E.left(true))), E.left(true)) + Util.deepStrictEqual(pipe(E.left(1), E.andThenDiscard(E.right("a"))), E.left(1)) + Util.deepStrictEqual(pipe(E.left(1), E.andThenDiscard(E.left(true))), E.left(1)) }) it("andThen", () => { - Util.deepStrictEqual(pipe(_.right(1), _.andThen(_.right("a"))), _.right("a")) - Util.deepStrictEqual(pipe(_.right(1), _.andThen(_.left(true))), _.left(true)) - Util.deepStrictEqual(pipe(_.left(1), _.andThen(_.right("a"))), _.left(1)) - Util.deepStrictEqual(pipe(_.left(1), _.andThen(_.left(true))), _.left(1)) + Util.deepStrictEqual(pipe(E.right(1), E.andThen(E.right("a"))), E.right("a")) + Util.deepStrictEqual(pipe(E.right(1), E.andThen(E.left(true))), E.left(true)) + Util.deepStrictEqual(pipe(E.left(1), E.andThen(E.right("a"))), E.left(1)) + Util.deepStrictEqual(pipe(E.left(1), E.andThen(E.left(true))), E.left(1)) }) it("orElse", () => { - Util.deepStrictEqual(pipe(_.right(1), _.orElse(() => _.right(2))), _.right(1)) - Util.deepStrictEqual(pipe(_.right(1), _.orElse(() => _.left("b"))), _.right(1)) - Util.deepStrictEqual(pipe(_.left("a"), _.orElse(() => _.right(2))), _.right(2)) - Util.deepStrictEqual(pipe(_.left("a"), _.orElse(() => _.left("b"))), _.left("b")) + Util.deepStrictEqual(pipe(E.right(1), E.orElse(() => E.right(2))), E.right(1)) + Util.deepStrictEqual(pipe(E.right(1), E.orElse(() => E.left("b"))), E.right(1)) + Util.deepStrictEqual(pipe(E.left("a"), E.orElse(() => E.right(2))), E.right(2)) + Util.deepStrictEqual(pipe(E.left("a"), E.orElse(() => E.left("b"))), E.left("b")) }) it("orElseEither", () => { - expect(pipe(_.right(1), _.orElseEither(() => _.right(2)))).toEqual(_.right(_.left(1))) - expect(pipe(_.right(1), _.orElseEither(() => _.left("b")))).toEqual(_.right(_.left(1))) - expect(pipe(_.left("a"), _.orElseEither(() => _.right(2)))).toEqual(_.right(_.right(2))) - expect(pipe(_.left("a"), _.orElseEither(() => _.left("b")))).toEqual(_.left("b")) + expect(pipe(E.right(1), E.orElseEither(() => E.right(2)))).toEqual(E.right(E.left(1))) + expect(pipe(E.right(1), E.orElseEither(() => E.left("b")))).toEqual(E.right(E.left(1))) + expect(pipe(E.left("a"), E.orElseEither(() => E.right(2)))).toEqual(E.right(E.right(2))) + expect(pipe(E.left("a"), E.orElseEither(() => E.left("b")))).toEqual(E.left("b")) }) it("map", () => { - const f = _.map(S.length) - Util.deepStrictEqual(pipe(_.right("abc"), f), _.right(3)) - Util.deepStrictEqual(pipe(_.left("s"), f), _.left("s")) + const f = E.map(S.length) + Util.deepStrictEqual(pipe(E.right("abc"), f), E.right(3)) + Util.deepStrictEqual(pipe(E.left("s"), f), E.left("s")) }) it("flatMap", () => { - const f = _.flatMap(flow(S.length, _.right)) - Util.deepStrictEqual(pipe(_.right("abc"), f), _.right(3)) - Util.deepStrictEqual(pipe(_.left("maError"), f), _.left("maError")) + const f = E.flatMap(flow(S.length, E.right)) + Util.deepStrictEqual(pipe(E.right("abc"), f), E.right(3)) + Util.deepStrictEqual(pipe(E.left("maError"), f), E.left("maError")) }) it("bimap", () => { - const f = _.bimap(S.length, (n: number) => n > 2) - Util.deepStrictEqual(pipe(_.right(1), f), _.right(false)) + const f = E.bimap(S.length, (n: number) => n > 2) + Util.deepStrictEqual(pipe(E.right(1), f), E.right(false)) }) it("mapLeft", () => { - const f = _.mapLeft(Util.double) - Util.deepStrictEqual(pipe(_.right("a"), f), _.right("a")) - Util.deepStrictEqual(pipe(_.left(1), f), _.left(2)) + const f = E.mapLeft(Util.double) + Util.deepStrictEqual(pipe(E.right("a"), f), E.right("a")) + Util.deepStrictEqual(pipe(E.left(1), f), E.left(2)) }) it("traverse", () => { - const traverse = _.traverse(O.Applicative)(( + const traverse = E.traverse(O.Applicative)(( n: number ) => (n >= 2 ? O.some(n) : O.none())) - Util.deepStrictEqual(pipe(_.left("a"), traverse), O.some(_.left("a"))) - Util.deepStrictEqual(pipe(_.right(1), traverse), O.none()) - Util.deepStrictEqual(pipe(_.right(3), traverse), O.some(_.right(3))) + Util.deepStrictEqual(pipe(E.left("a"), traverse), O.some(E.left("a"))) + Util.deepStrictEqual(pipe(E.right(1), traverse), O.none()) + Util.deepStrictEqual(pipe(E.right(3), traverse), O.some(E.right(3))) }) it("sequence", () => { - const sequence = _.sequence(O.Applicative) - Util.deepStrictEqual(sequence(_.right(O.some(1))), O.some(_.right(1))) - Util.deepStrictEqual(sequence(_.left("a")), O.some(_.left("a"))) - Util.deepStrictEqual(sequence(_.right(O.none())), O.none()) + const sequence = E.sequence(O.Applicative) + Util.deepStrictEqual(sequence(E.right(O.some(1))), O.some(E.right(1))) + Util.deepStrictEqual(sequence(E.left("a")), O.some(E.left("a"))) + Util.deepStrictEqual(sequence(E.right(O.none())), O.none()) }) it("match", () => { const f = (s: string) => `left${s.length}` const g = (s: string) => `right${s.length}` - const match = _.match(f, g) - Util.deepStrictEqual(match(_.left("abc")), "left3") - Util.deepStrictEqual(match(_.right("abc")), "right3") + const match = E.match(f, g) + Util.deepStrictEqual(match(E.left("abc")), "left3") + Util.deepStrictEqual(match(E.right("abc")), "right3") }) it("getOrElse", () => { - Util.deepStrictEqual(pipe(_.right(12), _.getOrElse(() => 17)), 12) - Util.deepStrictEqual(pipe(_.left("a"), _.getOrElse(() => 17)), 17) + Util.deepStrictEqual(pipe(E.right(12), E.getOrElse(() => 17)), 12) + Util.deepStrictEqual(pipe(E.left("a"), E.getOrElse(() => 17)), 17) }) it("contains", () => { - const contains = _.contains(N.Equivalence) - Util.deepStrictEqual(pipe(_.left("a"), contains(2)), false) - Util.deepStrictEqual(pipe(_.right(2), contains(2)), true) - Util.deepStrictEqual(pipe(_.right(2), contains(1)), false) + const contains = E.contains(N.Equivalence) + Util.deepStrictEqual(pipe(E.left("a"), contains(2)), false) + Util.deepStrictEqual(pipe(E.right(2), contains(2)), true) + Util.deepStrictEqual(pipe(E.right(2), contains(1)), false) }) it("filter", () => { const predicate = (n: number) => n > 10 - Util.deepStrictEqual(pipe(_.right(12), _.filter(predicate, () => -1)), _.right(12)) - Util.deepStrictEqual(pipe(_.right(7), _.filter(predicate, () => -1)), _.left(-1)) - Util.deepStrictEqual(pipe(_.left(12), _.filter(predicate, () => -1)), _.left(12)) + Util.deepStrictEqual(pipe(E.right(12), E.filter(predicate, () => -1)), E.right(12)) + Util.deepStrictEqual(pipe(E.right(7), E.filter(predicate, () => -1)), E.left(-1)) + Util.deepStrictEqual(pipe(E.left(12), E.filter(predicate, () => -1)), E.left(12)) }) it("isLeft", () => { - Util.deepStrictEqual(_.isLeft(_.right(1)), false) - Util.deepStrictEqual(_.isLeft(_.left(1)), true) + Util.deepStrictEqual(E.isLeft(E.right(1)), false) + Util.deepStrictEqual(E.isLeft(E.left(1)), true) }) it("isRight", () => { - Util.deepStrictEqual(_.isRight(_.right(1)), true) - Util.deepStrictEqual(_.isRight(_.left(1)), false) + Util.deepStrictEqual(E.isRight(E.right(1)), true) + Util.deepStrictEqual(E.isRight(E.left(1)), false) }) it("swap", () => { - Util.deepStrictEqual(_.reverse(_.right("a")), _.left("a")) - Util.deepStrictEqual(_.reverse(_.left("b")), _.right("b")) + Util.deepStrictEqual(E.reverse(E.right("a")), E.left("a")) + Util.deepStrictEqual(E.reverse(E.left("b")), E.right("b")) }) it("liftPredicate", () => { - const f = _.liftPredicate((n: number) => n >= 2, () => "e") - Util.deepStrictEqual(f(3), _.right(3)) - Util.deepStrictEqual(f(1), _.left("e")) + const f = E.liftPredicate((n: number) => n >= 2, () => "e") + Util.deepStrictEqual(f(3), E.right(3)) + Util.deepStrictEqual(f(1), E.left("e")) }) it("fromNullable", () => { - Util.deepStrictEqual(_.fromNullable(() => "default")(null), _.left("default")) - Util.deepStrictEqual(_.fromNullable(() => "default")(undefined), _.left("default")) - Util.deepStrictEqual(_.fromNullable(() => "default")(1), _.right(1)) + Util.deepStrictEqual(E.fromNullable(() => "default")(null), E.left("default")) + Util.deepStrictEqual(E.fromNullable(() => "default")(undefined), E.left("default")) + Util.deepStrictEqual(E.fromNullable(() => "default")(1), E.right(1)) }) it("filterMap", () => { const p = (n: number) => n > 2 const f = (n: number) => (p(n) ? O.some(n + 1) : O.none()) - Util.deepStrictEqual(pipe(_.left("123"), _.filterMap(f, () => "")), _.left("123")) - Util.deepStrictEqual(pipe(_.right(1), _.filterMap(f, () => "")), _.left(S.Monoid.empty)) - Util.deepStrictEqual(pipe(_.right(3), _.filterMap(f, () => "")), _.right(4)) + Util.deepStrictEqual(pipe(E.left("123"), E.filterMap(f, () => "")), E.left("123")) + Util.deepStrictEqual(pipe(E.right(1), E.filterMap(f, () => "")), E.left(S.Monoid.empty)) + Util.deepStrictEqual(pipe(E.right(3), E.filterMap(f, () => "")), E.right(4)) }) it("fromIterable", () => { - Util.deepStrictEqual(_.fromIterable(() => "e")([]), _.left("e")) - Util.deepStrictEqual(_.fromIterable(() => "e")(["a"]), _.right("a")) + Util.deepStrictEqual(E.fromIterable(() => "e")([]), E.left("e")) + Util.deepStrictEqual(E.fromIterable(() => "e")(["a"]), E.right("a")) }) it("firstRightOf", () => { - Util.deepStrictEqual(pipe(_.right(1), _.firstRightOf([])), _.right(1)) - Util.deepStrictEqual(pipe(_.left("e"), _.firstRightOf([])), _.left("e")) + Util.deepStrictEqual(pipe(E.right(1), E.firstRightOf([])), E.right(1)) + Util.deepStrictEqual(pipe(E.left("e"), E.firstRightOf([])), E.left("e")) Util.deepStrictEqual( - pipe(_.left("e1"), _.firstRightOf([_.left("e2"), _.left("e3"), _.left("e4"), _.right(1)])), - _.right(1) + pipe(E.left("e1"), E.firstRightOf([E.left("e2"), E.left("e3"), E.left("e4"), E.right(1)])), + E.right(1) ) Util.deepStrictEqual( - pipe(_.left("e1"), _.firstRightOf([_.left("e2"), _.left("e3"), _.left("e4")])), - _.left("e4") + pipe(E.left("e1"), E.firstRightOf([E.left("e2"), E.left("e3"), E.left("e4")])), + E.left("e4") ) }) it("fromOption", () => { - Util.deepStrictEqual(_.fromOption(() => "none")(O.none()), _.left("none")) - Util.deepStrictEqual(_.fromOption(() => "none")(O.some(1)), _.right(1)) + Util.deepStrictEqual(E.fromOption(() => "none")(O.none()), E.left("none")) + Util.deepStrictEqual(E.fromOption(() => "none")(O.some(1)), E.right(1)) }) it("liftOption", () => { - const f = _.liftOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "a") - Util.deepStrictEqual(f(1), _.right(1)) - Util.deepStrictEqual(f(-1), _.left("a")) + const f = E.liftOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "a") + Util.deepStrictEqual(f(1), E.right(1)) + Util.deepStrictEqual(f(-1), E.left("a")) }) it("flatMapOption", () => { - const f = _.flatMapOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "a") - Util.deepStrictEqual(f(_.right(1)), _.right(1)) - Util.deepStrictEqual(f(_.right(-1)), _.left("a")) - Util.deepStrictEqual(f(_.left("b")), _.left("b")) + const f = E.flatMapOption((n: number) => (n > 0 ? O.some(n) : O.none()), () => "a") + Util.deepStrictEqual(f(E.right(1)), E.right(1)) + Util.deepStrictEqual(f(E.right(-1)), E.left("a")) + Util.deepStrictEqual(f(E.left("b")), E.left("b")) }) it("exists", () => { - const gt2 = _.exists((n: number) => n > 2) - Util.deepStrictEqual(gt2(_.left("a")), false) - Util.deepStrictEqual(gt2(_.right(1)), false) - Util.deepStrictEqual(gt2(_.right(3)), true) + const gt2 = E.exists((n: number) => n > 2) + Util.deepStrictEqual(gt2(E.left("a")), false) + Util.deepStrictEqual(gt2(E.right(1)), false) + Util.deepStrictEqual(gt2(E.right(3)), true) }) it("do notation", () => { Util.deepStrictEqual( pipe( - _.right(1), - _.bindTo("a"), - _.bind("b", () => _.right("b")), - _.let("c", ({ a, b }) => [a, b]) + E.right(1), + E.bindTo("a"), + E.bind("b", () => E.right("b")), + E.let("c", ({ a, b }) => [a, b]) ), - _.right({ a: 1, b: "b", c: [1, "b"] }) + E.right({ a: 1, b: "b", c: [1, "b"] }) ) }) it("andThenBind", () => { Util.deepStrictEqual( - pipe(_.right(1), _.bindTo("a"), _.andThenBind("b", _.right("b"))), - _.right({ a: 1, b: "b" }) + pipe(E.right(1), E.bindTo("a"), E.andThenBind("b", E.right("b"))), + E.right({ a: 1, b: "b" }) ) }) it("product", () => { - const product = _.SemiProduct.product - Util.deepStrictEqual(product(_.right(1), _.right("a")), _.right([1, "a"])) - Util.deepStrictEqual(product(_.right(1), _.left("e2")), _.left("e2")) - Util.deepStrictEqual(product(_.left("e1"), _.right("a")), _.left("e1")) - Util.deepStrictEqual(product(_.left("e1"), _.left("2")), _.left("e1")) + const product = E.SemiProduct.product + Util.deepStrictEqual(product(E.right(1), E.right("a")), E.right([1, "a"])) + Util.deepStrictEqual(product(E.right(1), E.left("e2")), E.left("e2")) + Util.deepStrictEqual(product(E.left("e1"), E.right("a")), E.left("e1")) + Util.deepStrictEqual(product(E.left("e1"), E.left("2")), E.left("e1")) }) it("productMany", () => { const productMany: ( - self: _.Either, - collection: Iterable<_.Either> - ) => _.Either]> = _.SemiProduct.productMany + self: E.Either, + collection: Iterable> + ) => E.Either]> = E.SemiProduct.productMany - Util.deepStrictEqual(productMany(_.right(1), []), _.right([1])) + Util.deepStrictEqual(productMany(E.right(1), []), E.right([1])) Util.deepStrictEqual( - productMany(_.right(1), [_.right(2), _.right(3)]), - _.right([1, 2, 3]) + productMany(E.right(1), [E.right(2), E.right(3)]), + E.right([1, 2, 3]) ) Util.deepStrictEqual( - productMany(_.right(1), [_.left("e"), _.right(3)]), - _.left("e") + productMany(E.right(1), [E.left("e"), E.right(3)]), + E.left("e") ) expect( - productMany(_.left("e"), [_.right(2), _.right(3)]) - ).toEqual(_.left("e")) + productMany(E.left("e"), [E.right(2), E.right(3)]) + ).toEqual(E.left("e")) }) it("productAll", () => { - const productAll = _.Product.productAll - Util.deepStrictEqual(productAll([]), _.right([])) + const productAll = E.Product.productAll + Util.deepStrictEqual(productAll([]), E.right([])) Util.deepStrictEqual( - productAll([_.right(1), _.right(2), _.right(3)]), - _.right([1, 2, 3]) + productAll([E.right(1), E.right(2), E.right(3)]), + E.right([1, 2, 3]) ) Util.deepStrictEqual( - productAll([_.left("e"), _.right(2), _.right(3)]), - _.left("e") + productAll([E.left("e"), E.right(2), E.right(3)]), + E.left("e") ) }) it("coproduct", () => { - const coproduct = _.SemiCoproduct.coproduct - Util.deepStrictEqual(coproduct(_.right(1), _.right(2)), _.right(1)) - Util.deepStrictEqual(coproduct(_.right(1), _.left("e2")), _.right(1)) - Util.deepStrictEqual(coproduct(_.left("e1"), _.right(2)), _.right(2)) - Util.deepStrictEqual(coproduct(_.left("e1"), _.left("e2")), _.left("e2")) + const coproduct = E.SemiCoproduct.coproduct + Util.deepStrictEqual(coproduct(E.right(1), E.right(2)), E.right(1)) + Util.deepStrictEqual(coproduct(E.right(1), E.left("e2")), E.right(1)) + Util.deepStrictEqual(coproduct(E.left("e1"), E.right(2)), E.right(2)) + Util.deepStrictEqual(coproduct(E.left("e1"), E.left("e2")), E.left("e2")) }) it("coproductMany", () => { - const coproductMany = _.SemiCoproduct.coproductMany - Util.deepStrictEqual(coproductMany(_.right(1), [_.right(2)]), _.right(1)) + const coproductMany = E.SemiCoproduct.coproductMany + Util.deepStrictEqual(coproductMany(E.right(1), [E.right(2)]), E.right(1)) Util.deepStrictEqual( - coproductMany(_.right(1), [_.left("e2")]), - _.right(1) + coproductMany(E.right(1), [E.left("e2")]), + E.right(1) ) - Util.deepStrictEqual(coproductMany(_.left("e1"), [_.right(2)]), _.right(2)) - Util.deepStrictEqual(coproductMany(_.left("e1"), [_.left("e2")]), _.left("e2")) + Util.deepStrictEqual(coproductMany(E.left("e1"), [E.right(2)]), E.right(2)) + Util.deepStrictEqual(coproductMany(E.left("e1"), [E.left("e2")]), E.left("e2")) }) it("element", () => { - expect(pipe(_.right(1), _.tupled, _.appendElement(_.right("b")))).toEqual( - _.right([1, "b"]) + expect(pipe(E.right(1), E.tupled, E.appendElement(E.right("b")))).toEqual( + E.right([1, "b"]) ) }) it("liftNullable", () => { - const f = _.liftNullable((n: number) => (n > 0 ? n : null), () => "error") - Util.deepStrictEqual(f(1), _.right(1)) - Util.deepStrictEqual(f(-1), _.left("error")) + const f = E.liftNullable((n: number) => (n > 0 ? n : null), () => "error") + Util.deepStrictEqual(f(1), E.right(1)) + Util.deepStrictEqual(f(-1), E.left("error")) }) it("flatMapNullable", () => { - const f = _.flatMapNullable((n: number) => (n > 0 ? n : null), () => "error") - Util.deepStrictEqual(f(_.right(1)), _.right(1)) - Util.deepStrictEqual(f(_.right(-1)), _.left("error")) - Util.deepStrictEqual(f(_.left("a")), _.left("a")) + const f = E.flatMapNullable((n: number) => (n > 0 ? n : null), () => "error") + Util.deepStrictEqual(f(E.right(1)), E.right(1)) + Util.deepStrictEqual(f(E.right(-1)), E.left("error")) + Util.deepStrictEqual(f(E.left("a")), E.left("a")) }) it("merge", () => { - Util.deepStrictEqual(_.merge(_.right(1)), 1) - Util.deepStrictEqual(_.merge(_.left("a")), "a") + Util.deepStrictEqual(E.merge(E.right(1)), 1) + Util.deepStrictEqual(E.merge(E.left("a")), "a") }) it("liftThrowable", () => { - const f = _.liftThrowable((s: string) => { + const f = E.liftThrowable((s: string) => { const len = s.length if (len > 0) { return len } throw new Error("empty string") }, identity) - Util.deepStrictEqual(f("a"), _.right(1)) - Util.deepStrictEqual(f(""), _.left(new Error("empty string"))) + Util.deepStrictEqual(f("a"), E.right(1)) + Util.deepStrictEqual(f(""), E.left(new Error("empty string"))) }) it("zipWith", () => { - expect(pipe(_.left("a"), _.zipWith(_.right(2), (a, b) => a + b))).toEqual(_.left("a")) - expect(pipe(_.right(1), _.zipWith(_.left("a"), (a, b) => a + b))).toEqual(_.left("a")) - expect(pipe(_.right(1), _.zipWith(_.right(2), (a, b) => a + b))).toEqual(_.right(3)) + expect(pipe(E.left("a"), E.zipWith(E.right(2), (a, b) => a + b))).toEqual(E.left("a")) + expect(pipe(E.right(1), E.zipWith(E.left("a"), (a, b) => a + b))).toEqual(E.left("a")) + expect(pipe(E.right(1), E.zipWith(E.right(2), (a, b) => a + b))).toEqual(E.right(3)) }) it("sum", () => { - expect(pipe(_.left("a"), _.sum(_.right(2)))).toEqual(_.left("a")) - expect(pipe(_.right(1), _.sum(_.left("a")))).toEqual(_.left("a")) - expect(pipe(_.right(2), _.sum(_.right(3)))).toEqual(_.right(5)) + expect(pipe(E.left("a"), E.sum(E.right(2)))).toEqual(E.left("a")) + expect(pipe(E.right(1), E.sum(E.left("a")))).toEqual(E.left("a")) + expect(pipe(E.right(2), E.sum(E.right(3)))).toEqual(E.right(5)) }) it("multiply", () => { - expect(pipe(_.left("a"), _.multiply(_.right(2)))).toEqual(_.left("a")) - expect(pipe(_.right(1), _.multiply(_.left("a")))).toEqual(_.left("a")) - expect(pipe(_.right(2), _.multiply(_.right(3)))).toEqual(_.right(6)) + expect(pipe(E.left("a"), E.multiply(E.right(2)))).toEqual(E.left("a")) + expect(pipe(E.right(1), E.multiply(E.left("a")))).toEqual(E.left("a")) + expect(pipe(E.right(2), E.multiply(E.right(3)))).toEqual(E.right(6)) }) it("subtract", () => { - expect(pipe(_.left("a"), _.subtract(_.right(2)))).toEqual(_.left("a")) - expect(pipe(_.right(1), _.subtract(_.left("a")))).toEqual(_.left("a")) - expect(pipe(_.right(2), _.subtract(_.right(3)))).toEqual(_.right(-1)) + expect(pipe(E.left("a"), E.subtract(E.right(2)))).toEqual(E.left("a")) + expect(pipe(E.right(1), E.subtract(E.left("a")))).toEqual(E.left("a")) + expect(pipe(E.right(2), E.subtract(E.right(3)))).toEqual(E.right(-1)) }) it("divide", () => { - expect(pipe(_.left("a"), _.divide(_.right(2)))).toEqual(_.left("a")) - expect(pipe(_.right(1), _.divide(_.left("a")))).toEqual(_.left("a")) - expect(pipe(_.right(6), _.divide(_.right(3)))).toEqual(_.right(2)) + expect(pipe(E.left("a"), E.divide(E.right(2)))).toEqual(E.left("a")) + expect(pipe(E.right(1), E.divide(E.left("a")))).toEqual(E.left("a")) + expect(pipe(E.right(6), E.divide(E.right(3)))).toEqual(E.right(2)) }) it("getOptionalSemigroup", () => { - const OS = _.getOptionalSemigroup(S.Semigroup) - Util.deepStrictEqual(OS.combine(_.left("e"), _.left("e")), _.left("e")) - Util.deepStrictEqual(OS.combine(_.left("e"), _.right("a")), _.right("a")) - Util.deepStrictEqual(OS.combine(_.right("a"), _.left("e")), _.right("a")) - Util.deepStrictEqual(OS.combine(_.right("b"), _.right("a")), _.right("ba")) - Util.deepStrictEqual(OS.combine(_.right("a"), _.right("b")), _.right("ab")) + const OS = E.getOptionalSemigroup(S.Semigroup) + Util.deepStrictEqual(OS.combine(E.left("e"), E.left("e")), E.left("e")) + Util.deepStrictEqual(OS.combine(E.left("e"), E.right("a")), E.right("a")) + Util.deepStrictEqual(OS.combine(E.right("a"), E.left("e")), E.right("a")) + Util.deepStrictEqual(OS.combine(E.right("b"), E.right("a")), E.right("ba")) + Util.deepStrictEqual(OS.combine(E.right("a"), E.right("b")), E.right("ab")) - Util.deepStrictEqual(OS.combineMany(_.right("a"), [_.right("b")]), _.right("ab")) - Util.deepStrictEqual(OS.combineMany(_.left("e"), [_.right("b")]), _.right("b")) - Util.deepStrictEqual(OS.combineMany(_.right("a"), [_.left("e")]), _.right("a")) + Util.deepStrictEqual(OS.combineMany(E.right("a"), [E.right("b")]), E.right("ab")) + Util.deepStrictEqual(OS.combineMany(E.left("e"), [E.right("b")]), E.right("b")) + Util.deepStrictEqual(OS.combineMany(E.right("a"), [E.left("e")]), E.right("a")) }) it("getEquivalence", () => { - const isEquivalent = _.getEquivalence(S.Equivalence, N.Equivalence) - Util.deepStrictEqual(isEquivalent(_.right(1), _.right(1)), true) - Util.deepStrictEqual(isEquivalent(_.right(1), _.right(2)), false) - Util.deepStrictEqual(isEquivalent(_.right(1), _.left("foo")), false) - Util.deepStrictEqual(isEquivalent(_.left("foo"), _.left("foo")), true) - Util.deepStrictEqual(isEquivalent(_.left("foo"), _.left("bar")), false) - Util.deepStrictEqual(isEquivalent(_.left("foo"), _.right(1)), false) + const isEquivalent = E.getEquivalence(S.Equivalence, N.Equivalence) + Util.deepStrictEqual(isEquivalent(E.right(1), E.right(1)), true) + Util.deepStrictEqual(isEquivalent(E.right(1), E.right(2)), false) + Util.deepStrictEqual(isEquivalent(E.right(1), E.left("foo")), false) + Util.deepStrictEqual(isEquivalent(E.left("foo"), E.left("foo")), true) + Util.deepStrictEqual(isEquivalent(E.left("foo"), E.left("bar")), false) + Util.deepStrictEqual(isEquivalent(E.left("foo"), E.right(1)), false) }) it("toArray", () => { - expect(_.toArray(_.right(1))).toEqual([1]) - expect(_.toArray(_.left("error"))).toEqual([]) + expect(E.toArray(E.right(1))).toEqual([1]) + expect(E.toArray(E.left("error"))).toEqual([]) + }) + + it("toValidated", () => { + assert.deepStrictEqual(E.toValidated(E.right(1)), E.right(1)) + assert.deepStrictEqual(E.toValidated(E.left("e")), E.left(["e"])) + }) + + it("liftEither", () => { + const f = (n: number) => n >= 0 ? E.right(n) : E.left("negative number") + const g = E.liftEither(f) + assert.deepStrictEqual(g(1), E.right(1)) + assert.deepStrictEqual(g(-1), E.left(["negative number"])) + }) + + it("tupleValidated", () => { + assert.deepStrictEqual( + E.tupleValidated( + E.right(1), + E.right("hello") + ), + E.right([1, "hello"]) + ) + assert.deepStrictEqual( + E.tupleValidated( + E.fail("error1"), + E.fail("error2") + ), + E.left(["error1", "error2"]) + ) + }) + + it("structValidated", () => { + assert.deepStrictEqual( + E.structValidated({ + x: E.right(1), + y: E.right("hello") + }), + E.right({ x: 1, y: "hello" }) + ) + + assert.deepStrictEqual( + E.structValidated({ + x: E.fail("error1"), + y: E.fail("error2") + }), + E.left(["error1", "error2"]) + ) + }) + + it("zipWithValidated", () => { + assert.deepStrictEqual( + E.zipWithValidated( + E.right(1), + E.right(2), + N.sum + ), + E.right(3) + ) + + assert.deepStrictEqual( + E.zipWithValidated( + E.fail("error1"), + E.right(2), + N.sum + ), + E.fail("error1") + ) + + assert.deepStrictEqual( + E.zipWithValidated( + E.right(1), + E.fail("error2"), + N.sum + ), + E.fail("error2") + ) + + assert.deepStrictEqual( + E.zipWithValidated( + E.fail("error1"), + E.fail("error2"), + N.sum + ), + E.left(["error1", "error2"]) + ) + }) + + it("lift2Validated", () => { + const sum = E.lift2Validated(N.sum) + assert.deepStrictEqual(sum(E.right(1), E.right(2)), E.right(3)) + assert.deepStrictEqual(sum(E.fail("error1"), E.fail("error2")), E.left(["error1", "error2"])) }) }) From 1c961e3ccf071c40f1bcb307c5a6b6283375e28f Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 7 Feb 2023 05:30:38 +0100 Subject: [PATCH 214/255] add dual benchmark --- .eslintrc.cjs | 2 +- benchmark/dual.ts | 36 ++++++++++++++++++++++++++++++++++++ benchmark/tsconfig.json | 12 ++++++++++++ package.json | 1 + pnpm-lock.yaml | 13 +++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 benchmark/dual.ts create mode 100644 benchmark/tsconfig.json diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 2b0d2ed61..b64903406 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,6 +1,6 @@ /* eslint-disable no-undef */ module.exports = { - ignorePatterns: ["build", "dist", "dtslint", "*.mjs", "docs", "*.md"], + ignorePatterns: ["build", "dist", "dtslint", "benchmark", "*.mjs", "docs", "*.md"], parser: "@typescript-eslint/parser", parserOptions: { ecmaVersion: 2018, diff --git a/benchmark/dual.ts b/benchmark/dual.ts new file mode 100644 index 000000000..d48824b63 --- /dev/null +++ b/benchmark/dual.ts @@ -0,0 +1,36 @@ +import { sum } from "@fp-ts/core/Number" +import * as Benchmark from "benchmark" + +/* +sum(a, b) x 39,807,035 ops/sec ±0.79% (87 runs sampled) +binary(a, b) x 745,618,052 ops/sec ±0.53% (91 runs sampled) +sum(b)(a) x 2,423,147 ops/sec ±1.50% (82 runs sampled) +curried(b)(a) x 737,608,819 ops/sec ±0.60% (88 runs sampled) +*/ + +const suite = new Benchmark.Suite() + +const binary = (a: number, b: number): number => a + b + +const curried = (a: number) => (b: number): number => a + b + +suite + .add("sum(a, b)", function() { + sum(1, 2) + }) + .add("binary(a, b)", function() { + binary(1, 2) + }) + .add("sum(b)(a)", function() { + sum(2)(1) + }) + .add("curried(b)(a)", function() { + curried(2)(1) + }) + .on("cycle", function(event: any) { + console.log(String(event.target)) + }) + .on("complete", function(this: any) { + console.log("Fastest is " + this.filter("fastest").map("name")) + }) + .run({ async: true }) diff --git a/benchmark/tsconfig.json b/benchmark/tsconfig.json new file mode 100644 index 000000000..7836b3af8 --- /dev/null +++ b/benchmark/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "strict": true, + "module": "commonjs", + "paths": { + "@fp-ts/core": ["../src/index.ts"], + "@fp-ts/core/test/*": ["../test/*"], + "@fp-ts/core/examples/*": ["../examples/*"], + "@fp-ts/core/*": ["../src/*"] + } + } +} diff --git a/package.json b/package.json index 75890dad2..2e19f0f09 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "@typescript-eslint/parser": "^5.44.0", "@vitest/coverage-c8": "^0.27.1", "babel-plugin-annotate-pure-calls": "^0.4.0", + "benchmark": "^2.1.4", "c8": "^7.11.3", "concurrently": "^7.6.0", "cpx": "^1.5.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e0753f6a8..8a3e9567f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,6 +31,7 @@ importers: '@typescript-eslint/parser': ^5.44.0 '@vitest/coverage-c8': ^0.27.1 babel-plugin-annotate-pure-calls: ^0.4.0 + benchmark: ^2.1.4 c8: ^7.11.3 concurrently: ^7.6.0 cpx: ^1.5.0 @@ -75,6 +76,7 @@ importers: '@typescript-eslint/parser': 5.44.0_hsf322ms6xhhd4b5ne6lb74y4a '@vitest/coverage-c8': 0.27.1 babel-plugin-annotate-pure-calls: 0.4.0_@babel+core@7.20.5 + benchmark: 2.1.4 c8: 7.12.0 concurrently: 7.6.0 cpx: 1.5.0 @@ -1600,6 +1602,13 @@ packages: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} dev: true + /benchmark/2.1.4: + resolution: {integrity: sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==} + dependencies: + lodash: 4.17.21 + platform: 1.3.6 + dev: true + /better-path-resolve/1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} @@ -5377,6 +5386,10 @@ packages: pathe: 1.0.0 dev: true + /platform/1.3.6: + resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==} + dev: true + /pluralize/8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} From ea53fd9f2f71d6b328d584ce56bae093c1f57340 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 7 Feb 2023 06:05:23 +0100 Subject: [PATCH 215/255] refactor Equivalence --- docs/modules/typeclass/Equivalence.ts.md | 3 +-- src/typeclass/Equivalence.ts | 15 ++++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/modules/typeclass/Equivalence.ts.md b/docs/modules/typeclass/Equivalence.ts.md index 84d517f18..24453aec6 100644 --- a/docs/modules/typeclass/Equivalence.ts.md +++ b/docs/modules/typeclass/Equivalence.ts.md @@ -131,7 +131,7 @@ Added in v1.0.0 ## strict -Return an `Equivalence` that uses strict equality (===) to compare values +Return an `Equivalence` that uses strict equality (===) to compare values. **Signature** @@ -261,7 +261,6 @@ Added in v1.0.0 ```ts export interface Equivalence { - (that: A): (self: A) => boolean (self: A, that: A): boolean } ``` diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index c0bf8995c..a2e7efd6b 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -22,7 +22,6 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Equivalence { - (that: A): (self: A) => boolean (self: A, that: A): boolean } @@ -39,15 +38,17 @@ export interface EquivalenceTypeLambda extends TypeLambda { * @since 1.0.0 */ export const make = (isEquivalent: (self: A, that: A) => boolean): Equivalence => - dual(2, (self: A, that: A): boolean => self === that || isEquivalent(self, that)) + (self: A, that: A): boolean => self === that || isEquivalent(self, that) + +const isStrictEquivalent = (x: unknown, y: unknown) => x === y /** - * Return an `Equivalence` that uses strict equality (===) to compare values + * Return an `Equivalence` that uses strict equality (===) to compare values. * * @since 1.0.0 * @category constructors */ -export const strict: () => Equivalence = () => dual(2, (x, y) => x === y) +export const strict: () => Equivalence = () => isStrictEquivalent /** * @category instances @@ -168,14 +169,14 @@ export const getSemigroup = (): Semigroup> => }) ) -const empty: Equivalence = dual(2, (_x, _y) => true) +const isAlwaysEquivalent: Equivalence = (_x, _y) => true /** * @category instances * @since 1.0.0 */ export const getMonoid = (): Monoid> => - monoid.fromSemigroup(getSemigroup(), empty) + monoid.fromSemigroup(getSemigroup(), isAlwaysEquivalent) /** * @category combinators @@ -235,7 +236,7 @@ export const SemiProduct: semiProduct.SemiProduct = { productMany } -const of: (a: A) => Equivalence = () => empty +const of: (a: A) => Equivalence = () => isAlwaysEquivalent const productAll = (collection: Iterable>): Equivalence> => tuple>(...collection) From 2537fc7f349d2c893b635febb7e5ea391ea3d549 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 7 Feb 2023 06:36:11 +0100 Subject: [PATCH 216/255] refactor Semigroup --- benchmark/sumAll.ts | 27 +++++++++++++ docs/modules/typeclass/Monoid.ts.md | 16 ++++---- docs/modules/typeclass/Semigroup.ts.md | 37 +++++------------- src/Bigint.ts | 4 +- src/Boolean.ts | 4 +- src/Either.ts | 2 +- src/Identity.ts | 4 +- src/Number.ts | 4 +- src/Option.ts | 2 +- src/ReadonlyArray.ts | 13 ++----- src/String.ts | 2 +- src/typeclass/Monoid.ts | 5 ++- src/typeclass/Semigroup.ts | 54 +++++++++----------------- test/typeclass/Monoid.ts | 2 +- test/typeclass/Semigroup.ts | 2 +- 15 files changed, 82 insertions(+), 96 deletions(-) create mode 100644 benchmark/sumAll.ts diff --git a/benchmark/sumAll.ts b/benchmark/sumAll.ts new file mode 100644 index 000000000..e43db8427 --- /dev/null +++ b/benchmark/sumAll.ts @@ -0,0 +1,27 @@ +import { fromIterable } from "@fp-ts/core/internal/ReadonlyArray" +import { sumAll } from "@fp-ts/core/Number" +import * as Benchmark from "benchmark" + +/* +sumAll x 98,318,148 ops/sec ±0.46% (91 runs sampled) +sum x 104,495,149 ops/sec ±0.76% (90 runs sampled) +*/ + +const suite = new Benchmark.Suite() + +const sum = (collection: Iterable): number => fromIterable(collection).reduce((a, b) => a + b, 0) + +suite + .add("sumAll", function() { + sumAll([1, 2, 3, 4, 5]) + }) + .add("sum", function() { + sum([1, 2, 3, 4, 5]) + }) + .on("cycle", function(event: any) { + console.log(String(event.target)) + }) + .on("complete", function(this: any) { + console.log("Fastest is " + this.filter("fastest").map("name")) + }) + .run({ async: true }) diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index e4b4ace50..33f2df032 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -14,7 +14,7 @@ Added in v1.0.0 - [combinators](#combinators) - [array](#array) - - [readonlyArray](#readonlyarray) + - [mutableArray](#mutablearray) - [reverse](#reverse) - [struct](#struct) - [tuple](#tuple) @@ -39,26 +39,26 @@ Added in v1.0.0 ## array -Given a type `A`, this function creates and returns a `Monoid` for `Array`. -The returned `Monoid`'s `empty` value is the empty array. +Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. +The returned `Monoid`'s empty value is the empty array. **Signature** ```ts -export declare const array: () => Monoid +export declare const array: () => Monoid ``` Added in v1.0.0 -## readonlyArray +## mutableArray -Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. -The returned `Monoid`'s empty value is the empty array. +Given a type `A`, this function creates and returns a `Monoid` for `Array`. +The returned `Monoid`'s `empty` value is the empty array. **Signature** ```ts -export declare const readonlyArray: () => Monoid +export declare const mutableArray: () => Monoid ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index 294bb8219..d0ba8345b 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -14,12 +14,11 @@ Added in v1.0.0 - [combinators](#combinators) - [array](#array) - - [readonlyArray](#readonlyarray) + - [mutableArray](#mutablearray) - [struct](#struct) - [tuple](#tuple) - [constructors](#constructors) - [constant](#constant) - - [fromCombine](#fromcombine) - [make](#make) - [max](#max) - [min](#min) @@ -51,26 +50,26 @@ Added in v1.0.0 ## array -Given a type `A`, this function creates and returns a `Semigroup` for `Array`. +Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. The returned `Semigroup` combines two arrays by concatenating them. **Signature** ```ts -export declare const array: () => Semigroup +export declare const array: () => Semigroup ``` Added in v1.0.0 -## readonlyArray +## mutableArray -Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. +Given a type `A`, this function creates and returns a `Semigroup` for `Array`. The returned `Semigroup` combines two arrays by concatenating them. **Signature** ```ts -export declare const readonlyArray: () => Semigroup +export declare const mutableArray: () => Semigroup ``` Added in v1.0.0 @@ -121,18 +120,6 @@ export declare const constant: (a: A) => Semigroup Added in v1.0.0 -## fromCombine - -Useful when `combineMany` can't be optimised. - -**Signature** - -```ts -export declare const fromCombine: (combine: (self: A, that: A) => A) => Semigroup -``` - -Added in v1.0.0 - ## make **Signature** @@ -140,7 +127,7 @@ Added in v1.0.0 ```ts export declare const make: ( combine: (self: A, that: A) => A, - combineMany: (self: A, collection: Iterable) => A + combineMany?: (self: A, collection: Iterable) => A ) => Semigroup ``` @@ -316,14 +303,8 @@ Added in v1.0.0 ```ts export interface Semigroup { - readonly combine: { - (that: A): (self: A) => A - (self: A, that: A): A - } - readonly combineMany: { - (collection: Iterable): (self: A) => A - (self: A, collection: Iterable): A - } + readonly combine: (self: A, that: A) => A + readonly combineMany: (self: A, collection: Iterable) => A } ``` diff --git a/src/Bigint.ts b/src/Bigint.ts index dd2df7a1f..cd8edb700 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -26,7 +26,7 @@ export const isBigint: (u: unknown) => u is bigint = predicate.isBigint export const sum: { (that: bigint): (self: bigint) => bigint (self: bigint, that: bigint): bigint -} = semigroup.bigintSum.combine +} = dual(2, semigroup.bigintSum.combine) /** * @category algebraic operations @@ -35,7 +35,7 @@ export const sum: { export const multiply: { (that: bigint): (self: bigint) => bigint (self: bigint, that: bigint): bigint -} = semigroup.bigintMultiply.combine +} = dual(2, semigroup.bigintMultiply.combine) /** * @category algebraic operations diff --git a/src/Boolean.ts b/src/Boolean.ts index 01e537fb2..34ee3d9fd 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -120,7 +120,7 @@ export const MonoidAny: monoid.Monoid = monoid.booleanAny export const and: { (that: boolean): (self: boolean) => boolean (self: boolean, that: boolean): boolean -} = semigroup.booleanAll.combine +} = dual(2, semigroup.booleanAll.combine) /** * @category combinators @@ -129,7 +129,7 @@ export const and: { export const or: { (that: boolean): (self: boolean) => boolean (self: boolean, that: boolean): boolean -} = semigroup.booleanAny.combine +} = dual(2, semigroup.booleanAny.combine) /** * @category combinators diff --git a/src/Either.ts b/src/Either.ts index bb74e1e28..702581a7f 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1266,7 +1266,7 @@ export const exists: { * @since 1.0.0 */ export const getOptionalSemigroup = (S: Semigroup): Semigroup> => - semigroup.fromCombine(( + semigroup.make(( x, y ) => (isLeft(y) ? x : isLeft(x) ? y : right(S.combine(x.right, y.right)))) diff --git a/src/Identity.ts b/src/Identity.ts index 17cc41ec7..18aabe5d6 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -188,8 +188,8 @@ export const getSemiCoproduct = ( S: Semigroup ): semiCoproduct.SemiCoproduct> => ({ imap, - coproduct: S.combine, - coproductMany: S.combineMany + coproduct: dual(2, S.combine), + coproductMany: dual(2, S.combineMany) }) /** diff --git a/src/Number.ts b/src/Number.ts index 89b081e1a..763fad5b6 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -34,7 +34,7 @@ export const isNumber: Refinement = predicate.isNumber export const sum: { (that: number): (self: number) => number (self: number, that: number): number -} = semigroup.numberSum.combine +} = dual(2, semigroup.numberSum.combine) /** * @example @@ -49,7 +49,7 @@ export const sum: { export const multiply: { (that: number): (self: number) => number (self: number, that: number): number -} = semigroup.numberMultiply.combine +} = dual(2, semigroup.numberMultiply.combine) /** * @example diff --git a/src/Option.ts b/src/Option.ts index 3b38f4f78..8f1e49658 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1008,7 +1008,7 @@ export const getOptionalMonoid = ( Semigroup: Semigroup ): Monoid> => monoid.fromSemigroup( - semigroup.fromCombine((self, that) => + semigroup.make((self, that) => isNone(self) ? that : isNone(that) ? self : some(Semigroup.combine(self.value, that.value)) ), none() diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 6c9f03ff5..73a0ada7f 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -33,7 +33,6 @@ import type * as product_ from "@fp-ts/core/typeclass/Product" import * as semiApplicative from "@fp-ts/core/typeclass/SemiApplicative" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" -import { fromCombine } from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" import * as traversableFilterable from "@fp-ts/core/typeclass/TraversableFilterable" @@ -2221,9 +2220,7 @@ export const unfold = (b: B, f: (b: B) => Option): Array< */ export const getUnionSemigroup = ( isEquivalent: (self: A, that: A) => boolean -): Semigroup> => - // @ts-expect-error - fromCombine(union(isEquivalent)) +): Semigroup> => semigroup.make(union(isEquivalent)) as any /** * @category instances @@ -2247,9 +2244,7 @@ export const getUnionMonoid = ( */ export const getIntersectionSemigroup = ( isEquivalent: (self: A, that: A) => boolean -): Semigroup> => - // @ts-expect-error - fromCombine(intersection(isEquivalent)) +): Semigroup> => semigroup.make(intersection(isEquivalent)) as any /** * Returns a `Semigroup` for `ReadonlyArray`. @@ -2257,7 +2252,7 @@ export const getIntersectionSemigroup = ( * @category instances * @since 1.0.0 */ -export const getSemigroup: () => Semigroup> = semigroup.readonlyArray +export const getSemigroup: () => Semigroup> = semigroup.array /** * Returns a `Monoid` for `ReadonlyArray`. @@ -2265,7 +2260,7 @@ export const getSemigroup: () => Semigroup> = semigroup.read * @category instances * @since 1.0.0 */ -export const getMonoid: () => Monoid> = monoid.readonlyArray +export const getMonoid: () => Monoid> = monoid.array /** * This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. diff --git a/src/String.ts b/src/String.ts index 689445bdf..b4092648b 100644 --- a/src/String.ts +++ b/src/String.ts @@ -63,7 +63,7 @@ export const empty: "" = "" as const export const concat: { (that: string): (self: string) => string (self: string, that: string): string -} = Semigroup.combine +} = dual(2, Semigroup.combine) /** * @example diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index ed42ae462..3a3f78246 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -144,7 +144,8 @@ export const tuple = >( * @category combinators * @since 1.0.0 */ -export const array = (): Monoid> => fromSemigroup(semigroup.array(), []) +export const mutableArray = (): Monoid> => + fromSemigroup(semigroup.mutableArray(), []) /** * Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. @@ -153,7 +154,7 @@ export const array = (): Monoid> => fromSemigroup(semigroup.array * @category combinators * @since 1.0.0 */ -export const readonlyArray: () => Monoid> = array as any +export const array: () => Monoid> = mutableArray as any /** * This function creates and returns a new `Monoid` for a struct of values based on the given `Monoid`s for each property in the struct. diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index a028f65ce..4587c67c8 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -14,14 +14,8 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Semigroup { - readonly combine: { - (that: A): (self: A) => A - (self: A, that: A): A - } - readonly combineMany: { - (collection: Iterable): (self: A) => A - (self: A, collection: Iterable): A - } + readonly combine: (self: A, that: A) => A + readonly combineMany: (self: A, collection: Iterable) => A } /** @@ -33,37 +27,25 @@ export interface SemigroupTypeLambda extends TypeLambda { } /** + * @param combineMany - Useful when `combineMany` can be optimised + * * @category constructors * @since 1.0.0 */ export const make = ( combine: (self: A, that: A) => A, - combineMany: (self: A, collection: Iterable) => A + combineMany: (self: A, collection: Iterable) => A = (self, collection) => + fromIterable(collection).reduce(combine, self) ): Semigroup => ({ - combine: dual(2, combine), - combineMany: dual(2, combineMany) + combine, + combineMany }) -/** - * Useful when `combineMany` can't be optimised. - * - * @category constructors - * @since 1.0.0 - */ -export const fromCombine = (combine: (self: A, that: A) => A): Semigroup => - make(combine, (self, collection) => { - let out: A = self - for (const a of collection) { - out = combine(out, a) - } - return out - }) - /** * @category instances * @since 1.0.0 */ -export const string: Semigroup = fromCombine((self, that) => self + that) +export const string: Semigroup = make((self, that) => self + that) /** * `number` semigroup under addition. @@ -71,7 +53,7 @@ export const string: Semigroup = fromCombine((self, that) => self + that * @category instances * @since 1.0.0 */ -export const numberSum: Semigroup = fromCombine((self, that) => self + that) +export const numberSum: Semigroup = make((self, that) => self + that) /** * `number` semigroup under multiplication. @@ -102,7 +84,7 @@ export const numberMultiply: Semigroup = make( * @category instances * @since 1.0.0 */ -export const bigintSum: Semigroup = fromCombine((self, that) => self + that) +export const bigintSum: Semigroup = make((self, that) => self + that) /** * `bigint` semigroup under multiplication. @@ -181,7 +163,7 @@ export const booleanAny: Semigroup = make( export const tuple = >( ...semigroups: { readonly [K in keyof A]: Semigroup } ): Semigroup => - fromCombine((self, that) => semigroups.map((S, i) => S.combine(self[i], that[i])) as any) + make((self, that) => semigroups.map((S, i) => S.combine(self[i], that[i])) as any) /** * Given a type `A`, this function creates and returns a `Semigroup` for `Array`. @@ -190,7 +172,7 @@ export const tuple = >( * @category combinators * @since 1.0.0 */ -export const array = (): Semigroup> => fromCombine((self, that) => self.concat(that)) +export const mutableArray = (): Semigroup> => make((self, that) => self.concat(that)) /** * Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. @@ -199,7 +181,7 @@ export const array = (): Semigroup> => fromCombine((self, that) => s * @category combinators * @since 1.0.0 */ -export const readonlyArray: () => Semigroup> = array as any +export const array: () => Semigroup> = mutableArray as any /** * This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. @@ -213,7 +195,7 @@ export const readonlyArray: () => Semigroup> = array as any export const struct = (semigroups: { readonly [K in keyof A]: Semigroup }): Semigroup< { readonly [K in keyof A]: A[K] } > => - fromCombine((self, that) => { + make((self, that) => { const r = {} as any for (const k in semigroups) { if (Object.prototype.hasOwnProperty.call(semigroups, k)) { @@ -230,7 +212,7 @@ export const struct = (semigroups: { readonly [K in keyof A]: Semigroup * @since 1.0.0 */ export const min = (O: Order): Semigroup => - fromCombine((self, that) => O.compare(self, that) === -1 ? self : that) + make((self, that) => O.compare(self, that) === -1 ? self : that) /** * `Semigroup` that returns last maximum of elements. @@ -239,7 +221,7 @@ export const min = (O: Order): Semigroup => * @since 1.0.0 */ export const max = (O: Order): Semigroup => - fromCombine((self, that) => O.compare(self, that) === 1 ? self : that) + make((self, that) => O.compare(self, that) === 1 ? self : that) /** * @category constructors @@ -272,7 +254,7 @@ export const intercalate: { } = dual( 2, (S: Semigroup, separator: A): Semigroup => - fromCombine((self, that) => S.combineMany(self, [separator, that])) + make((self, that) => S.combineMany(self, [separator, that])) ) /** diff --git a/test/typeclass/Monoid.ts b/test/typeclass/Monoid.ts index ffa346819..3ac669b4d 100644 --- a/test/typeclass/Monoid.ts +++ b/test/typeclass/Monoid.ts @@ -5,7 +5,7 @@ import * as U from "../util" describe("Monoid", () => { it("exports", () => { - expect(_.array).exists + expect(_.mutableArray).exists }) it("min", () => { diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index 2612c7890..ae381c20d 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -7,7 +7,7 @@ import * as U from "../util" describe("Semigroup", () => { it("exports", () => { - expect(_.array).exists + expect(_.mutableArray).exists }) it("reverse", () => { From 88cac199dd53511aaf4c5a9e229c3f4c0f8fb09e Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 7 Feb 2023 06:38:58 +0100 Subject: [PATCH 217/255] refactor Order --- docs/modules/typeclass/Order.ts.md | 5 +---- src/typeclass/Order.ts | 7 ++----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index 3048ec3d4..b10153372 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -231,10 +231,7 @@ Added in v1.0.0 ```ts export interface Order { - readonly compare: { - (that: A): (self: A) => -1 | 0 | 1 - (self: A, that: A): -1 | 0 | 1 - } + readonly compare: (self: A, that: A) => -1 | 0 | 1 } ``` diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 09c30cacb..3773a217f 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -17,10 +17,7 @@ import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" * @since 1.0.0 */ export interface Order { - readonly compare: { - (that: A): (self: A) => -1 | 0 | 1 - (self: A, that: A): -1 | 0 | 1 - } + readonly compare: (self: A, that: A) => -1 | 0 | 1 } /** @@ -38,7 +35,7 @@ export interface OrderTypeLambda extends TypeLambda { export const make = ( compare: (self: A, that: A) => -1 | 0 | 1 ): Order => ({ - compare: dual(2, (self, that) => self === that ? 0 : compare(self, that)) + compare: (self, that) => self === that ? 0 : compare(self, that) }) /** From cd3cb76155403402007599d959ea828060747b12 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 7 Feb 2023 06:58:51 +0100 Subject: [PATCH 218/255] refactor SemiProduct --- docs/modules/typeclass/Order.ts.md | 2 +- docs/modules/typeclass/SemiProduct.ts.md | 61 +++++++---------------- src/Either.ts | 48 +++++++----------- src/Identity.ts | 18 +++---- src/Option.ts | 20 +++----- src/Predicate.ts | 39 ++++++--------- src/ReadonlyArray.ts | 7 +-- src/These.ts | 62 +++++++++--------------- src/typeclass/Equivalence.ts | 21 +++----- src/typeclass/Order.ts | 20 ++------ src/typeclass/SemiProduct.ts | 36 +++++--------- src/typeclass/Semigroup.ts | 25 +++------- 12 files changed, 121 insertions(+), 238 deletions(-) diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index b10153372..268baebed 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -116,7 +116,7 @@ Added in v1.0.0 **Signature** ```ts -export declare const make: (compare: (self: A, that: A) => -1 | 0 | 1) => Order +export declare const make: (compare: (self: A, that: A) => 0 | 1 | -1) => Order ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/SemiProduct.ts.md b/docs/modules/typeclass/SemiProduct.ts.md index 2811d3cfd..c1927871c 100644 --- a/docs/modules/typeclass/SemiProduct.ts.md +++ b/docs/modules/typeclass/SemiProduct.ts.md @@ -31,7 +31,7 @@ Added in v1.0.0 ## productMany -Useful when `productMany` can't be optimised. +Returns a default `productMany` implementation. **Signature** @@ -41,22 +41,11 @@ export declare const productMany: ( (f: (a: A) => B): (self: Kind) => Kind (self: Kind, f: (a: A) => B): Kind }, - product: { - (that: Kind): ( - self: Kind - ) => Kind - (self: Kind, that: Kind): Kind< - F, - R1 & R2, - O1 | O2, - E1 | E2, - [A, B] - > - } -) => { - (collection: Iterable>): (self: Kind) => Kind - (self: Kind, collection: Iterable>): Kind -} + product: ( + self: Kind, + that: Kind + ) => Kind +) => (self: Kind, collection: Iterable>) => Kind ``` Added in v1.0.0 @@ -96,31 +85,15 @@ Added in v1.0.0 ```ts export interface SemiProduct extends Invariant { - readonly product: { - (that: Kind): ( - self: Kind - ) => Kind - (self: Kind, that: Kind): Kind< - F, - R1 & R2, - O1 | O2, - E1 | E2, - [A, B] - > - } - - readonly productMany: { - (collection: Iterable>): ( - self: Kind - ) => Kind]> - (self: Kind, collection: Iterable>): Kind< - F, - R, - O, - E, - [A, ...Array] - > - } + readonly product: ( + self: Kind, + that: Kind + ) => Kind + + readonly productMany: ( + self: Kind, + collection: Iterable> + ) => Kind]> } ``` @@ -192,7 +165,7 @@ Added in v1.0.0 ## productComposition -Returns a default binary `product` composition. +Returns a default `product` composition. **Signature** @@ -210,7 +183,7 @@ Added in v1.0.0 ## productManyComposition -Returns a default binary `productMany` composition. +Returns a default `productMany` composition. **Signature** diff --git a/src/Either.ts b/src/Either.ts index 702581a7f..cf684c5c7 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -458,34 +458,25 @@ export const Monad: monad.Monad = { flatMap } -const product: { - (that: Either): (self: Either) => Either - (self: Either, that: Either): Either -} = dual( - 2, - (self: Either, that: Either): Either => - isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self -) +const product = (self: Either, that: Either): Either => + isRight(self) ? (isRight(that) ? right([self.right, that.right]) : that) : self -const productMany: { - (collection: Iterable>): (self: Either) => Either]> - (self: Either, collection: Iterable>): Either]> -} = dual( - 2, - (self: Either, collection: Iterable>): Either]> => { - if (isLeft(self)) { - return self - } - const out: [A, ...Array] = [self.right] - for (const e of collection) { - if (isLeft(e)) { - return e - } - out.push(e.right) +const productMany = ( + self: Either, + collection: Iterable> +): Either]> => { + if (isLeft(self)) { + return self + } + const out: [A, ...Array] = [self.right] + for (const e of collection) { + if (isLeft(e)) { + return e } - return right(out) + out.push(e.right) } -) + return right(out) +} /** * @category instances @@ -1520,10 +1511,7 @@ export const liftEither = , E, B>( f: (...a: A) => Either ) => (...a: A): Validated => toValidated(f(...a)) -const productValidated: { - (that: Validated): (self: Validated) => Validated - (self: Validated, that: Validated): Validated -} = dual(2, ( +const productValidated = ( self: Validated, that: Validated ): Validated => @@ -1533,7 +1521,7 @@ const productValidated: { : self : isLeft(that) ? that - : right([self.right, that.right])) + : right([self.right, that.right]) const productManyValidated = semiProduct.productMany(map, productValidated) diff --git a/src/Identity.ts b/src/Identity.ts index 18aabe5d6..71fec1041 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -121,18 +121,12 @@ export const Monad: monad.Monad = { flatMap } -const product: { - (that: Identity): (self: Identity) => Identity<[A, B]> - (self: Identity, that: Identity): Identity<[A, B]> -} = dual(2, (self: Identity, that: Identity): Identity<[A, B]> => [self, that]) - -const productMany: { - (collection: Iterable): (self: Identity) => [A, ...Array] - (self: Identity, collection: Iterable): [A, ...Array] -} = dual( - 2, - (self: Identity, collection: Iterable): [A, ...Array] => [self, ...collection] -) +const product = (self: Identity, that: Identity): Identity<[A, B]> => [self, that] + +const productMany = ( + self: Identity, + collection: Iterable +): [A, ...Array] => [self, ...collection] /** * @category instances diff --git a/src/Option.ts b/src/Option.ts index 8f1e49658..4f984f0ff 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -888,19 +888,13 @@ export const Monad: monad.Monad = { flatMap } -const product: { - (that: Option): (self: Option) => Option<[A, B]> - (self: Option, that: Option): Option<[A, B]> -} = dual( - 2, - (self: Option, that: Option): Option<[A, B]> => - isSome(self) && isSome(that) ? some([self.value, that.value]) : none() -) +const product = (self: Option, that: Option): Option<[A, B]> => + isSome(self) && isSome(that) ? some([self.value, that.value]) : none() -const productMany: { - (collection: Iterable>): (self: Option) => Option<[A, ...Array]> - (self: Option, collection: Iterable>): Option<[A, ...Array]> -} = dual(2, (self: Option, collection: Iterable>): Option<[A, ...Array]> => { +const productMany = ( + self: Option, + collection: Iterable> +): Option<[A, ...Array]> => { if (isNone(self)) { return none() } @@ -912,7 +906,7 @@ const productMany: { out.push(o.value) } return some(out) -}) +} /** * @category instances diff --git a/src/Predicate.ts b/src/Predicate.ts index 0e7b444ff..a35d038bc 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -140,34 +140,25 @@ export const Of: of_.Of = { */ export const unit: Predicate = of_.unit(Of) -const product: { - (that: Predicate): (self: Predicate) => Predicate<[A, B]> - (self: Predicate, that: Predicate): Predicate<[A, B]> -} = dual( - 2, - (self: Predicate, that: Predicate): Predicate<[A, B]> => - ([a, b]) => self(a) && that(b) -) +const product = (self: Predicate, that: Predicate): Predicate<[A, B]> => + ([a, b]) => self(a) && that(b) -const productMany: { - (collection: Iterable>): (self: Predicate) => Predicate<[A, ...Array]> - (self: Predicate, collection: Iterable>): Predicate<[A, ...Array]> -} = dual( - 2, - (self: Predicate, collection: Iterable>): Predicate<[A, ...Array]> => - ([head, ...tail]) => { - if (self(head) === false) { +const productMany = ( + self: Predicate, + collection: Iterable> +): Predicate<[A, ...Array]> => + ([head, ...tail]) => { + if (self(head) === false) { + return false + } + const predicates = readonlyArray.fromIterable(collection) + for (let i = 0; i < predicates.length; i++) { + if (predicates[i](tail[i]) === false) { return false } - const predicates = readonlyArray.fromIterable(collection) - for (let i = 0; i < predicates.length; i++) { - if (predicates[i](tail[i]) === false) { - return false - } - } - return true } -) + return true + } /** * @category instances diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 73a0ada7f..bd226ed36 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1756,10 +1756,7 @@ export const sequenceNonEmpty = ( self: NonEmptyReadonlyArray> ) => Kind>) => traverseNonEmpty(F)(identity) -const product: { - (that: ReadonlyArray): (self: ReadonlyArray) => ReadonlyArray<[A, B]> - (self: ReadonlyArray, that: ReadonlyArray): ReadonlyArray<[A, B]> -} = dual(2, (self: ReadonlyArray, that: ReadonlyArray): ReadonlyArray<[A, B]> => { +const product = (self: ReadonlyArray, that: ReadonlyArray): ReadonlyArray<[A, B]> => { if (isEmpty(self) || isEmpty(that)) { return empty() } @@ -1770,7 +1767,7 @@ const product: { } } return out -}) +} const productMany = semiProduct.productMany(map, product) diff --git a/src/These.ts b/src/These.ts index bd1c06b98..18e19ec2f 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1045,33 +1045,30 @@ export const compact: { filterMap(self, identity, onNone) ) -const product: { - (that: Validated): (self: Validated) => Validated - (self: Validated, that: Validated): Validated -} = dual( - 2, - (self: Validated, that: Validated): Validated => { - if (isLeft(self)) { - return self - } - if (isRight(self)) { - if (isLeft(that)) { - return that - } - if (isRight(that)) { - return right([self.right, that.right]) - } - return both(that.left, [self.right, that.right]) - } +const product = ( + self: Validated, + that: Validated +): Validated => { + if (isLeft(self)) { + return self + } + if (isRight(self)) { if (isLeft(that)) { - return left(RA.appendAllNonEmpty(that.left)(self.left)) + return that } if (isRight(that)) { - return both(self.left, [self.right, that.right]) + return right([self.right, that.right]) } - return both(RA.appendAllNonEmpty(that.left)(self.left), [self.right, that.right]) + return both(that.left, [self.right, that.right]) } -) + if (isLeft(that)) { + return left(RA.appendAllNonEmpty(that.left)(self.left)) + } + if (isRight(that)) { + return both(self.left, [self.right, that.right]) + } + return both(RA.appendAllNonEmpty(that.left)(self.left), [self.right, that.right]) +} const productAll = ( collection: Iterable> @@ -1097,22 +1094,11 @@ const productAll = ( return right(rights) } -const productMany: { - ( - collection: Iterable> - ): (self: Validated) => Validated]> - ( - self: Validated, - collection: Iterable> - ): Validated]> -} = dual( - 2, - ( - self: Validated, - collection: Iterable> - ): Validated]> => - map(product(self, productAll(collection)), ([a, as]) => [a, ...as]) -) +const productMany = ( + self: Validated, + collection: Iterable> +): Validated]> => + map(product(self, productAll(collection)), ([a, as]) => [a, ...as]) /** * @category instances diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index a2e7efd6b..77c2fd593 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -209,22 +209,13 @@ export const Invariant: invariant.Invariant = { imap } -const product: { - (that: Equivalence): (self: Equivalence) => Equivalence<[A, B]> - (self: Equivalence, that: Equivalence): Equivalence<[A, B]> -} = dual( - 2, - (self: Equivalence, that: Equivalence): Equivalence<[A, B]> => tuple(self, that) -) +const product = (self: Equivalence, that: Equivalence): Equivalence<[A, B]> => + tuple(self, that) -const productMany: { - (collection: Iterable>): (self: Equivalence) => Equivalence<[A, ...Array]> - (self: Equivalence, collection: Iterable>): Equivalence<[A, ...Array]> -} = dual( - 2, - (self: Equivalence, collection: Iterable>): Equivalence<[A, ...Array]> => - tuple(self, ...collection) -) +const productMany = ( + self: Equivalence, + collection: Iterable> +): Equivalence<[A, ...Array]> => tuple(self, ...collection) /** * @category instances diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 3773a217f..cbcbafb2d 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -33,7 +33,7 @@ export interface OrderTypeLambda extends TypeLambda { * @since 1.0.0 */ export const make = ( - compare: (self: A, that: A) => -1 | 0 | 1 + compare: Order["compare"] ): Order => ({ compare: (self, that) => self === that ? 0 : compare(self, that) }) @@ -202,22 +202,10 @@ export const Invariant: invariant.Invariant = { imap } -const product: { - (that: Order): (self: Order) => Order<[A, B]> - (self: Order, that: Order): Order<[A, B]> -} = dual( - 2, - (self: Order, that: Order): Order<[A, B]> => tuple(self, that) -) +const product = (self: Order, that: Order): Order<[A, B]> => tuple(self, that) -const productMany: { - (collection: Iterable>): (self: Order) => Order<[A, ...Array]> - (self: Order, collection: Iterable>): Order<[A, ...Array]> -} = dual( - 2, - (self: Order, collection: Iterable>): Order<[A, ...Array]> => - tuple(self, ...collection) -) +const productMany = (self: Order, collection: Iterable>): Order<[A, ...Array]> => + tuple(self, ...collection) /** * @category instances diff --git a/src/typeclass/SemiProduct.ts b/src/typeclass/SemiProduct.ts index 25e70d21a..b1dc41b1c 100644 --- a/src/typeclass/SemiProduct.ts +++ b/src/typeclass/SemiProduct.ts @@ -12,29 +12,19 @@ import type { SemiApplicative } from "@fp-ts/core/typeclass/SemiApplicative" * @since 1.0.0 */ export interface SemiProduct extends Invariant { - readonly product: { - ( - that: Kind - ): (self: Kind) => Kind - ( - self: Kind, - that: Kind - ): Kind - } + readonly product: ( + self: Kind, + that: Kind + ) => Kind - readonly productMany: { - ( - collection: Iterable> - ): (self: Kind) => Kind]> - ( - self: Kind, - collection: Iterable> - ): Kind]> - } + readonly productMany: ( + self: Kind, + collection: Iterable> + ) => Kind]> } /** - * Useful when `productMany` can't be optimised. + * Returns a default `productMany` implementation. * * @category constructors * @since 1.0.0 @@ -43,7 +33,7 @@ export const productMany = ( map: Covariant["map"], product: SemiProduct["product"] ): SemiProduct["productMany"] => - dual(2, ( + ( self: Kind, collection: Iterable> ) => { @@ -55,10 +45,10 @@ export const productMany = ( ) } return out - }) + } /** - * Returns a default binary `product` composition. + * Returns a default `product` composition. * * @since 1.0.0 */ @@ -78,7 +68,7 @@ export const productComposition = ( > => F.map(F.product(self, that), ([ga, gb]) => G.product(ga, gb)) /** - * Returns a default binary `productMany` composition. + * Returns a default `productMany` composition. * * @since 1.0.0 */ diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 4587c67c8..f7928b6e1 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -33,8 +33,8 @@ export interface SemigroupTypeLambda extends TypeLambda { * @since 1.0.0 */ export const make = ( - combine: (self: A, that: A) => A, - combineMany: (self: A, collection: Iterable) => A = (self, collection) => + combine: Semigroup["combine"], + combineMany: Semigroup["combineMany"] = (self, collection) => fromIterable(collection).reduce(combine, self) ): Semigroup => ({ combine, @@ -302,22 +302,13 @@ export const Invariant: invariant.Invariant = { imap } -const product: { - (that: Semigroup): (self: Semigroup) => Semigroup<[A, B]> - (self: Semigroup, that: Semigroup): Semigroup<[A, B]> -} = dual( - 2, - (self: Semigroup, that: Semigroup): Semigroup<[A, B]> => tuple(self, that) -) +const product = (self: Semigroup, that: Semigroup): Semigroup<[A, B]> => + tuple(self, that) -const productMany: { - (collection: Iterable>): (self: Semigroup) => Semigroup<[A, ...Array]> - (self: Semigroup, collection: Iterable>): Semigroup<[A, ...Array]> -} = dual( - 2, - (self: Semigroup, collection: Iterable>): Semigroup<[A, ...Array]> => - tuple(self, ...collection) -) +const productMany = ( + self: Semigroup, + collection: Iterable> +): Semigroup<[A, ...Array]> => tuple(self, ...collection) /** * @category instances From dc78722c55c72403f9006195af406ce4ddebe6e4 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 7 Feb 2023 07:17:02 +0100 Subject: [PATCH 219/255] refactor SemiCoproduct --- benchmark/These/product.ts | 22 ++++++++++++ docs/modules/typeclass/SemiCoproduct.ts.md | 26 +++++---------- src/Either.ts | 39 +++++++++++----------- src/Option.ts | 15 +++------ src/These.ts | 36 +++++++++----------- src/typeclass/SemiCoproduct.ts | 26 +++++---------- 6 files changed, 80 insertions(+), 84 deletions(-) create mode 100644 benchmark/These/product.ts diff --git a/benchmark/These/product.ts b/benchmark/These/product.ts new file mode 100644 index 000000000..515e5d52b --- /dev/null +++ b/benchmark/These/product.ts @@ -0,0 +1,22 @@ +import { Product, right, fail } from "@fp-ts/core/These" +import * as Benchmark from "benchmark" + +/* +*/ + +const suite = new Benchmark.Suite() + +suite + .add("Product.product", function() { + Product.product(right(1), fail('e')) + }) + .add("Product.productAll", function() { + Product.productAll([right(1), fail('e')]) + }) + .on("cycle", function(event: any) { + console.log(String(event.target)) + }) + .on("complete", function(this: any) { + console.log("Fastest is " + this.filter("fastest").map("name")) + }) + .run({ async: true }) diff --git a/docs/modules/typeclass/SemiCoproduct.ts.md b/docs/modules/typeclass/SemiCoproduct.ts.md index 7ff611ea7..cba0175d7 100644 --- a/docs/modules/typeclass/SemiCoproduct.ts.md +++ b/docs/modules/typeclass/SemiCoproduct.ts.md @@ -27,23 +27,15 @@ Added in v1.0.0 ```ts export interface SemiCoproduct extends Invariant { - readonly coproduct: { - (that: Kind): ( - self: Kind - ) => Kind - (self: Kind, that: Kind): Kind< - F, - R1 & R2, - O1 | O2, - E1 | E2, - A | B - > - } - - readonly coproductMany: { - (collection: Iterable>): (self: Kind) => Kind - (self: Kind, collection: Iterable>): Kind - } + readonly coproduct: ( + self: Kind, + that: Kind + ) => Kind + + readonly coproductMany: ( + self: Kind, + collection: Iterable> + ) => Kind } ``` diff --git a/src/Either.ts b/src/Either.ts index cf684c5c7..d49a32f62 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -641,14 +641,15 @@ export const getFirstLeftSemigroup: (S: Semigroup) => Semigroup(M: Monoid) => Monoid> = applicative .getMonoid(Applicative) -/** - * @category error handling - * @since 1.0.0 - */ -export const firstRightOf: { - (collection: Iterable>): (self: Either) => Either - (self: Either, collection: Iterable>): Either -} = dual(2, (self: Either, collection: Iterable>): Either => { +const coproduct = ( + self: Either, + that: Either +): Either => isRight(self) ? self : that + +const coproductMany = ( + self: Either, + collection: Iterable> +): Either => { let out = self if (isRight(out)) { return out @@ -659,16 +660,7 @@ export const firstRightOf: { } } return out -}) - -const coproduct: { - (that: Either): (self: Either) => Either - (self: Either, that: Either): Either -} = dual( - 2, - (self: Either, that: Either): Either => - isRight(self) ? self : that -) +} /** * @category instances @@ -677,9 +669,18 @@ const coproduct: { export const SemiCoproduct: semiCoproduct.SemiCoproduct = { imap, coproduct, - coproductMany: firstRightOf + coproductMany } +/** + * @category error handling + * @since 1.0.0 + */ +export const firstRightOf: { + (collection: Iterable>): (self: Either) => Either + (self: Either, collection: Iterable>): Either +} = dual(2, coproductMany) + /** * Semigroup returning the left-most `Right` value. * diff --git a/src/Option.ts b/src/Option.ts index 4f984f0ff..2625a42c2 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1078,15 +1078,10 @@ export const getFailureMonoid: (M: Monoid) => Monoid> = applicat Applicative ) -const coproduct: { - (that: Option): (self: Option) => Option - (self: Option, that: Option): Option -} = dual(2, (self: Option, that: Option): Option => isSome(self) ? self : that) - -const coproductMany: { - (collection: Iterable>): (self: Option) => Option - (self: Option, collection: Iterable>): Option -} = dual(2, (self: Option, collection: Iterable>): Option => { +const coproduct = (self: Option, that: Option): Option => + isSome(self) ? self : that + +const coproductMany = (self: Option, collection: Iterable>): Option => { let out = self if (isSome(out)) { return out @@ -1097,7 +1092,7 @@ const coproductMany: { } } return out -}) +} /** * @category instances diff --git a/src/These.ts b/src/These.ts index 18e19ec2f..4601a6af0 100644 --- a/src/These.ts +++ b/src/These.ts @@ -917,14 +917,10 @@ export const orElseFail: { orElse(self, () => left(onLeft())) ) -/** - * @category error handling - * @since 1.0.0 - */ -export const firstRightOrBothOf: { - (collection: Iterable>): (self: These) => These - (self: These, collection: Iterable>): These -} = dual(2, (self: These, collection: Iterable>): These => { +const coproduct = (self: These, that: These): These => + isRightOrBoth(self) ? self : that + +const coproductMany = (self: These, collection: Iterable>): These => { let out = self if (isRightOrBoth(out)) { return out @@ -935,16 +931,16 @@ export const firstRightOrBothOf: { } } return out -}) +} -const coproduct: { - (that: These): (self: These) => These - (self: These, that: These): These -} = dual( - 2, - (self: These, that: These): These => - isRightOrBoth(self) ? self : that -) +/** + * @category error handling + * @since 1.0.0 + */ +export const firstRightOrBothOf: { + (collection: Iterable>): (self: These) => These + (self: These, collection: Iterable>): These +} = dual(2, coproductMany) /** * @category instances @@ -953,7 +949,7 @@ const coproduct: { export const SemiCoproduct: semiCoproduct.SemiCoproduct = { imap, coproduct, - coproductMany: firstRightOrBothOf + coproductMany } /** @@ -1062,12 +1058,12 @@ const product = ( return both(that.left, [self.right, that.right]) } if (isLeft(that)) { - return left(RA.appendAllNonEmpty(that.left)(self.left)) + return left(RA.appendAllNonEmpty(self.left, that.left)) } if (isRight(that)) { return both(self.left, [self.right, that.right]) } - return both(RA.appendAllNonEmpty(that.left)(self.left), [self.right, that.right]) + return both(RA.appendAllNonEmpty(self.left, that.left), [self.right, that.right]) } const productAll = ( diff --git a/src/typeclass/SemiCoproduct.ts b/src/typeclass/SemiCoproduct.ts index cee0ba850..57d85526d 100644 --- a/src/typeclass/SemiCoproduct.ts +++ b/src/typeclass/SemiCoproduct.ts @@ -11,25 +11,15 @@ import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" * @since 1.0.0 */ export interface SemiCoproduct extends Invariant { - readonly coproduct: { - ( - that: Kind - ): (self: Kind) => Kind - ( - self: Kind, - that: Kind - ): Kind - } + readonly coproduct: ( + self: Kind, + that: Kind + ) => Kind - readonly coproductMany: { - ( - collection: Iterable> - ): (self: Kind) => Kind - ( - self: Kind, - collection: Iterable> - ): Kind - } + readonly coproductMany: ( + self: Kind, + collection: Iterable> + ) => Kind } /** From c8dbfa893b6629541ed535d07bf8fe1c1d79e55f Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 7 Feb 2023 16:06:37 +0100 Subject: [PATCH 220/255] docs: guards --- docs/modules/Bigint.ts.md | 11 +++++ docs/modules/Boolean.ts.md | 13 ++++- docs/modules/Either.ts.md | 37 ++++++++++++-- docs/modules/Number.ts.md | 13 ++++- docs/modules/Option.ts.md | 8 ++-- docs/modules/Predicate.ts.md | 65 +++++++++++++++++++++++-- docs/modules/ReadonlyArray.ts.md | 24 +++++++++- docs/modules/String.ts.md | 11 +++++ docs/modules/Symbol.ts.md | 11 +++++ docs/modules/These.ts.md | 65 ++++++++++++++++++++++--- patches/docs-ts@0.6.10.patch | 4 +- src/Bigint.ts | 10 ++++ src/Boolean.ts | 13 ++++- src/Either.ts | 38 ++++++++++++--- src/Number.ts | 13 ++++- src/Option.ts | 12 ++--- src/Predicate.ts | 63 ++++++++++++++++++++---- src/ReadonlyArray.ts | 22 ++++++++- src/String.ts | 10 ++++ src/Symbol.ts | 10 ++++ src/These.ts | 82 ++++++++++++++++++++++++++------ 21 files changed, 468 insertions(+), 67 deletions(-) diff --git a/docs/modules/Bigint.ts.md b/docs/modules/Bigint.ts.md index 097868766..cec597bc5 100644 --- a/docs/modules/Bigint.ts.md +++ b/docs/modules/Bigint.ts.md @@ -82,12 +82,23 @@ Added in v1.0.0 ## isBigint +Tests if a value is a `bigint`. + **Signature** ```ts export declare const isBigint: (u: unknown) => u is bigint ``` +**Example** + +```ts +import { isBigint } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(isBigint(1n), true) +assert.deepStrictEqual(isBigint(1), false) +``` + Added in v1.0.0 # instances diff --git a/docs/modules/Boolean.ts.md b/docs/modules/Boolean.ts.md index 0c02e35ee..1194d0b11 100644 --- a/docs/modules/Boolean.ts.md +++ b/docs/modules/Boolean.ts.md @@ -73,10 +73,21 @@ Added in v1.0.0 ## isBoolean +Tests if a value is a `boolean`. + **Signature** ```ts -export declare const isBoolean: Refinement +export declare const isBoolean: (input: unknown) => input is boolean +``` + +**Example** + +```ts +import { isBoolean } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(isBoolean(true), true) +assert.deepStrictEqual(isBoolean('true'), false) ``` Added in v1.0.0 diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 59de30c1a..940c50630 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -927,20 +927,29 @@ Added in v1.0.0 ## isEither -Returns `true` if the specified value is an instance of `Either`, `false` -otherwise. +Tests if a value is a `Either`. **Signature** ```ts -export declare const isEither: (u: unknown) => u is Either +export declare const isEither: (input: unknown) => input is Either +``` + +**Example** + +```ts +import { isEither, left, right } from '@fp-ts/core/Either' + +assert.deepStrictEqual(isEither(right(1)), true) +assert.deepStrictEqual(isEither(left('error')), true) +assert.deepStrictEqual(isEither({ right: 1 }), false) ``` Added in v1.0.0 ## isLeft -Returns `true` if the either is an instance of `Left`, `false` otherwise. +Determine if a `Either` is a `Left`. **Signature** @@ -948,11 +957,20 @@ Returns `true` if the either is an instance of `Left`, `false` otherwise. export declare const isLeft: (self: Either) => self is Left ``` +**Example** + +```ts +import { isLeft, left, right } from '@fp-ts/core/Either' + +assert.deepStrictEqual(isLeft(right(1)), false) +assert.deepStrictEqual(isLeft(left('error')), true) +``` + Added in v1.0.0 ## isRight -Returns `true` if the either is an instance of `Right`, `false` otherwise. +Determine if a `Either` is a `Right`. **Signature** @@ -960,6 +978,15 @@ Returns `true` if the either is an instance of `Right`, `false` otherwise. export declare const isRight: (self: Either) => self is Right ``` +**Example** + +```ts +import { isRight, left, right } from '@fp-ts/core/Either' + +assert.deepStrictEqual(isRight(right(1)), true) +assert.deepStrictEqual(isRight(left('error')), false) +``` + Added in v1.0.0 # instances diff --git a/docs/modules/Number.ts.md b/docs/modules/Number.ts.md index dbdba912b..8f701ced0 100644 --- a/docs/modules/Number.ts.md +++ b/docs/modules/Number.ts.md @@ -146,10 +146,21 @@ Added in v1.0.0 ## isNumber +Tests if a value is a `number`. + **Signature** ```ts -export declare const isNumber: predicate.Refinement +export declare const isNumber: (input: unknown) => input is number +``` + +**Example** + +```ts +import { isNumber } from '@fp-ts/core/Number' + +assert.deepStrictEqual(isNumber(2), true) +assert.deepStrictEqual(isNumber('2'), false) ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index e826e1013..0619e7cd5 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -858,7 +858,7 @@ Added in v1.0.0 ## isNone -Returns `true` if the `Option` is `None`, `false` otherwise. +Determine if a `Option` is a `None`. **Signature** @@ -879,12 +879,12 @@ Added in v1.0.0 ## isOption -Checks if the specified value is an instance of `Option`, returns `true` if it is, `false` otherwise. +Tests if a value is a `Option`. **Signature** ```ts -export declare const isOption: (u: unknown) => u is Option +export declare const isOption: (input: unknown) => input is Option ``` **Example** @@ -901,7 +901,7 @@ Added in v1.0.0 ## isSome -Returns `true` if the `Option` is an instance of `Some`, `false` otherwise. +Determine if a `Option` is a `Some`. **Signature** diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index 5cd48378d..ee98f9ce6 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -134,50 +134,105 @@ Added in v1.0.0 ## isBigint +Tests if a value is a `bigint`. + **Signature** ```ts -export declare const isBigint: (u: unknown) => u is bigint +export declare const isBigint: (input: unknown) => input is bigint +``` + +**Example** + +```ts +import { isBigint } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isBigint(1n), true) +assert.deepStrictEqual(isBigint(1), false) ``` Added in v1.0.0 ## isBoolean +Tests if a value is a `boolean`. + **Signature** ```ts -export declare const isBoolean: Refinement +export declare const isBoolean: (input: unknown) => input is boolean +``` + +**Example** + +```ts +import { isBoolean } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isBoolean(true), true) +assert.deepStrictEqual(isBoolean('true'), false) ``` Added in v1.0.0 ## isNumber +Tests if a value is a `number`. + **Signature** ```ts -export declare const isNumber: Refinement +export declare const isNumber: (input: unknown) => input is number +``` + +**Example** + +```ts +import { isNumber } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isNumber(2), true) +assert.deepStrictEqual(isNumber('2'), false) ``` Added in v1.0.0 ## isString +Tests if a value is a `string`. + **Signature** ```ts -export declare const isString: Refinement +export declare const isString: (input: unknown) => input is string +``` + +**Example** + +```ts +import { isString } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isString('a'), true) +assert.deepStrictEqual(isString(1), false) ``` Added in v1.0.0 ## isSymbol +Tests if a value is a `symbol`. + **Signature** ```ts -export declare const isSymbol: (u: unknown) => u is symbol +export declare const isSymbol: (input: unknown) => input is symbol +``` + +**Example** + +```ts +import { isSymbol } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isSymbol(Symbol.for('a')), true) +assert.deepStrictEqual(isSymbol('a'), false) ``` Added in v1.0.0 diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 020c797d9..730724ab8 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -1106,7 +1106,7 @@ Added in v1.0.0 ## isEmpty -Test whether a `ReadonlyArray` is empty narrowing down the type to `[]`. +Determine if a `ReadonlyArray` is empty narrowing down the type to `[]`. **Signature** @@ -1114,11 +1114,22 @@ Test whether a `ReadonlyArray` is empty narrowing down the type to `[]`. export declare const isEmpty: (self: readonly A[]) => self is readonly [] ``` +**Example** + +```ts +import { isEmpty } from '@fp-ts/core/ReadonlyArray' + +assert.deepStrictEqual(isEmpty([]), true) +assert.deepStrictEqual(isEmpty([1, 2, 3]), false) +``` + Added in v1.0.0 ## isNonEmpty -Test whether a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyReadonlyArray`. +Determine if a `ReadonlyArray` is empty narrowing down the type to `NonEmptyReadonlyArray`. + +A `ReadonlyArray` is considered to be a `NonEmptyReadonlyArray` if it contains at least one element. **Signature** @@ -1126,6 +1137,15 @@ Test whether a `ReadonlyArray` is non empty narrowing down the type to `NonEmpty export declare const isNonEmpty: (self: readonly A[]) => self is readonly [A, ...A[]] ``` +**Example** + +```ts +import { isNonEmpty } from '@fp-ts/core/ReadonlyArray' + +assert.deepStrictEqual(isNonEmpty([]), false) +assert.deepStrictEqual(isNonEmpty([1, 2, 3]), true) +``` + Added in v1.0.0 # instances diff --git a/docs/modules/String.ts.md b/docs/modules/String.ts.md index a4b9ffd14..46c8fae6f 100644 --- a/docs/modules/String.ts.md +++ b/docs/modules/String.ts.md @@ -52,12 +52,23 @@ Added in v1.0.0 ## isString +Tests if a value is a `string`. + **Signature** ```ts export declare const isString: Refinement ``` +**Example** + +```ts +import { isString } from '@fp-ts/core/String' + +assert.deepStrictEqual(isString('a'), true) +assert.deepStrictEqual(isString(1), false) +``` + Added in v1.0.0 # instances diff --git a/docs/modules/Symbol.ts.md b/docs/modules/Symbol.ts.md index 4f3bcc7b8..15df595cc 100644 --- a/docs/modules/Symbol.ts.md +++ b/docs/modules/Symbol.ts.md @@ -21,10 +21,21 @@ Added in v1.0.0 ## isSymbol +Tests if a value is a `symbol`. + **Signature** ```ts export declare const isSymbol: (u: unknown) => u is symbol ``` +**Example** + +```ts +import { isSymbol } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isSymbol(Symbol.for('a')), true) +assert.deepStrictEqual(isSymbol('a'), false) +``` + Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index b13050772..bddc0d78a 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -922,7 +922,7 @@ Added in v1.0.0 ## isBoth -Returns `true` if the these is an instance of `Both`, `false` otherwise +Determine if a `These` is a `Both`. **Signature** @@ -930,11 +930,21 @@ Returns `true` if the these is an instance of `Both`, `false` otherwise export declare const isBoth: (self: These) => self is Both ``` +**Example** + +```ts +import { isBoth, left, right, both } from '@fp-ts/core/These' + +assert.deepStrictEqual(isBoth(right(1)), false) +assert.deepStrictEqual(isBoth(left('error')), false) +assert.deepStrictEqual(isBoth(both('error', 1)), true) +``` + Added in v1.0.0 ## isLeft -Returns `true` if the these is an instance of `Left`, `false` otherwise +Determine if a `These` is a `Left`. **Signature** @@ -942,21 +952,43 @@ Returns `true` if the these is an instance of `Left`, `false` otherwise export declare const isLeft: (self: These) => self is Left ``` +**Example** + +```ts +import { isLeft, left, right, both } from '@fp-ts/core/These' + +assert.deepStrictEqual(isLeft(right(1)), false) +assert.deepStrictEqual(isLeft(left('error')), true) +assert.deepStrictEqual(isLeft(both('error', 1)), false) +``` + Added in v1.0.0 ## isLeftOrBoth +Determine if a `These` is a `Left` or a `Both`. + **Signature** ```ts export declare const isLeftOrBoth: (self: These) => self is Left | Both ``` +**Example** + +```ts +import { isLeftOrBoth, left, right, both } from '@fp-ts/core/These' + +assert.deepStrictEqual(isLeftOrBoth(right(1)), false) +assert.deepStrictEqual(isLeftOrBoth(left('error')), true) +assert.deepStrictEqual(isLeftOrBoth(both('error', 1)), true) +``` + Added in v1.0.0 ## isRight -Returns `true` if the these is an instance of `Right`, `false` otherwise +Determine if a `These` is a `Right`. **Signature** @@ -964,27 +996,48 @@ Returns `true` if the these is an instance of `Right`, `false` otherwise export declare const isRight: (self: These) => self is Right ``` +**Example** + +```ts +import { isRight, left, right, both } from '@fp-ts/core/These' + +assert.deepStrictEqual(isRight(right(1)), true) +assert.deepStrictEqual(isRight(left('error')), false) +assert.deepStrictEqual(isRight(both('error', 1)), false) +``` + Added in v1.0.0 ## isRightOrBoth +Determine if a `These` is a `Right` or a `Both`. + **Signature** ```ts export declare const isRightOrBoth: (self: These) => self is Right | Both ``` +**Example** + +```ts +import { isRightOrBoth, left, right, both } from '@fp-ts/core/These' + +assert.deepStrictEqual(isRightOrBoth(right(1)), true) +assert.deepStrictEqual(isRightOrBoth(left('error')), false) +assert.deepStrictEqual(isRightOrBoth(both('error', 1)), true) +``` + Added in v1.0.0 ## isThese -Returns `true` if the specified value is an instance of `These`, `false` -otherwise. +Tests if a value is a `These`. **Signature** ```ts -export declare const isThese: (u: unknown) => u is These +export declare const isThese: (input: unknown) => input is These ``` Added in v1.0.0 diff --git a/patches/docs-ts@0.6.10.patch b/patches/docs-ts@0.6.10.patch index ae7d9cbe1..dd3c9ed12 100644 --- a/patches/docs-ts@0.6.10.patch +++ b/patches/docs-ts@0.6.10.patch @@ -20,8 +20,8 @@ index c0f282ca9e3ddd93e44a62e1d05c1cc45b9f5c6a..616f7f6223459e0621522279ea7fc1cf + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": true, + "moduleResolution": "node", -+ "target": "es2015", -+ "lib": ["es2015"], ++ "target": "ES2021", ++ "lib": ["ES2021"], + "paths": { + "@fp-ts/core": ["../../src/index.ts"], + "@fp-ts/core/test/*": ["../../test/*"], diff --git a/src/Bigint.ts b/src/Bigint.ts index cd8edb700..eaab9a780 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -14,6 +14,16 @@ import * as order from "@fp-ts/core/typeclass/Order" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** + * Tests if a value is a `bigint`. + * + * @param input - The value to test. + * + * @example + * import { isBigint } from "@fp-ts/core/Bigint" + * + * assert.deepStrictEqual(isBigint(1n), true) + * assert.deepStrictEqual(isBigint(1), false) + * * @category guards * @since 1.0.0 */ diff --git a/src/Boolean.ts b/src/Boolean.ts index 34ee3d9fd..52889069a 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -7,7 +7,6 @@ */ import type { LazyArg } from "@fp-ts/core/Function" import { dual } from "@fp-ts/core/Function" -import type { Refinement } from "@fp-ts/core/Predicate" import * as predicate from "@fp-ts/core/Predicate" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" @@ -15,10 +14,20 @@ import * as order from "@fp-ts/core/typeclass/Order" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** + * Tests if a value is a `boolean`. + * + * @param input - The value to test. + * + * @example + * import { isBoolean } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(isBoolean(true), true) + * assert.deepStrictEqual(isBoolean("true"), false) + * * @category guards * @since 1.0.0 */ -export const isBoolean: Refinement = predicate.isBoolean +export const isBoolean: (input: unknown) => input is boolean = predicate.isBoolean /** * Defines the match over a boolean value. diff --git a/src/Either.ts b/src/Either.ts index d49a32f62..db70d04bd 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -106,18 +106,34 @@ export const of: (a: A) => Either = right // ------------------------------------------------------------------------------------- /** - * Returns `true` if the specified value is an instance of `Either`, `false` - * otherwise. + * Tests if a value is a `Either`. + * + * @param input - The value to test. + * + * @example + * import { isEither, left, right } from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(isEither(right(1)), true) + * assert.deepStrictEqual(isEither(left("error")), true) + * assert.deepStrictEqual(isEither({ right: 1 }), false) * * @category guards * @since 1.0.0 */ -export const isEither = (u: unknown): u is Either => - typeof u === "object" && u != null && structural in u && "_tag" in u && - (u["_tag"] === "Left" || u["_tag"] === "Right") +export const isEither = (input: unknown): input is Either => + typeof input === "object" && input != null && structural in input && "_tag" in input && + (input["_tag"] === "Left" || input["_tag"] === "Right") /** - * Returns `true` if the either is an instance of `Left`, `false` otherwise. + * Determine if a `Either` is a `Left`. + * + * @param self - The `Either` to check. + * + * @example + * import { isLeft, left, right } from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(isLeft(right(1)), false) + * assert.deepStrictEqual(isLeft(left("error")), true) * * @category guards * @since 1.0.0 @@ -125,7 +141,15 @@ export const isEither = (u: unknown): u is Either => export const isLeft: (self: Either) => self is Left = either.isLeft /** - * Returns `true` if the either is an instance of `Right`, `false` otherwise. + * Determine if a `Either` is a `Right`. + * + * @param self - The `Either` to check. + * + * @example + * import { isRight, left, right } from '@fp-ts/core/Either' + * + * assert.deepStrictEqual(isRight(right(1)), true) + * assert.deepStrictEqual(isRight(left("error")), false) * * @category guards * @since 1.0.0 diff --git a/src/Number.ts b/src/Number.ts index 763fad5b6..04dad0bf2 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -8,7 +8,6 @@ import { dual } from "@fp-ts/core/Function" import type { Ordering } from "@fp-ts/core/Ordering" import * as predicate from "@fp-ts/core/Predicate" -import type { Refinement } from "@fp-ts/core/Predicate" import * as bounded from "@fp-ts/core/typeclass/Bounded" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" @@ -16,10 +15,20 @@ import * as order from "@fp-ts/core/typeclass/Order" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** + * Tests if a value is a `number`. + * + * @param input - The value to test. + * + * @example + * import { isNumber } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(isNumber(2), true) + * assert.deepStrictEqual(isNumber("2"), false) + * * @category guards * @since 1.0.0 */ -export const isNumber: Refinement = predicate.isNumber +export const isNumber: (input: unknown) => input is number = predicate.isNumber /** * @example diff --git a/src/Option.ts b/src/Option.ts index 2625a42c2..8ddbcbd61 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -112,7 +112,7 @@ export const of: (value: A) => Option = some // ------------------------------------------------------------------------------------- /** - * Checks if the specified value is an instance of `Option`, returns `true` if it is, `false` otherwise. + * Tests if a value is a `Option`. * * @param input - The value to check. * @@ -126,12 +126,12 @@ export const of: (value: A) => Option = some * @category guards * @since 1.0.0 */ -export const isOption = (u: unknown): u is Option => - typeof u === "object" && u != null && structural in u && "_tag" in u && - (u["_tag"] === "None" || u["_tag"] === "Some") +export const isOption = (input: unknown): input is Option => + typeof input === "object" && input != null && structural in input && "_tag" in input && + (input["_tag"] === "None" || input["_tag"] === "Some") /** - * Returns `true` if the `Option` is `None`, `false` otherwise. + * Determine if a `Option` is a `None`. * * @param self - The `Option` to check. * @@ -147,7 +147,7 @@ export const isOption = (u: unknown): u is Option => export const isNone: (self: Option) => self is None = option.isNone /** - * Returns `true` if the `Option` is an instance of `Some`, `false` otherwise. + * Determine if a `Option` is a `Some`. * * @param self - The `Option` to check. * diff --git a/src/Predicate.ts b/src/Predicate.ts index a35d038bc..52203c853 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -37,37 +37,84 @@ export interface Refinement { } /** + * Tests if a value is a `string`. + * + * @param input - The value to test. + * + * @example + * import { isString } from '@fp-ts/core/Predicate' + * + * assert.deepStrictEqual(isString("a"), true) + * assert.deepStrictEqual(isString(1), false) + * * @category guards * @since 1.0.0 */ -export const isString: Refinement = (u: unknown): u is string => - typeof u === "string" +export const isString = (input: unknown): input is string => typeof input === "string" /** + * Tests if a value is a `number`. + * + * @param input - The value to test. + * + * @example + * import { isNumber } from '@fp-ts/core/Predicate' + * + * assert.deepStrictEqual(isNumber(2), true) + * assert.deepStrictEqual(isNumber("2"), false) + * * @category guards * @since 1.0.0 */ -export const isNumber: Refinement = (u: unknown): u is number => - typeof u === "number" +export const isNumber = (input: unknown): input is number => typeof input === "number" /** + * Tests if a value is a `boolean`. + * + * @param input - The value to test. + * + * @example + * import { isBoolean } from '@fp-ts/core/Predicate' + * + * assert.deepStrictEqual(isBoolean(true), true) + * assert.deepStrictEqual(isBoolean("true"), false) + * * @category guards * @since 1.0.0 */ -export const isBoolean: Refinement = (u: unknown): u is boolean => - typeof u === "boolean" +export const isBoolean = (input: unknown): input is boolean => typeof input === "boolean" /** + * Tests if a value is a `bigint`. + * + * @param input - The value to test. + * + * @example + * import { isBigint } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isBigint(1n), true) + * assert.deepStrictEqual(isBigint(1), false) + * * @category guards * @since 1.0.0 */ -export const isBigint = (u: unknown): u is bigint => typeof u === "bigint" +export const isBigint = (input: unknown): input is bigint => typeof input === "bigint" /** + * Tests if a value is a `symbol`. + * + * @param input - The value to test. + * + * @example + * import { isSymbol } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isSymbol(Symbol.for("a")), true) + * assert.deepStrictEqual(isSymbol("a"), false) + * * @category guards * @since 1.0.0 */ -export const isSymbol = (u: unknown): u is symbol => typeof u === "symbol" +export const isSymbol = (input: unknown): input is symbol => typeof input === "symbol" /** * @category constructors diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index bd226ed36..d581aaaa6 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -311,7 +311,15 @@ export const scanRight: { }) /** - * Test whether a `ReadonlyArray` is empty narrowing down the type to `[]`. + * Determine if a `ReadonlyArray` is empty narrowing down the type to `[]`. + * + * @param self - The `ReadonlyArray` to check. + * + * @example + * import { isEmpty } from "@fp-ts/core/ReadonlyArray" + * + * assert.deepStrictEqual(isEmpty([]), true); + * assert.deepStrictEqual(isEmpty([1, 2, 3]), false); * * @category guards * @since 1.0.0 @@ -319,7 +327,17 @@ export const scanRight: { export const isEmpty = (self: ReadonlyArray): self is readonly [] => self.length === 0 /** - * Test whether a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyReadonlyArray`. + * Determine if a `ReadonlyArray` is empty narrowing down the type to `NonEmptyReadonlyArray`. + * + * A `ReadonlyArray` is considered to be a `NonEmptyReadonlyArray` if it contains at least one element. + * + * @param self - The `ReadonlyArray` to check. + * + * @example + * import { isNonEmpty } from "@fp-ts/core/ReadonlyArray" + * + * assert.deepStrictEqual(isNonEmpty([]), false); + * assert.deepStrictEqual(isNonEmpty([1, 2, 3]), true); * * @category guards * @since 1.0.0 diff --git a/src/String.ts b/src/String.ts index b4092648b..d283a6d38 100644 --- a/src/String.ts +++ b/src/String.ts @@ -17,6 +17,16 @@ import * as order from "@fp-ts/core/typeclass/Order" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** + * Tests if a value is a `string`. + * + * @param input - The value to test. + * + * @example + * import { isString } from '@fp-ts/core/String' + * + * assert.deepStrictEqual(isString("a"), true) + * assert.deepStrictEqual(isString(1), false) + * * @category guards * @since 1.0.0 */ diff --git a/src/Symbol.ts b/src/Symbol.ts index 9abf22a9e..0bd198ac5 100644 --- a/src/Symbol.ts +++ b/src/Symbol.ts @@ -5,6 +5,16 @@ import * as predicate from "@fp-ts/core/Predicate" /** + * Tests if a value is a `symbol`. + * + * @param input - The value to test. + * + * @example + * import { isSymbol } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isSymbol(Symbol.for("a")), true) + * assert.deepStrictEqual(isSymbol("a"), false) + * * @category guards * @since 1.0.0 */ diff --git a/src/These.ts b/src/These.ts index 4601a6af0..6b0783343 100644 --- a/src/These.ts +++ b/src/These.ts @@ -199,8 +199,33 @@ export const reverse: (self: These) => These = match( (e, a) => both(a, e) ) +// ------------------------------------------------------------------------------------- +// guards +// ------------------------------------------------------------------------------------- + /** - * Returns `true` if the these is an instance of `Left`, `false` otherwise + * Tests if a value is a `These`. + * + * @param input - The value to check. + * + * @category guards + * @since 1.0.0 + */ +export const isThese = (input: unknown): input is These => + typeof input === "object" && input != null && structural in input && "_tag" in input && + (input["_tag"] === "Left" || input["_tag"] === "Right" || input["_tag"] === "Both") + +/** + * Determine if a `These` is a `Left`. + * + * @param self - The `These` to check. + * + * @example + * import { isLeft, left, right, both } from '@fp-ts/core/These' + * + * assert.deepStrictEqual(isLeft(right(1)), false) + * assert.deepStrictEqual(isLeft(left("error")), true) + * assert.deepStrictEqual(isLeft(both("error", 1)), false) * * @category guards * @since 1.0.0 @@ -208,6 +233,17 @@ export const reverse: (self: These) => These = match( export const isLeft = (self: These): self is Left => self._tag === "Left" /** + * Determine if a `These` is a `Left` or a `Both`. + * + * @param self - The `These` to check. + * + * @example + * import { isLeftOrBoth, left, right, both } from '@fp-ts/core/These' + * + * assert.deepStrictEqual(isLeftOrBoth(right(1)), false) + * assert.deepStrictEqual(isLeftOrBoth(left("error")), true) + * assert.deepStrictEqual(isLeftOrBoth(both("error", 1)), true) + * * @category guards * @since 1.0.0 */ @@ -215,7 +251,16 @@ export const isLeftOrBoth = (self: These): self is Left | Both(self: These): self is Left | Both(self: These): self is Right => self._tag === "Right" /** + * Determine if a `These` is a `Right` or a `Both`. + * + * @param self - The `These` to check. + * + * @example + * import { isRightOrBoth, left, right, both } from '@fp-ts/core/These' + * + * assert.deepStrictEqual(isRightOrBoth(right(1)), true) + * assert.deepStrictEqual(isRightOrBoth(left("error")), false) + * assert.deepStrictEqual(isRightOrBoth(both("error", 1)), true) + * * @category guards * @since 1.0.0 */ @@ -230,23 +286,21 @@ export const isRightOrBoth = (self: These): self is Right | Both< self._tag !== "Left" /** - * Returns `true` if the these is an instance of `Both`, `false` otherwise + * Determine if a `These` is a `Both`. * - * @category guards - * @since 1.0.0 - */ -export const isBoth = (self: These): self is Both => self._tag === "Both" - -/** - * Returns `true` if the specified value is an instance of `These`, `false` - * otherwise. + * @param self - The `These` to check. + * + * @example + * import { isBoth, left, right, both } from '@fp-ts/core/These' + * + * assert.deepStrictEqual(isBoth(right(1)), false) + * assert.deepStrictEqual(isBoth(left("error")), false) + * assert.deepStrictEqual(isBoth(both("error", 1)), true) * * @category guards * @since 1.0.0 */ -export const isThese = (u: unknown): u is These => - typeof u === "object" && u != null && structural in u && "_tag" in u && - (u["_tag"] === "Left" || u["_tag"] === "Right" || u["_tag"] === "Both") +export const isBoth = (self: These): self is Both => self._tag === "Both" /** * Lifts a function that may throw to one returning a `These`. From 2d9ee1ccfa5cfee3bc88e98c7177b0e655a97498 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 7 Feb 2023 17:09:04 +0100 Subject: [PATCH 221/255] guides: validations --- guides/Either.md | 110 +++++++++++++++++++++++++++++++++++++++++++++++ src/Either.ts | 3 ++ 2 files changed, 113 insertions(+) diff --git a/guides/Either.md b/guides/Either.md index 0ab81f654..b7a80a985 100644 --- a/guides/Either.md +++ b/guides/Either.md @@ -609,3 +609,113 @@ console.log(sumOfRightAndLeft); // left("not a number") | `multiply` | `Either`, `Either` | `Either` | | `subtract` | `Either`, `Either` | `Either` | | `divide` | `Either`, `Either` | `Either` | + +# Validations + +Say you must implement a web form to signup for an account. The form contains two field: `username` and `password` and the following validation rules must hold: + +- `username` must not be empty +- `username` can't have dashes in it +- `password` needs to have at least 6 characters +- `password` needs to have at least one capital letter +- `password` needs to have at least one number + +The `Either` type represents a computation that might fail with an error of type `E` or succeed with a value of type `A`, so is a good candidate for implementing our validation rules. + +For example let's encode each `password` rule: + +```ts +import * as E from "@fp-ts/core/Either"; + +const minLength = (s: string): E.Either => + s.length >= 6 ? E.right(s) : E.left("at least 6 characters"); + +const oneCapital = (s: string): E.Either => + /[A-Z]/g.test(s) ? E.right(s) : E.left("at least one capital letter"); + +const oneNumber = (s: string): E.Either => + /[0-9]/g.test(s) ? E.right(s) : E.left("at least one number"); +``` + +We can chain all the rules using `flatMap`: + +```ts +import { pipe } from "@fp-ts/core/Function"; + +const validatePassword = (s: string): E.Either => + pipe(minLength(s), E.flatMap(oneCapital), E.flatMap(oneNumber)); +``` + +Because we are using `Either` the checks are **fail-fast**. That is, any failed check shortcircuits subsequent checks so we will only ever get one error. + +```ts +assert.deepStrictEqual(validatePassword("ab"), E.left("at least 6 characters")); + +assert.deepStrictEqual( + validatePassword("abcdef"), + E.left("at least one capital letter") +); + +assert.deepStrictEqual( + validatePassword("Abcdef"), + E.left("at least one number") +); +``` + +However this could lead to a bad UX, it would be nice to have all of these errors be reported simultaneously. + +The `Validated` abstraction may help here. + +## Validated + +Validations are similar to `Either`, where they represent a computation that may fail with an error of type `E` or succeed with a value of type `A`. Unlike typical computations involving `Either`, however, validations are capable of **accumulating multiple failures**. + +For this to be possible, the `Validated` data type must have the ability to combine two or more values of type `E` and the simplest way is to wrap them in a (non-empty) `ReadonlyArray`. + +This is the definition of the `Validated` data type: + +```ts +/** + * Represents a computation that may fail with one or more errors of type `E` + * or succeed with a value of type `A`. + */ +export type Validated = Either, A>; +``` + +To proceed, we must first modify all the rules so that they return a `Validated` value. + +Instead of having to rewrite all previous functions, which can be cumbersome, we can use the `liftEither` helper. This helper converts a check that outputs an `Either` into a check that outputs a `Validate`. + +```ts +const minLengthValidated = E.liftEither(minLength); +// ^? const minLengthValidated: (s: string) => E.Validated +const oneCapitalValidated = E.liftEither(oneCapital); +// ^? const oneCapitalValidated: (s: string) => E.Validated +const oneNumberValidated = E.liftEither(oneNumber); +// ^? const oneNumberValidated: (s: string) => E.Validated +``` + +Let's bring it all together. The `validatePassword` function takes a string `s` as input, and uses the `tupleValidated` helper to perform all three validation checks, returning a `Validated` value that collects all the validation error messages. If all the checks pass, the function returns the original string s as a successful `Validated` value: + +```ts +const validatePassword = (s: string): E.Validated => + pipe( + E.tupleValidated( + minLengthValidated(s), + oneCapitalValidated(s), + oneNumberValidated(s) + ), + E.map(() => s) + ); + +assert.deepStrictEqual( + validatePassword("ab"), + E.left([ + "at least 6 characters", + "at least one capital letter", + "at least one number", + ]) +); + +assert.deepStrictEqual(validatePassword("Abcde6"), E.right("Abcde6")); +``` diff --git a/src/Either.ts b/src/Either.ts index db70d04bd..8a168c58b 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1466,6 +1466,9 @@ export const andThenBind: { // ------------------------------------------------------------------------------------- /** + * Represents a computation that may fail with one or more errors of type `E` + * or succeed with a value of type `A`. + * * @category model * @since 1.0.0 */ From 2fa21df7c90cf47ef6ff2265a7ac1741e733310a Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 7 Feb 2023 17:35:54 +0100 Subject: [PATCH 222/255] Either: remove Validated --- docs/modules/Either.ts.md | 294 -------------------------------------- src/Either.ts | 293 ------------------------------------- test/Either.ts | 96 ------------- 3 files changed, 683 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 940c50630..d1c42f9db 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -24,9 +24,7 @@ Added in v1.0.0 - [getFirstLeftSemigroup](#getfirstleftsemigroup) - [getFirstRightSemigroup](#getfirstrightsemigroup) - [zipWith](#zipwith) - - [zipWithValidated](#zipwithvalidated) - [constructors](#constructors) - - [fail](#fail) - [left](#left) - [of](#of) - [right](#right) @@ -38,7 +36,6 @@ Added in v1.0.0 - [toArray](#toarray) - [toOption](#tooption) - [toRefinement](#torefinement) - - [toValidated](#tovalidated) - [debugging](#debugging) - [inspectLeft](#inspectleft) - [inspectRight](#inspectright) @@ -73,7 +70,6 @@ Added in v1.0.0 - [isRight](#isright) - [instances](#instances) - [Applicative](#applicative) - - [ApplicativeValidated](#applicativevalidated) - [Bicovariant](#bicovariant) - [Chainable](#chainable) - [Covariant](#covariant) @@ -84,13 +80,10 @@ Added in v1.0.0 - [Of](#of) - [Pointed](#pointed) - [Product](#product) - - [ProductValidated](#productvalidated) - [SemiAlternative](#semialternative) - [SemiApplicative](#semiapplicative) - - [SemiApplicativeValidated](#semiapplicativevalidated) - [SemiCoproduct](#semicoproduct) - [SemiProduct](#semiproduct) - - [SemiProductValidated](#semiproductvalidated) - [Traversable](#traversable) - [getOptionalSemigroup](#getoptionalsemigroup) - [interop](#interop) @@ -101,8 +94,6 @@ Added in v1.0.0 - [merge](#merge) - [lifting](#lifting) - [lift2](#lift2) - - [lift2Validated](#lift2validated) - - [liftEither](#lifteither) - [liftOption](#liftoption) - [liftPredicate](#liftpredicate) - [mapping](#mapping) @@ -112,8 +103,6 @@ Added in v1.0.0 - [flap](#flap) - [map](#map) - [tupled](#tupled) -- [model](#model) - - [Validated (type alias)](#validated-type-alias) - [models](#models) - [Either (type alias)](#either-type-alias) - [Left (interface)](#left-interface) @@ -131,7 +120,6 @@ Added in v1.0.0 - [traverseTap](#traversetap) - [type lambdas](#type-lambdas) - [EitherTypeLambda (interface)](#eithertypelambda-interface) - - [ValidatedTypeLambda (interface)](#validatedtypelambda-interface) - [utils](#utils) - [andThen](#andthen) - [ap](#ap) @@ -142,9 +130,7 @@ Added in v1.0.0 - [flatten](#flatten) - [reverse](#reverse) - [struct](#struct) - - [structValidated](#structvalidated) - [tuple](#tuple) - - [tupleValidated](#tuplevalidated) - [unit](#unit) --- @@ -294,64 +280,8 @@ export declare const zipWith: { Added in v1.0.0 -## zipWithValidated - -Composes two `Validated` values, using the binary function `f`, in case both `self` and `that` values are right. - -Errors are accumulated. - -**Signature** - -```ts -export declare const zipWithValidated: { - (that: Either, f: (a: A, b: B) => C): ( - self: Either - ) => Either - ( - self: Either, - that: Either, - f: (a: A, b: B) => C - ): Either -} -``` - -**Example** - -```ts -import * as E from '@fp-ts/core/Either' -import * as N from '@fp-ts/core/Number' - -assert.deepStrictEqual(E.zipWithValidated(E.right(1), E.right(2), N.sum), E.right(3)) - -assert.deepStrictEqual(E.zipWithValidated(E.fail('error1'), E.fail('error2'), N.sum), E.left(['error1', 'error2'])) -``` - -Added in v1.0.0 - # constructors -## fail - -Constructs a `Validated` with a `Left` value. - -This is useful when you need to represent an error that occurred during validation. - -**Signature** - -```ts -export declare const fail: (e: E) => Either -``` - -**Example** - -```ts -import * as E from '@fp-ts/core/Either' - -assert.deepStrictEqual(E.fail('error'), E.left(['error'])) -``` - -Added in v1.0.0 - ## left Constructs a new `Either` holding a `Left` value. This usually represents a failure, due to the right-bias of this @@ -538,30 +468,6 @@ export declare const toRefinement: (f: (a: A) => Either Added in v1.0.0 -## toValidated - -Transforms an `Either` value into a `Validated` value. - -This function is useful for transforming an `Either` with an error value into a `Validated` value that is more suited -for sequential composition and error accumulation. - -**Signature** - -```ts -export declare const toValidated: (self: Either) => Either -``` - -**Example** - -```ts -import * as E from '@fp-ts/core/Either' - -assert.deepStrictEqual(E.toValidated(E.right(1)), E.right(1)) -assert.deepStrictEqual(E.toValidated(E.left('error')), E.left(['error'])) -``` - -Added in v1.0.0 - # debugging ## inspectLeft @@ -1001,16 +907,6 @@ export declare const Applicative: applicative.Applicative Added in v1.0.0 -## ApplicativeValidated - -**Signature** - -```ts -export declare const ApplicativeValidated: applicative.Applicative -``` - -Added in v1.0.0 - ## Bicovariant **Signature** @@ -1111,16 +1007,6 @@ export declare const Product: product_.Product Added in v1.0.0 -## ProductValidated - -**Signature** - -```ts -export declare const ProductValidated: product_.Product -``` - -Added in v1.0.0 - ## SemiAlternative **Signature** @@ -1141,16 +1027,6 @@ export declare const SemiApplicative: semiApplicative.SemiApplicative -``` - -Added in v1.0.0 - ## SemiCoproduct **Signature** @@ -1171,16 +1047,6 @@ export declare const SemiProduct: semiProduct.SemiProduct Added in v1.0.0 -## SemiProductValidated - -**Signature** - -```ts -export declare const SemiProductValidated: semiProduct.SemiProduct -``` - -Added in v1.0.0 - ## Traversable **Signature** @@ -1300,66 +1166,6 @@ export declare const lift2: ( Added in v1.0.0 -## lift2Validated - -Lifts a binary function into `Validated`. - -**Signature** - -```ts -export declare const lift2Validated: ( - f: (a: A, b: B) => C -) => { - (that: Either): ( - self: Either - ) => Either - (self: Either, that: Either): Either< - readonly [E1 | E2, ...(E1 | E2)[]], - C - > -} -``` - -**Example** - -```ts -import * as E from '@fp-ts/core/Either' -import * as N from '@fp-ts/core/Number' - -const sum = E.lift2Validated(N.sum) - -assert.deepStrictEqual(sum(E.right(1), E.right(2)), E.right(3)) -assert.deepStrictEqual(sum(E.fail('error1'), E.fail('error2')), E.left(['error1', 'error2'])) -``` - -Added in v1.0.0 - -## liftEither - -Lifts an `Either`-returning function into a function that returns a `Validated`. - -**Signature** - -```ts -export declare const liftEither: ( - f: (...a: A) => Either -) => (...a: A) => Either -``` - -**Example** - -```ts -import * as E from '@fp-ts/core/Either' - -const f = (n: number) => (n >= 0 ? E.right(n) : E.left('negative number')) -const g = E.liftEither(f) - -assert.deepStrictEqual(g(1), E.right(1)) -assert.deepStrictEqual(g(-1), E.left(['negative number'])) -``` - -Added in v1.0.0 - ## liftOption **Signature** @@ -1494,18 +1300,6 @@ export declare const tupled: (self: Either) => Either Added in v1.0.0 -# model - -## Validated (type alias) - -**Signature** - -```ts -export type Validated = Either, A> -``` - -Added in v1.0.0 - # models ## Either (type alias) @@ -1696,18 +1490,6 @@ export interface EitherTypeLambda extends TypeLambda { Added in v1.0.0 -## ValidatedTypeLambda (interface) - -**Signature** - -```ts -export interface ValidatedTypeLambda extends TypeLambda { - readonly type: Validated -} -``` - -Added in v3.0.0 - # utils ## andThen @@ -1841,50 +1623,6 @@ export declare const struct: >>( Added in v1.0.0 -## structValidated - -Creates a `Validated` structure by using an object where each property is a `Validated`. - -Errors are accumulated. - -**Signature** - -```ts -export declare const structValidated: }>( - fields: R -) => Either< - readonly [ - [R[keyof R]] extends [Either] ? E : never, - ...([R[keyof R]] extends [Either] ? E : never)[] - ], - { [K in keyof R]: [R[K]] extends [Either] ? A : never } -> -``` - -**Example** - -```ts -import * as E from '@fp-ts/core/Either' - -assert.deepStrictEqual( - E.structValidated({ - x: E.right(1), - y: E.right('hello'), - }), - E.right({ x: 1, y: 'hello' }) -) - -assert.deepStrictEqual( - E.structValidated({ - x: E.fail('error1'), - y: E.fail('error2'), - }), - E.left(['error1', 'error2']) -) -``` - -Added in v1.0.0 - ## tuple **Signature** @@ -1900,38 +1638,6 @@ export declare const tuple: []>( Added in v1.0.0 -## tupleValidated - -Creates a `Validated` structure by using a tuple where each element is a `Validated`. - -Errors are accumulated. - -**Signature** - -```ts -export declare const tupleValidated: []>( - ...elements: T -) => Either< - readonly [ - [T[number]] extends [Either] ? E : never, - ...([T[number]] extends [Either] ? E : never)[] - ], - { [I in keyof T]: [T[I]] extends [Either] ? A : never } -> -``` - -**Example** - -```ts -import * as E from '@fp-ts/core/Either' - -assert.deepStrictEqual(E.tupleValidated(E.right(1), E.right('hello')), E.right([1, 'hello'])) - -assert.deepStrictEqual(E.tupleValidated(E.fail('error1'), E.fail('error2')), E.left(['error1', 'error2'])) -``` - -Added in v1.0.0 - ## unit **Signature** diff --git a/src/Either.ts b/src/Either.ts index 8a168c58b..0e16af1e1 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -8,11 +8,9 @@ import type { Kind, TypeLambda } from "@fp-ts/core/HKT" import { structural } from "@fp-ts/core/internal/effect" import * as either from "@fp-ts/core/internal/Either" import * as option from "@fp-ts/core/internal/Option" -import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import * as N from "@fp-ts/core/Number" import type { Option } from "@fp-ts/core/Option" import type { Predicate, Refinement } from "@fp-ts/core/Predicate" -import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" import * as applicative from "@fp-ts/core/typeclass/Applicative" import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" import * as chainable from "@fp-ts/core/typeclass/Chainable" @@ -1460,294 +1458,3 @@ export const andThenBind: { that: Either ): Either } = semiProduct.andThenBind(SemiProduct) - -// ------------------------------------------------------------------------------------- -// Validated -// ------------------------------------------------------------------------------------- - -/** - * Represents a computation that may fail with one or more errors of type `E` - * or succeed with a value of type `A`. - * - * @category model - * @since 1.0.0 - */ -export type Validated = Either, A> - -/** - * @category type lambdas - * @since 3.0.0 - */ -export interface ValidatedTypeLambda extends TypeLambda { - readonly type: Validated -} - -/** - * Constructs a `Validated` with a `Left` value. - * - * This is useful when you need to represent an error that occurred during validation. - * - * @param e - The error value to put in the `Left` of the resulting `Validated`. - * - * @example - * import * as E from '@fp-ts/core/Either' - * - * assert.deepStrictEqual(E.fail("error"), E.left(["error"])) - * - * @category constructors - * @since 1.0.0 - */ -export const fail = (e: E): Validated => left([e]) - -/** - * Transforms an `Either` value into a `Validated` value. - * - * This function is useful for transforming an `Either` with an error value into a `Validated` value that is more suited - * for sequential composition and error accumulation. - * - * @param self - The `Either` value to convert. - * - * @example - * import * as E from '@fp-ts/core/Either' - * - * assert.deepStrictEqual(E.toValidated(E.right(1)), E.right(1)) - * assert.deepStrictEqual(E.toValidated(E.left("error")), E.left(["error"])) - * - * @category conversions - * @since 1.0.0 - */ -export const toValidated: (self: Either) => Validated = mapLeft((e) => [e]) - -/** - * Lifts an `Either`-returning function into a function that returns a `Validated`. - * - * @param f - The `Either`-returning function to lift. - * - * @example - * import * as E from '@fp-ts/core/Either' - * - * const f = (n: number) => n >= 0 ? E.right(n) : E.left("negative number") - * const g = E.liftEither(f) - * - * assert.deepStrictEqual(g(1), E.right(1)) - * assert.deepStrictEqual(g(-1), E.left(["negative number"])) - * - * @category lifting - * @since 1.0.0 - */ -export const liftEither = , E, B>( - f: (...a: A) => Either -) => (...a: A): Validated => toValidated(f(...a)) - -const productValidated = ( - self: Validated, - that: Validated -): Validated => - isLeft(self) - ? isLeft(that) - ? left([...self.left, ...that.left]) - : self - : isLeft(that) - ? that - : right([self.right, that.right]) - -const productManyValidated = semiProduct.productMany(map, productValidated) - -/** - * @category instances - * @since 1.0.0 - */ -export const SemiProductValidated: semiProduct.SemiProduct = { - imap, - product: productValidated, - productMany: productManyValidated -} - -const productAllValidated = ( - collection: Iterable> -): Validated> => { - const as = readonlyArray.fromIterable(collection) - return productManyValidated(as[0], as.slice(1)) -} - -/** - * @category instances - * @since 1.0.0 - */ -export const ProductValidated: product_.Product = { - imap, - of, - product: productValidated, - productMany: productManyValidated, - productAll: productAllValidated -} - -/** - * Creates a `Validated` structure by using a tuple where each element is a `Validated`. - * - * Errors are accumulated. - * - * @param elements - A tuple of `Validated` values. - * - * @example - * import * as E from '@fp-ts/core/Either' - * - * assert.deepStrictEqual( - * E.tupleValidated( - * E.right(1), - * E.right("hello") - * ), - * E.right([1, "hello"]) - * ) - * - * assert.deepStrictEqual( - * E.tupleValidated( - * E.fail("error1"), - * E.fail("error2") - * ), - * E.left(["error1", "error2"]) - * ) - * - * @since 1.0.0 - */ -export const tupleValidated: >>( - ...elements: T -) => Validated< - [T[number]] extends [Validated] ? E : never, - { [I in keyof T]: [T[I]] extends [Validated] ? A : never } -> = product_.tuple(ProductValidated) - -/** - * Creates a `Validated` structure by using an object where each property is a `Validated`. - * - * Errors are accumulated. - * - * @param fields - A struct of `Validated` values. - * - * @example - * import * as E from '@fp-ts/core/Either' - * - * assert.deepStrictEqual( - * E.structValidated({ - * x: E.right(1), - * y: E.right("hello") - * }), - * E.right({ x: 1, y: "hello" }) - * ) - * - * assert.deepStrictEqual( - * E.structValidated({ - * x: E.fail("error1"), - * y: E.fail("error2") - * }), - * E.left(["error1", "error2"]) - * ) - * - * @since 1.0.0 - */ -export const structValidated: }>( - fields: R -) => Validated< - [R[keyof R]] extends [Validated] ? E : never, - { [K in keyof R]: [R[K]] extends [Validated] ? A : never } -> = product_.struct(ProductValidated) - -/** - * @category instances - * @since 1.0.0 - */ -export const SemiApplicativeValidated: semiApplicative.SemiApplicative = { - imap, - map, - product: productValidated, - productMany: productManyValidated -} - -/** - * Composes two `Validated` values, using the binary function `f`, in case both `self` and `that` values are right. - * - * Errors are accumulated. - * - * @param self - first `Validated` value to compose. - * @param that - second `Validated` value to compose. - * @param f - binary function used to compute the `Validated` result from `self` and `that`. - * - * @example - * import * as E from '@fp-ts/core/Either' - * import * as N from '@fp-ts/core/Number' - * - * assert.deepStrictEqual( - * E.zipWithValidated( - * E.right(1), - * E.right(2), - * N.sum - * ), - * E.right(3) - * ) - * - * assert.deepStrictEqual( - * E.zipWithValidated( - * E.fail("error1"), - * E.fail("error2"), - * N.sum - * ), - * E.left(["error1", "error2"]) - * ) - * - * @category combining - * @since 1.0.0 - */ -export const zipWithValidated: { - ( - that: Validated, - f: (a: A, b: B) => C - ): (self: Validated) => Validated - ( - self: Validated, - that: Validated, - f: (a: A, b: B) => C - ): Validated -} = semiApplicative.zipWith(SemiApplicativeValidated) - -/** - * Lifts a binary function into `Validated`. - * - * @param f - The function to lift. - * - * @example - * import * as E from '@fp-ts/core/Either' - * import * as N from '@fp-ts/core/Number' - * - * const sum = E.lift2Validated(N.sum) - * - * assert.deepStrictEqual(sum(E.right(1), E.right(2)), E.right(3)) - * assert.deepStrictEqual( - * sum( - * E.fail("error1"), - * E.fail("error2") - * ), - * E.left(["error1", "error2"]) - * ) - * - * @category lifting - * @since 1.0.0 - */ -export const lift2Validated: ( - f: (a: A, b: B) => C -) => { - (that: Validated): (self: Validated) => Validated - (self: Validated, that: Validated): Validated -} = semiApplicative.lift2(SemiApplicativeValidated) - -/** - * @category instances - * @since 1.0.0 - */ -export const ApplicativeValidated: applicative.Applicative = { - imap, - map, - of, - product: productValidated, - productMany: productManyValidated, - productAll: productAllValidated -} diff --git a/test/Either.ts b/test/Either.ts index ae2c87fdd..ae955ccce 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -74,11 +74,6 @@ describe.concurrent("Either", () => { expect(E.traverse).exist expect(E.sequence).exist expect(E.traverseTap).exist - - expect(E.SemiProductValidated).exist - expect(E.ProductValidated).exist - expect(E.SemiApplicativeValidated).exist - expect(E.ApplicativeValidated).exist }) it("structural tracking", () => { @@ -521,95 +516,4 @@ describe.concurrent("Either", () => { expect(E.toArray(E.right(1))).toEqual([1]) expect(E.toArray(E.left("error"))).toEqual([]) }) - - it("toValidated", () => { - assert.deepStrictEqual(E.toValidated(E.right(1)), E.right(1)) - assert.deepStrictEqual(E.toValidated(E.left("e")), E.left(["e"])) - }) - - it("liftEither", () => { - const f = (n: number) => n >= 0 ? E.right(n) : E.left("negative number") - const g = E.liftEither(f) - assert.deepStrictEqual(g(1), E.right(1)) - assert.deepStrictEqual(g(-1), E.left(["negative number"])) - }) - - it("tupleValidated", () => { - assert.deepStrictEqual( - E.tupleValidated( - E.right(1), - E.right("hello") - ), - E.right([1, "hello"]) - ) - assert.deepStrictEqual( - E.tupleValidated( - E.fail("error1"), - E.fail("error2") - ), - E.left(["error1", "error2"]) - ) - }) - - it("structValidated", () => { - assert.deepStrictEqual( - E.structValidated({ - x: E.right(1), - y: E.right("hello") - }), - E.right({ x: 1, y: "hello" }) - ) - - assert.deepStrictEqual( - E.structValidated({ - x: E.fail("error1"), - y: E.fail("error2") - }), - E.left(["error1", "error2"]) - ) - }) - - it("zipWithValidated", () => { - assert.deepStrictEqual( - E.zipWithValidated( - E.right(1), - E.right(2), - N.sum - ), - E.right(3) - ) - - assert.deepStrictEqual( - E.zipWithValidated( - E.fail("error1"), - E.right(2), - N.sum - ), - E.fail("error1") - ) - - assert.deepStrictEqual( - E.zipWithValidated( - E.right(1), - E.fail("error2"), - N.sum - ), - E.fail("error2") - ) - - assert.deepStrictEqual( - E.zipWithValidated( - E.fail("error1"), - E.fail("error2"), - N.sum - ), - E.left(["error1", "error2"]) - ) - }) - - it("lift2Validated", () => { - const sum = E.lift2Validated(N.sum) - assert.deepStrictEqual(sum(E.right(1), E.right(2)), E.right(3)) - assert.deepStrictEqual(sum(E.fail("error1"), E.fail("error2")), E.left(["error1", "error2"])) - }) }) From a221a30ae7d2467cd576deb251f5ccb84ae87013 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 7 Feb 2023 18:06:05 +0100 Subject: [PATCH 223/255] fix CI --- docs/modules/Option.ts.md | 2 +- pnpm-lock.yaml | 6 +++--- src/Option.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 0619e7cd5..66321e601 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -628,7 +628,7 @@ export declare const getEquivalence: (E: Equivalence) => Equivalence( /** * @example * import { none, some, getEquivalence } from '@fp-ts/core/Option' - * import * as N from '@fp-ts/core/number' + * import * as N from '@fp-ts/core/Number' * * const isEquivalent = getEquivalence(N.Equivalence) * assert.deepStrictEqual(isEquivalent(none(), none()), true) From 6d7fd8a62f22b35cdb32ceb20f8c21bd3fe8f401 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 7 Feb 2023 17:31:26 +0000 Subject: [PATCH 224/255] Version Packages --- .changeset/brown-foxes-explain.md | 5 --- .changeset/dull-pets-run.md | 5 --- .changeset/fresh-zebras-own.md | 5 --- .changeset/hot-lobsters-greet.md | 5 --- .changeset/khaki-eagles-lay.md | 5 --- .changeset/mean-buckets-shake.md | 5 --- .changeset/perfect-fishes-sing.md | 5 --- .changeset/pink-chefs-report.md | 5 --- .changeset/plenty-bats-try.md | 5 --- .changeset/poor-crabs-drum.md | 5 --- .changeset/popular-dingos-ring.md | 5 --- .changeset/quiet-zoos-dream.md | 5 --- .changeset/smooth-terms-pay.md | 5 --- .changeset/stale-otters-sell.md | 5 --- .changeset/swift-tomatoes-smile.md | 5 --- .changeset/tender-bugs-shave.md | 5 --- .changeset/unlucky-berries-boil.md | 5 --- .changeset/witty-toes-breathe.md | 5 --- .changeset/yellow-elephants-travel.md | 5 --- CHANGELOG.md | 44 +++++++++++++++++++++++++++ package.json | 2 +- 21 files changed, 45 insertions(+), 96 deletions(-) delete mode 100644 .changeset/brown-foxes-explain.md delete mode 100644 .changeset/dull-pets-run.md delete mode 100644 .changeset/fresh-zebras-own.md delete mode 100644 .changeset/hot-lobsters-greet.md delete mode 100644 .changeset/khaki-eagles-lay.md delete mode 100644 .changeset/mean-buckets-shake.md delete mode 100644 .changeset/perfect-fishes-sing.md delete mode 100644 .changeset/pink-chefs-report.md delete mode 100644 .changeset/plenty-bats-try.md delete mode 100644 .changeset/poor-crabs-drum.md delete mode 100644 .changeset/popular-dingos-ring.md delete mode 100644 .changeset/quiet-zoos-dream.md delete mode 100644 .changeset/smooth-terms-pay.md delete mode 100644 .changeset/stale-otters-sell.md delete mode 100644 .changeset/swift-tomatoes-smile.md delete mode 100644 .changeset/tender-bugs-shave.md delete mode 100644 .changeset/unlucky-berries-boil.md delete mode 100644 .changeset/witty-toes-breathe.md delete mode 100644 .changeset/yellow-elephants-travel.md diff --git a/.changeset/brown-foxes-explain.md b/.changeset/brown-foxes-explain.md deleted file mode 100644 index 7d44fcbe0..000000000 --- a/.changeset/brown-foxes-explain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -Identity: remove exports except do notation ones diff --git a/.changeset/dull-pets-run.md b/.changeset/dull-pets-run.md deleted file mode 100644 index 7af61da86..000000000 --- a/.changeset/dull-pets-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add default handler to `getOrThrow` diff --git a/.changeset/fresh-zebras-own.md b/.changeset/fresh-zebras-own.md deleted file mode 100644 index 6254f51fe..000000000 --- a/.changeset/fresh-zebras-own.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -Either: make orElse, orElseEither lazy and remove catchAll diff --git a/.changeset/hot-lobsters-greet.md b/.changeset/hot-lobsters-greet.md deleted file mode 100644 index be446f79d..000000000 --- a/.changeset/hot-lobsters-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -Option: remove fromThrowable diff --git a/.changeset/khaki-eagles-lay.md b/.changeset/khaki-eagles-lay.md deleted file mode 100644 index ed5f02669..000000000 --- a/.changeset/khaki-eagles-lay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -algebraic operations: add support for bigint diff --git a/.changeset/mean-buckets-shake.md b/.changeset/mean-buckets-shake.md deleted file mode 100644 index 9baf53a07..000000000 --- a/.changeset/mean-buckets-shake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -Option: remove coproductEither diff --git a/.changeset/perfect-fishes-sing.md b/.changeset/perfect-fishes-sing.md deleted file mode 100644 index e40995071..000000000 --- a/.changeset/perfect-fishes-sing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -Option: add `reduceAll` diff --git a/.changeset/pink-chefs-report.md b/.changeset/pink-chefs-report.md deleted file mode 100644 index c24598d1a..000000000 --- a/.changeset/pink-chefs-report.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -rename `element` to `appendElement` diff --git a/.changeset/plenty-bats-try.md b/.changeset/plenty-bats-try.md deleted file mode 100644 index d02914d45..000000000 --- a/.changeset/plenty-bats-try.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -Function: flip apply diff --git a/.changeset/poor-crabs-drum.md b/.changeset/poor-crabs-drum.md deleted file mode 100644 index a9e23201c..000000000 --- a/.changeset/poor-crabs-drum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -Covariant: flip flap diff --git a/.changeset/popular-dingos-ring.md b/.changeset/popular-dingos-ring.md deleted file mode 100644 index a502f4aaa..000000000 --- a/.changeset/popular-dingos-ring.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -Either: rename `firstSuccessOf` to `firstRightOf` diff --git a/.changeset/quiet-zoos-dream.md b/.changeset/quiet-zoos-dream.md deleted file mode 100644 index f137d0e4f..000000000 --- a/.changeset/quiet-zoos-dream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -remove `orElseSucceed` diff --git a/.changeset/smooth-terms-pay.md b/.changeset/smooth-terms-pay.md deleted file mode 100644 index 09b523ed8..000000000 --- a/.changeset/smooth-terms-pay.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -remove `imap` from exports diff --git a/.changeset/stale-otters-sell.md b/.changeset/stale-otters-sell.md deleted file mode 100644 index 153dc3ac7..000000000 --- a/.changeset/stale-otters-sell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -Option: make orElse, orElseEither lazy and remove catchAll diff --git a/.changeset/swift-tomatoes-smile.md b/.changeset/swift-tomatoes-smile.md deleted file mode 100644 index a80b3e6c1..000000000 --- a/.changeset/swift-tomatoes-smile.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -Option, Either, These: switch to interfaces diff --git a/.changeset/tender-bugs-shave.md b/.changeset/tender-bugs-shave.md deleted file mode 100644 index dca859734..000000000 --- a/.changeset/tender-bugs-shave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -Option: remove `compact` diff --git a/.changeset/unlucky-berries-boil.md b/.changeset/unlucky-berries-boil.md deleted file mode 100644 index 9513485f0..000000000 --- a/.changeset/unlucky-berries-boil.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -Option: change `firstSomeOf` signature diff --git a/.changeset/witty-toes-breathe.md b/.changeset/witty-toes-breathe.md deleted file mode 100644 index e14fd4788..000000000 --- a/.changeset/witty-toes-breathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -Function: add dual utility diff --git a/.changeset/yellow-elephants-travel.md b/.changeset/yellow-elephants-travel.md deleted file mode 100644 index de9881813..000000000 --- a/.changeset/yellow-elephants-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": minor ---- - -Either: remove `fromThrowable` diff --git a/CHANGELOG.md b/CHANGELOG.md index d8a133203..714dfcce6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,49 @@ # @fp-ts/core +## 0.2.0 + +### Minor Changes + +- [#55](https://github.com/fp-ts/core/pull/55) [`b3e7ff34`](https://github.com/fp-ts/core/commit/b3e7ff34596b9cf90cc94c7349cf340fb0df82ef) Thanks [@gcanti](https://github.com/gcanti)! - Identity: remove exports except do notation ones + +- [#55](https://github.com/fp-ts/core/pull/55) [`a99a23a1`](https://github.com/fp-ts/core/commit/a99a23a15ccd1c9d1f623f39d4727cb3ff0be3f7) Thanks [@gcanti](https://github.com/gcanti)! - Either: make orElse, orElseEither lazy and remove catchAll + +- [#55](https://github.com/fp-ts/core/pull/55) [`31b5fffc`](https://github.com/fp-ts/core/commit/31b5fffc175f4740c8f31f05afba48b6b8cb9cd6) Thanks [@gcanti](https://github.com/gcanti)! - Option: remove fromThrowable + +- [#55](https://github.com/fp-ts/core/pull/55) [`14de6de2`](https://github.com/fp-ts/core/commit/14de6de207c63d460ecabcb6b13f5d9abb697f05) Thanks [@gcanti](https://github.com/gcanti)! - Option: remove coproductEither + +- [#55](https://github.com/fp-ts/core/pull/55) [`f3cc9d2c`](https://github.com/fp-ts/core/commit/f3cc9d2cf2440586f2681f447ae9056d94a631d7) Thanks [@gcanti](https://github.com/gcanti)! - rename `element` to `appendElement` + +- [#55](https://github.com/fp-ts/core/pull/55) [`2bb91d1e`](https://github.com/fp-ts/core/commit/2bb91d1e15ec62bfa762bb17aec6c97305b94692) Thanks [@gcanti](https://github.com/gcanti)! - Function: flip apply + +- [#55](https://github.com/fp-ts/core/pull/55) [`9569811e`](https://github.com/fp-ts/core/commit/9569811ea5506fb4206c1b9dbde7dbdbe7e9a8bc) Thanks [@gcanti](https://github.com/gcanti)! - Covariant: flip flap + +- [#55](https://github.com/fp-ts/core/pull/55) [`ae3338c0`](https://github.com/fp-ts/core/commit/ae3338c091284e0af7b24e1be818a96d59a77f09) Thanks [@gcanti](https://github.com/gcanti)! - Either: rename `firstSuccessOf` to `firstRightOf` + +- [#55](https://github.com/fp-ts/core/pull/55) [`a4a6ebbc`](https://github.com/fp-ts/core/commit/a4a6ebbcf73b453e526fbc42a76424732b8fdb23) Thanks [@gcanti](https://github.com/gcanti)! - remove `orElseSucceed` + +- [#55](https://github.com/fp-ts/core/pull/55) [`99088b21`](https://github.com/fp-ts/core/commit/99088b21a5945cb744a380947ee79378f19766f3) Thanks [@gcanti](https://github.com/gcanti)! - remove `imap` from exports + +- [#55](https://github.com/fp-ts/core/pull/55) [`d4fcf63e`](https://github.com/fp-ts/core/commit/d4fcf63e16f15ac86a96e89b0b47c7d2647a6fe6) Thanks [@gcanti](https://github.com/gcanti)! - Option: make orElse, orElseEither lazy and remove catchAll + +- [#55](https://github.com/fp-ts/core/pull/55) [`bfb22498`](https://github.com/fp-ts/core/commit/bfb22498cb9287d40e231b4992937e3313fae1fe) Thanks [@gcanti](https://github.com/gcanti)! - Option: remove `compact` + +- [#55](https://github.com/fp-ts/core/pull/55) [`4463f4f1`](https://github.com/fp-ts/core/commit/4463f4f1649ca2f984d715d0aa22055a3a8d6519) Thanks [@gcanti](https://github.com/gcanti)! - Option: change `firstSomeOf` signature + +- [#55](https://github.com/fp-ts/core/pull/55) [`18f70fcb`](https://github.com/fp-ts/core/commit/18f70fcb18c5e8f26980fd88c1192808df241631) Thanks [@gcanti](https://github.com/gcanti)! - Either: remove `fromThrowable` + +### Patch Changes + +- [#55](https://github.com/fp-ts/core/pull/55) [`ce345a8d`](https://github.com/fp-ts/core/commit/ce345a8dd5bae7694cdbdd1bf5056b337175810d) Thanks [@gcanti](https://github.com/gcanti)! - add default handler to `getOrThrow` + +- [#55](https://github.com/fp-ts/core/pull/55) [`615d492e`](https://github.com/fp-ts/core/commit/615d492ea79b47472da256b4dea6f33835f24d23) Thanks [@gcanti](https://github.com/gcanti)! - algebraic operations: add support for bigint + +- [#55](https://github.com/fp-ts/core/pull/55) [`14f87fb3`](https://github.com/fp-ts/core/commit/14f87fb33061ef1e36a5695c0f28578c9f860cf1) Thanks [@gcanti](https://github.com/gcanti)! - Option: add `reduceAll` + +- [#51](https://github.com/fp-ts/core/pull/51) [`175d6b9e`](https://github.com/fp-ts/core/commit/175d6b9e93dbf6bfbea80b34a06f26ceb3d725aa) Thanks [@gcanti](https://github.com/gcanti)! - Option, Either, These: switch to interfaces + +- [#51](https://github.com/fp-ts/core/pull/51) [`3efb6d8a`](https://github.com/fp-ts/core/commit/3efb6d8a9a343ca177ec7bcc3e360974aec307cf) Thanks [@gcanti](https://github.com/gcanti)! - Function: add dual utility + ## 0.1.1 ### Patch Changes diff --git a/package.json b/package.json index 2e19f0f09..29a3b38f9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fp-ts/core", - "version": "0.1.1", + "version": "0.2.0", "publishConfig": { "access": "public", "directory": "dist" From cf4918de74504ec59dd00df0ff251a549fb51284 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 8 Feb 2023 07:44:57 +0100 Subject: [PATCH 225/255] ReadonlyArray: handle mutable arrays in isEmpty, isNonEmpty guards --- .changeset/unlucky-walls-prove.md | 5 +++++ docs/modules/ReadonlyArray.ts.md | 10 +++++++--- dtslint/ts4.7/ReadonlyArray.ts | 28 ++++++++++++++++++++++++++++ src/ReadonlyArray.ts | 14 ++++++++++---- src/internal/ReadonlyArray.ts | 8 ++++++-- 5 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 .changeset/unlucky-walls-prove.md diff --git a/.changeset/unlucky-walls-prove.md b/.changeset/unlucky-walls-prove.md new file mode 100644 index 000000000..872f4419a --- /dev/null +++ b/.changeset/unlucky-walls-prove.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +ReadonlyArray: handle mutable arrays in isEmpty, isNonEmpty guards diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 730724ab8..fd2927a9d 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -1111,7 +1111,8 @@ Determine if a `ReadonlyArray` is empty narrowing down the type to `[]`. **Signature** ```ts -export declare const isEmpty: (self: readonly A[]) => self is readonly [] +export declare function isEmpty(self: Array): self is [] +export declare function isEmpty(self: ReadonlyArray): self is readonly [] ``` **Example** @@ -1127,14 +1128,17 @@ Added in v1.0.0 ## isNonEmpty -Determine if a `ReadonlyArray` is empty narrowing down the type to `NonEmptyReadonlyArray`. +Determine if a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyArray`. A `ReadonlyArray` is considered to be a `NonEmptyReadonlyArray` if it contains at least one element. **Signature** ```ts -export declare const isNonEmpty: (self: readonly A[]) => self is readonly [A, ...A[]] +export declare const isNonEmpty: { + (self: A[]): self is [A, ...A[]] + (self: readonly A[]): self is readonly [A, ...A[]] +} ``` **Example** diff --git a/dtslint/ts4.7/ReadonlyArray.ts b/dtslint/ts4.7/ReadonlyArray.ts index 26b7012ee..5f59ead93 100644 --- a/dtslint/ts4.7/ReadonlyArray.ts +++ b/dtslint/ts4.7/ReadonlyArray.ts @@ -6,6 +6,34 @@ declare const neas: RA.NonEmptyArray declare const ras: ReadonlyArray declare const as: Array +// ------------------------------------------------------------------------------------- +// isEmpty +// ------------------------------------------------------------------------------------- + +if (RA.isEmpty(ras)) { + // $ExpectType readonly [] + ras +} + +if (RA.isEmpty(as)) { + // $ExpectType [] + as +} + +// ------------------------------------------------------------------------------------- +// isNonEmpty +// ------------------------------------------------------------------------------------- + +if (RA.isNonEmpty(ras)) { + // $ExpectType readonly [number, ...number[]] + ras +} + +if (RA.isNonEmpty(as)) { + // $ExpectType [number, ...number[]] + as +} + // ------------------------------------------------------------------------------------- // map // ------------------------------------------------------------------------------------- diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index d581aaaa6..d8902c488 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -324,10 +324,14 @@ export const scanRight: { * @category guards * @since 1.0.0 */ -export const isEmpty = (self: ReadonlyArray): self is readonly [] => self.length === 0 +export function isEmpty(self: Array): self is [] +export function isEmpty(self: ReadonlyArray): self is readonly [] +export function isEmpty(self: ReadonlyArray): self is readonly [] { + return self.length === 0 +} /** - * Determine if a `ReadonlyArray` is empty narrowing down the type to `NonEmptyReadonlyArray`. + * Determine if a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyArray`. * * A `ReadonlyArray` is considered to be a `NonEmptyReadonlyArray` if it contains at least one element. * @@ -342,8 +346,10 @@ export const isEmpty = (self: ReadonlyArray): self is readonly [] => self. * @category guards * @since 1.0.0 */ -export const isNonEmpty: (self: ReadonlyArray) => self is NonEmptyReadonlyArray = - readonlyArray.isNonEmpty +export const isNonEmpty: { + (self: Array): self is NonEmptyArray + (self: ReadonlyArray): self is NonEmptyReadonlyArray +} = readonlyArray.isNonEmpty /** * Return the number of elements in a `ReadonlyArray`. diff --git a/src/internal/ReadonlyArray.ts b/src/internal/ReadonlyArray.ts index b57460040..de2139f91 100644 --- a/src/internal/ReadonlyArray.ts +++ b/src/internal/ReadonlyArray.ts @@ -2,10 +2,14 @@ * @since 1.0.0 */ -import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" +import type { NonEmptyArray, NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" /** @internal */ -export const isNonEmpty = (as: ReadonlyArray): as is NonEmptyReadonlyArray => as.length > 0 +export function isNonEmpty(self: Array): self is NonEmptyArray +export function isNonEmpty(self: ReadonlyArray): self is NonEmptyReadonlyArray +export function isNonEmpty(self: ReadonlyArray): self is readonly [] { + return self.length > 0 +} /** @internal */ export const fromIterable = (collection: Iterable): Array => From 549509b8a02a515becd514cfbb00044b313d5ede Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 8 Feb 2023 10:20:12 +0100 Subject: [PATCH 226/255] Number: add remainder --- .changeset/six-otters-cover.md | 5 +++++ docs/modules/Number.ts.md | 25 +++++++++++++++++++++++++ src/Number.ts | 31 +++++++++++++++++++++++++++++++ test/Number.ts | 16 ++++++++++++++++ 4 files changed, 77 insertions(+) create mode 100644 .changeset/six-otters-cover.md diff --git a/.changeset/six-otters-cover.md b/.changeset/six-otters-cover.md new file mode 100644 index 000000000..2d46347f5 --- /dev/null +++ b/.changeset/six-otters-cover.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Number: add remainder diff --git a/docs/modules/Number.ts.md b/docs/modules/Number.ts.md index 8f701ced0..cb381fc4a 100644 --- a/docs/modules/Number.ts.md +++ b/docs/modules/Number.ts.md @@ -20,6 +20,7 @@ Added in v1.0.0 - [divide](#divide) - [multiply](#multiply) - [multiplyAll](#multiplyall) + - [remainder](#remainder) - [subtract](#subtract) - [sum](#sum) - [sumAll](#sumall) @@ -94,6 +95,30 @@ export declare const multiplyAll: (collection: Iterable) => number Added in v1.0.0 +## remainder + +Returns the remainder left over when one operand is divided by a second operand. + +It always takes the sign of the dividend. + +**Signature** + +```ts +export declare const remainder: { (divisor: number): (self: number) => number; (self: number, divisor: number): number } +``` + +**Example** + +```ts +import { remainder } from '@fp-ts/core/Number' + +assert.deepStrictEqual(remainder(2, 2), 0) +assert.deepStrictEqual(remainder(3, 2), 1) +assert.deepStrictEqual(remainder(-4, 2), -0) +``` + +Added in v1.0.0 + ## subtract **Signature** diff --git a/src/Number.ts b/src/Number.ts index 04dad0bf2..1d9515099 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -219,6 +219,37 @@ export const sumAll: (collection: Iterable) => number = MonoidSum.combin */ export const multiplyAll: (collection: Iterable) => number = MonoidMultiply.combineAll +/** + * Returns the remainder left over when one operand is divided by a second operand. + * + * It always takes the sign of the dividend. + * + * @param self - The dividend. + * @param divisor - The divisor. + * + * @example + * import { remainder } from "@fp-ts/core/Number" + * + * assert.deepStrictEqual(remainder(2, 2), 0) + * assert.deepStrictEqual(remainder(3, 2), 1) + * assert.deepStrictEqual(remainder(-4, 2), -0) + * + * @category algebraic operations + * @since 1.0.0 + */ +export const remainder: { + (divisor: number): (self: number) => number + (self: number, divisor: number): number +} = dual(2, (self: number, divisor: number): number => { + // https://stackoverflow.com/questions/3966484/why-does-modulus-operator-return-fractional-number-in-javascript/31711034#31711034 + const valDecCount = (self.toString().split(".")[1] || "").length + const stepDecCount = (divisor.toString().split(".")[1] || "").length + const decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount + const valInt = parseInt(self.toFixed(decCount).replace(".", "")) + const stepInt = parseInt(divisor.toFixed(decCount).replace(".", "")) + return (valInt % stepInt) / Math.pow(10, decCount) +}) + /* Missing: diff --git a/test/Number.ts b/test/Number.ts index 5a3f89c0e..bfefd8b45 100644 --- a/test/Number.ts +++ b/test/Number.ts @@ -84,4 +84,20 @@ describe.concurrent("Number", () => { deepStrictEqual(Number.sign(10), 1) deepStrictEqual(Number.sign(0.1), 1) }) + + it("remainder", () => { + assert.deepStrictEqual(Number.remainder(2, 2), 0) + assert.deepStrictEqual(Number.remainder(3, 2), 1) + assert.deepStrictEqual(Number.remainder(4, 2), 0) + assert.deepStrictEqual(Number.remainder(-2, 2), -0) + assert.deepStrictEqual(Number.remainder(-3, 2), -1) + assert.deepStrictEqual(Number.remainder(-4, 2), -0) + assert.deepStrictEqual(Number.remainder(-2.8, -.2), -0) + assert.deepStrictEqual(Number.remainder(-2, -.2), -0) + assert.deepStrictEqual(Number.remainder(-1.5, -.2), -0.1) + assert.deepStrictEqual(Number.remainder(0, -.2), 0) + assert.deepStrictEqual(Number.remainder(1, -.2), 0) + assert.deepStrictEqual(Number.remainder(2.6, -.2), 0) + assert.deepStrictEqual(Number.remainder(3.1, -.2), 0.1) + }) }) From 5efa9c03572c9f39dd0e801dfe404e9e18d5fba2 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 8 Feb 2023 12:25:33 +0100 Subject: [PATCH 227/255] Predicate: add more guards --- .changeset/fresh-teachers-compete.md | 5 + README.md | 15 + docs/modules/Function.ts.md | 25 ++ docs/modules/Predicate.ts.md | 384 ++++++++++++++++++-- dtslint/index.d.ts | 2 +- dtslint/{ts4.7 => ts4.8}/FlatMap.ts | 0 dtslint/{ts4.7 => ts4.8}/Monoid.ts | 0 dtslint/{ts4.7 => ts4.8}/Option.ts | 0 dtslint/ts4.8/Predicate.ts | 162 +++++++++ dtslint/{ts4.7 => ts4.8}/Product.ts | 0 dtslint/{ts4.7 => ts4.8}/ReadonlyArray.ts | 0 dtslint/{ts4.7 => ts4.8}/ReadonlyRecord.ts | 0 dtslint/{ts4.7 => ts4.8}/SemiAlternative.ts | 0 dtslint/{ts4.7 => ts4.8}/SemiProduct.ts | 0 dtslint/{ts4.7 => ts4.8}/Semigroup.ts | 0 dtslint/{ts4.7 => ts4.8}/Tuple.ts | 0 dtslint/{ts4.7 => ts4.8}/index.d.ts | 0 dtslint/{ts4.7 => ts4.8}/index.ts | 0 dtslint/{ts4.7 => ts4.8}/tsconfig.json | 0 dtslint/{ts4.7 => ts4.8}/tslint.json | 0 src/Function.ts | 16 + src/Number.ts | 12 +- src/Predicate.ts | 275 +++++++++++++- test/Number.ts | 1 + test/Predicate.ts | 101 ++++- 25 files changed, 958 insertions(+), 40 deletions(-) create mode 100644 .changeset/fresh-teachers-compete.md rename dtslint/{ts4.7 => ts4.8}/FlatMap.ts (100%) rename dtslint/{ts4.7 => ts4.8}/Monoid.ts (100%) rename dtslint/{ts4.7 => ts4.8}/Option.ts (100%) create mode 100644 dtslint/ts4.8/Predicate.ts rename dtslint/{ts4.7 => ts4.8}/Product.ts (100%) rename dtslint/{ts4.7 => ts4.8}/ReadonlyArray.ts (100%) rename dtslint/{ts4.7 => ts4.8}/ReadonlyRecord.ts (100%) rename dtslint/{ts4.7 => ts4.8}/SemiAlternative.ts (100%) rename dtslint/{ts4.7 => ts4.8}/SemiProduct.ts (100%) rename dtslint/{ts4.7 => ts4.8}/Semigroup.ts (100%) rename dtslint/{ts4.7 => ts4.8}/Tuple.ts (100%) rename dtslint/{ts4.7 => ts4.8}/index.d.ts (100%) rename dtslint/{ts4.7 => ts4.8}/index.ts (100%) rename dtslint/{ts4.7 => ts4.8}/tsconfig.json (100%) rename dtslint/{ts4.7 => ts4.8}/tslint.json (100%) diff --git a/.changeset/fresh-teachers-compete.md b/.changeset/fresh-teachers-compete.md new file mode 100644 index 000000000..70413c6e7 --- /dev/null +++ b/.changeset/fresh-teachers-compete.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Predicate: add more guards diff --git a/README.md b/README.md index ddef982b5..5b0bc56d1 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,21 @@ A huge thanks to my sponsors who made the development of `@fp-ts/core` possible. If you also want to **become a sponsor** to ensure this library continues to improve and receive maintenance, check out my [GitHub Sponsors profile](https://github.com/sponsors/gcanti?o=sd&sc=t) +## Requirements + +- TypeScript 4.8 or newer +- The `strict` flag enabled in your `tsconfig.json` file + +``` +{ + // ... + "compilerOptions": { + // ... + "strict": true, + } +} +``` + # Typed functional programming in TypeScript This project represents the next major iteration of [`fp-ts`](https://github.com/gcanti/fp-ts) and it's objective is a reconciliation with [`@effect`](https://github.com/Effect-TS) in order to unify the ecosystems. diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 6d9ffe7c7..2f9a4cdd9 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -12,6 +12,8 @@ Added in v1.0.0

Table of contents

+- [guards](#guards) + - [isFunction](#isfunction) - [type lambdas](#type-lambdas) - [FunctionTypeLambda (interface)](#functiontypelambda-interface) - [utils](#utils) @@ -39,6 +41,29 @@ Added in v1.0.0 --- +# guards + +## isFunction + +Tests if a value is a `function`. + +**Signature** + +```ts +export declare const isFunction: (input: unknown) => input is Function +``` + +**Example** + +```ts +import { isFunction } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isFunction(isFunction), true) +assert.deepStrictEqual(isFunction('function'), false) +``` + +Added in v1.0.0 + # type lambdas ## FunctionTypeLambda (interface) diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index ee98f9ce6..0b9fbddda 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -14,8 +14,6 @@ Added in v1.0.0 - [combinators](#combinators) - [contramap](#contramap) -- [constructors](#constructors) - - [id](#id) - [do notation](#do-notation) - [Do](#do) - [andThenBind](#andthenbind) @@ -23,9 +21,23 @@ Added in v1.0.0 - [guards](#guards) - [isBigint](#isbigint) - [isBoolean](#isboolean) + - [isDate](#isdate) + - [isError](#iserror) + - [isFunction](#isfunction) + - [isNever](#isnever) + - [isNotNull](#isnotnull) + - [isNotNullable](#isnotnullable) + - [isNotUndefined](#isnotundefined) + - [isNull](#isnull) + - [isNullable](#isnullable) - [isNumber](#isnumber) + - [isObject](#isobject) + - [isReadonlyRecord](#isreadonlyrecord) + - [isRecord](#isrecord) - [isString](#isstring) - [isSymbol](#issymbol) + - [isUndefined](#isundefined) + - [isUnknown](#isunknown) - [instances](#instances) - [Contravariant](#contravariant) - [Invariant](#invariant) @@ -38,10 +50,10 @@ Added in v1.0.0 - [getSemigroupAny](#getsemigroupany) - [models](#models) - [Predicate (interface)](#predicate-interface) + - [Refinement (interface)](#refinement-interface) - [type lambdas](#type-lambdas) - [PredicateTypeLambda (interface)](#predicatetypelambda-interface) - [utils](#utils) - - [Refinement (interface)](#refinement-interface) - [all](#all) - [and](#and) - [any](#any) @@ -72,18 +84,6 @@ export declare const contramap: { Added in v1.0.0 -# constructors - -## id - -**Signature** - -```ts -export declare const id:
() => Refinement -``` - -Added in v1.0.0 - # do notation ## Do @@ -148,6 +148,7 @@ export declare const isBigint: (input: unknown) => input is bigint import { isBigint } from '@fp-ts/core/Predicate' assert.deepStrictEqual(isBigint(1n), true) + assert.deepStrictEqual(isBigint(1), false) ``` @@ -169,11 +170,220 @@ export declare const isBoolean: (input: unknown) => input is boolean import { isBoolean } from '@fp-ts/core/Predicate' assert.deepStrictEqual(isBoolean(true), true) + assert.deepStrictEqual(isBoolean('true'), false) ``` Added in v1.0.0 +## isDate + +A guard that succeeds when the input is a `Date`. + +**Signature** + +```ts +export declare const isDate: (input: unknown) => input is Date +``` + +**Example** + +```ts +import { isDate } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isDate(new Date()), true) + +assert.deepStrictEqual(isDate(null), false) +assert.deepStrictEqual(isDate({}), false) +``` + +Added in v1.0.0 + +## isError + +A guard that succeeds when the input is an `Error`. + +**Signature** + +```ts +export declare const isError: (input: unknown) => input is Error +``` + +**Example** + +```ts +import { isError } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isError(new Error()), true) + +assert.deepStrictEqual(isError(null), false) +assert.deepStrictEqual(isError({}), false) +``` + +Added in v1.0.0 + +## isFunction + +Tests if a value is a `function`. + +**Signature** + +```ts +export declare const isFunction: (input: unknown) => input is Function +``` + +**Example** + +```ts +import { isFunction } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isFunction(isFunction), true) + +assert.deepStrictEqual(isFunction('function'), false) +``` + +Added in v1.0.0 + +## isNever + +A guard that always fails. + +**Signature** + +```ts +export declare const isNever: (input: unknown) => input is never +``` + +**Example** + +```ts +import { isNever } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isNever(null), false) +assert.deepStrictEqual(isNever(undefined), false) +assert.deepStrictEqual(isNever({}), false) +assert.deepStrictEqual(isNever([]), false) +``` + +Added in v1.0.0 + +## isNotNull + +Tests if a value is not `undefined`. + +**Signature** + +```ts +export declare const isNotNull: (input: A) => input is Exclude +``` + +**Example** + +```ts +import { isNotNull } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isNotNull(undefined), true) +assert.deepStrictEqual(isNotNull('null'), true) + +assert.deepStrictEqual(isNotNull(null), false) +``` + +Added in v1.0.0 + +## isNotNullable + +A guard that succeeds when the input is not `null` or `undefined`. + +**Signature** + +```ts +export declare const isNotNullable: (input: A) => input is NonNullable +``` + +**Example** + +```ts +import { isNotNullable } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isNotNullable({}), true) +assert.deepStrictEqual(isNotNullable([]), true) + +assert.deepStrictEqual(isNotNullable(null), false) +assert.deepStrictEqual(isNotNullable(undefined), false) +``` + +Added in v1.0.0 + +## isNotUndefined + +Tests if a value is not `undefined`. + +**Signature** + +```ts +export declare const isNotUndefined: (input: A) => input is Exclude +``` + +**Example** + +```ts +import { isNotUndefined } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isNotUndefined(null), true) +assert.deepStrictEqual(isNotUndefined('undefined'), true) + +assert.deepStrictEqual(isNotUndefined(undefined), false) +``` + +Added in v1.0.0 + +## isNull + +Tests if a value is `undefined`. + +**Signature** + +```ts +export declare const isNull: (input: unknown) => input is null +``` + +**Example** + +```ts +import { isNull } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isNull(null), true) + +assert.deepStrictEqual(isNull(undefined), false) +assert.deepStrictEqual(isNull('null'), false) +``` + +Added in v1.0.0 + +## isNullable + +A guard that succeeds when the input is `null` or `undefined`. + +**Signature** + +```ts +export declare const isNullable: (input: A) => input is Extract +``` + +**Example** + +```ts +import { isNullable } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isNullable(null), true) +assert.deepStrictEqual(isNullable(undefined), true) + +assert.deepStrictEqual(isNullable({}), false) +assert.deepStrictEqual(isNullable([]), false) +``` + +Added in v1.0.0 + ## isNumber Tests if a value is a `number`. @@ -190,11 +400,88 @@ export declare const isNumber: (input: unknown) => input is number import { isNumber } from '@fp-ts/core/Predicate' assert.deepStrictEqual(isNumber(2), true) + assert.deepStrictEqual(isNumber('2'), false) ``` Added in v1.0.0 +## isObject + +Tests if a value is an `object`. + +**Signature** + +```ts +export declare const isObject: (input: unknown) => input is object +``` + +**Example** + +```ts +import { isObject } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isObject({}), true) +assert.deepStrictEqual(isObject([]), true) + +assert.deepStrictEqual(isObject(null), false) +assert.deepStrictEqual(isObject(undefined), false) +``` + +Added in v1.0.0 + +## isReadonlyRecord + +A guard that succeeds when the input is a readonly record. + +**Signature** + +```ts +export declare const isReadonlyRecord: (input: unknown) => input is {} +``` + +**Example** + +```ts +import { isReadonlyRecord } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isReadonlyRecord({}), true) +assert.deepStrictEqual(isReadonlyRecord({ a: 1 }), true) + +assert.deepStrictEqual(isReadonlyRecord([]), false) +assert.deepStrictEqual(isReadonlyRecord([1, 2, 3]), false) +assert.deepStrictEqual(isReadonlyRecord(null), false) +assert.deepStrictEqual(isReadonlyRecord(undefined), false) +``` + +Added in v1.0.0 + +## isRecord + +A guard that succeeds when the input is a record. + +**Signature** + +```ts +export declare const isRecord: (input: unknown) => input is {} +``` + +**Example** + +```ts +import { isRecord } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isRecord({}), true) +assert.deepStrictEqual(isRecord({ a: 1 }), true) + +assert.deepStrictEqual(isRecord([]), false) +assert.deepStrictEqual(isRecord([1, 2, 3]), false) +assert.deepStrictEqual(isRecord(null), false) +assert.deepStrictEqual(isRecord(undefined), false) +``` + +Added in v1.0.0 + ## isString Tests if a value is a `string`. @@ -211,6 +498,7 @@ export declare const isString: (input: unknown) => input is string import { isString } from '@fp-ts/core/Predicate' assert.deepStrictEqual(isString('a'), true) + assert.deepStrictEqual(isString(1), false) ``` @@ -232,11 +520,59 @@ export declare const isSymbol: (input: unknown) => input is symbol import { isSymbol } from '@fp-ts/core/Predicate' assert.deepStrictEqual(isSymbol(Symbol.for('a')), true) + assert.deepStrictEqual(isSymbol('a'), false) ``` Added in v1.0.0 +## isUndefined + +Tests if a value is `undefined`. + +**Signature** + +```ts +export declare const isUndefined: (input: unknown) => input is undefined +``` + +**Example** + +```ts +import { isUndefined } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isUndefined(undefined), true) + +assert.deepStrictEqual(isUndefined(null), false) +assert.deepStrictEqual(isUndefined('undefined'), false) +``` + +Added in v1.0.0 + +## isUnknown + +A guard that always succeeds. + +**Signature** + +```ts +export declare const isUnknown: (input: unknown) => input is unknown +``` + +**Example** + +```ts +import { isUnknown } from '@fp-ts/core/Predicate' + +assert.deepStrictEqual(isUnknown(null), true) +assert.deepStrictEqual(isUnknown(undefined), true) + +assert.deepStrictEqual(isUnknown({}), true) +assert.deepStrictEqual(isUnknown([]), true) +``` + +Added in v1.0.0 + # instances ## Contravariant @@ -343,34 +679,34 @@ export interface Predicate { Added in v1.0.0 -# type lambdas - -## PredicateTypeLambda (interface) +## Refinement (interface) **Signature** ```ts -export interface PredicateTypeLambda extends TypeLambda { - readonly type: Predicate +export interface Refinement { + (a: A): a is B } ``` Added in v1.0.0 -# utils +# type lambdas -## Refinement (interface) +## PredicateTypeLambda (interface) **Signature** ```ts -export interface Refinement { - (a: A): a is B +export interface PredicateTypeLambda extends TypeLambda { + readonly type: Predicate } ``` Added in v1.0.0 +# utils + ## all **Signature** diff --git a/dtslint/index.d.ts b/dtslint/index.d.ts index 611f70e40..22568c17c 100644 --- a/dtslint/index.d.ts +++ b/dtslint/index.d.ts @@ -1 +1 @@ -// TypeScript Version: 4.7 +// TypeScript Version: 4.8 diff --git a/dtslint/ts4.7/FlatMap.ts b/dtslint/ts4.8/FlatMap.ts similarity index 100% rename from dtslint/ts4.7/FlatMap.ts rename to dtslint/ts4.8/FlatMap.ts diff --git a/dtslint/ts4.7/Monoid.ts b/dtslint/ts4.8/Monoid.ts similarity index 100% rename from dtslint/ts4.7/Monoid.ts rename to dtslint/ts4.8/Monoid.ts diff --git a/dtslint/ts4.7/Option.ts b/dtslint/ts4.8/Option.ts similarity index 100% rename from dtslint/ts4.7/Option.ts rename to dtslint/ts4.8/Option.ts diff --git a/dtslint/ts4.8/Predicate.ts b/dtslint/ts4.8/Predicate.ts new file mode 100644 index 000000000..abcdae77f --- /dev/null +++ b/dtslint/ts4.8/Predicate.ts @@ -0,0 +1,162 @@ +import * as _ from '@fp-ts/core/Predicate' + +declare const u: unknown +declare const anys: Array +declare const unknowns: Array +declare const numberOrNull: Array +declare const numberOrUndefined: Array +declare const numberOrNullOrUndefined: Array + +// ------------------------------------------------------------------------------------- +// isString +// ------------------------------------------------------------------------------------- + +// $ExpectType string[] +unknowns.filter(_.isString) + +// ------------------------------------------------------------------------------------- +// isNumber +// ------------------------------------------------------------------------------------- + +// $ExpectType number[] +unknowns.filter(_.isNumber) + +// ------------------------------------------------------------------------------------- +// isBoolean +// ------------------------------------------------------------------------------------- + +// $ExpectType boolean[] +unknowns.filter(_.isBoolean) + +// ------------------------------------------------------------------------------------- +// isBigint +// ------------------------------------------------------------------------------------- + +// $ExpectType bigint[] +unknowns.filter(_.isBigint) + +// ------------------------------------------------------------------------------------- +// isSymbol +// ------------------------------------------------------------------------------------- + +// $ExpectType symbol[] +unknowns.filter(_.isSymbol) + +// ------------------------------------------------------------------------------------- +// isUndefined +// ------------------------------------------------------------------------------------- + +// $ExpectType undefined[] +unknowns.filter(_.isUndefined) + +// ------------------------------------------------------------------------------------- +// isNotUndefined +// ------------------------------------------------------------------------------------- + +// $ExpectType number[] +numberOrUndefined.filter(_.isNotUndefined) + +// $ExpectType (number | null)[] +numberOrNullOrUndefined.filter(_.isNotUndefined) + +// ------------------------------------------------------------------------------------- +// isUndefined +// ------------------------------------------------------------------------------------- + +// $ExpectType null[] +unknowns.filter(_.isNull) + +// ------------------------------------------------------------------------------------- +// isNotUndefined +// ------------------------------------------------------------------------------------- + +// $ExpectType number[] +numberOrNull.filter(_.isNotNull) + +// $ExpectType (number | undefined)[] +numberOrNullOrUndefined.filter(_.isNotNull) + +// ------------------------------------------------------------------------------------- +// isNever +// ------------------------------------------------------------------------------------- + +// $ExpectType never[] +unknowns.filter(_.isNever) + +// ------------------------------------------------------------------------------------- +// isUnknown +// ------------------------------------------------------------------------------------- + +// $ExpectType unknown[] +anys.filter(_.isUnknown) + +// ------------------------------------------------------------------------------------- +// isObject +// ------------------------------------------------------------------------------------- + +// $ExpectType object[] +anys.filter(_.isObject) + +// ------------------------------------------------------------------------------------- +// isNullable +// ------------------------------------------------------------------------------------- + +// $ExpectType null[] +numberOrNull.filter(_.isNullable) + +// $ExpectType undefined[] +numberOrUndefined.filter(_.isNullable) + +// $ExpectType (null | undefined)[] +numberOrNullOrUndefined.filter(_.isNullable) + +if (_.isNullable(u)) { + // $ExpectType never + u +} + +// ------------------------------------------------------------------------------------- +// isNotNullable +// ------------------------------------------------------------------------------------- + +// $ExpectType number[] +numberOrNull.filter(_.isNotNullable) + +// $ExpectType number[] +numberOrUndefined.filter(_.isNotNullable) + +// $ExpectType number[] +numberOrNullOrUndefined.filter(_.isNotNullable) + +if (_.isNotNullable(u)) { + // $ExpectType {} + u +} + +// ------------------------------------------------------------------------------------- +// isError +// ------------------------------------------------------------------------------------- + +// $ExpectType Error[] +unknowns.filter(_.isError) + +// ------------------------------------------------------------------------------------- +// isDate +// ------------------------------------------------------------------------------------- + +// $ExpectType Date[] +unknowns.filter(_.isDate) + +// ------------------------------------------------------------------------------------- +// isRecord +// ------------------------------------------------------------------------------------- + +// $ExpectType { [x: string]: unknown; [x: symbol]: unknown; }[] +unknowns.filter(_.isRecord) + +// ------------------------------------------------------------------------------------- +// isReadonlyRecord +// ------------------------------------------------------------------------------------- + +// $ExpectType { readonly [x: string]: unknown; readonly [x: symbol]: unknown; }[] +unknowns.filter(_.isReadonlyRecord) diff --git a/dtslint/ts4.7/Product.ts b/dtslint/ts4.8/Product.ts similarity index 100% rename from dtslint/ts4.7/Product.ts rename to dtslint/ts4.8/Product.ts diff --git a/dtslint/ts4.7/ReadonlyArray.ts b/dtslint/ts4.8/ReadonlyArray.ts similarity index 100% rename from dtslint/ts4.7/ReadonlyArray.ts rename to dtslint/ts4.8/ReadonlyArray.ts diff --git a/dtslint/ts4.7/ReadonlyRecord.ts b/dtslint/ts4.8/ReadonlyRecord.ts similarity index 100% rename from dtslint/ts4.7/ReadonlyRecord.ts rename to dtslint/ts4.8/ReadonlyRecord.ts diff --git a/dtslint/ts4.7/SemiAlternative.ts b/dtslint/ts4.8/SemiAlternative.ts similarity index 100% rename from dtslint/ts4.7/SemiAlternative.ts rename to dtslint/ts4.8/SemiAlternative.ts diff --git a/dtslint/ts4.7/SemiProduct.ts b/dtslint/ts4.8/SemiProduct.ts similarity index 100% rename from dtslint/ts4.7/SemiProduct.ts rename to dtslint/ts4.8/SemiProduct.ts diff --git a/dtslint/ts4.7/Semigroup.ts b/dtslint/ts4.8/Semigroup.ts similarity index 100% rename from dtslint/ts4.7/Semigroup.ts rename to dtslint/ts4.8/Semigroup.ts diff --git a/dtslint/ts4.7/Tuple.ts b/dtslint/ts4.8/Tuple.ts similarity index 100% rename from dtslint/ts4.7/Tuple.ts rename to dtslint/ts4.8/Tuple.ts diff --git a/dtslint/ts4.7/index.d.ts b/dtslint/ts4.8/index.d.ts similarity index 100% rename from dtslint/ts4.7/index.d.ts rename to dtslint/ts4.8/index.d.ts diff --git a/dtslint/ts4.7/index.ts b/dtslint/ts4.8/index.ts similarity index 100% rename from dtslint/ts4.7/index.ts rename to dtslint/ts4.8/index.ts diff --git a/dtslint/ts4.7/tsconfig.json b/dtslint/ts4.8/tsconfig.json similarity index 100% rename from dtslint/ts4.7/tsconfig.json rename to dtslint/ts4.8/tsconfig.json diff --git a/dtslint/ts4.7/tslint.json b/dtslint/ts4.8/tslint.json similarity index 100% rename from dtslint/ts4.7/tslint.json rename to dtslint/ts4.8/tslint.json diff --git a/src/Function.ts b/src/Function.ts index 0b7a5c61a..1cbd357d3 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -15,6 +15,22 @@ export interface FunctionTypeLambda extends TypeLambda { readonly type: (a: this["In"]) => this["Target"] } +/** + * Tests if a value is a `function`. + * + * @param input - The value to test. + * + * @example + * import { isFunction } from '@fp-ts/core/Predicate' + * + * assert.deepStrictEqual(isFunction(isFunction), true) + * assert.deepStrictEqual(isFunction("function"), false) + * + * @category guards + * @since 1.0.0 + */ +export const isFunction = (input: unknown): input is Function => typeof input === "function" + /** * Creates a function that is both data-last and data-first. * diff --git a/src/Number.ts b/src/Number.ts index 1d9515099..0cddcacfa 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -242,12 +242,12 @@ export const remainder: { (self: number, divisor: number): number } = dual(2, (self: number, divisor: number): number => { // https://stackoverflow.com/questions/3966484/why-does-modulus-operator-return-fractional-number-in-javascript/31711034#31711034 - const valDecCount = (self.toString().split(".")[1] || "").length - const stepDecCount = (divisor.toString().split(".")[1] || "").length - const decCount = valDecCount > stepDecCount ? valDecCount : stepDecCount - const valInt = parseInt(self.toFixed(decCount).replace(".", "")) - const stepInt = parseInt(divisor.toFixed(decCount).replace(".", "")) - return (valInt % stepInt) / Math.pow(10, decCount) + const selfDecCount = (self.toString().split(".")[1] || "").length + const divisorDecCount = (divisor.toString().split(".")[1] || "").length + const decCount = selfDecCount > divisorDecCount ? selfDecCount : divisorDecCount + const selfInt = parseInt(self.toFixed(decCount).replace(".", "")) + const divisorInt = parseInt(divisor.toFixed(decCount).replace(".", "")) + return (selfInt % divisorInt) / Math.pow(10, decCount) }) /* diff --git a/src/Predicate.ts b/src/Predicate.ts index 52203c853..35d726721 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -1,7 +1,7 @@ /** * @since 1.0.0 */ -import { constFalse, constTrue, dual } from "@fp-ts/core/Function" +import { constFalse, constTrue, dual, isFunction as isFunction_ } from "@fp-ts/core/Function" import type { TypeLambda } from "@fp-ts/core/HKT" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" @@ -30,6 +30,7 @@ export interface PredicateTypeLambda extends TypeLambda { } /** + * @category models * @since 1.0.0 */ export interface Refinement { @@ -45,6 +46,7 @@ export interface Refinement { * import { isString } from '@fp-ts/core/Predicate' * * assert.deepStrictEqual(isString("a"), true) + * * assert.deepStrictEqual(isString(1), false) * * @category guards @@ -61,6 +63,7 @@ export const isString = (input: unknown): input is string => typeof input === "s * import { isNumber } from '@fp-ts/core/Predicate' * * assert.deepStrictEqual(isNumber(2), true) + * * assert.deepStrictEqual(isNumber("2"), false) * * @category guards @@ -77,6 +80,7 @@ export const isNumber = (input: unknown): input is number => typeof input === "n * import { isBoolean } from '@fp-ts/core/Predicate' * * assert.deepStrictEqual(isBoolean(true), true) + * * assert.deepStrictEqual(isBoolean("true"), false) * * @category guards @@ -93,6 +97,7 @@ export const isBoolean = (input: unknown): input is boolean => typeof input === * import { isBigint } from "@fp-ts/core/Predicate" * * assert.deepStrictEqual(isBigint(1n), true) + * * assert.deepStrictEqual(isBigint(1), false) * * @category guards @@ -109,6 +114,7 @@ export const isBigint = (input: unknown): input is bigint => typeof input === "b * import { isSymbol } from "@fp-ts/core/Predicate" * * assert.deepStrictEqual(isSymbol(Symbol.for("a")), true) + * * assert.deepStrictEqual(isSymbol("a"), false) * * @category guards @@ -117,10 +123,271 @@ export const isBigint = (input: unknown): input is bigint => typeof input === "b export const isSymbol = (input: unknown): input is symbol => typeof input === "symbol" /** - * @category constructors + * Tests if a value is a `function`. + * + * @param input - The value to test. + * + * @example + * import { isFunction } from '@fp-ts/core/Predicate' + * + * assert.deepStrictEqual(isFunction(isFunction), true) + * + * assert.deepStrictEqual(isFunction("function"), false) + * + * @category guards + * @since 1.0.0 + */ +export const isFunction: (input: unknown) => input is Function = isFunction_ + +/** + * Tests if a value is `undefined`. + * + * @param input - The value to test. + * + * @example + * import { isUndefined } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isUndefined(undefined), true) + * + * assert.deepStrictEqual(isUndefined(null), false) + * assert.deepStrictEqual(isUndefined("undefined"), false) + * + * @category guards + * @since 1.0.0 + */ +export const isUndefined = (input: unknown): input is undefined => input === undefined + +/** + * Tests if a value is not `undefined`. + * + * @param input - The value to test. + * + * @example + * import { isNotUndefined } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isNotUndefined(null), true) + * assert.deepStrictEqual(isNotUndefined("undefined"), true) + * + * assert.deepStrictEqual(isNotUndefined(undefined), false) + * + * @category guards + * @since 1.0.0 + */ +export const isNotUndefined = (input: A): input is Exclude => input !== undefined + +/** + * Tests if a value is `undefined`. + * + * @param input - The value to test. + * + * @example + * import { isNull } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isNull(null), true) + * + * assert.deepStrictEqual(isNull(undefined), false) + * assert.deepStrictEqual(isNull("null"), false) + * + * @category guards + * @since 1.0.0 + */ +export const isNull = (input: unknown): input is null => input === null + +/** + * Tests if a value is not `undefined`. + * + * @param input - The value to test. + * + * @example + * import { isNotNull } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isNotNull(undefined), true) + * assert.deepStrictEqual(isNotNull("null"), true) + * + * assert.deepStrictEqual(isNotNull(null), false) + * + * @category guards + * @since 1.0.0 + */ +export const isNotNull = (input: A): input is Exclude => input !== null + +/** + * A guard that always fails. + * + * @param _ - The value to test. + * + * @example + * import { isNever } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isNever(null), false) + * assert.deepStrictEqual(isNever(undefined), false) + * assert.deepStrictEqual(isNever({}), false) + * assert.deepStrictEqual(isNever([]), false) + * + * @category guards + * @since 1.0.0 + */ +export const isNever: (input: unknown) => input is never = (_: unknown): _ is never => false + +/** + * A guard that always succeeds. + * + * @param _ - The value to test. + * + * @example + * import { isUnknown } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isUnknown(null), true) + * assert.deepStrictEqual(isUnknown(undefined), true) + * + * assert.deepStrictEqual(isUnknown({}), true) + * assert.deepStrictEqual(isUnknown([]), true) + * + * @category guards + * @since 1.0.0 + */ +export const isUnknown: (input: unknown) => input is unknown = (_): _ is unknown => true + +/** + * Tests if a value is an `object`. + * + * @param input - The value to test. + * + * @example + * import { isObject } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isObject({}), true) + * assert.deepStrictEqual(isObject([]), true) + * + * assert.deepStrictEqual(isObject(null), false) + * assert.deepStrictEqual(isObject(undefined), false) + * + * @category guards + * @since 1.0.0 + */ +export const isObject = (input: unknown): input is object => + typeof input === "object" && input != null + +/** + * A guard that succeeds when the input is `null` or `undefined`. + * + * @param input - The value to test. + * + * @example + * import { isNullable } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isNullable(null), true) + * assert.deepStrictEqual(isNullable(undefined), true) + * + * assert.deepStrictEqual(isNullable({}), false) + * assert.deepStrictEqual(isNullable([]), false) + * + * @category guards + * @since 1.0.0 + */ +export const isNullable = (input: A): input is Extract => + input === null || input === undefined + +/** + * A guard that succeeds when the input is not `null` or `undefined`. + * + * @param input - The value to test. + * + * @example + * import { isNotNullable } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isNotNullable({}), true) + * assert.deepStrictEqual(isNotNullable([]), true) + * + * assert.deepStrictEqual(isNotNullable(null), false) + * assert.deepStrictEqual(isNotNullable(undefined), false) + * + * @category guards + * @since 1.0.0 + */ +export const isNotNullable = (input: A): input is NonNullable => + input !== null && input !== undefined + +/** + * A guard that succeeds when the input is an `Error`. + * + * @param input - The value to test. + * + * @example + * import { isError } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isError(new Error()), true) + * + * assert.deepStrictEqual(isError(null), false) + * assert.deepStrictEqual(isError({}), false) + * + * @category guards + * @since 1.0.0 + */ +export const isError = (input: unknown): input is Error => input instanceof Error + +/** + * A guard that succeeds when the input is a `Date`. + * + * @param input - The value to test. + * + * @example + * import { isDate } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isDate(new Date()), true) + * + * assert.deepStrictEqual(isDate(null), false) + * assert.deepStrictEqual(isDate({}), false) + * + * @category guards + * @since 1.0.0 + */ +export const isDate = (input: unknown): input is Date => input instanceof Date + +/** + * A guard that succeeds when the input is a record. + * + * @param input - The value to test. + * + * @example + * import { isRecord } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isRecord({}), true) + * assert.deepStrictEqual(isRecord({ a: 1 }), true) + * + * assert.deepStrictEqual(isRecord([]), false) + * assert.deepStrictEqual(isRecord([1, 2, 3]), false) + * assert.deepStrictEqual(isRecord(null), false) + * assert.deepStrictEqual(isRecord(undefined), false) + * + * @category guards + * @since 1.0.0 + */ +export const isRecord = (input: unknown): input is { [x: string | symbol]: unknown } => + isObject(input) && !Array.isArray(input) + +/** + * A guard that succeeds when the input is a readonly record. + * + * @param input - The value to test. + * + * @example + * import { isReadonlyRecord } from "@fp-ts/core/Predicate" + * + * assert.deepStrictEqual(isReadonlyRecord({}), true) + * assert.deepStrictEqual(isReadonlyRecord({ a: 1 }), true) + * + * assert.deepStrictEqual(isReadonlyRecord([]), false) + * assert.deepStrictEqual(isReadonlyRecord([1, 2, 3]), false) + * assert.deepStrictEqual(isReadonlyRecord(null), false) + * assert.deepStrictEqual(isReadonlyRecord(undefined), false) + * + * @category guards * @since 1.0.0 */ -export const id = (): Refinement => (_): _ is A => true +export const isReadonlyRecord: ( + input: unknown +) => input is { readonly [x: string | symbol]: unknown } = isRecord /** * @since 1.0.0 @@ -172,7 +439,7 @@ export const tupled: (self: Predicate) => Predicate = invari /** * @since 1.0.0 */ -export const of = (_: A): Predicate => id() +export const of = (_: A): Predicate => isUnknown /** * @category instances diff --git a/test/Number.ts b/test/Number.ts index bfefd8b45..067b22705 100644 --- a/test/Number.ts +++ b/test/Number.ts @@ -89,6 +89,7 @@ describe.concurrent("Number", () => { assert.deepStrictEqual(Number.remainder(2, 2), 0) assert.deepStrictEqual(Number.remainder(3, 2), 1) assert.deepStrictEqual(Number.remainder(4, 2), 0) + assert.deepStrictEqual(Number.remainder(2.5, 2), 0.5) assert.deepStrictEqual(Number.remainder(-2, 2), -0) assert.deepStrictEqual(Number.remainder(-3, 2), -1) assert.deepStrictEqual(Number.remainder(-4, 2), -0) diff --git a/test/Predicate.ts b/test/Predicate.ts index a3d77776d..0dc009046 100644 --- a/test/Predicate.ts +++ b/test/Predicate.ts @@ -39,11 +39,6 @@ describe.concurrent("Predicate", () => { expect(_.struct).exist }) - it("id", () => { - const refinement = _.id() - deepStrictEqual(refinement("a"), true) - }) - it("compose", () => { const refinement = pipe(isString, _.compose(NonEmptyString)) deepStrictEqual(refinement("a"), true) @@ -165,4 +160,100 @@ describe.concurrent("Predicate", () => { deepStrictEqual(predicate(-2), false) deepStrictEqual(predicate(1), true) }) + + it("isFunction", () => { + assert.deepStrictEqual(_.isFunction(_.isFunction), true) + assert.deepStrictEqual(_.isFunction("function"), false) + }) + + it("isUndefined", () => { + assert.deepStrictEqual(_.isUndefined(undefined), true) + assert.deepStrictEqual(_.isUndefined(null), false) + assert.deepStrictEqual(_.isUndefined("undefined"), false) + }) + + it("isNotUndefined", () => { + assert.deepStrictEqual(_.isNotUndefined(undefined), false) + assert.deepStrictEqual(_.isNotUndefined(null), true) + assert.deepStrictEqual(_.isNotUndefined("undefined"), true) + }) + + it("isNull", () => { + assert.deepStrictEqual(_.isNull(null), true) + assert.deepStrictEqual(_.isNull(undefined), false) + assert.deepStrictEqual(_.isNull("null"), false) + }) + + it("isNotNull", () => { + assert.deepStrictEqual(_.isNotNull(null), false) + assert.deepStrictEqual(_.isNotNull(undefined), true) + assert.deepStrictEqual(_.isNotNull("null"), true) + }) + + it("isNever", () => { + assert.deepStrictEqual(_.isNever(null), false) + assert.deepStrictEqual(_.isNever(undefined), false) + assert.deepStrictEqual(_.isNever({}), false) + assert.deepStrictEqual(_.isNever([]), false) + }) + + it("isUnknown", () => { + assert.deepStrictEqual(_.isUnknown(null), true) + assert.deepStrictEqual(_.isUnknown(undefined), true) + assert.deepStrictEqual(_.isUnknown({}), true) + assert.deepStrictEqual(_.isUnknown([]), true) + }) + + it("isObject", () => { + assert.deepStrictEqual(_.isObject({}), true) + assert.deepStrictEqual(_.isObject([]), true) + assert.deepStrictEqual(_.isObject(null), false) + assert.deepStrictEqual(_.isObject(undefined), false) + }) + + it("isNullable", () => { + assert.deepStrictEqual(_.isNullable(null), true) + assert.deepStrictEqual(_.isNullable(undefined), true) + assert.deepStrictEqual(_.isNullable({}), false) + assert.deepStrictEqual(_.isNullable([]), false) + }) + + it("isNotNullable", () => { + assert.deepStrictEqual(_.isNotNullable({}), true) + assert.deepStrictEqual(_.isNotNullable([]), true) + assert.deepStrictEqual(_.isNotNullable(null), false) + assert.deepStrictEqual(_.isNotNullable(undefined), false) + }) + + it("isError", () => { + assert.deepStrictEqual(_.isError(new Error()), true) + assert.deepStrictEqual(_.isError(null), false) + assert.deepStrictEqual(_.isError({}), false) + }) + + it("isDate", () => { + assert.deepStrictEqual(_.isDate(new Date()), true) + assert.deepStrictEqual(_.isDate(null), false) + assert.deepStrictEqual(_.isDate({}), false) + }) + + it("isRecord", () => { + assert.deepStrictEqual(_.isRecord({}), true) + assert.deepStrictEqual(_.isRecord({ a: 1 }), true) + + assert.deepStrictEqual(_.isRecord([]), false) + assert.deepStrictEqual(_.isRecord([1, 2, 3]), false) + assert.deepStrictEqual(_.isRecord(null), false) + assert.deepStrictEqual(_.isRecord(undefined), false) + }) + + it("isReadonlyRecord", () => { + assert.deepStrictEqual(_.isReadonlyRecord({}), true) + assert.deepStrictEqual(_.isReadonlyRecord({ a: 1 }), true) + + assert.deepStrictEqual(_.isReadonlyRecord([]), false) + assert.deepStrictEqual(_.isReadonlyRecord([1, 2, 3]), false) + assert.deepStrictEqual(_.isReadonlyRecord(null), false) + assert.deepStrictEqual(_.isReadonlyRecord(undefined), false) + }) }) From c48d2f56063c31db5a42d426fa9a9ef270977843 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 8 Feb 2023 16:28:48 +0100 Subject: [PATCH 228/255] add getOrThrowWith to Option, Either, These --- .changeset/sharp-sloths-compete.md | 5 ++ docs/modules/Either.ts.md | 43 +++++++++++ docs/modules/Option.ts.md | 39 +++++++++- docs/modules/These.ts.md | 93 ++++++++++++++++++++++++ src/Either.ts | 46 +++++++++++- src/Option.ts | 44 +++++++++-- src/These.ts | 113 +++++++++++++++++++++++++---- test/Either.ts | 8 ++ test/Option.ts | 7 ++ test/These.ts | 36 ++++++++- 10 files changed, 402 insertions(+), 32 deletions(-) create mode 100644 .changeset/sharp-sloths-compete.md diff --git a/.changeset/sharp-sloths-compete.md b/.changeset/sharp-sloths-compete.md new file mode 100644 index 000000000..8ac44b57d --- /dev/null +++ b/.changeset/sharp-sloths-compete.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +add getOrThrowWith to Option, Either, These diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index d1c42f9db..b06e5d6d5 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -89,6 +89,7 @@ Added in v1.0.0 - [interop](#interop) - [fromNullable](#fromnullable) - [getOrThrow](#getorthrow) + - [getOrThrowWith](#getorthrowwith) - [liftNullable](#liftnullable) - [liftThrowable](#liftthrowable) - [merge](#merge) @@ -1101,12 +1102,54 @@ Added in v1.0.0 ## getOrThrow +Extracts the value of an `Either` or throws if the `Either` is `Left`. + +The thrown error is a default error. To configure the error thrown, see {@link getOrThrowWith}. + **Signature** ```ts export declare const getOrThrow: (self: Either) => A ``` +**Example** + +```ts +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(E.getOrThrow(E.right(1)), 1) +assert.throws(() => E.getOrThrow(E.left('error'))) +``` + +Added in v1.0.0 + +## getOrThrowWith + +Extracts the value of an `Either` or throws if the `Either` is `Left`. + +If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. + +**Signature** + +```ts +export declare const getOrThrowWith: { + (onLeft: (e: E) => unknown): (self: Either) => A + (self: Either, onLeft: (e: E) => unknown): A +} +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual( + E.getOrThrowWith(E.right(1), () => new Error('Unexpected Left')), + 1 +) +assert.throws(() => E.getOrThrowWith(E.left('error'), () => new Error('Unexpected Left'))) +``` + Added in v1.0.0 ## liftNullable diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 66321e601..e64a57d45 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -81,6 +81,7 @@ Added in v1.0.0 - [fromNullable](#fromnullable) - [getOrNull](#getornull) - [getOrThrow](#getorthrow) + - [getOrThrowWith](#getorthrowwith) - [getOrUndefined](#getorundefined) - [liftNullable](#liftnullable) - [liftThrowable](#liftthrowable) @@ -1108,7 +1109,9 @@ Added in v1.0.0 ## getOrThrow -Returns the contained value if the `Option` is `Some`, otherwise throws an error. +Extracts the value of an `Option` or throws if the `Option` is `None`. + +The thrown error is a default error. To configure the error thrown, see {@link getOrThrowWith}. **Signature** @@ -1119,11 +1122,39 @@ export declare const getOrThrow: (self: Option) => A **Example** ```ts -import { pipe } from '@fp-ts/core/Function' import * as O from '@fp-ts/core/Option' -assert.deepStrictEqual(pipe(O.some(1), O.getOrThrow), 1) -assert.throws(() => pipe(O.none(), O.getOrThrow)) +assert.deepStrictEqual(O.getOrThrow(O.some(1)), 1) +assert.throws(() => O.getOrThrow(O.none())) +``` + +Added in v1.0.0 + +## getOrThrowWith + +Extracts the value of an `Option` or throws if the `Option` is `None`. + +If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. + +**Signature** + +```ts +export declare const getOrThrowWith: { + (onNone: () => unknown): (self: Option) => A + (self: Option, onNone: () => unknown): A +} +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual( + O.getOrThrowWith(O.some(1), () => new Error('Unexpected None')), + 1 +) +assert.throws(() => O.getOrThrowWith(O.none(), () => new Error('Unexpected None'))) ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index bddc0d78a..247638397 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -104,7 +104,9 @@ Added in v1.0.0 - [Traversable](#traversable) - [interop](#interop) - [getOrThrow](#getorthrow) + - [getOrThrowWith](#getorthrowwith) - [getRightOnlyOrThrow](#getrightonlyorthrow) + - [getRightOnlyOrThrowWith](#getrightonlyorthrowwith) - [liftThrowable](#liftthrowable) - [lifting](#lifting) - [lift2](#lift2) @@ -1208,22 +1210,113 @@ Added in v1.0.0 ## getOrThrow +Extracts the value of a `These` or throws if the `These` is `Left`. + +The thrown error is a default error. To configure the error thrown, see {@link getOrThrowWith}. + **Signature** ```ts export declare const getOrThrow: (self: These) => A ``` +**Example** + +```ts +import * as T from '@fp-ts/core/These' + +assert.deepStrictEqual(T.getOrThrow(T.right(1)), 1) +assert.deepStrictEqual(T.getOrThrow(T.both('warning', 1)), 1) +assert.throws(() => T.getOrThrow(T.left('error'))) +``` + +Added in v1.0.0 + +## getOrThrowWith + +Extracts the value of a `These` or throws if the `These` is `Left`. + +If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. + +**Signature** + +```ts +export declare const getOrThrowWith: { + (onLeft: (e: E) => unknown): (self: These) => A + (self: These, onLeft: (e: E) => unknown): A +} +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/These' + +assert.deepStrictEqual( + E.getOrThrowWith(E.right(1), () => new Error('Unexpected Left')), + 1 +) +assert.deepStrictEqual( + E.getOrThrowWith(E.both('warning', 1), () => new Error('Unexpected Left')), + 1 +) +assert.throws(() => E.getOrThrowWith(E.left('error'), () => new Error('Unexpected Left'))) +``` + Added in v1.0.0 ## getRightOnlyOrThrow +Extracts the value of a `These` or throws if the `These` is not a `Right`. + +The thrown error is a default error. To configure the error thrown, see {@link getRightOnlyOrThrowWith}. + **Signature** ```ts export declare const getRightOnlyOrThrow: (self: These) => A ``` +**Example** + +```ts +import * as T from '@fp-ts/core/These' + +assert.deepStrictEqual(T.getRightOnlyOrThrow(T.right(1)), 1) +assert.throws(() => T.getRightOnlyOrThrow(T.both('error', 1))) +assert.throws(() => T.getRightOnlyOrThrow(T.left('error'))) +``` + +Added in v1.0.0 + +## getRightOnlyOrThrowWith + +Extracts the value of a `These` or throws if the `These` is `Left`. + +If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. + +**Signature** + +```ts +export declare const getRightOnlyOrThrowWith: { + (onLeftOrBoth: (e: E) => unknown): (self: These) => A + (self: These, onLeftOrBoth: (e: E) => unknown): A +} +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/These' + +assert.deepStrictEqual( + E.getRightOnlyOrThrowWith(E.right(1), () => new Error('Unexpected Left or Both')), + 1 +) +assert.throws(() => E.getRightOnlyOrThrowWith(E.both('warning', 1), () => new Error('Unexpected Left or Both'))) +assert.throws(() => E.getRightOnlyOrThrowWith(E.left('error'), () => new Error('Unexpected Left or Both'))) +``` + Added in v1.0.0 ## liftThrowable diff --git a/src/Either.ts b/src/Either.ts index 0e16af1e1..cb1fba13b 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -943,15 +943,55 @@ export const flatMapNullable: { ): Either> => flatMap(self, liftNullable(f, onNullable))) /** + * Extracts the value of an `Either` or throws if the `Either` is `Left`. + * + * If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. + * + * @param self - The `Either` to extract the value from. + * @param onLeft - A function that will be called if the `Either` is `Left`. It returns the error to be thrown. + * + * @example + * import * as E from "@fp-ts/core/Either" + * + * assert.deepStrictEqual( + * E.getOrThrowWith(E.right(1), () => new Error('Unexpected Left')), + * 1 + * ) + * assert.throws(() => E.getOrThrowWith(E.left("error"), () => new Error('Unexpected Left'))) + * * @category interop * @since 1.0.0 */ -export const getOrThrow = (self: Either): A => { +export const getOrThrowWith: { + (onLeft: (e: E) => unknown): (self: Either) => A + (self: Either, onLeft: (e: E) => unknown): A +} = dual(2, (self: Either, onLeft: (e: E) => unknown): A => { if (isRight(self)) { return self.right } - throw new Error("getOrThrow called on a Left") -} + throw onLeft(self.left) +}) + +/** + * Extracts the value of an `Either` or throws if the `Either` is `Left`. + * + * The thrown error is a default error. To configure the error thrown, see {@link getOrThrowWith}. + * + * @param self - The `Either` to extract the value from. + * @throws `Error("getOrThrow called on a Left")` + * + * @example + * import * as E from "@fp-ts/core/Either" + * + * assert.deepStrictEqual(E.getOrThrow(E.right(1)), 1) + * assert.throws(() => E.getOrThrow(E.left("error"))) + * + * @category interop + * @since 1.0.0 + */ +export const getOrThrow: (self: Either) => A = getOrThrowWith(() => + new Error("getOrThrow called on a Left") +) /** * Lifts a function that may throw to one returning a `Either`. diff --git a/src/Option.ts b/src/Option.ts index 7d6eb0d68..a51cb4b1b 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -546,27 +546,55 @@ export const liftThrowable = , B>( } /** - * Returns the contained value if the `Option` is `Some`, otherwise throws an error. + * Extracts the value of an `Option` or throws if the `Option` is `None`. + * + * If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. * * @param self - The `Option` to extract the value from. - * @throws `Error("getOrThrow called on a None")` + * @param onNone - A function that will be called if the `Option` is `None`. It returns the error to be thrown. * * @example - * import { pipe } from '@fp-ts/core/Function' * import * as O from '@fp-ts/core/Option' * - * assert.deepStrictEqual(pipe(O.some(1), O.getOrThrow), 1) - * assert.throws(() => pipe(O.none(), O.getOrThrow)) + * assert.deepStrictEqual( + * O.getOrThrowWith(O.some(1), () => new Error('Unexpected None')), + * 1 + * ) + * assert.throws(() => O.getOrThrowWith(O.none(), () => new Error('Unexpected None'))) * * @category interop * @since 1.0.0 */ -export const getOrThrow = (self: Option): A => { +export const getOrThrowWith: { + (onNone: () => unknown): (self: Option) => A + (self: Option, onNone: () => unknown): A +} = dual(2, (self: Option, onNone: () => unknown): A => { if (isSome(self)) { return self.value } - throw new Error("getOrThrow called on a None") -} + throw onNone() +}) + +/** + * Extracts the value of an `Option` or throws if the `Option` is `None`. + * + * The thrown error is a default error. To configure the error thrown, see {@link getOrThrowWith}. + * + * @param self - The `Option` to extract the value from. + * @throws `Error("getOrThrow called on a None")` + * + * @example + * import * as O from '@fp-ts/core/Option' + * + * assert.deepStrictEqual(O.getOrThrow(O.some(1)), 1) + * assert.throws(() => O.getOrThrow(O.none())) + * + * @category interop + * @since 1.0.0 + */ +export const getOrThrow: (self: Option) => A = getOrThrowWith(() => + new Error("getOrThrow called on a None") +) // ------------------------------------------------------------------------------------- // mapping diff --git a/src/These.ts b/src/These.ts index 6b0783343..c9b1d8445 100644 --- a/src/These.ts +++ b/src/These.ts @@ -308,39 +308,122 @@ export const isBoth = (self: These): self is Both => self._tag * @category interop * @since 1.0.0 */ -export const liftThrowable = , B, E>( +export const liftThrowable: , B, E>( f: (...a: A) => B, onThrow: (error: unknown) => E -): ((...a: A) => These) => - (...a) => { - try { - return right(f(...a)) - } catch (e) { - return left(onThrow(e)) - } - } +) => ((...a: A) => These) = E.liftThrowable /** + * Extracts the value of a `These` or throws if the `These` is `Left`. + * + * If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. + * + * @param self - The `These` to extract the value from. + * @param onLeft - A function that will be called if the `These` is `Left`. It returns the error to be thrown. + * + * @example + * import * as E from "@fp-ts/core/These" + * + * assert.deepStrictEqual( + * E.getOrThrowWith(E.right(1), () => new Error('Unexpected Left')), + * 1 + * ) + * assert.deepStrictEqual( + * E.getOrThrowWith(E.both("warning", 1), () => new Error('Unexpected Left')), + * 1 + * ) + * assert.throws(() => E.getOrThrowWith(E.left("error"), () => new Error('Unexpected Left'))) + * * @category interop * @since 1.0.0 */ -export const getOrThrow = (self: These): A => { +export const getOrThrowWith: { + (onLeft: (e: E) => unknown): (self: These) => A + (self: These, onLeft: (e: E) => unknown): A +} = dual(2, (self: These, onLeft: (e: E) => unknown): A => { if (isRightOrBoth(self)) { return self.right } - throw new Error("getOrThrow called on a Left") -} + throw onLeft(self.left) +}) + +/** + * Extracts the value of a `These` or throws if the `These` is `Left`. + * + * The thrown error is a default error. To configure the error thrown, see {@link getOrThrowWith}. + * + * @param self - The `These` to extract the value from. + * @throws `Error("getOrThrow called on a Left")` + * + * @example + * import * as T from "@fp-ts/core/These" + * + * assert.deepStrictEqual(T.getOrThrow(T.right(1)), 1) + * assert.deepStrictEqual(T.getOrThrow(T.both("warning", 1)), 1) + * assert.throws(() => T.getOrThrow(T.left("error"))) + * + * @category interop + * @since 1.0.0 + */ +export const getOrThrow: (self: These) => A = getOrThrowWith(() => + new Error("getOrThrow called on a Left") +) /** + * Extracts the value of a `These` or throws if the `These` is `Left`. + * + * If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. + * + * @param self - The `These` to extract the value from. + * @param onLeft - A function that will be called if the `These` is `Left`. It returns the error to be thrown. + * + * @example + * import * as E from "@fp-ts/core/These" + * + * assert.deepStrictEqual( + * E.getRightOnlyOrThrowWith( + * E.right(1), + * () => new Error("Unexpected Left or Both") + * ), + * 1 + * ) + * assert.throws(() => E.getRightOnlyOrThrowWith(E.both("warning", 1), () => new Error("Unexpected Left or Both"))) + * assert.throws(() => E.getRightOnlyOrThrowWith(E.left("error"), () => new Error("Unexpected Left or Both"))) + * * @category interop * @since 1.0.0 */ -export const getRightOnlyOrThrow = (self: These): A => { +export const getRightOnlyOrThrowWith: { + (onLeftOrBoth: (e: E) => unknown): (self: These) => A + (self: These, onLeftOrBoth: (e: E) => unknown): A +} = dual(2, (self: These, onLeftOrBoth: (e: E) => unknown): A => { if (isRight(self)) { return self.right } - throw new Error("getRightOnlyOrThrow called on Left or Both") -} + throw onLeftOrBoth(self.left) +}) + +/** + * Extracts the value of a `These` or throws if the `These` is not a `Right`. + * + * The thrown error is a default error. To configure the error thrown, see {@link getRightOnlyOrThrowWith}. + * + * @param self - The `These` to extract the value from. + * @throws `Error("getOrThrow called on a Left")` + * + * @example + * import * as T from "@fp-ts/core/These" + * + * assert.deepStrictEqual(T.getRightOnlyOrThrow(T.right(1)), 1) + * assert.throws(() => T.getRightOnlyOrThrow(T.both("error", 1))) + * assert.throws(() => T.getRightOnlyOrThrow(T.left("error"))) + * + * @category interop + * @since 1.0.0 + */ +export const getRightOnlyOrThrow: (self: These) => A = getRightOnlyOrThrowWith(() => + new Error("getRightOnlyOrThrow called on a Left or a Both") +) /** * @category conversions diff --git a/test/Either.ts b/test/Either.ts index ae955ccce..a1efc061d 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -172,6 +172,14 @@ describe.concurrent("Either", () => { ) }) + it("getOrThrowWith", () => { + expect(pipe(E.right(1), E.getOrThrowWith((e) => new Error(`Unexpected Left: ${e}`)))).toEqual(1) + expect(() => pipe(E.left("e"), E.getOrThrowWith((e) => new Error(`Unexpected Left: ${e}`)))) + .toThrowError( + new Error("Unexpected Left: e") + ) + }) + it("andThenDiscard", () => { Util.deepStrictEqual(pipe(E.right(1), E.andThenDiscard(E.right("a"))), E.right(1)) Util.deepStrictEqual(pipe(E.right(1), E.andThenDiscard(E.left(true))), E.left(true)) diff --git a/test/Option.ts b/test/Option.ts index 208598adb..a6dda11ab 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -191,6 +191,13 @@ describe.concurrent("Option", () => { ) }) + it("getOrThrowWith", () => { + expect(pipe(_.some(1), _.getOrThrowWith(() => new Error("Unexpected None")))).toEqual(1) + expect(() => pipe(_.none(), _.getOrThrowWith(() => new Error("Unexpected None")))).toThrowError( + new Error("Unexpected None") + ) + }) + it("of", () => { Util.deepStrictEqual(_.of(1), _.some(1)) }) diff --git a/test/These.ts b/test/These.ts index 56b7e8303..0ad9170cd 100644 --- a/test/These.ts +++ b/test/These.ts @@ -491,13 +491,45 @@ describe("These", () => { ) }) + it("getOrThrowWith", () => { + expect(pipe(_.right(1), _.getOrThrowWith((e) => new Error(`Unexpected Left: ${e}`)))).toEqual(1) + expect(pipe(_.both("w", 1), _.getOrThrowWith((e) => new Error(`Unexpected Left: ${e}`)))) + .toEqual(1) + expect(() => pipe(_.left("e"), _.getOrThrowWith((e) => new Error(`Unexpected Left: ${e}`)))) + .toThrowError( + new Error("Unexpected Left: e") + ) + }) + it("getRightOnlyOrThrow", () => { expect(pipe(_.right(1), _.getRightOnlyOrThrow)).toEqual(1) expect(() => pipe(_.left("e"), _.getRightOnlyOrThrow)).toThrow( - new Error("getRightOnlyOrThrow called on Left or Both") + new Error("getRightOnlyOrThrow called on a Left or a Both") ) expect(() => pipe(_.both("e", 1), _.getRightOnlyOrThrow)).toThrow( - new Error("getRightOnlyOrThrow called on Left or Both") + new Error("getRightOnlyOrThrow called on a Left or a Both") + ) + }) + + it("getRightOnlyOrThrowWith", () => { + expect( + pipe(_.right(1), _.getRightOnlyOrThrowWith((e) => new Error(`Unexpected Left or Both: ${e}`))) + ).toEqual(1) + expect(() => + pipe( + _.left("e"), + _.getRightOnlyOrThrowWith((e) => new Error(`Unexpected Left or Both: ${e}`)) + ) + ).toThrow( + new Error("Unexpected Left or Both: e") + ) + expect(() => + pipe( + _.both("e", 1), + _.getRightOnlyOrThrowWith((e) => new Error(`Unexpected Left or Both: ${e}`)) + ) + ).toThrow( + new Error("Unexpected Left or Both: e") ) }) From b382f867d901f1221acc9a3f6f07e5039b717342 Mon Sep 17 00:00:00 2001 From: gcanti Date: Thu, 9 Feb 2023 08:02:56 +0100 Subject: [PATCH 229/255] add Contributing Guide --- .github/CONTRIBUTING.md | 34 ++++++++++++++++++ .github/ISSUE_TEMPLATE/Bug_report.md | 37 ++++++++------------ .github/ISSUE_TEMPLATE/Documentation.md | 24 ++++++++++--- .github/ISSUE_TEMPLATE/Feature_request.md | 42 +++++++---------------- .github/PULL_REQUEST_TEMPLATE.md | 27 +++++++++++++-- 5 files changed, 103 insertions(+), 61 deletions(-) create mode 100644 .github/CONTRIBUTING.md diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 000000000..8058b38eb --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,34 @@ +# Contributing to `@fp-ts/core` + +We welcome all contributions to the `@fp-ts/core` library. Your help makes the library better for everyone! + +## Creating an Issue + +Before you begin working on a contribution, it's important to create an issue that describes what you would like to build or improve. This helps to ensure that someone else isn't already working on something similar, and also helps the maintainers understand your goals. + +## Development Workflow + +1. Fork the repository on GitHub. +2. Clone your forked repository using the following command: `git clone git@github.com:{your_username}/core.git` +3. Install dependencies with `pnpm install`. +4. Make your contributions and commit your changes. +5. If you have made changes to the code, run `pnpm changeset` and select the appropriate level of change (`patch`, `minor`, `major`) + +### Available Commands + +- `pnpm build`: Deletes the `dist` folder and recompiles the `src` code into `dist`. +- `pnpm test`: Runs all vitest tests in watch mode. +- `pnpm coverage`: Runs all vitest tests and collects coverage information. +- `pnpm dtslint`: Runs type-level tests. + +### Writing Tests + +`@fp-ts/core` uses vitest for testing. After making your contributions, it's important to write tests to ensure that they work as intended. Before submitting your pull request, run `pnpm coverage` to make sure there are no unintended breaking changes and that your code has 100% coverage. + +### Documentation + +API documentation for `@fp-ts/core` can be found in the source code as JSDoc comments. Be sure to include documentation for any changes you make to the API. + +## Licensing + +By contributing your code to the `@fp-ts/core` GitHub repository, you agree to license your contribution under the MIT license. diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index 40007b8b8..fdf87f94d 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -1,35 +1,26 @@ ---- -name: "\U0001F41B Bug report" -about: Create a report to help make `@fp-ts/core` better ---- +# Bug Report -## 🐛 Bug report +Thank you for reporting a bug in `@fp-ts/core`. Your contribution to this project is greatly appreciated and will help make the library better for everyone. -### Current Behavior +## Describing the Bug - +Please provide a clear and concise description of the issue you are encountering, including any error messages or unexpected behavior you have observed. -### Expected behavior +## Steps to Reproduce - +In order to help us understand and resolve the issue, please provide the steps to reproduce the behavior, along with a minimal, self-contained code example that demonstrates the problem. -### Reproducible example +## Expected Behavior -### Suggested solution(s) +Please describe what you expected to happen, and how the current behavior differs from your expectations. - +## Environment -### Additional context +Please provide the following information to help us understand your setup: - +- Library version: [e.g. `0.8.1`] +- TypeScript version: [e.g. `4.2.2`] -### Your environment +## Additional Context -Which versions of `@fp-ts/core` are affected by this issue? Did this work in previous versions of `@fp-ts/core`? - - - -| Software | Version(s) | -| ----------- | ---------- | -| @fp-ts/core | | -| TypeScript | | +Any additional information or context that you think would be helpful in resolving the issue. diff --git a/.github/ISSUE_TEMPLATE/Documentation.md b/.github/ISSUE_TEMPLATE/Documentation.md index 5326e0d94..666a25ca8 100644 --- a/.github/ISSUE_TEMPLATE/Documentation.md +++ b/.github/ISSUE_TEMPLATE/Documentation.md @@ -1,6 +1,20 @@ ---- -name: "\U0001F41B Documentation" -about: Improvements or suggestions of `@fp-ts/core` documentation ---- +# Improving Documentation -## 📖 Documentation +We welcome all suggestions and improvements to the documentation of `@fp-ts/core`. Your contributions help make the library easier to understand and use for everyone. + +## How to Contribute + +To contribute to the documentation, follow these steps: + +1. Make the desired changes to the documentation files. +2. Submit a pull request with a clear description of the changes and why they are beneficial. + +## Content Guidelines + +When contributing to the documentation, please keep in mind the following guidelines: + +- Write clear and concise explanations of features and concepts. +- Use examples and code snippets to help illustrate your explanations. +- Follow the same formatting and style used in the existing documentation. + +Thank you for your contributions to the `@fp-ts/core` documentation! diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md index 9d658b4b2..952611a86 100644 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ b/.github/ISSUE_TEMPLATE/Feature_request.md @@ -1,41 +1,23 @@ ---- -name: "\U0001F680Feature request" -about: Suggest an idea for `@fp-ts/core` ---- +# Feature Request -## 🚀 Feature request +Thank you for submitting a feature request for `@fp-ts/core`. Your contributions help shape the future of this library. -### Current Behavior +## Describing the Feature - +Please provide a clear and concise description of the new feature you would like to see added to `@fp-ts/core`. -### Desired Behavior +## Problem to Solve - +Please describe the problem that this new feature will solve, and why it's important. -### Suggested Solution +## Use Case - +Please provide a use case or an example of how this feature will be used. - +## Alternatives Considered -### Who does this impact? Who is this for? +Please describe any alternatives you have considered and why you believe this new feature is a better solution. - +## Additional Context -### Describe alternatives you've considered - - - -### Additional context - - - -### Your environment - - - -| Software | Version(s) | -| ----------- | ---------- | -| @fp-ts/core | | -| TypeScript | | +Please provide any additional information or context that might be relevant to this feature request. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 80a9cf2bb..1c2de5df1 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,4 +1,25 @@ -**Before submitting a pull request,** please make sure the following is done: +# Pull Request Template -- If you've fixed a bug or added code that should be tested, add tests! -- Ensure the test suite passes (`npm test`). +## Description + +Please describe the changes you have made and the purpose of the changes. If applicable, provide context or links to relevant issues or discussions. + +## Types of Changes + +What types of changes does your code introduce to the library? + +- [ ] Bugfix +- [ ] New feature +- [ ] Documentation update + +## Checklist + +- [ ] I have read the [contributing guidelines](https://github.com/fp-ts/core/blob/main/.github/CONTRIBUTING.md) for this repository +- [ ] I have written tests for the changes I have made +- [ ] I have run `pnpm coverage` and my code is 100% covered +- [ ] I have updated the documentation (if applicable) +- [ ] I agree to license my contribution under the MIT license + +## Additional Information + +Is there anything else you would like to add? Are there any questions that need to be answered before merging this pull request? From 92dfb6d8521cbac1bc8b75bd3e1963ca0a061c66 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 9 Feb 2023 07:12:30 +0000 Subject: [PATCH 230/255] Version Packages --- .changeset/fresh-teachers-compete.md | 5 ----- .changeset/sharp-sloths-compete.md | 5 ----- .changeset/six-otters-cover.md | 5 ----- .changeset/unlucky-walls-prove.md | 5 ----- CHANGELOG.md | 12 ++++++++++++ package.json | 2 +- 6 files changed, 13 insertions(+), 21 deletions(-) delete mode 100644 .changeset/fresh-teachers-compete.md delete mode 100644 .changeset/sharp-sloths-compete.md delete mode 100644 .changeset/six-otters-cover.md delete mode 100644 .changeset/unlucky-walls-prove.md diff --git a/.changeset/fresh-teachers-compete.md b/.changeset/fresh-teachers-compete.md deleted file mode 100644 index 70413c6e7..000000000 --- a/.changeset/fresh-teachers-compete.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -Predicate: add more guards diff --git a/.changeset/sharp-sloths-compete.md b/.changeset/sharp-sloths-compete.md deleted file mode 100644 index 8ac44b57d..000000000 --- a/.changeset/sharp-sloths-compete.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -add getOrThrowWith to Option, Either, These diff --git a/.changeset/six-otters-cover.md b/.changeset/six-otters-cover.md deleted file mode 100644 index 2d46347f5..000000000 --- a/.changeset/six-otters-cover.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -Number: add remainder diff --git a/.changeset/unlucky-walls-prove.md b/.changeset/unlucky-walls-prove.md deleted file mode 100644 index 872f4419a..000000000 --- a/.changeset/unlucky-walls-prove.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@fp-ts/core": patch ---- - -ReadonlyArray: handle mutable arrays in isEmpty, isNonEmpty guards diff --git a/CHANGELOG.md b/CHANGELOG.md index 714dfcce6..b7f3ab017 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # @fp-ts/core +## 0.2.1 + +### Patch Changes + +- [#59](https://github.com/fp-ts/core/pull/59) [`5efa9c03`](https://github.com/fp-ts/core/commit/5efa9c03572c9f39dd0e801dfe404e9e18d5fba2) Thanks [@gcanti](https://github.com/gcanti)! - Predicate: add more guards + +- [#60](https://github.com/fp-ts/core/pull/60) [`c48d2f56`](https://github.com/fp-ts/core/commit/c48d2f56063c31db5a42d426fa9a9ef270977843) Thanks [@gcanti](https://github.com/gcanti)! - add getOrThrowWith to Option, Either, These + +- [#57](https://github.com/fp-ts/core/pull/57) [`549509b8`](https://github.com/fp-ts/core/commit/549509b8a02a515becd514cfbb00044b313d5ede) Thanks [@gcanti](https://github.com/gcanti)! - Number: add remainder + +- [#56](https://github.com/fp-ts/core/pull/56) [`cf4918de`](https://github.com/fp-ts/core/commit/cf4918de74504ec59dd00df0ff251a549fb51284) Thanks [@gcanti](https://github.com/gcanti)! - ReadonlyArray: handle mutable arrays in isEmpty, isNonEmpty guards + ## 0.2.0 ### Minor Changes diff --git a/package.json b/package.json index 29a3b38f9..a0ab494fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fp-ts/core", - "version": "0.2.0", + "version": "0.2.1", "publishConfig": { "access": "public", "directory": "dist" From 698737997cb93d0b007a3931901ec2d877672305 Mon Sep 17 00:00:00 2001 From: "maksim.khramtsov" Date: Fri, 10 Feb 2023 16:16:07 +0100 Subject: [PATCH 231/255] fix: flip bounds in the reverse function --- src/typeclass/Bounded.ts | 4 ++-- test/typeclass/Bounded.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/typeclass/Bounded.ts b/src/typeclass/Bounded.ts index c188e2e61..d0a7f7d17 100644 --- a/src/typeclass/Bounded.ts +++ b/src/typeclass/Bounded.ts @@ -67,6 +67,6 @@ export const clamp = (B: Bounded): (a: A) => A => order.clamp(B)(B.minBoun */ export const reverse = (B: Bounded): Bounded => ({ ...order.reverse(B), - minBound: B.minBound, - maxBound: B.maxBound + minBound: B.maxBound, + maxBound: B.minBound }) diff --git a/test/typeclass/Bounded.ts b/test/typeclass/Bounded.ts index 0744c5c9b..1e4d5c4bc 100644 --- a/test/typeclass/Bounded.ts +++ b/test/typeclass/Bounded.ts @@ -14,7 +14,7 @@ describe("Bounded", () => { it("reverse", () => { const B = _.reverse({ ...Number.Order, minBound: 10, maxBound: 1 }) - U.deepStrictEqual(B.maxBound, 1) - U.deepStrictEqual(B.minBound, 10) + U.deepStrictEqual(B.maxBound, 10) + U.deepStrictEqual(B.minBound, 1) }) }) From ec4e466741b343ae120f394b648dc4acfae9ddec Mon Sep 17 00:00:00 2001 From: "maksim.khramtsov" Date: Fri, 10 Feb 2023 18:31:17 +0100 Subject: [PATCH 232/255] add .idea/ in .gitignore add note to changeset --- .changeset/flat-news-whisper.md | 5 +++++ .gitignore | 1 + 2 files changed, 6 insertions(+) create mode 100644 .changeset/flat-news-whisper.md diff --git a/.changeset/flat-news-whisper.md b/.changeset/flat-news-whisper.md new file mode 100644 index 000000000..7d665ee0c --- /dev/null +++ b/.changeset/flat-news-whisper.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +fix bounds flipping in reverse function diff --git a/.gitignore b/.gitignore index f691932a9..b168db00d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ yarn-error.log tmp/ build/ dist/ +.idea/ \ No newline at end of file From 86ffe96d207f147a2dd7536bb3f8015dc3539820 Mon Sep 17 00:00:00 2001 From: "maksim.khramtsov" Date: Thu, 9 Feb 2023 14:42:37 +0100 Subject: [PATCH 233/255] add boolean combinators --- docs/modules/Boolean.ts.md | 84 +++++++++++++++++++++++++- docs/modules/typeclass/Semigroup.ts.md | 13 ++++ src/Boolean.ts | 70 +++++++++++++++++++-- src/typeclass/Semigroup.ts | 22 +++++++ test/Boolean.ts | 47 ++++++++++++++ 5 files changed, 230 insertions(+), 6 deletions(-) diff --git a/docs/modules/Boolean.ts.md b/docs/modules/Boolean.ts.md index 1194d0b11..937debf60 100644 --- a/docs/modules/Boolean.ts.md +++ b/docs/modules/Boolean.ts.md @@ -18,8 +18,13 @@ Added in v1.0.0 - [combinators](#combinators) - [and](#and) + - [implies](#implies) + - [nand](#nand) + - [nor](#nor) - [not](#not) - [or](#or) + - [xnor](#xnor) + - [xor](#xor) - [guards](#guards) - [isBoolean](#isboolean) - [instances](#instances) @@ -29,6 +34,7 @@ Added in v1.0.0 - [Order](#order) - [SemigroupAll](#semigroupall) - [SemigroupAny](#semigroupany) + - [SemigroupExclusiveAny](#semigroupexclusiveany) - [pattern matching](#pattern-matching) - [match](#match) - [utils](#utils) @@ -49,6 +55,36 @@ export declare const and: { (that: boolean): (self: boolean) => boolean; (self: Added in v1.0.0 +## implies + +**Signature** + +```ts +export declare const implies: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } +``` + +Added in v1.0.0 + +## nand + +**Signature** + +```ts +export declare const nand: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } +``` + +Added in v1.0.0 + +## nor + +**Signature** + +```ts +export declare const nor: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } +``` + +Added in v1.0.0 + ## not **Signature** @@ -69,6 +105,26 @@ export declare const or: { (that: boolean): (self: boolean) => boolean; (self: b Added in v1.0.0 +## xnor + +**Signature** + +```ts +export declare const xnor: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } +``` + +Added in v1.0.0 + +## xor + +**Signature** + +```ts +export declare const xor: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } +``` + +Added in v1.0.0 + # guards ## isBoolean @@ -156,10 +212,11 @@ export declare const SemigroupAll: semigroup.Semigroup ```ts import { SemigroupAll } from '@fp-ts/core/Boolean' -import { pipe } from '@fp-ts/core/Function' assert.deepStrictEqual(SemigroupAll.combine(true, true), true) assert.deepStrictEqual(SemigroupAll.combine(true, false), false) +assert.deepStrictEqual(SemigroupAll.combine(false, true), false) +assert.deepStrictEqual(SemigroupAll.combine(false, false), false) ``` Added in v1.0.0 @@ -178,15 +235,38 @@ export declare const SemigroupAny: semigroup.Semigroup ```ts import { SemigroupAny } from '@fp-ts/core/Boolean' -import { pipe } from '@fp-ts/core/Function' assert.deepStrictEqual(SemigroupAny.combine(true, true), true) assert.deepStrictEqual(SemigroupAny.combine(true, false), true) +assert.deepStrictEqual(SemigroupAny.combine(false, true), true) assert.deepStrictEqual(SemigroupAny.combine(false, false), false) ``` Added in v1.0.0 +## SemigroupExclusiveAny + +`boolean` semigroup under disjunction. + +**Signature** + +```ts +export declare const SemigroupExclusiveAny: semigroup.Semigroup +``` + +**Example** + +```ts +import { SemigroupExclusiveAny } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(SemigroupExclusiveAny.combine(true, true), false) +assert.deepStrictEqual(SemigroupExclusiveAny.combine(true, false), true) +assert.deepStrictEqual(SemigroupExclusiveAny.combine(false, true), true) +assert.deepStrictEqual(SemigroupExclusiveAny.combine(false, false), false) +``` + +Added in v1.0.0 + # pattern matching ## match diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index d0ba8345b..b409a802f 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -30,6 +30,7 @@ Added in v1.0.0 - [bigintSum](#bigintsum) - [booleanAll](#booleanall) - [booleanAny](#booleanany) + - [booleanExclusiveAny](#booleanexclusiveany) - [first](#first) - [last](#last) - [numberMultiply](#numbermultiply) @@ -237,6 +238,18 @@ export declare const booleanAny: Semigroup Added in v1.0.0 +## booleanExclusiveAny + +`boolean` semigroup under exclusive disjunction. + +**Signature** + +```ts +export declare const booleanExclusiveAny: Semigroup +``` + +Added in v1.0.0 + ## first Always return the first argument. diff --git a/src/Boolean.ts b/src/Boolean.ts index 52889069a..48ef82cc0 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -6,7 +6,7 @@ * @since 1.0.0 */ import type { LazyArg } from "@fp-ts/core/Function" -import { dual } from "@fp-ts/core/Function" +import { dual, flow } from "@fp-ts/core/Function" import * as predicate from "@fp-ts/core/Predicate" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" @@ -76,10 +76,11 @@ export const Order: order.Order = order.boolean * * @example * import { SemigroupAll } from '@fp-ts/core/Boolean' - * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(SemigroupAll.combine(true, true), true) * assert.deepStrictEqual(SemigroupAll.combine(true, false), false) + * assert.deepStrictEqual(SemigroupAll.combine(false, true), false) + * assert.deepStrictEqual(SemigroupAll.combine(false, false), false) * * @category instances * @since 1.0.0 @@ -91,10 +92,10 @@ export const SemigroupAll: semigroup.Semigroup = semigroup.booleanAll * * @example * import { SemigroupAny } from '@fp-ts/core/Boolean' - * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(SemigroupAny.combine(true, true), true) * assert.deepStrictEqual(SemigroupAny.combine(true, false), true) + * assert.deepStrictEqual(SemigroupAny.combine(false, true), true) * assert.deepStrictEqual(SemigroupAny.combine(false, false), false) * * @category instances @@ -102,6 +103,22 @@ export const SemigroupAll: semigroup.Semigroup = semigroup.booleanAll */ export const SemigroupAny: semigroup.Semigroup = semigroup.booleanAny +/** + * `boolean` semigroup under disjunction. + * + * @example + * import { SemigroupExclusiveAny } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(SemigroupExclusiveAny.combine(true, true), false) + * assert.deepStrictEqual(SemigroupExclusiveAny.combine(true, false), true) + * assert.deepStrictEqual(SemigroupExclusiveAny.combine(false, true), true) + * assert.deepStrictEqual(SemigroupExclusiveAny.combine(false, false), false) + * + * @category instances + * @since 1.0.0 + */ +export const SemigroupExclusiveAny: semigroup.Semigroup = semigroup.booleanExclusiveAny + /** * `boolean` monoid under conjunction. * @@ -122,6 +139,12 @@ export const MonoidAll: monoid.Monoid = monoid.booleanAll */ export const MonoidAny: monoid.Monoid = monoid.booleanAny +/** + * @category combinators + * @since 1.0.0 + */ +export const not = (self: boolean): boolean => !self + /** * @category combinators * @since 1.0.0 @@ -131,6 +154,15 @@ export const and: { (self: boolean, that: boolean): boolean } = dual(2, semigroup.booleanAll.combine) +/** + * @category combinators + * @since 1.0.0 + */ +export const nand: { + (that: boolean): (self: boolean) => boolean + (self: boolean, that: boolean): boolean +} = dual(2, flow(semigroup.booleanAll.combine, not)) + /** * @category combinators * @since 1.0.0 @@ -144,7 +176,37 @@ export const or: { * @category combinators * @since 1.0.0 */ -export const not = (self: boolean): boolean => !self +export const nor: { + (that: boolean): (self: boolean) => boolean + (self: boolean, that: boolean): boolean +} = dual(2, flow(semigroup.booleanAny.combine, not)) + +/** + * @category combinators + * @since 1.0.0 + */ +export const xor: { + (that: boolean): (self: boolean) => boolean + (self: boolean, that: boolean): boolean +} = dual(2, semigroup.booleanExclusiveAny.combine) + +/** + * @category combinators + * @since 1.0.0 + */ +export const xnor: { + (that: boolean): (self: boolean) => boolean + (self: boolean, that: boolean): boolean +} = dual(2, flow(semigroup.booleanExclusiveAny.combine, not)) + +/** + * @category combinators + * @since 1.0.0 + */ +export const implies: { + (that: boolean): (self: boolean) => boolean + (self: boolean, that: boolean): boolean +} = dual(2, (self, that) => self ? that : true) /** * @since 1.0.0 diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index f7928b6e1..f2c42c881 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -151,6 +151,28 @@ export const booleanAny: Semigroup = make( } ) +/** + * `boolean` semigroup under exclusive disjunction. + * + * @category instances + * @since 1.0.0 + */ +export const booleanExclusiveAny: Semigroup = make( + (self, that) => self !== that, + (self, collection) => { + let isEmptyIterable = true + for (const b of collection) { + if (isEmptyIterable) { + isEmptyIterable = false + } + if (b !== self) { + return true + } + } + return isEmptyIterable ? self : false + } +) + /** * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. * The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. diff --git a/test/Boolean.ts b/test/Boolean.ts index cf6cc8705..0462c4fec 100644 --- a/test/Boolean.ts +++ b/test/Boolean.ts @@ -8,6 +8,7 @@ describe.concurrent("Boolean", () => { expect(Boolean.MonoidAll).exist expect(Boolean.SemigroupAny).exist expect(Boolean.MonoidAny).exist + expect(Boolean.SemigroupExclusiveAny).exist expect(Boolean.all).exist expect(Boolean.any).exist }) @@ -26,6 +27,13 @@ describe.concurrent("Boolean", () => { deepStrictEqual(pipe(false, Boolean.and(false)), false) }) + it("nand", () => { + deepStrictEqual(pipe(true, Boolean.nand(true)), false) + deepStrictEqual(pipe(true, Boolean.nand(false)), true) + deepStrictEqual(pipe(false, Boolean.nand(true)), true) + deepStrictEqual(pipe(false, Boolean.nand(false)), true) + }) + it("or", () => { deepStrictEqual(pipe(true, Boolean.or(true)), true) deepStrictEqual(pipe(true, Boolean.or(false)), true) @@ -33,11 +41,50 @@ describe.concurrent("Boolean", () => { deepStrictEqual(pipe(false, Boolean.or(false)), false) }) + it("nor", () => { + deepStrictEqual(pipe(true, Boolean.nor(true)), false) + deepStrictEqual(pipe(true, Boolean.nor(false)), false) + deepStrictEqual(pipe(false, Boolean.nor(true)), false) + deepStrictEqual(pipe(false, Boolean.nor(false)), true) + }) + + it("xor", () => { + deepStrictEqual(pipe(true, Boolean.xor(true)), false) + deepStrictEqual(pipe(true, Boolean.xor(false)), true) + deepStrictEqual(pipe(false, Boolean.xor(true)), true) + deepStrictEqual(pipe(false, Boolean.xor(false)), false) + }) + + it("xnor", () => { + deepStrictEqual(pipe(true, Boolean.xnor(true)), true) + deepStrictEqual(pipe(true, Boolean.xnor(false)), false) + deepStrictEqual(pipe(false, Boolean.xnor(true)), false) + deepStrictEqual(pipe(false, Boolean.xnor(false)), true) + }) + + it("implies", () => { + deepStrictEqual(pipe(true, Boolean.implies(true)), true) + deepStrictEqual(pipe(true, Boolean.implies(false)), false) + deepStrictEqual(pipe(false, Boolean.implies(true)), true) + deepStrictEqual(pipe(false, Boolean.implies(false)), true) + }) + it("not", () => { deepStrictEqual(pipe(true, Boolean.not), false) deepStrictEqual(pipe(false, Boolean.not), true) }) + describe.concurrent("SemigroupExclusiveAny", () => { + it("baseline", () => { + deepStrictEqual(Boolean.SemigroupExclusiveAny.combineMany(true, []), true) + deepStrictEqual(Boolean.SemigroupExclusiveAny.combineMany(false, []), false) + deepStrictEqual(Boolean.SemigroupExclusiveAny.combineMany(false, [true]), true) + deepStrictEqual(Boolean.SemigroupExclusiveAny.combineMany(false, [false]), false) + deepStrictEqual(Boolean.SemigroupExclusiveAny.combineMany(true, [true]), false) + deepStrictEqual(Boolean.SemigroupExclusiveAny.combineMany(true, [false]), true) + }) + }) + describe.concurrent("MonoidAll", () => { it("baseline", () => { deepStrictEqual(Boolean.MonoidAll.combineMany(true, [true, true]), true) From 8fb5e3262545af9d7ac5055c670a8dfd9cc14d49 Mon Sep 17 00:00:00 2001 From: "maksim.khramtsov" Date: Thu, 9 Feb 2023 17:23:54 +0100 Subject: [PATCH 234/255] review: rename booleanExclusiveAny to booleanXor --- docs/modules/Boolean.ts.md | 16 ++++++++-------- docs/modules/typeclass/Semigroup.ts.md | 6 +++--- src/Boolean.ts | 16 ++++++++-------- src/typeclass/Semigroup.ts | 2 +- test/Boolean.ts | 16 ++++++++-------- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/modules/Boolean.ts.md b/docs/modules/Boolean.ts.md index 937debf60..fc1974b3b 100644 --- a/docs/modules/Boolean.ts.md +++ b/docs/modules/Boolean.ts.md @@ -34,7 +34,7 @@ Added in v1.0.0 - [Order](#order) - [SemigroupAll](#semigroupall) - [SemigroupAny](#semigroupany) - - [SemigroupExclusiveAny](#semigroupexclusiveany) + - [SemigroupXor](#semigroupxor) - [pattern matching](#pattern-matching) - [match](#match) - [utils](#utils) @@ -244,25 +244,25 @@ assert.deepStrictEqual(SemigroupAny.combine(false, false), false) Added in v1.0.0 -## SemigroupExclusiveAny +## SemigroupXor `boolean` semigroup under disjunction. **Signature** ```ts -export declare const SemigroupExclusiveAny: semigroup.Semigroup +export declare const SemigroupXor: semigroup.Semigroup ``` **Example** ```ts -import { SemigroupExclusiveAny } from '@fp-ts/core/Boolean' +import { SemigroupXor } from '@fp-ts/core/Boolean' -assert.deepStrictEqual(SemigroupExclusiveAny.combine(true, true), false) -assert.deepStrictEqual(SemigroupExclusiveAny.combine(true, false), true) -assert.deepStrictEqual(SemigroupExclusiveAny.combine(false, true), true) -assert.deepStrictEqual(SemigroupExclusiveAny.combine(false, false), false) +assert.deepStrictEqual(SemigroupXor.combine(true, true), false) +assert.deepStrictEqual(SemigroupXor.combine(true, false), true) +assert.deepStrictEqual(SemigroupXor.combine(false, true), true) +assert.deepStrictEqual(SemigroupXor.combine(false, false), false) ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index b409a802f..6436699aa 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -30,7 +30,7 @@ Added in v1.0.0 - [bigintSum](#bigintsum) - [booleanAll](#booleanall) - [booleanAny](#booleanany) - - [booleanExclusiveAny](#booleanexclusiveany) + - [booleanXor](#booleanxor) - [first](#first) - [last](#last) - [numberMultiply](#numbermultiply) @@ -238,14 +238,14 @@ export declare const booleanAny: Semigroup Added in v1.0.0 -## booleanExclusiveAny +## booleanXor `boolean` semigroup under exclusive disjunction. **Signature** ```ts -export declare const booleanExclusiveAny: Semigroup +export declare const booleanXor: Semigroup ``` Added in v1.0.0 diff --git a/src/Boolean.ts b/src/Boolean.ts index 48ef82cc0..20e4845ee 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -107,17 +107,17 @@ export const SemigroupAny: semigroup.Semigroup = semigroup.booleanAny * `boolean` semigroup under disjunction. * * @example - * import { SemigroupExclusiveAny } from '@fp-ts/core/Boolean' + * import { SemigroupXor } from '@fp-ts/core/Boolean' * - * assert.deepStrictEqual(SemigroupExclusiveAny.combine(true, true), false) - * assert.deepStrictEqual(SemigroupExclusiveAny.combine(true, false), true) - * assert.deepStrictEqual(SemigroupExclusiveAny.combine(false, true), true) - * assert.deepStrictEqual(SemigroupExclusiveAny.combine(false, false), false) + * assert.deepStrictEqual(SemigroupXor.combine(true, true), false) + * assert.deepStrictEqual(SemigroupXor.combine(true, false), true) + * assert.deepStrictEqual(SemigroupXor.combine(false, true), true) + * assert.deepStrictEqual(SemigroupXor.combine(false, false), false) * * @category instances * @since 1.0.0 */ -export const SemigroupExclusiveAny: semigroup.Semigroup = semigroup.booleanExclusiveAny +export const SemigroupXor: semigroup.Semigroup = semigroup.booleanXor /** * `boolean` monoid under conjunction. @@ -188,7 +188,7 @@ export const nor: { export const xor: { (that: boolean): (self: boolean) => boolean (self: boolean, that: boolean): boolean -} = dual(2, semigroup.booleanExclusiveAny.combine) +} = dual(2, semigroup.booleanXor.combine) /** * @category combinators @@ -197,7 +197,7 @@ export const xor: { export const xnor: { (that: boolean): (self: boolean) => boolean (self: boolean, that: boolean): boolean -} = dual(2, flow(semigroup.booleanExclusiveAny.combine, not)) +} = dual(2, flow(semigroup.booleanXor.combine, not)) /** * @category combinators diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index f2c42c881..4f55e4977 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -157,7 +157,7 @@ export const booleanAny: Semigroup = make( * @category instances * @since 1.0.0 */ -export const booleanExclusiveAny: Semigroup = make( +export const booleanXor: Semigroup = make( (self, that) => self !== that, (self, collection) => { let isEmptyIterable = true diff --git a/test/Boolean.ts b/test/Boolean.ts index 0462c4fec..edbd739b6 100644 --- a/test/Boolean.ts +++ b/test/Boolean.ts @@ -8,7 +8,7 @@ describe.concurrent("Boolean", () => { expect(Boolean.MonoidAll).exist expect(Boolean.SemigroupAny).exist expect(Boolean.MonoidAny).exist - expect(Boolean.SemigroupExclusiveAny).exist + expect(Boolean.SemigroupXor).exist expect(Boolean.all).exist expect(Boolean.any).exist }) @@ -74,14 +74,14 @@ describe.concurrent("Boolean", () => { deepStrictEqual(pipe(false, Boolean.not), true) }) - describe.concurrent("SemigroupExclusiveAny", () => { + describe.concurrent("SemigroupXor", () => { it("baseline", () => { - deepStrictEqual(Boolean.SemigroupExclusiveAny.combineMany(true, []), true) - deepStrictEqual(Boolean.SemigroupExclusiveAny.combineMany(false, []), false) - deepStrictEqual(Boolean.SemigroupExclusiveAny.combineMany(false, [true]), true) - deepStrictEqual(Boolean.SemigroupExclusiveAny.combineMany(false, [false]), false) - deepStrictEqual(Boolean.SemigroupExclusiveAny.combineMany(true, [true]), false) - deepStrictEqual(Boolean.SemigroupExclusiveAny.combineMany(true, [false]), true) + deepStrictEqual(Boolean.SemigroupXor.combineMany(true, []), true) + deepStrictEqual(Boolean.SemigroupXor.combineMany(false, []), false) + deepStrictEqual(Boolean.SemigroupXor.combineMany(false, [true]), true) + deepStrictEqual(Boolean.SemigroupXor.combineMany(false, [false]), false) + deepStrictEqual(Boolean.SemigroupXor.combineMany(true, [true]), false) + deepStrictEqual(Boolean.SemigroupXor.combineMany(true, [false]), true) }) }) From 3e8e194dc8618a7a2ebc4b780bd8e2c2c2c132f7 Mon Sep 17 00:00:00 2001 From: "maksim.khramtsov" Date: Fri, 10 Feb 2023 10:00:45 +0100 Subject: [PATCH 235/255] review: get rid incorrect combineMany implementation and add tests --- src/typeclass/Semigroup.ts | 16 +--------------- test/Boolean.ts | 2 ++ 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 4f55e4977..e69731d75 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -157,21 +157,7 @@ export const booleanAny: Semigroup = make( * @category instances * @since 1.0.0 */ -export const booleanXor: Semigroup = make( - (self, that) => self !== that, - (self, collection) => { - let isEmptyIterable = true - for (const b of collection) { - if (isEmptyIterable) { - isEmptyIterable = false - } - if (b !== self) { - return true - } - } - return isEmptyIterable ? self : false - } -) +export const booleanXor: Semigroup = make((self, that) => self !== that) /** * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. diff --git a/test/Boolean.ts b/test/Boolean.ts index edbd739b6..4d1b3414d 100644 --- a/test/Boolean.ts +++ b/test/Boolean.ts @@ -82,6 +82,8 @@ describe.concurrent("Boolean", () => { deepStrictEqual(Boolean.SemigroupXor.combineMany(false, [false]), false) deepStrictEqual(Boolean.SemigroupXor.combineMany(true, [true]), false) deepStrictEqual(Boolean.SemigroupXor.combineMany(true, [false]), true) + deepStrictEqual(Boolean.SemigroupXor.combineMany(true, [true, false]), false) + deepStrictEqual(Boolean.SemigroupXor.combineMany(true, [false, true]), false) }) }) From 17e17837029fafd145246d6561e87a83d0efbf2d Mon Sep 17 00:00:00 2001 From: "maksim.khramtsov" Date: Sat, 11 Feb 2023 08:36:56 +0100 Subject: [PATCH 236/255] add missing semigroup and monoids rename `xnor` to `eqv` --- docs/modules/Boolean.ts.md | 52 ++++++++++++++++++----- docs/modules/typeclass/Monoid.ts.md | 30 ++++++++++++++ docs/modules/typeclass/Semigroup.ts.md | 13 ++++++ src/Boolean.ts | 24 ++++++++++- src/typeclass/Monoid.ts | 20 +++++++++ src/typeclass/Semigroup.ts | 8 ++++ test/Boolean.ts | 57 +++++++++++++++++++------- 7 files changed, 177 insertions(+), 27 deletions(-) diff --git a/docs/modules/Boolean.ts.md b/docs/modules/Boolean.ts.md index fc1974b3b..81067e7aa 100644 --- a/docs/modules/Boolean.ts.md +++ b/docs/modules/Boolean.ts.md @@ -18,12 +18,12 @@ Added in v1.0.0 - [combinators](#combinators) - [and](#and) + - [eqv](#eqv) - [implies](#implies) - [nand](#nand) - [nor](#nor) - [not](#not) - [or](#or) - - [xnor](#xnor) - [xor](#xor) - [guards](#guards) - [isBoolean](#isboolean) @@ -31,6 +31,8 @@ Added in v1.0.0 - [Equivalence](#equivalence) - [MonoidAll](#monoidall) - [MonoidAny](#monoidany) + - [MonoidEqv](#monoideqv) + - [MonoidXor](#monoidxor) - [Order](#order) - [SemigroupAll](#semigroupall) - [SemigroupAny](#semigroupany) @@ -55,6 +57,16 @@ export declare const and: { (that: boolean): (self: boolean) => boolean; (self: Added in v1.0.0 +## eqv + +**Signature** + +```ts +export declare const eqv: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } +``` + +Added in v1.0.0 + ## implies **Signature** @@ -105,16 +117,6 @@ export declare const or: { (that: boolean): (self: boolean) => boolean; (self: b Added in v1.0.0 -## xnor - -**Signature** - -```ts -export declare const xnor: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } -``` - -Added in v1.0.0 - ## xor **Signature** @@ -188,6 +190,34 @@ export declare const MonoidAny: monoid.Monoid Added in v1.0.0 +## MonoidEqv + +`boolean` monoid under equivalence. + +The `empty` value is `true`. + +**Signature** + +```ts +export declare const MonoidEqv: monoid.Monoid +``` + +Added in v1.0.0 + +## MonoidXor + +`boolean` monoid under exclusive disjunction. + +The `empty` value is `false`. + +**Signature** + +```ts +export declare const MonoidXor: monoid.Monoid +``` + +Added in v1.0.0 + ## Order **Signature** diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index 33f2df032..3fb15fc44 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -27,6 +27,8 @@ Added in v1.0.0 - [bigintSum](#bigintsum) - [booleanAll](#booleanall) - [booleanAny](#booleanany) + - [booleanEqv](#booleaneqv) + - [booleanXor](#booleanxor) - [numberMultiply](#numbermultiply) - [numberSum](#numbersum) - [string](#string) @@ -209,6 +211,34 @@ export declare const booleanAny: Monoid Added in v1.0.0 +## booleanEqv + +`boolean` monoid under equivalence. + +The `empty` value is `true`. + +**Signature** + +```ts +export declare const booleanEqv: Monoid +``` + +Added in v1.0.0 + +## booleanXor + +`boolean` monoid under exclusive disjunction. + +The `empty` value is `false`. + +**Signature** + +```ts +export declare const booleanXor: Monoid +``` + +Added in v1.0.0 + ## numberMultiply `number` monoid under multiplication. diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index 6436699aa..be1e901f8 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -30,6 +30,7 @@ Added in v1.0.0 - [bigintSum](#bigintsum) - [booleanAll](#booleanall) - [booleanAny](#booleanany) + - [booleanEqv](#booleaneqv) - [booleanXor](#booleanxor) - [first](#first) - [last](#last) @@ -238,6 +239,18 @@ export declare const booleanAny: Semigroup Added in v1.0.0 +## booleanEqv + +`boolean` semigroup under equivalence. + +**Signature** + +```ts +export declare const booleanEqv: Semigroup +``` + +Added in v1.0.0 + ## booleanXor `boolean` semigroup under exclusive disjunction. diff --git a/src/Boolean.ts b/src/Boolean.ts index 20e4845ee..bfca26447 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -139,6 +139,26 @@ export const MonoidAll: monoid.Monoid = monoid.booleanAll */ export const MonoidAny: monoid.Monoid = monoid.booleanAny +/** + * `boolean` monoid under exclusive disjunction. + * + * The `empty` value is `false`. + * + * @category instances + * @since 1.0.0 + */ +export const MonoidXor: monoid.Monoid = monoid.booleanXor + +/** + * `boolean` monoid under equivalence. + * + * The `empty` value is `true`. + * + * @category instances + * @since 1.0.0 + */ +export const MonoidEqv: monoid.Monoid = monoid.booleanEqv + /** * @category combinators * @since 1.0.0 @@ -194,10 +214,10 @@ export const xor: { * @category combinators * @since 1.0.0 */ -export const xnor: { +export const eqv: { (that: boolean): (self: boolean) => boolean (self: boolean, that: boolean): boolean -} = dual(2, flow(semigroup.booleanXor.combine, not)) +} = dual(2, semigroup.booleanEqv.combine) /** * @category combinators diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index 3a3f78246..85eb51462 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -119,6 +119,26 @@ export const booleanAll: Monoid = fromSemigroup(semigroup.booleanAll, t */ export const booleanAny: Monoid = fromSemigroup(semigroup.booleanAny, false) +/** + * `boolean` monoid under exclusive disjunction. + * + * The `empty` value is `false`. + * + * @category instances + * @since 1.0.0 + */ +export const booleanXor: Monoid = fromSemigroup(semigroup.booleanXor, false) + +/** + * `boolean` monoid under equivalence. + * + * The `empty` value is `true`. + * + * @category instances + * @since 1.0.0 + */ +export const booleanEqv: Monoid = fromSemigroup(semigroup.booleanEqv, true) + /** * This function creates and returns a new `Monoid` for a tuple of values based on the given `Monoid`s for each element in the tuple. * The returned `Monoid` combines two tuples of the same type by applying the corresponding `Monoid` passed as arguments to each element in the tuple. diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index e69731d75..8679fbbee 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -159,6 +159,14 @@ export const booleanAny: Semigroup = make( */ export const booleanXor: Semigroup = make((self, that) => self !== that) +/** + * `boolean` semigroup under equivalence. + * + * @category instances + * @since 1.0.0 + */ +export const booleanEqv: Semigroup = make((self, that) => self === that) + /** * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. * The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. diff --git a/test/Boolean.ts b/test/Boolean.ts index 4d1b3414d..523f05326 100644 --- a/test/Boolean.ts +++ b/test/Boolean.ts @@ -55,11 +55,11 @@ describe.concurrent("Boolean", () => { deepStrictEqual(pipe(false, Boolean.xor(false)), false) }) - it("xnor", () => { - deepStrictEqual(pipe(true, Boolean.xnor(true)), true) - deepStrictEqual(pipe(true, Boolean.xnor(false)), false) - deepStrictEqual(pipe(false, Boolean.xnor(true)), false) - deepStrictEqual(pipe(false, Boolean.xnor(false)), true) + it("eqv", () => { + deepStrictEqual(pipe(true, Boolean.eqv(true)), true) + deepStrictEqual(pipe(true, Boolean.eqv(false)), false) + deepStrictEqual(pipe(false, Boolean.eqv(true)), false) + deepStrictEqual(pipe(false, Boolean.eqv(false)), true) }) it("implies", () => { @@ -74,16 +74,45 @@ describe.concurrent("Boolean", () => { deepStrictEqual(pipe(false, Boolean.not), true) }) - describe.concurrent("SemigroupXor", () => { + describe.concurrent("MonoidXor", () => { it("baseline", () => { - deepStrictEqual(Boolean.SemigroupXor.combineMany(true, []), true) - deepStrictEqual(Boolean.SemigroupXor.combineMany(false, []), false) - deepStrictEqual(Boolean.SemigroupXor.combineMany(false, [true]), true) - deepStrictEqual(Boolean.SemigroupXor.combineMany(false, [false]), false) - deepStrictEqual(Boolean.SemigroupXor.combineMany(true, [true]), false) - deepStrictEqual(Boolean.SemigroupXor.combineMany(true, [false]), true) - deepStrictEqual(Boolean.SemigroupXor.combineMany(true, [true, false]), false) - deepStrictEqual(Boolean.SemigroupXor.combineMany(true, [false, true]), false) + deepStrictEqual(Boolean.MonoidXor.combineMany(true, []), true) + deepStrictEqual(Boolean.MonoidXor.combineMany(false, []), false) + deepStrictEqual(Boolean.MonoidXor.combineMany(false, [true]), true) + deepStrictEqual(Boolean.MonoidXor.combineMany(false, [false]), false) + deepStrictEqual(Boolean.MonoidXor.combineMany(true, [true]), false) + deepStrictEqual(Boolean.MonoidXor.combineMany(true, [false]), true) + deepStrictEqual(Boolean.MonoidXor.combineMany(true, [true, false]), false) + deepStrictEqual(Boolean.MonoidXor.combineMany(true, [false, true]), false) + deepStrictEqual(Boolean.MonoidXor.combineAll([true, false]), true) + deepStrictEqual(Boolean.MonoidXor.combineAll([false, true]), true) + }) + + it("should handle iterables", () => { + deepStrictEqual(Boolean.MonoidXor.combineAll(new Set([true, true])), true) + deepStrictEqual(Boolean.MonoidXor.combineAll(new Set([true, false])), true) + deepStrictEqual(Boolean.MonoidXor.combineAll(new Set([false, false])), false) + }) + }) + + describe.concurrent("MonoidEqv", () => { + it("baseline", () => { + deepStrictEqual(Boolean.MonoidEqv.combineMany(true, []), true) + deepStrictEqual(Boolean.MonoidEqv.combineMany(false, []), false) + deepStrictEqual(Boolean.MonoidEqv.combineMany(false, [true]), false) + deepStrictEqual(Boolean.MonoidEqv.combineMany(false, [false]), true) + deepStrictEqual(Boolean.MonoidEqv.combineMany(true, [true]), true) + deepStrictEqual(Boolean.MonoidEqv.combineMany(true, [false]), false) + deepStrictEqual(Boolean.MonoidEqv.combineMany(true, [true, false]), false) + deepStrictEqual(Boolean.MonoidEqv.combineMany(true, [false, true]), false) + deepStrictEqual(Boolean.MonoidEqv.combineAll([true, false]), false) + deepStrictEqual(Boolean.MonoidEqv.combineAll([false, true]), false) + }) + + it("should handle iterables", () => { + deepStrictEqual(Boolean.MonoidEqv.combineAll(new Set([true, true])), true) + deepStrictEqual(Boolean.MonoidEqv.combineAll(new Set([true, false])), false) + deepStrictEqual(Boolean.MonoidEqv.combineAll(new Set([false, false])), false) }) }) From 61707e83fc5a5533bf9a70e10577befe79983947 Mon Sep 17 00:00:00 2001 From: "maksim.khramtsov" Date: Sat, 11 Feb 2023 08:39:10 +0100 Subject: [PATCH 237/255] add note to changeset --- .changeset/mighty-meals-dream.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/mighty-meals-dream.md diff --git a/.changeset/mighty-meals-dream.md b/.changeset/mighty-meals-dream.md new file mode 100644 index 000000000..181f6585a --- /dev/null +++ b/.changeset/mighty-meals-dream.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": minor +--- + +add missing boolean semigroups, monoids and combinators From de08677789fedb14a85dd6fc900b4bbdd6733246 Mon Sep 17 00:00:00 2001 From: "maksim.khramtsov" Date: Sat, 11 Feb 2023 16:33:36 +0100 Subject: [PATCH 238/255] add missed semigroupEqv and test assertions on new members exported from Boolean module --- docs/modules/Boolean.ts.md | 26 +++++++++++++++++++++++++- src/Boolean.ts | 17 ++++++++++++++++- test/Boolean.ts | 8 ++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/docs/modules/Boolean.ts.md b/docs/modules/Boolean.ts.md index 81067e7aa..c3f014c8f 100644 --- a/docs/modules/Boolean.ts.md +++ b/docs/modules/Boolean.ts.md @@ -36,6 +36,7 @@ Added in v1.0.0 - [Order](#order) - [SemigroupAll](#semigroupall) - [SemigroupAny](#semigroupany) + - [SemigroupEqv](#semigroupeqv) - [SemigroupXor](#semigroupxor) - [pattern matching](#pattern-matching) - [match](#match) @@ -274,9 +275,32 @@ assert.deepStrictEqual(SemigroupAny.combine(false, false), false) Added in v1.0.0 +## SemigroupEqv + +`boolean` semigroup under equivalence. + +**Signature** + +```ts +export declare const SemigroupEqv: semigroup.Semigroup +``` + +**Example** + +```ts +import { SemigroupEqv } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(SemigroupEqv.combine(true, true), true) +assert.deepStrictEqual(SemigroupEqv.combine(true, false), false) +assert.deepStrictEqual(SemigroupEqv.combine(false, true), false) +assert.deepStrictEqual(SemigroupEqv.combine(false, false), true) +``` + +Added in v1.0.0 + ## SemigroupXor -`boolean` semigroup under disjunction. +`boolean` semigroup under exclusive disjunction. **Signature** diff --git a/src/Boolean.ts b/src/Boolean.ts index bfca26447..6d7c4b084 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -104,7 +104,7 @@ export const SemigroupAll: semigroup.Semigroup = semigroup.booleanAll export const SemigroupAny: semigroup.Semigroup = semigroup.booleanAny /** - * `boolean` semigroup under disjunction. + * `boolean` semigroup under exclusive disjunction. * * @example * import { SemigroupXor } from '@fp-ts/core/Boolean' @@ -118,6 +118,21 @@ export const SemigroupAny: semigroup.Semigroup = semigroup.booleanAny * @since 1.0.0 */ export const SemigroupXor: semigroup.Semigroup = semigroup.booleanXor +/** + * `boolean` semigroup under equivalence. + * + * @example + * import { SemigroupEqv } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(SemigroupEqv.combine(true, true), true) + * assert.deepStrictEqual(SemigroupEqv.combine(true, false), false) + * assert.deepStrictEqual(SemigroupEqv.combine(false, true), false) + * assert.deepStrictEqual(SemigroupEqv.combine(false, false), true) + * + * @category instances + * @since 1.0.0 + */ +export const SemigroupEqv: semigroup.Semigroup = semigroup.booleanEqv /** * `boolean` monoid under conjunction. diff --git a/test/Boolean.ts b/test/Boolean.ts index 523f05326..fdbf97c24 100644 --- a/test/Boolean.ts +++ b/test/Boolean.ts @@ -9,8 +9,16 @@ describe.concurrent("Boolean", () => { expect(Boolean.SemigroupAny).exist expect(Boolean.MonoidAny).exist expect(Boolean.SemigroupXor).exist + expect(Boolean.MonoidXor).exist + expect(Boolean.SemigroupEqv).exist + expect(Boolean.MonoidEqv).exist expect(Boolean.all).exist expect(Boolean.any).exist + expect(Boolean.xor).exist + expect(Boolean.eqv).exist + expect(Boolean.nand).exist + expect(Boolean.nor).exist + expect(Boolean.implies).exist }) it("isBoolean", () => { From f7cc0fc1ccdf930704358ee84cca22faada172bf Mon Sep 17 00:00:00 2001 From: gcanti Date: Sat, 11 Feb 2023 10:29:09 +0100 Subject: [PATCH 239/255] refactor Option guide --- .changeset/famous-spies-attend.md | 5 + .changeset/mighty-meals-dream.md | 2 +- README.md | 5 +- docs/modules/Either.ts.md | 27 +- docs/modules/Option.ts.md | 1118 ++++++++++++++++------------- guides/Either.md | 9 +- guides/Option.md | 590 +++++++++------ src/Either.ts | 21 +- src/Option.ts | 403 +++++------ src/Predicate.ts | 43 +- test/Either.ts | 1 + test/Option.ts | 1 + 12 files changed, 1235 insertions(+), 990 deletions(-) create mode 100644 .changeset/famous-spies-attend.md diff --git a/.changeset/famous-spies-attend.md b/.changeset/famous-spies-attend.md new file mode 100644 index 000000000..ae24facf3 --- /dev/null +++ b/.changeset/famous-spies-attend.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +export productAll from Option, Either, Predicate diff --git a/.changeset/mighty-meals-dream.md b/.changeset/mighty-meals-dream.md index 181f6585a..94563a8ed 100644 --- a/.changeset/mighty-meals-dream.md +++ b/.changeset/mighty-meals-dream.md @@ -1,5 +1,5 @@ --- -"@fp-ts/core": minor +"@fp-ts/core": patch --- add missing boolean semigroups, monoids and combinators diff --git a/README.md b/README.md index 5b0bc56d1..00dc1dd2d 100644 --- a/README.md +++ b/README.md @@ -76,9 +76,8 @@ npm install @fp-ts/core - Guides (WIP) - [Typeclass overview](./guides/typeclass.md) - [Standard TypeScript types](./guides/ts-types.md) - - Functional Error handling - - [The `Option` data type](./guides/Option.md) - - [The `Either` data type](./guides/Either.md) + - Data types + - [`Option`](./guides/Option.md) - [API Reference](https://fp-ts.github.io/core/) # License diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index b06e5d6d5..53a643b36 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -115,6 +115,7 @@ Added in v1.0.0 - [flatMap](#flatmap) - [flatMapNullable](#flatmapnullable) - [flatMapOption](#flatmapoption) + - [productAll](#productall) - [traversing](#traversing) - [sequence](#sequence) - [traverse](#traverse) @@ -1475,6 +1476,28 @@ export declare const flatMapOption: { Added in v1.0.0 +## productAll + +Flattens a collection of `Either`s into a single `Either` that contains a list of all the `Right` values. +If there is a `Left` value in the collection, it returns `Left` as the result. + +**Signature** + +```ts +export declare const productAll: (collection: Iterable>) => Either +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(E.productAll([E.right(1), E.right(2), E.right(3)]), E.right([1, 2, 3])) +assert.deepStrictEqual(E.productAll([E.right(1), E.left('error'), E.right(3)]), E.left('error')) +``` + +Added in v1.0.0 + # traversing ## sequence @@ -1657,7 +1680,7 @@ Added in v1.0.0 ```ts export declare const struct: >>( - r: R + fields: R ) => Either< [R[keyof R]] extends [Either] ? E : never, { [K in keyof R]: [R[K]] extends [Either] ? A : never } @@ -1672,7 +1695,7 @@ Added in v1.0.0 ```ts export declare const tuple: []>( - ...tuple: T + ...elements: T ) => Either< [T[number]] extends [Either] ? E : never, { [I in keyof T]: [T[I]] extends [Either] ? A : never } diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index e64a57d45..aadaf7d80 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -32,8 +32,13 @@ Added in v1.0.0 - [conversions](#conversions) - [fromEither](#fromeither) - [fromIterable](#fromiterable) + - [fromNullable](#fromnullable) - [getLeft](#getleft) + - [getOrThrow](#getorthrow) + - [getOrThrowWith](#getorthrowwith) - [getRight](#getright) + - [liftNullable](#liftnullable) + - [liftThrowable](#liftthrowable) - [toArray](#toarray) - [toEither](#toeither) - [toRefinement](#torefinement) @@ -50,7 +55,6 @@ Added in v1.0.0 - [getEquivalence](#getequivalence) - [error handling](#error-handling) - [firstSomeOf](#firstsomeof) - - [getOrElse](#getorelse) - [orElse](#orelse) - [orElseEither](#orelseeither) - [filtering](#filtering) @@ -58,45 +62,19 @@ Added in v1.0.0 - [filterMap](#filtermap) - [partitionMap](#partitionmap) - [folding](#folding) - - [Foldable](#foldable) - [reduceCompact](#reducecompact) +- [getters](#getters) + - [getOrElse](#getorelse) + - [getOrNull](#getornull) + - [getOrUndefined](#getorundefined) - [guards](#guards) - [isNone](#isnone) - [isOption](#isoption) - [isSome](#issome) -- [instances](#instances) - - [Alternative](#alternative) - - [Applicative](#applicative) - - [Coproduct](#coproduct) - - [Filterable](#filterable) - - [Monad](#monad) - - [Product](#product) - - [SemiAlternative](#semialternative) - - [SemiApplicative](#semiapplicative) - - [SemiCoproduct](#semicoproduct) - - [SemiProduct](#semiproduct) - - [Traversable](#traversable) - - [getOptionalMonoid](#getoptionalmonoid) -- [interop](#interop) - - [fromNullable](#fromnullable) - - [getOrNull](#getornull) - - [getOrThrow](#getorthrow) - - [getOrThrowWith](#getorthrowwith) - - [getOrUndefined](#getorundefined) - - [liftNullable](#liftnullable) - - [liftThrowable](#liftthrowable) - [lifting](#lifting) - [lift2](#lift2) - [liftEither](#lifteither) - [liftPredicate](#liftpredicate) -- [mapping](#mapping) - - [Covariant](#covariant) - - [Invariant](#invariant) - - [as](#as) - - [asUnit](#asunit) - - [flap](#flap) - - [map](#map) - - [tupled](#tupled) - [models](#models) - [None (interface)](#none-interface) - [Option (type alias)](#option-type-alias) @@ -104,32 +82,53 @@ Added in v1.0.0 - [pattern matching](#pattern-matching) - [match](#match) - [sequencing](#sequencing) - - [Chainable](#chainable) - - [FlatMap](#flatmap) + - [productAll](#productall) + - [sequence](#sequence) + - [struct](#struct) + - [traverse](#traverse) + - [traverseTap](#traversetap) + - [tuple](#tuple) +- [sorting](#sorting) + - [getOrder](#getorder) +- [transforming](#transforming) - [andThen](#andthen) - [andThenDiscard](#andthendiscard) + - [as](#as) + - [asUnit](#asunit) - [composeKleisliArrow](#composekleisliarrow) + - [flap](#flap) - [flatMap](#flatmap) - [flatMapEither](#flatmapeither) - [flatMapNullable](#flatmapnullable) - [flatten](#flatten) + - [map](#map) - [tap](#tap) -- [sorting](#sorting) - - [getOrder](#getorder) -- [traversing](#traversing) - - [sequence](#sequence) - - [traverse](#traverse) - - [traverseTap](#traversetap) + - [tupled](#tupled) - [type lambdas](#type-lambdas) - [OptionTypeLambda (interface)](#optiontypelambda-interface) - [utils](#utils) + - [Alternative](#alternative) + - [Applicative](#applicative) + - [Chainable](#chainable) + - [Coproduct](#coproduct) + - [Covariant](#covariant) + - [Filterable](#filterable) + - [FlatMap](#flatmap) + - [Foldable](#foldable) + - [Invariant](#invariant) + - [Monad](#monad) - [Of](#of) - [Pointed](#pointed) + - [Product](#product) + - [SemiAlternative](#semialternative) + - [SemiApplicative](#semiapplicative) + - [SemiCoproduct](#semicoproduct) + - [SemiProduct](#semiproduct) + - [Traversable](#traversable) - [appendElement](#appendelement) - [contains](#contains) - [exists](#exists) - - [struct](#struct) - - [tuple](#tuple) + - [getOptionalMonoid](#getoptionalmonoid) - [unit](#unit) --- @@ -312,9 +311,6 @@ Added in v1.0.0 Creates a new `Option` that represents the absence of a value. -This can be useful when working with optional values or to represent a computation that failed. -It returns a new `Option` object that does not contain any value. - **Signature** ```ts @@ -339,8 +335,6 @@ Added in v1.0.0 Creates a new `Option` that wraps the given value. -This can be useful when working with optional values or to represent a computation that succeeded with a value. - **Signature** ```ts @@ -368,7 +362,7 @@ import * as O from '@fp-ts/core/Option' import * as E from '@fp-ts/core/Either' assert.deepStrictEqual(O.fromEither(E.right(1)), O.some(1)) -assert.deepStrictEqual(O.fromEither(E.left('a')), O.none()) +assert.deepStrictEqual(O.fromEither(E.left('error message')), O.none()) ``` Added in v1.0.0 @@ -389,13 +383,35 @@ export declare const fromIterable: (collection: Iterable) => Option ```ts import { fromIterable, some, none } from '@fp-ts/core/Option' -const collection = [1, 2, 3] -assert.deepStrictEqual(fromIterable(collection), some(1)) +assert.deepStrictEqual(fromIterable([1, 2, 3]), some(1)) assert.deepStrictEqual(fromIterable([]), none()) ``` Added in v1.0.0 +## fromNullable + +Constructs a new `Option` from a nullable type. If the value is `null` or `undefined`, returns `None`, otherwise +returns the value wrapped in a `Some`. + +**Signature** + +```ts +export declare const fromNullable: (nullableValue: A) => Option> +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual(O.fromNullable(undefined), O.none()) +assert.deepStrictEqual(O.fromNullable(null), O.none()) +assert.deepStrictEqual(O.fromNullable(1), O.some(1)) +``` + +Added in v1.0.0 + ## getLeft Converts a `Either` to an `Option` discarding the value. @@ -413,7 +429,59 @@ import * as O from '@fp-ts/core/Option' import * as E from '@fp-ts/core/Either' assert.deepStrictEqual(O.getLeft(E.right('ok')), O.none()) -assert.deepStrictEqual(O.getLeft(E.left('err')), O.some('err')) +assert.deepStrictEqual(O.getLeft(E.left('error')), O.some('error')) +``` + +Added in v1.0.0 + +## getOrThrow + +Extracts the value of an `Option` or throws if the `Option` is `None`. + +The thrown error is a default error. To configure the error thrown, see {@link getOrThrowWith}. + +**Signature** + +```ts +export declare const getOrThrow: (self: Option) => A +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual(O.getOrThrow(O.some(1)), 1) +assert.throws(() => O.getOrThrow(O.none())) +``` + +Added in v1.0.0 + +## getOrThrowWith + +Extracts the value of an `Option` or throws if the `Option` is `None`. + +If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. + +**Signature** + +```ts +export declare const getOrThrowWith: { + (onNone: () => unknown): (self: Option) => A + (self: Option, onNone: () => unknown): A +} +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual( + O.getOrThrowWith(O.some(1), () => new Error('Unexpected None')), + 1 +) +assert.throws(() => O.getOrThrowWith(O.none(), () => new Error('Unexpected None'))) ``` Added in v1.0.0 @@ -442,6 +510,62 @@ assert.deepStrictEqual(O.getRight(E.left('err')), O.none()) Added in v1.0.0 +## liftNullable + +This API is useful for lifting a function that returns `null` or `undefined` into the `Option` context. + +**Signature** + +```ts +export declare const liftNullable: ( + f: (...a: A) => B | null | undefined +) => (...a: A) => Option> +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +const parse = (s: string): number | undefined => { + const n = parseFloat(s) + return isNaN(n) ? undefined : n +} + +const parseOption = O.liftNullable(parse) + +assert.deepStrictEqual(parseOption('1'), O.some(1)) +assert.deepStrictEqual(parseOption('not a number'), O.none()) +``` + +Added in v1.0.0 + +## liftThrowable + +A utility function that lifts a function that throws exceptions into a function that returns an `Option`. + +This function is useful for any function that might throw an exception, allowing the developer to handle +the exception in a more functional way. + +**Signature** + +```ts +export declare const liftThrowable: (f: (...a: A) => B) => (...a: A) => Option +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +const parse = O.liftThrowable(JSON.parse) + +assert.deepStrictEqual(parse('1'), O.some(1)) +assert.deepStrictEqual(parse(''), O.none()) +``` + +Added in v1.0.0 + ## toArray Transforms an `Option` into an `Array`. @@ -457,10 +581,10 @@ export declare const toArray: (self: Option) => A[] **Example** ```ts -import { some, none, toArray } from '@fp-ts/core/Option' +import * as O from '@fp-ts/core/Option' -assert.deepStrictEqual(toArray(some(1)), [1]) -assert.deepStrictEqual(toArray(none()), []) +assert.deepStrictEqual(O.toArray(O.some(1)), [1]) +assert.deepStrictEqual(O.toArray(O.none()), []) ``` Added in v1.0.0 @@ -494,13 +618,26 @@ Added in v1.0.0 ## toRefinement -Returns a `Refinement` from a `Option` returning function. -This function ensures that a `Refinement` definition is type-safe. +Returns a type guard from a `Option` returning function. +This function ensures that a type guard definition is type-safe. **Signature** ```ts -export declare const toRefinement: (f: (a: A) => Option) => Refinement +export declare const toRefinement: (f: (a: A) => Option) => (a: A) => a is B +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +const parsePositive = (n: number): O.Option => (n > 0 ? O.some(n) : O.none()) + +const isPositive = O.toRefinement(parsePositive) + +assert.deepStrictEqual(isPositive(1), true) +assert.deepStrictEqual(isPositive(-1), false) ``` Added in v1.0.0 @@ -645,7 +782,7 @@ Added in v1.0.0 ## firstSomeOf -Given an `Iterable` collection of `Option`s, the function returns the first `Some` found in the collection. +Given an `Iterable` collection of `Option`s, returns the first `Some` found in the collection. **Signature** @@ -653,41 +790,12 @@ Given an `Iterable` collection of `Option`s, the function returns the first `Som export declare const firstSomeOf: (collection: Iterable>) => Option ``` -Added in v1.0.0 - -## getOrElse - -Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` - -**Signature** - -```ts -export declare const getOrElse: { - (onNone: LazyArg): (self: Option) => B | A - (self: Option, onNone: LazyArg): A | B -} -``` - **Example** ```ts -import { some, none, getOrElse } from '@fp-ts/core/Option' -import { pipe } from '@fp-ts/core/Function' +import * as O from '@fp-ts/core/Option' -assert.deepStrictEqual( - pipe( - some(1), - getOrElse(() => 0) - ), - 1 -) -assert.deepStrictEqual( - pipe( - none(), - getOrElse(() => 0) - ), - 0 -) +assert.deepStrictEqual(O.firstSomeOf([O.none(), O.some(1), O.some(2)]), O.some(1)) ``` Added in v1.0.0 @@ -814,16 +922,6 @@ Added in v1.0.0 # folding -## Foldable - -**Signature** - -```ts -export declare const Foldable: foldable.Foldable -``` - -Added in v1.0.0 - ## reduceCompact Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. @@ -855,232 +953,41 @@ assert.deepStrictEqual( Added in v1.0.0 -# guards +# getters -## isNone +## getOrElse -Determine if a `Option` is a `None`. +Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` **Signature** ```ts -export declare const isNone: (self: Option) => self is None -``` - -**Example** - -```ts -import { some, none, isNone } from '@fp-ts/core/Option' - -assert.deepStrictEqual(isNone(some(1)), false) -assert.deepStrictEqual(isNone(none()), true) -``` - -Added in v1.0.0 - -## isOption - -Tests if a value is a `Option`. - -**Signature** - -```ts -export declare const isOption: (input: unknown) => input is Option -``` - -**Example** - -```ts -import { some, none, isOption } from '@fp-ts/core/Option' - -assert.deepStrictEqual(isOption(some(1)), true) -assert.deepStrictEqual(isOption(none()), true) -assert.deepStrictEqual(isOption({}), false) -``` - -Added in v1.0.0 - -## isSome - -Determine if a `Option` is a `Some`. - -**Signature** - -```ts -export declare const isSome: (self: Option) => self is Some -``` - -**Example** - -```ts -import { some, none, isSome } from '@fp-ts/core/Option' - -assert.deepStrictEqual(isSome(some(1)), true) -assert.deepStrictEqual(isSome(none()), false) -``` - -Added in v1.0.0 - -# instances - -## Alternative - -**Signature** - -```ts -export declare const Alternative: alternative.Alternative -``` - -Added in v1.0.0 - -## Applicative - -**Signature** - -```ts -export declare const Applicative: applicative.Applicative -``` - -Added in v1.0.0 - -## Coproduct - -**Signature** - -```ts -export declare const Coproduct: coproduct_.Coproduct -``` - -Added in v1.0.0 - -## Filterable - -**Signature** - -```ts -export declare const Filterable: filterable.Filterable -``` - -Added in v1.0.0 - -## Monad - -**Signature** - -```ts -export declare const Monad: monad.Monad -``` - -Added in v1.0.0 - -## Product - -**Signature** - -```ts -export declare const Product: product_.Product -``` - -Added in v1.0.0 - -## SemiAlternative - -**Signature** - -```ts -export declare const SemiAlternative: semiAlternative.SemiAlternative -``` - -Added in v1.0.0 - -## SemiApplicative - -**Signature** - -```ts -export declare const SemiApplicative: semiApplicative.SemiApplicative -``` - -Added in v1.0.0 - -## SemiCoproduct - -**Signature** - -```ts -export declare const SemiCoproduct: semiCoproduct.SemiCoproduct -``` - -Added in v1.0.0 - -## SemiProduct - -**Signature** - -```ts -export declare const SemiProduct: semiProduct.SemiProduct -``` - -Added in v1.0.0 - -## Traversable - -**Signature** - -```ts -export declare const Traversable: traversable.Traversable -``` - -Added in v1.0.0 - -## getOptionalMonoid - -Monoid that models the combination of values that may be absent, elements that are `None` are ignored -while elements that are `Some` are combined using the provided `Semigroup`. - -**Signature** - -```ts -export declare const getOptionalMonoid: (Semigroup: Semigroup) => Monoid> +export declare const getOrElse: { + (onNone: LazyArg): (self: Option) => B | A + (self: Option, onNone: LazyArg): A | B +} ``` **Example** ```ts -import { getOptionalMonoid, some, none } from '@fp-ts/core/Option' -import * as N from '@fp-ts/core/Number' +import { some, none, getOrElse } from '@fp-ts/core/Option' import { pipe } from '@fp-ts/core/Function' -const M = getOptionalMonoid(N.SemigroupSum) -assert.deepStrictEqual(M.combine(none(), none()), none()) -assert.deepStrictEqual(M.combine(some(1), none()), some(1)) -assert.deepStrictEqual(M.combine(none(), some(1)), some(1)) -assert.deepStrictEqual(M.combine(some(1), some(2)), some(3)) -``` - -Added in v1.0.0 - -# interop - -## fromNullable - -Constructs a new `Option` from a nullable type. If the value is `null` or `undefined`, returns `None`, otherwise -returns the value wrapped in a `Some`. - -**Signature** - -```ts -export declare const fromNullable: (nullableValue: A) => Option> -``` - -**Example** - -```ts -import { none, some, fromNullable } from '@fp-ts/core/Option' - -assert.deepStrictEqual(fromNullable(undefined), none()) -assert.deepStrictEqual(fromNullable(null), none()) -assert.deepStrictEqual(fromNullable(1), some(1)) +assert.deepStrictEqual( + pipe( + some(1), + getOrElse(() => 0) + ), + 1 +) +assert.deepStrictEqual( + pipe( + none(), + getOrElse(() => 0) + ), + 0 +) ``` Added in v1.0.0 @@ -1097,52 +1004,23 @@ export declare const getOrNull: (self: Option) => A | null **Example** -```ts -import { some, none, getOrNull } from '@fp-ts/core/Option' -import { pipe } from '@fp-ts/core/Function' - -assert.deepStrictEqual(pipe(some(1), getOrNull), 1) -assert.deepStrictEqual(pipe(none(), getOrNull), null) -``` - -Added in v1.0.0 - -## getOrThrow - -Extracts the value of an `Option` or throws if the `Option` is `None`. - -The thrown error is a default error. To configure the error thrown, see {@link getOrThrowWith}. - -**Signature** - -```ts -export declare const getOrThrow: (self: Option) => A -``` - -**Example** - ```ts import * as O from '@fp-ts/core/Option' -assert.deepStrictEqual(O.getOrThrow(O.some(1)), 1) -assert.throws(() => O.getOrThrow(O.none())) +assert.deepStrictEqual(O.getOrNull(O.some(1)), 1) +assert.deepStrictEqual(O.getOrNull(O.none()), null) ``` Added in v1.0.0 -## getOrThrowWith - -Extracts the value of an `Option` or throws if the `Option` is `None`. +## getOrUndefined -If a default error is sufficient for your use case and you don't need to configure the thrown error, see {@link getOrThrow}. +Returns the value of the `Option` if it is a `Some`, otherwise returns `undefined`. **Signature** ```ts -export declare const getOrThrowWith: { - (onNone: () => unknown): (self: Option) => A - (self: Option, onNone: () => unknown): A -} +export declare const getOrUndefined: (self: Option) => A | undefined ``` **Example** @@ -1150,89 +1028,74 @@ export declare const getOrThrowWith: { ```ts import * as O from '@fp-ts/core/Option' -assert.deepStrictEqual( - O.getOrThrowWith(O.some(1), () => new Error('Unexpected None')), - 1 -) -assert.throws(() => O.getOrThrowWith(O.none(), () => new Error('Unexpected None'))) +assert.deepStrictEqual(O.getOrUndefined(O.some(1)), 1) +assert.deepStrictEqual(O.getOrUndefined(O.none()), undefined) ``` Added in v1.0.0 -## getOrUndefined +# guards -Returns the value of the `Option` if it is a `Some`, otherwise returns `undefined`. +## isNone + +Determine if a `Option` is a `None`. **Signature** ```ts -export declare const getOrUndefined: (self: Option) => A | undefined +export declare const isNone: (self: Option) => self is None ``` **Example** ```ts -import { some, none, getOrUndefined } from '@fp-ts/core/Option' -import { pipe } from '@fp-ts/core/Function' +import { some, none, isNone } from '@fp-ts/core/Option' -assert.deepStrictEqual(pipe(some(1), getOrUndefined), 1) -assert.deepStrictEqual(pipe(none(), getOrUndefined), undefined) +assert.deepStrictEqual(isNone(some(1)), false) +assert.deepStrictEqual(isNone(none()), true) ``` Added in v1.0.0 -## liftNullable +## isOption -This API is useful for lifting a function that returns `null` or `undefined` into the `Option` context. +Tests if a value is a `Option`. **Signature** ```ts -export declare const liftNullable: ( - f: (...a: A) => B | null | undefined -) => (...a: A) => Option> +export declare const isOption: (input: unknown) => input is Option ``` **Example** ```ts -import { liftNullable, none, some } from '@fp-ts/core/Option' - -const parse = (s: string): number | undefined => { - const n = parseFloat(s) - return isNaN(n) ? undefined : n -} - -const parseOption = liftNullable(parse) +import { some, none, isOption } from '@fp-ts/core/Option' -assert.deepStrictEqual(parseOption('1'), some(1)) -assert.deepStrictEqual(parseOption('not a number'), none()) +assert.deepStrictEqual(isOption(some(1)), true) +assert.deepStrictEqual(isOption(none()), true) +assert.deepStrictEqual(isOption({}), false) ``` Added in v1.0.0 -## liftThrowable - -A utility function that lifts a function that throws exceptions into a function that returns an `Option`. +## isSome -This function is useful for any function that might throw an exception, allowing the developer to handle -the exception in a more functional way. +Determine if a `Option` is a `Some`. **Signature** ```ts -export declare const liftThrowable: (f: (...a: A) => B) => (...a: A) => Option +export declare const isSome: (self: Option) => self is Some ``` **Example** ```ts -import { liftThrowable, some, none } from '@fp-ts/core/Option' - -const parse = liftThrowable(JSON.parse) +import { some, none, isSome } from '@fp-ts/core/Option' -assert.deepStrictEqual(parse('1'), some(1)) -assert.deepStrictEqual(parse(''), none()) +assert.deepStrictEqual(isSome(some(1)), true) +assert.deepStrictEqual(isSome(none()), false) ``` Added in v1.0.0 @@ -1308,198 +1171,268 @@ assert.deepStrictEqual(getOption(1), O.some(1)) Added in v1.0.0 -# mapping +# models -## Covariant +## None (interface) **Signature** ```ts -export declare const Covariant: covariant.Covariant +export interface None { + readonly _tag: 'None' +} ``` Added in v1.0.0 -## Invariant +## Option (type alias) **Signature** ```ts -export declare const Invariant: invariant.Invariant +export type Option = None | Some ``` Added in v1.0.0 -## as - -Maps the `Some` value of this `Option` to the specified constant value. +## Some (interface) **Signature** ```ts -export declare const as: { <_, B>(self: Option<_>, b: B): Option; (b: B): <_>(self: Option<_>) => Option } +export interface Some { + readonly _tag: 'Some' + readonly value: A +} ``` Added in v1.0.0 -## asUnit +# pattern matching -Returns the `Option` resulting from mapping the `Some` value to `void`. +## match -This is useful when the value of the `Option` is not needed, but the presence or absence of the value is important. +Matches the given `Option` and returns either the provided `onNone` value or the result of the provided `onSome` +function when passed the `Option`'s value. **Signature** ```ts -export declare const asUnit: <_>(self: Option<_>) => Option +export declare const match: { + (onNone: LazyArg, onSome: (a: A) => C): (self: Option) => B | C + (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C +} +``` + +**Example** + +```ts +import { some, none, match } from '@fp-ts/core/Option' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual( + pipe( + some(1), + match( + () => 'a none', + (a) => `a some containing ${a}` + ) + ), + 'a some containing 1' +) + +assert.deepStrictEqual( + pipe( + none(), + match( + () => 'a none', + (a) => `a some containing ${a}` + ) + ), + 'a none' +) ``` Added in v1.0.0 -## flap +# sequencing + +## productAll + +Flattens a collection of `Option`s into a single `Option` that contains a list of all the `Some` values. +If there is a `None` value in the collection, it returns `None` as the result. **Signature** ```ts -export declare const flap: { - (a: A, self: Option<(a: A) => B>): Option - (self: Option<(a: A) => B>): (a: A) => Option -} +export declare const productAll: (collection: Iterable>) => Option +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual(O.productAll([O.some(1), O.some(2), O.some(3)]), O.some([1, 2, 3])) +assert.deepStrictEqual(O.productAll([O.some(1), O.none(), O.some(3)]), O.none()) ``` Added in v1.0.0 -## map +## sequence -Maps the `Some` side of an `Option` value to a new `Option` value. +Combines an `Option` of an `F`-structure to an `F`-structure of an `Option` with the same inner type. **Signature** ```ts -export declare const map: { - (f: (a: A) => B): (self: Option) => Option - (self: Option, f: (a: A) => B): Option -} +export declare const sequence: ( + F: applicative.Applicative +) => (self: Option>) => Kind> +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +const sequence = O.sequence(E.Applicative) + +assert.deepStrictEqual(sequence(O.some(E.right(1))), E.right(O.some(1))) +assert.deepStrictEqual(sequence(O.some(E.left('error'))), E.left('error')) +assert.deepStrictEqual(sequence(O.none()), E.right(O.none())) ``` Added in v1.0.0 -## tupled +## struct + +Takes a struct of `Option`s and returns an `Option` of a struct of values. **Signature** ```ts -export declare const tupled: (self: Option) => Option<[A]> +export declare const struct: >>( + fields: R +) => Option<{ [K in keyof R]: [R[K]] extends [Option] ? A : never }> +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual(O.struct({ a: O.some(1), b: O.some('hello') }), O.some({ a: 1, b: 'hello' })) +assert.deepStrictEqual(O.struct({ a: O.some(1), b: O.none() }), O.none()) ``` Added in v1.0.0 -# models +## traverse -## None (interface) +Applies an `Option` value to an effectful function that returns an `F` value. **Signature** ```ts -export interface None { - readonly _tag: 'None' +export declare const traverse: ( + F: applicative.Applicative +) => { + (f: (a: A) => Kind): (self: Option) => Kind> + (self: Option, f: (a: A) => Kind): Kind> } ``` -Added in v1.0.0 +**Example** -## Option (type alias) +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' -**Signature** +const traverse = O.traverse(E.Applicative) +const f = (n: number) => (n >= 0 ? E.right(1) : E.left('negative')) -```ts -export type Option = None | Some +assert.deepStrictEqual(traverse(O.some(1), f), E.right(O.some(1))) +assert.deepStrictEqual(traverse(O.some(-1), f), E.left('negative')) +assert.deepStrictEqual(traverse(O.none(), f), E.right(O.none())) ``` Added in v1.0.0 -## Some (interface) +## traverseTap **Signature** ```ts -export interface Some { - readonly _tag: 'Some' - readonly value: A +export declare const traverseTap: ( + F: applicative.Applicative +) => { + (self: Option, f: (a: A) => Kind): Kind> + (f: (a: A) => Kind): (self: Option) => Kind> } ``` Added in v1.0.0 -# pattern matching - -## match +## tuple -Matches the given `Option` and returns either the provided `onNone` value or the result of the provided `onSome` -function when passed the `Option`'s value. +Takes a tuple of `Option`s and returns an `Option` of a tuple of values. **Signature** ```ts -export declare const match: { - (onNone: LazyArg, onSome: (a: A) => C): (self: Option) => B | C - (self: Option, onNone: LazyArg, onSome: (a: A) => C): B | C -} +export declare const tuple: []>( + ...elements: T +) => Option<{ [I in keyof T]: [T[I]] extends [Option] ? A : never }> ``` **Example** ```ts -import { some, none, match } from '@fp-ts/core/Option' -import { pipe } from '@fp-ts/core/Function' - -assert.deepStrictEqual( - pipe( - some(1), - match( - () => 'a none', - (a) => `a some containing ${a}` - ) - ), - 'a some containing 1' -) +import * as O from '@fp-ts/core/Option' -assert.deepStrictEqual( - pipe( - none(), - match( - () => 'a none', - (a) => `a some containing ${a}` - ) - ), - 'a none' -) +assert.deepStrictEqual(O.tuple(O.some(1), O.some('hello')), O.some([1, 'hello'])) +assert.deepStrictEqual(O.tuple(O.some(1), O.none()), O.none()) ``` Added in v1.0.0 -# sequencing +# sorting -## Chainable +## getOrder + +The `Order` instance allows `Option` values to be compared with +`compare`, whenever there is an `Order` instance for +the type the `Option` contains. + +`None` is considered to be less than any `Some` value. **Signature** ```ts -export declare const Chainable: chainable.Chainable +export declare const getOrder: (O: Order) => Order> ``` -Added in v1.0.0 - -## FlatMap - -**Signature** +**Example** ```ts -export declare const FlatMap: flatMap_.FlatMap +import { none, some, getOrder } from '@fp-ts/core/Option' +import * as N from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' + +const O = getOrder(N.Order) +assert.deepStrictEqual(O.compare(none(), none()), 0) +assert.deepStrictEqual(O.compare(none(), some(1)), -1) +assert.deepStrictEqual(O.compare(some(1), none()), 1) +assert.deepStrictEqual(O.compare(some(1), some(2)), -1) +assert.deepStrictEqual(O.compare(some(1), some(1)), 0) ``` Added in v1.0.0 +# transforming + ## andThen **Signature** @@ -1530,6 +1463,32 @@ export declare const andThenDiscard: { Added in v1.0.0 +## as + +Maps the `Some` value of this `Option` to the specified constant value. + +**Signature** + +```ts +export declare const as: { <_, B>(self: Option<_>, b: B): Option; (b: B): <_>(self: Option<_>) => Option } +``` + +Added in v1.0.0 + +## asUnit + +Returns the `Option` resulting from mapping the `Some` value to `void`. + +This is useful when the value of the `Option` is not needed, but the presence or absence of the value is important. + +**Signature** + +```ts +export declare const asUnit: <_>(self: Option<_>) => Option +``` + +Added in v1.0.0 + ## composeKleisliArrow **Signature** @@ -1543,6 +1502,19 @@ export declare const composeKleisliArrow: { Added in v1.0.0 +## flap + +**Signature** + +```ts +export declare const flap: { + (a: A, self: Option<(a: A) => B>): Option + (self: Option<(a: A) => B>): (a: A) => Option +} +``` + +Added in v1.0.0 + ## flatMap Applies a function to the value of an `Option` and flattens the result, if the input is `Some`. @@ -1648,6 +1620,21 @@ export declare const flatten: (self: Option>) => Option Added in v1.0.0 +## map + +Maps the `Some` side of an `Option` value to a new `Option` value. + +**Signature** + +```ts +export declare const map: { + (f: (a: A) => B): (self: Option) => Option + (self: Option, f: (a: A) => B): Option +} +``` + +Added in v1.0.0 + ## tap Applies the provided function `f` to the value of the `Option` if it is `Some` and returns the original `Option` @@ -1666,98 +1653,131 @@ export declare const tap: { Added in v1.0.0 -# sorting +## tupled -## getOrder +**Signature** -The `Order` instance allows `Option` values to be compared with -`compare`, whenever there is an `Order` instance for -the type the `Option` contains. +```ts +export declare const tupled: (self: Option) => Option<[A]> +``` -`None` is considered to be less than any `Some` value. +Added in v1.0.0 + +# type lambdas + +## OptionTypeLambda (interface) **Signature** ```ts -export declare const getOrder: (O: Order) => Order> +export interface OptionTypeLambda extends TypeLambda { + readonly type: Option +} ``` -**Example** +Added in v1.0.0 + +# utils + +## Alternative + +**Signature** ```ts -import { none, some, getOrder } from '@fp-ts/core/Option' -import * as N from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' +export declare const Alternative: alternative.Alternative +``` -const O = getOrder(N.Order) -assert.deepStrictEqual(O.compare(none(), none()), 0) -assert.deepStrictEqual(O.compare(none(), some(1)), -1) -assert.deepStrictEqual(O.compare(some(1), none()), 1) -assert.deepStrictEqual(O.compare(some(1), some(2)), -1) -assert.deepStrictEqual(O.compare(some(1), some(1)), 0) +Added in v1.0.0 + +## Applicative + +**Signature** + +```ts +export declare const Applicative: applicative.Applicative ``` Added in v1.0.0 -# traversing +## Chainable + +**Signature** -## sequence +```ts +export declare const Chainable: chainable.Chainable +``` + +Added in v1.0.0 + +## Coproduct **Signature** ```ts -export declare const sequence: ( - F: applicative.Applicative -) => (self: Option>) => Kind> +export declare const Coproduct: coproduct_.Coproduct ``` Added in v1.0.0 -## traverse +## Covariant **Signature** ```ts -export declare const traverse: ( - F: applicative.Applicative -) => { - (f: (a: A) => Kind): (self: Option) => Kind> - (self: Option, f: (a: A) => Kind): Kind> -} +export declare const Covariant: covariant.Covariant ``` Added in v1.0.0 -## traverseTap +## Filterable **Signature** ```ts -export declare const traverseTap: ( - F: applicative.Applicative -) => { - (self: Option, f: (a: A) => Kind): Kind> - (f: (a: A) => Kind): (self: Option) => Kind> -} +export declare const Filterable: filterable.Filterable ``` Added in v1.0.0 -# type lambdas +## FlatMap -## OptionTypeLambda (interface) +**Signature** + +```ts +export declare const FlatMap: flatMap_.FlatMap +``` + +Added in v1.0.0 + +## Foldable **Signature** ```ts -export interface OptionTypeLambda extends TypeLambda { - readonly type: Option -} +export declare const Foldable: foldable.Foldable ``` Added in v1.0.0 -# utils +## Invariant + +**Signature** + +```ts +export declare const Invariant: invariant.Invariant +``` + +Added in v1.0.0 + +## Monad + +**Signature** + +```ts +export declare const Monad: monad.Monad +``` + +Added in v1.0.0 ## Of @@ -1779,6 +1799,66 @@ export declare const Pointed: pointed.Pointed Added in v1.0.0 +## Product + +**Signature** + +```ts +export declare const Product: product_.Product +``` + +Added in v1.0.0 + +## SemiAlternative + +**Signature** + +```ts +export declare const SemiAlternative: semiAlternative.SemiAlternative +``` + +Added in v1.0.0 + +## SemiApplicative + +**Signature** + +```ts +export declare const SemiApplicative: semiApplicative.SemiApplicative +``` + +Added in v1.0.0 + +## SemiCoproduct + +**Signature** + +```ts +export declare const SemiCoproduct: semiCoproduct.SemiCoproduct +``` + +Added in v1.0.0 + +## SemiProduct + +**Signature** + +```ts +export declare const SemiProduct: semiProduct.SemiProduct +``` + +Added in v1.0.0 + +## Traversable + +**Signature** + +```ts +export declare const Traversable: traversable.Traversable +``` + +Added in v1.0.0 + ## appendElement Appends an element to the end of a tuple. @@ -1849,26 +1929,32 @@ assert.deepStrictEqual(pipe(none(), exists(isEven)), false) Added in v1.0.0 -## struct +## getOptionalMonoid + +Monoid that models the combination of values that may be absent, elements that are `None` are ignored +while elements that are `Some` are combined using the provided `Semigroup`. + +The `empty` value is `none()`. **Signature** ```ts -export declare const struct: >>( - r: R -) => Option<{ [K in keyof R]: [R[K]] extends [Option] ? A : never }> +export declare const getOptionalMonoid: (Semigroup: Semigroup) => Monoid> ``` -Added in v1.0.0 +**Example** -## tuple +```ts +import * as O from '@fp-ts/core/Option' +import * as N from '@fp-ts/core/Number' +import { pipe } from '@fp-ts/core/Function' -**Signature** +const M = O.getOptionalMonoid(N.SemigroupSum) -```ts -export declare const tuple: []>( - ...tuple: T -) => Option<{ [I in keyof T]: [T[I]] extends [Option] ? A : never }> +assert.deepStrictEqual(M.combine(O.none(), O.none()), O.none()) +assert.deepStrictEqual(M.combine(O.some(1), O.none()), O.some(1)) +assert.deepStrictEqual(M.combine(O.none(), O.some(1)), O.some(1)) +assert.deepStrictEqual(M.combine(O.some(1), O.some(2)), O.some(3)) ``` Added in v1.0.0 diff --git a/guides/Either.md b/guides/Either.md index b7a80a985..a37855a80 100644 --- a/guides/Either.md +++ b/guides/Either.md @@ -578,10 +578,11 @@ This is because the `zipWith` function only combines the values if both `Either` **Cheat sheet** (combining) -| Name | Given | To | -| --------- | ----------------------------------------------- | --------------------- | -| `zipWith` | `Either`, `Either`, `(A, B) => C` | `Either` | -| `ap` | `Either B>`, `Either` | `Either` | +| Name | Given | To | +| ------------ | ----------------------------------------------- | --------------------- | +| `zipWith` | `Either`, `Either`, `(A, B) => C` | `Either` | +| `productAll` | `Iterable>` | `Either` | +| `ap` | `Either B>`, `Either` | `Either` | For convenience, a series of algebraic operations such as sums and products are exported. diff --git a/guides/Option.md b/guides/Option.md index c682320b1..378580d21 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -1,31 +1,22 @@ # The `Option` data type -The `Option` data type is a powerful and flexible tool in functional programming, it can be found in the `@fp-ts/core/Option module`. It is used to model optional values in TypeScript, by providing a container that can hold either a value of a specific type (`Some`) or no value at all (`None`). This helps in handling the presence or absence of a value in a safe and predictable way, making it easy to chain computations and handle errors in a functional way. +The `Option` data type represents an optional value: every `Option` is either `Some` and contains a value, or `None`, and does not. `Option` types are very common in functional programming, as they have a number of uses: -There are two possible interpretations of the `Option` data type: - -1. as a representation of an **optional value** of type `A` -2. as a representation of the result of a **computation that can fail** or return a value of type `A` - -**Optional value** - -In the first of these two interpretations, the `None` union member represents the absence of the value, while the `Some` union member represents the presence of the value of type `A` - -**Computation that can fail** - -In the second of these two interpretations, the `None` union member represents the result of a computation that has failed and therefore was not able to return any value, while the `Some` union member represents the result of a computation that has succeeded and was able to return a value of type `A`. +- Initial values +- Return values for functions that are not defined over their entire input range (partial functions) +- Return value for otherwise reporting simple errors, where `None` is returned on error +- Optional struct fields +- Optional function arguments # Definition -The `Option` data type is the union of two members: `None` and `Some`. The way chosen by the `@fp-ts/core` library to model this union in TypeScript is to use a feature of the language called [Discriminating Unions](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminating-unions). - -> A common technique for working with unions is to have a single field which uses literal types which you can use to let TypeScript narrow down the possible current type +The `Option` data type is a union of two members: `None` and `Some`. The `@fp-ts/core` library models this union in TypeScript using a feature called [Discriminating Unions](https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#discriminatory-unions). -By convention in `@fp-ts/core`, this single field which uses literal types is named "\_tag" (but you can use any name when defining your unions). +A common approach for working with unions is to have a single field that uses literal types, which helps TypeScript narrow down the possible current type. In `@fp-ts/core`, this single field is named "\_tag" (but any name can be used when defining your own unions). -Furthermore, `Option` is a "polymorphic" data type, that is, it makes use of a feature of TypeScript named ["Generics"](https://www.typescriptlang.org/docs/handbook/2/generics.html), meaning that the `Option` data type is a container that can hold any type. +The `Option` data type is a "polymorphic" data type, which makes use of a feature of TypeScript named ["Generics"](https://www.typescriptlang.org/docs/handbook/2/generics.html). This means that the `Option` data type is a container that can hold any type. -Here's the complete definition of the `Option` type: +Here is the complete definition of the `Option` data type: ```ts // Represents the absence of a value @@ -36,7 +27,7 @@ export type None = { // Represents the presence of a value export type Some = { - // Discriminating field used to identify the variant + // Discriminatory field used to identify the variant readonly _tag: "Some"; // The actual value readonly value: A; @@ -46,33 +37,34 @@ export type Some = { export type Option = None | Some; ``` -The `Option` type is defined as a union of two other types, `None` and `Some`, that represent the two possible states of the `Option`: having a value or not. - -The type parameter `A` is used to specify the type of the value that the `Option` holds. - +The type parameter `A` is used to specify the type of the `value` that the `Option` holds. The `_tag` field is used to distinguish between the two variants, `None` and `Some`. # Using `Option` -To create an instance of `Option`, you can use the `some` and `none` constructors, which construct a new `Option` holding a `Some` or `None` value respectively: +The `Option` data type can be used to handle the presence or absence of a value in a safe and predictable manner. The `Option` data type has two constructors `some` and `none` that can be used to create a new instance of `Option` holding either a `Some` value or a `None` value, respectively. + +## Constructing a `Some` value + +The `some` constructor takes a value of type `A` and returns an instance of `Option` that holds that value: ```ts -import { none, some } from "@fp-ts/core/Option"; +import { some } from "@fp-ts/core/Option"; -const success: Option = some(1); -const failure: Option = none(); +const value: Option = some(1); // an Option holding the number 1 ``` -Let's summarize the two cases in a table: +## Constructing a `None` value -**Cheat sheet** (constructors) +The `none` constructor returns an instance of `Option representing the absence of a value: -| Name | Given | To | -| ------ | ----- | --------------- | -| `some` | `A` | `Option` | -| `none` | | `Option` | +```ts +import { none } from "@fp-ts/core/Option"; + +const empty: Option = none(); // an Option holding no value +``` -It is important to note that the `none` constructor by default returns a value of type `Option`, this makes it possible to assign this value to any `Option`, whatever the type `A` is. +By default, `none` returns an instance of `Option`, which can be assigned to any `Option` regardless of the type `A`: ```ts const optionNumber: Option = none(); @@ -80,7 +72,7 @@ const optionString: Option = none(); const optionBoolean: Option = none(); ``` -Alternatively, if it is useful to you, you can specify the desired type at the call site, explicitly indicating which type `A` you are interested in. This way, you don't need the type annotations: +However, if you prefer, you can specify the desired type at the call site by explicitly indicating the type `A` you're interested in. In this case, you won't need to provide type annotations: ```ts const optionNumber = none(); @@ -88,21 +80,159 @@ const optionString = none(); const optionBoolean = none(); ``` -In this way you don't need to specify the type of the variables `optionNumber`, `optionString`, `optionBoolean` because TypeScript infers the type from the call site. +Here's a quick reference guide for the two constructors: + +**Cheat sheet** (constructors) + +| **Function** | **Given input** | **Resulting Output** | +| ------------ | --------------- | -------------------- | +| `some` | `A` | `Option` | +| `none` | | `Option` | + +With these two constructors, you can construct an `Option` holding either a `Some` value or a `None` value, depending on your needs. # Conversions +The following table provides a quick reference for the various conversion functions available in this module: + **Cheat sheet** (conversions) -| Name | Given | To | Note | -| -------------- | --------------------------------- | ------------------ | --------------------- | -| `fromEither` | `Either` | `Option` | | -| `toEither` | `Option`, `onNone: LazyArg` | `Either` | | -| `getRight` | `Either` | `Option` | alias of `fromEither` | -| `getLeft` | `Either` | `Option` | | -| `toRefinement` | `A => Option` | `Refinement` | | -| `fromIterable` | `Iterable` | `Option` | | -| `toArray` | `Option` | `Array` | | +| **Function** | **Given input** | **Resulting Output** | +| -------------- | --------------------------------- | -------------------- | --------------------- | +| `fromEither` | `Either` | `Option` | | +| `toEither` | `Option`, `onNone: LazyArg` | `Either` | | +| `getRight` | `Either` | `Option` | alias of `fromEither` | +| `getLeft` | `Either` | `Option` | | +| `toRefinement` | `A => Option` | `Refinement` | | +| `fromIterable` | `Iterable` | `Option` | | +| `toArray` | `Option` | `Array` | | + +## fromEither + +The `fromEither` function takes in an `Either` value and returns an `Option`. This is useful when you have a value that can either be of type `E` (an error) or `A` (the correct value), and you want to convert it to an `Option` discarding the error. + +Example: + +```ts +import * as O from "@fp-ts/core/Option"; +import * as E from "@fp-ts/core/Either"; + +console.log(O.fromEither(E.right(1))); // some(1) +console.log(O.fromEither(E.left("error message"))); // none() +``` + +In this example, `fromEither` is used to convert the `Either` value `E.right(1)` to an `Option`. The result is `some(1)`, which indicates that the input `Either` was of type `Right` and contained the value `1`. + +If the input `Either` was of type `Left` (`E.left("error message")` in this case), the result would be `none()`, which indicates that the input contained an error and no valid value was present. + +## toEither + +The `toEither` function takes in an `Option` value and a `LazyArg` value and returns an `Either`. + +The `LazyArg` value is a lazy (or "deferred") argument that is only executed if the input `Option` is `None`. If the input `Option` is `None`, the `toEither` function returns an `Either` with the `Left` value being the result of the lazy argument. If the input `Option` is `Some`, the `toEither` function returns an `Either` with the `Right` value being the value contained in the `Some` case of the `Option`. + +Here's an example of how to use toEither: + +```ts +import { pipe } from "@fp-ts/core/Function"; +import * as O from "@fp-ts/core/Option"; +import * as E from "@fp-ts/core/Either"; + +const onNone = () => "error"; +console.log(pipe(O.some(1), O.toEither(onNone))); // right(1) +console.log(pipe(O.none(), O.toEither(onNone))); // left("error") +``` + +## getRight + +The `getRight` function is an alias for `fromEither`, and is used to convert an `Either` value to an `Option`. See the explanation and example for `fromEither` for more information. + +## getLeft + +The `getLeft` function is a utility function that is used to extract the `Left` value from an `Either` value. The function takes in a single argument - an `Either` value and returns an `Option` value. + +```ts +import * as O from "@fp-ts/core/Option"; +import * as E from "@fp-ts/core/Either"; + +console.log(O.getLeft(E.right("ok"))); // none() +console.log(O.getLeft(E.left("error"))); // some("error") +``` + +Note that the `Option` value returned by the `getLeft` function will be `Some(value)` if the input `Either` value is a `Left` value, and `None` if the input `Either` value is a `Right` value. + +## toRefinement + +This function allows to convert a function `A => Option` into a `(a: A) => a is B`, which can be used as a predefined type guard. +A type guard function is used to check if a value is of a certain type. + +The `toRefinement` ensures that a type guard definition is type-safe. + +Here is an example of using `toRefinement` to create a type guard for positive numbers: + +```ts +import * as O from "@fp-ts/core/Option"; + +// This function checks if a given number is positive +const parsePositive = (n: number): O.Option => + n > 0 ? O.some(n) : O.none(); + +// convert the `parsePositive` function into a type guard +const isPositive = O.toRefinement(parsePositive); + +console.log(isPositive(1)); // true +console.log(isPositive(-1)); // false +``` + +In this example, `parsePositive` is a function that takes in a number and returns an `Option`. If the number is positive, it returns `some(n)`, where `n` is the positive number. If the number is not positive, it returns `none()`. + +`toRefinement` takes in the `parsePositive` function and returns a type guard function `isPositive`. The `isPositive` function can be used to check if a value is a positive number and can be used in type refinement statements to provide type-safety for your code. + +## fromIterable + +The `fromIterable` function takes an iterable (something you can loop over, for example arrays, sets, maps, etc.) and returns an `Option` value. + +If the iterable is not empty (i.e., it has at least one item), `fromIterable` returns the first value of the iterable wrapped in a `Some` value. If the iterable is empty, `fromIterable` returns `None`. + +Here are two examples to demonstrate the usage of `fromIterable`: + +```ts +import { fromIterable, some, none } from "@fp-ts/core/Option"; + +console.log(fromIterable([1, 2, 3])); // some(1) +``` + +In this example, `fromIterable` is passed an array with three values. Since the array is not empty, `fromIterable` returns the first value, `1`, wrapped in a `Some` value. + +```ts +console.log(fromIterable([])); // none() +``` + +In this example, `fromIterable` is passed an empty array. Since the array is empty, `fromIterable` returns `None`. + +## toArray + +The `toArray` function takes in an `Option` value and returns an array. + +If the input is a `Some` value, the value inside the `Some` is wrapped in an array and returned. + +If the input is a `None` value, an empty array is returned. + +Here are two examples of how `toArray` can be used: + +```ts +import * as O from "@fp-ts/core/Option"; + +console.log(O.toArray(O.some(1))); // [1] +``` + +In this example, `some(1)` is passed as the argument to `toArray`, which returns an array with the value `1`. + +```ts +console.log(O.toArray(O.none())); // [] +``` + +In this example, `none()` is passed as the argument to `toArray`, which returns an empty array. # Modeling optional properties with `Option` @@ -114,9 +244,7 @@ interface User { username: string; email: Option; } -``` -```ts import { some, none } from "@fp-ts/core/Option"; // case with email @@ -154,8 +282,9 @@ const success: Option = pipe( ``` As you can see you can transform the result of your computation without unwrapping and wrapping the underlying value of `Option`. +This allows for a safe and convenient way of transforming optional values. -What is very convenient about `Option` is how the absence of value (i.e. a `None`) is handled. See the example below: +What is also convenient about `Option` is how the absence of value (i.e. a `None`) is handled. See the example below: ```ts import { pipe } from "@fp-ts/core/Function"; @@ -168,28 +297,30 @@ const failure: Option = pipe( ); ``` -As you can see, even though we started with a `None` value, we can still operate on our `Option`. No errors are thrown or shown to the user, unless we do it intentionally. What happens is that when the `Option` is `None`, the mapping doesn't even happen and the `None` value representing the absence of value is returned unchanged. +As you can see, even though we started with a `None` value, we can still operate on our `Option`. No errors are thrown or shown to the user, unless we do it intentionally. When the `Option` is `None, the mapping doesn't even occur, and the `None` value representing the absence of value is returned unchanged. # Handling failing computations -Let's see how to use the `Option` data type to model a computation that can fail, such as a function that can throw an exception based on certain conditions. Let's take the case of the following function: +In software development, there are times when a function can "fail" to produce a result, either because of invalid inputs, lack of data, or other reasons. The `Option` data type helps us to handle these cases in a clean and functional way. + +Here's an example of a function `parseNumber` that takes a `string` as input and returns either a `number` or `null` depending on the input: ```ts -function parseNumber(s: string): number { +function parseNumber(s: string): number | null { const n = parseFloat(s); if (isNaN(n)) { - throw new Error(); + return null; } return n; } ``` -An alternative to throwing an exception is to always return a value, but this value will be of type `Option` instead of `number`, with the following interpretation: +A better way to handle these types of computations is to use the `Option` data type. This data type offers a cleaner way to model the "success" or "failure" of a computation. With `Option`, we can eliminate the need to return a `null` value. Instead, we will always return a value, but this value will be of type `Option`. -- if `parseNumber` returns a `None` value, it means that the computation failed -- if the result is instead a `Some` value, it means that the computation succeeded and the computed value is wrapped inside the `Some` +- if `parseNumber` returns a `None` value, it means that the computation "failed" +- if the result is a `Some` value, it means that the computation "succeeded" and the computed value is wrapped inside the `Some` -Let's see how we can rewrite the `parseNumber` function without throwing exceptions and using the `Option` data type instead: +Here's how the `parseNumber` function would look using the `Option` data type: ```ts import { Option, none, some } from "@fp-ts/core/Option"; @@ -203,7 +334,7 @@ console.log(parseNumber("2")); // some(2) console.log(parseNumber("Not a number")); // none() ``` -What happens if we add a call to the `parseNumber` function to a pipeline that already involves an `Option`? +Now, let's say we have a pipeline of computations that already involves the `Option` data type and we want to add a call to the `parseNumber` function. We might run into an issue with the following code: ```ts import { pipe } from "@fp-ts/core/Function"; @@ -216,9 +347,7 @@ const result = pipe( ); ``` -There's something wrong, we received an error from the type checker, what happened? - -The problem is that in the second `map` the parameter `n` is of type `Option` and not `number`. +The code above generates a type-checker error. This happens because the second `map` function expects the input `n` to be of type `number`, but `n` is of type `Option`. ```ts const result = pipe( @@ -228,7 +357,7 @@ const result = pipe( ); ``` -Fortunately, the fix is simple, when adding a computation that returns an `Option` to our pipeline we should use the `flatMap` function instead of the `map` function: +To solve this issue, we need to use the `flatMap` function instead of the `map` function when adding a computation that returns an `Option` to our pipeline: ```ts import { pipe } from "@fp-ts/core/Function"; @@ -245,14 +374,14 @@ Let's summarize the two cases in a table: **Cheat sheet** (sequencing) -| Name | Given | To | -| --------- | ----------------------------- | ----------- | -| `map` | `Option`, `A => B` | `Option` | -| `flatMap` | `Option`, `A => Option` | `Option` | +| **Function** | **Given input** | **Resulting Output** | +| ------------ | ----------------------------- | -------------------- | +| `map` | `Option`, `A => B` | `Option` | +| `flatMap` | `Option`, `A => Option` | `Option` | -The `flatMap` function offers the same convenience as the `map` function, which only continues with the computations contained in the pipeline if a `None` value is **not** encountered: +The `flatMap` function works similarly to the `map` function, but with the added feature of only continuing with the computations if a `None` value is not encountered. Let's look at some code examples to understand how these functions work in practice. -**Happy path, starting with a valid input** +**Example 1: Successful Path with Valid Input** ```ts import { pipe } from "@fp-ts/core/Function"; @@ -266,7 +395,9 @@ const success: Option = pipe( ); // some(1) ``` -**Error path, starting with an invalid input** +In this example, the `pipe` function is used to chain together a series of computations, starting with a string value of `"2"`. This value is first passed to the `flatMap` function which applies the `parseNumber` function to parse the input string to a number. If the parsing is successful, the resulting number is then passed to the `map` function which doubles it. Finally, the resulting value is passed to another `map` function which subtracts `3` from it. The final output of the pipeline is the `Option` value of `some(1)`. + +**Example 2: Error Path with Invalid Input** ```ts import { pipe } from "@fp-ts/core/Function"; @@ -280,7 +411,9 @@ const failure: Option = pipe( ); // none() ``` -**Error path, starting with None** +In this example, the input to the pipeline is the string value of `"Not a number"`. When this value is passed to the `flatMap` function which applies the `parseNumber` function, it will return `None` as the string cannot be parsed to a number. This means that the following `map `functions will not be executed and the final output of the pipeline will be `None`. + +**Example 3: Error Path Starting with None** ```ts import { pipe } from "@fp-ts/core/Function"; @@ -294,53 +427,56 @@ const noneStart: Option = pipe( ); // none() ``` -When using this approach, the **desired outcome** is always in clear view while defining your pipeline. This allows you to focus on the expected result, while leaving it to `Option` to handle any potential errors that may arise seamlessly and transparently. +In this example, we start the pipeline with the `None` value, which represents an absent or empty value. This means that the `flatMap` step will not be executed and any subsequent steps in the pipeline will not be executed either. -You can focus on the successful scenario and let `Option` handle the tedious task of managing potential errors at every step of the pipeline, without the need for explicit handling. +The advantage of using this approach is that the desired outcome is always in clear view while defining your pipeline. This allows you to focus on the expected result, while leaving it to the `Option` type to handle any potential errors that may arise seamlessly and transparently. + +You can concentrate on the successful scenario and let `Option` handle the management of potential errors at every step of the pipeline, without the need for explicit error handling. # Debugging -At any time, it is possible to inspect what is happening in your pipeline using two utility functions: +Debugging your code can be difficult, especially when you have multiple transformations happening in a pipeline. The `Option` module provides two utility functions, `inspectSome` and `inspectNone`, that can help you inspect what is happening in your code and diagnose issues. -**Cheat sheet** (debugging) +The `inspectSome` function returns the original `Option` value, but if it is a `Some`, the provided callback function is called with the value wrapped inside the `Some`. -| Name | Given | To | Note | -| ------------- | ------------------------- | ----------- | ------------------------------------ | -| `inspectSome` | `Option`, `A => void` | `Option` | callback called if it is a `Some` | -| `inspectNone` | `Option`, `() => void` | `Option` | callback called if it is a `None` | +The `inspectNone` function returns the original `Option` value, but if it is a `None`, the provided callback function is called without any arguments. -Let's see an example where both are in action: +Here is an example of how you can use `inspectSome` and `inspectNone` to debug a pipeline: ```ts import { pipe } from "@fp-ts/core/Function"; -import { - Option, - some, - inspectSome, - flatMap, - inspectNone, - map, -} from "@fp-ts/core/Option"; - -const failure: Option = pipe( - some("Not a number"), - inspectSome(console.log), - flatMap((s) => parseNumber(s)), - inspectNone(() => console.error("none")), - map((x) => x2), - map((x) => x - 3) +import * as O from "@fp-ts/core/Option"; + +const failure: O.Option = pipe( + O.some("Not a number"), // start with a Some containing the string "Not a number" + O.inspectSome(console.log), // log the value if it is a Some + O.flatMap((s) => parseNumber(s)), // attempt to parse the string as a number + O.inspectNone(() => console.error("none")), // log an error if the parseNumber function returns None + O.map((x) => x * 2), // double the number if it is a Some + O.map((x) => x - 3) // subtract 3 from the number if it is a Some ); -// "Not a number" -// "none" +// logs "Not a number" to the console +// logs "none" to the console (because the parseNumber function returns None) ``` -Please note that these two functions should only be used for debugging purposes and it is not recommended to use them for performing side effects or encoding business logic. +It is important to note that `inspectSome` and `inspectNone` should only be used for debugging purposes, and it is not recommended to use them for performing side effects or encoding business logic. + +**Cheat sheet** (debugging) -# Pattern matching and error handling +| **Function** | **Given input** | **Resulting Output** | **Note** | +| ------------- | ------------------------- | -------------------- | ------------------------------------ | +| `inspectSome` | `Option`, `A => void` | `Option` | callback called if it is a `Some` | +| `inspectNone` | `Option`, `() => void` | `Option` | callback called if it is a `None` | + +# Pattern matching We have seen how easy and convenient it is to build pipelines involving the `Option` data type, leaving it to handle any errors that may occur at any step. However, at some point, you will be interested in manually handling the error to understand the overall result obtained from the pipeline and decide what to do accordingly. -The fastest way to get the value wrapped in an `Option` is to call the `getOrThrow` function, but be aware that, as the name suggests, an exception will be thrown in case the `Option` you are querying is a `None`: +## Getting the value from an `Option` + +To extract the value from an `Option`, you can use the `getOrThrow` function, which retrieves the value wrapped in an `Option`, or throws an error if the `Option` you are querying is a `None`. + +Here's an example of how you can use `getOrThrow`: ```ts import { getOrThrow, some, none } from "@fp-ts/core/Option"; @@ -349,25 +485,25 @@ console.log(getOrThrow(some(10)); // 10 console.log(getOrThrow(none()); // throws new Error("getOrThrow called on a None") ``` -A more safe alternative is using the `isSome` and `isNone` guards: +However, using `getOrThrow` can lead to exceptions being thrown in your code, which can lead to unexpected behavior and crashes. To avoid this, you can use the `isSome` and `isNone` guards: ```ts import { some, isSome } from "@fp-ts/core/Option"; -const success = some(1); +const option = some(1); -// Use the `isSome` function to check if the `success` is an instance of `Some` -if (isSome(success)) { - console.log(`Option has a value: ${success.value}`); +// Use the `isSome` function to check if the `option` is an instance of `Some` +if (isSome(option)) { + console.log(`Option has a value: ${option.value}`); } else { console.log(`Option is empty.`); } -// Option has a value: 1 +// Output: Option has a value: 1 ``` -Another alternative is [pattern matching](https://github.com/gvergnaud/ts-pattern#what-is-pattern-matching) on the `Option`. +## Pattern matching with `Option` -The `match` function allows you to match on the `None` and `Some` cases of an `Option` value and provide different actions for each. +An alternative way to handle the cases of an `Option` being `None` or `Some` is by using the `match` function. The `match` function allows you to provide different actions for each case of the `Option` value. ```ts import { pipe } from "@fp-ts/core/Function"; @@ -386,84 +522,111 @@ const output = match( (value) => `Option has a value: ${value}` ); -console.log(output); // Option has a value: 1 +console.log(output); // Output: Option has a value: 1 ``` -One reason to use `match` instead of `isSome` or `isNone` is that `match` is more expressive and provides a clear way to handle both cases of an `Option`. With `match`, you can directly provide two functions to handle the case of the `Option` being `None` or `Some`, respectively. On the other hand, with `isSome`, you would need to manually check the value and take separate actions based on whether it's `Some` or `None`. With `match`, the code can be more concise and easy to understand. Additionally, if you have complex logic to handle both cases, using `match` can make the code easier to read and maintain. +Using `match` instead of `isSome` or `isNone` can be more expressive and provide a clear way to handle both cases of an `Option`. Additionally, if you have complex logic to handle both cases, using `match` can make your code easier to read and maintain. + +## Other functions for extracting values from an `Option` -There are specializations of `match` to make working with code that does not use `Option` more convenient and faster, particularly `getOrNull` and `getOrUndefined`. +To make working with code that does not use `Option` more convenient, there are specializations of `match` called `getOrNull` and `getOrUndefined`, which allow you to retrieve the value of an `Option` or `null` or `undefined`, respectively. + +Here's an example of how you can use `getOrNull` and `getOrUndefined`: ```ts -import { getOrNull, getOrUndefined, some, none } from "@fp-ts/core/Option"; +import * as O from "@fp-ts/core/Option"; -getOrNull(some(5)); // 5 -getOrNull(none()); // null +O.getOrNull(O.some(5)); // 5 +O.getOrNull(O.none()); // null -getOrUndefined(some(5)); // 5 -getOrUndefined(none()); // undefined +O.getOrUndefined(O.some(5)); // 5 +O.getOrUndefined(O.none()); // undefined ``` -For greater flexibility, there is also the `getOrElse` function which allows you to set what value corresponds to the `None` case: +`getOrElse` allows you to specify a default value that should be returned if the `Option` is `None`. Here's an example of how you can use `getOrElse`: ```ts -import { getOrElse, some, none } from "@fp-ts/core/Option"; +import * as O from "@fp-ts/core/Option"; -getOrElse(some(5), () => 0); // 5 -getOrElse(none(), () => 0); // 0 +O.getOrElse(O.some(5), () => 0); // 5 +O.getOrElse(O.none(), () => 0); // 0 ``` -It often happens that the action you want to take when a computation returns `None` is to continue with another computation that returns an `Option`, in this case you can use the `orElse` API: +Sometimes, when a computation returns `None`, you may want to continue with another computation that returns an `Option`. In this case, you can use the `orElse` function. This is useful for implementing retry logic, for example, where you want to attempt a computation multiple times until you either succeed or exhaust all possible attempts. + +Here's an example: ```ts import { pipe } from "@fp-ts/core/Function"; -import { Option, some, none, orElse } from "@fp-ts/core/Option"; +import * as O from "@fp-ts/core/Option"; -const fetchData = (): Option => { - // Imagine we have a function that returns an `Option` of data - return Math.random() < 0.5 ? some("Data fetched successfully") : none(); +const tryToConnect = (): O.Option => { + // Imagine we have a function that returns an `Option` of connection status + return Math.random() < 0.5 ? O.some("Connected successfully") : O.none(); }; -const retryFetchData = (): Option => +const retryConnect = (attemptsLeft: number): O.Option => pipe( - fetchData(), // Call the function for the first time - orElse(() => fetchData()) // If it fails, call it again + tryToConnect(), // Try to connect for the first time + O.orElse(() => { + // If it fails, check if we still have attempts left + if (attemptsLeft > 0) { + return retryConnect(attemptsLeft - 1); // If we do, try again with one less attempt + } + return O.none(); // If we don't, return none + }) ); -const result = retryFetchData(); +const result = retryConnect(3); // Try to connect three times +``` + +In this example, the function `tryToConnect` returns an `Option` representing the connection status. We use `orElse` to implement retry logic by attempting the connection again if the first attempt fails (returns `None`) and we still have attempts left. If all attempts fail, `retryConnect` returns `None`. + +The `firstSomeOf` function is used to retrieve the first value that is present within an `Iterable` of `Option` values. The function takes an `Iterable` of `Option` values and returns the first `Option` value that is `Some`, or `None` if there are no `Some` values in the `Iterable`. + +Here is an example of how you can use `firstSomeOf`: + +```ts +import * as O from "@fp-ts/core/Option"; + +const arr = [O.none(), O.some(2), O.none(), O.some(3)]; + +const first = O.firstSomeOf(arr); // some(2) ``` -**Cheat sheet** (error handling) +**Cheat sheet** (pattern matching) -| Name | Given | To | -| ---------------- | --------------------------------------------------- | ---------------- | -| `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | -| `getOrThrow` | `Option` | `A` (may throw) | -| `getOrNull` | `Option` | `A \| null` | -| `getOrUndefined` | `Option` | `A \| undefined` | -| `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | -| `orElse` | `Option`, `LazyArg>` | `Option` | -| `firstSomeOf` | `Iterable>` | `Option` | +| **Function** | **Given input** | **Resulting Output** | +| ---------------- | --------------------------------------------------- | -------------------- | +| `match` | `Option`, `onNone: LazyArg`, `onSome: A => C` | `B \| C` | +| `getOrThrow` | `Option` | `A` (may throw) | +| `getOrThrowWith` | `Option`, `onNone: () => unknown` | `A` (may throw) | +| `getOrNull` | `Option` | `A \| null` | +| `getOrUndefined` | `Option` | `A \| undefined` | +| `getOrElse` | `Option`, `onNone: LazyArg` | `A \| B` | +| `orElse` | `Option`, `LazyArg>` | `Option` | +| `firstSomeOf` | `Iterable>` | `Option` | -# Interop +# Interop with Code Using Nullable Types -A need that arises quickly when using the `Option` data type is the ability to interoperate with code that does not share the same style, in particular code that for example uses `undefined` or `null` to indicate that a value is optional, or code that throws exceptions. +When using the `Option` data type, you may need to interact with code that uses `undefined` or `null` to indicate optional values. The `Option` data type provides several APIs to make this task easier. -The `Option` data type offers a series of APIs to make this task easier, let's start with the first of the two cases, that is when the need is to interoperate with code that use a nullable type to indicate that a value is optional. +## Converting a Nullable Value to an Option -It is possible to create an `Option` from a nullable value using the `fromNullable` API, let's see an example: +You can create an `Option` from a nullable value using the `fromNullable` API. ```ts -import { fromNullable } from "@fp-ts/core/Option"; +import * as O from "@fp-ts/core/Option"; -console.log(fromNullable(null)); // none() -console.log(fromNullable(undefined)); // none() -console.log(fromNullable(1)); // some(1) +console.log(O.fromNullable(null)); // none() +console.log(O.fromNullable(undefined)); // none() +console.log(O.fromNullable(1)); // some(1) ``` -Instead of a single value, we can also modify the definition of a function that returns a nullable value to a function that returns an `Option` (a process that goes by the name of "lifting"): +You can also modify a function that returns a nullable value to a function that returns an `Option` using the `liftNullable` API. This process is known as "lifting." ```ts -import { liftNullable, none, some } from "@fp-ts/core/Option"; +import * as O from "@fp-ts/core/Option"; const parse = (s: string): number | undefined => { const n = parseFloat(s); @@ -471,32 +634,32 @@ const parse = (s: string): number | undefined => { }; // const parseOption: (s: string) => Option -const parseOption = liftNullable(parse); +const parseOption = O.liftNullable(parse); console.log(parseOption("1")); // some(1) console.log(parseOption("not a number")); // none() ``` -On the other hand, if we have a value of type `Option` and we want to convert it into a nullable value we have two possibilities: +## Converting an Option to a Nullable Value -- convert `None` to `null` -- convert `None` to `undefined` +If you have a value of type `Option` and want to convert it to a nullable value, you have two options: -The two APIs `getOrNull` and `getOrUndefined` respectively achieve these two tasks: +- Convert `None` to `null` using the `getOrNull` API +- Convert `None` to `undefined` using the `getOrUndefined` API ```ts -import { getOrNull, getOrUndefined, some, none } from "@fp-ts/core/Option"; +import * as O from "@fp-ts/core/Option"; -console.log(getOrNull(some(1))); // 1 -console.log(getOrNull(none())); // null +console.log(O.getOrNull(O.some(1))); // 1 +console.log(O.getOrNull(O.none())); // null -console.log(getOrUndefined(some(1))); // 1 -console.log(getOrUndefined(none())); // undefined +console.log(O.getOrUndefined(O.some(1))); // 1 +console.log(O.getOrUndefined(O.none())); // undefined ``` **Cheat sheet** (interop - nullable) -| Name | Given | To | +| **Function** | **Given input** | **Resulting Output** | | ----------------- | -------------------------------------------------- | ------------------------------------ | | `fromNullable` | `A` | `Option>` | | `liftNullable` | `(...a: A) => B \| null \| undefined` | `(...a: A) => Option` | @@ -504,58 +667,6 @@ console.log(getOrUndefined(none())); // undefined | `getOrNull` | `Option` | `A \| null` | | `getOrUndefined` | `Option` | `A \| undefined` | -Now let's see the other case, that is when we need to interoperate with code that throws exceptions. - -In a previous section, we saw how to convert the following function that can throw exceptions: - -```ts -function parseNumber(s: string): number { - const n = parseFloat(s); - if (isNaN(n)) { - throw new Error(); - } - return n; -} -``` - -into a function that returns a `Option`: - -```ts -import { some, none } from "@fp-ts/core/Option"; - -function parseNumber(s: string): Option { - const n = parseFloat(s); - return isNaN(n) ? none() : some(n); -} -``` - -However, this involves tedious, error-prone, and boilerplate-heavy work. It would be much more convenient not to have to rewrite the `parseNumber` function from scratch but only to transform it into the desired result in one step, and that's exactly what the `fromThrowable` API takes care of doing: - -```ts -import { liftThrowable } from "@fp-ts/core/Option"; - -const parse = liftThrowable(JSON.parse); - -console.log(parse("1")); // some(1) -console.log(parse("")); // none() -``` - -On the other hand, if we have a value of type `Option` and want to get the wrapped value, accepting the fact that if the `Option` is a `None` we will get an exception, we can use the `getOrThrow` API: - -```ts -import { getOrThrow, some, none } from "@fp-ts/core/Option"; - -console.log(getOrThrow(some(10)); // 10 -console.log(getOrThrow(none()); // throws new Error("getOrThrow called on a None") -``` - -**Cheat sheet** (interop - throwing) - -| Name | Given | To | -| --------------- | ---------------------------- | ------------------------ | -| `liftThrowable` | `(...a: A) => B` (may throw) | `(...a: A) => Option` | -| `getOrThrow` | `Option` | `A` (may throw) | - # Combining two or more `Option`s The `zipWith` function allows you to combine two `Option`s using a provided function. The resulting value is a new `Option` that holds the combined value of both original `Option`s. @@ -578,9 +689,15 @@ const combine = zipWith(name, age, (n, a) => ({ name: n, age: a })); console.log(combine); // some({ name: 'John', age: 25 }) ``` -The `zipWith` function takes three arguments: the two `Option`s that you want to combine, and a function that takes two arguments - the values held by the two `Option`s - and returns the combined value. +The `zipWith` function takes three arguments: + +- The first `Option` you want to combine +- The second `Option` you want to combine +- A function that takes two arguments, which are the values held by the two `Options`, and returns the combined value -If either of the two `Option`s is `None`, the resulting `Option` will be `None` as well: +It's important to note that if either of the two `Option`s is `None`, the resulting `Option` will also be `None`. This is because the `zipWith` function only combines the values if both `Option`s are `Some`. + +For example: ```ts const name: Option = none(); @@ -589,28 +706,39 @@ const combine = zipWith(name, age, (n, a) => ({ name: n, age: a })); console.log(combine); // none() ``` -This is because the `zipWith` function only combines the values if both `Option`s are `Some`. - **Cheat sheet** (combining) -| Name | Given | To | -| --------- | --------------------------------------- | ----------- | -| `zipWith` | `Option`, `Option`, `(A, B) => C` | `Option` | -| `ap` | `Option<(a: A) => B>`, `Option` | `Option` | +| **Function** | **Given input** | **Resulting Output** | +| ------------ | --------------------------------------- | -------------------- | +| `zipWith` | `Option`, `Option`, `(A, B) => C` | `Option` | +| `productAll` | `Iterable>` | `Option` | +| `ap` | `Option<(a: A) => B>`, `Option` | `Option` | + +## Algebraic operations with `Option`s -For convenience, a series of algebraic operations such as sums and products are exported. +In addition to `zipWith`, a series of algebraic operations such as sums, products, subtractions, and divisions are exported to make it easier to work with `Option`s. + +For example, consider the following `Option`s holding numbers: ```ts -import { some, none, sum } from "@fp-ts/core/Option"; +import * as O from "@fp-ts/core/Option"; + +const num1 = O.some(3); +const num2 = O.some(4); +const num3 = O.none(); +``` -const num1 = some(3); -const num2 = some(4); -const num3 = none(); +Summing two `Some` values will result in a `Some` with the sum of the values: +```ts // Summing two `Some` values will result in a `Some` with the sum of the values const sumOfSome = sum(num1, num2); console.log(sumOfSome); // some(7) +``` +Summing a `Some` and a `None` will result in a `None`: + +```ts // Summing a `Some` and a `None` will result in a `None` const sumOfSomeAndNone = sum(num1, num3); console.log(sumOfSomeAndNone); // none() @@ -618,9 +746,9 @@ console.log(sumOfSomeAndNone); // none() **Cheat sheet** (algebraic operations) -| Name | Given | To | -| ---------- | ---------------------------------- | ---------------- | -| `sum` | `Option`, `Option` | `Option` | -| `multiply` | `Option`, `Option` | `Option` | -| `subtract` | `Option`, `Option` | `Option` | -| `divide` | `Option`, `Option` | `Option` | +| **Function** | **Given input** | **Resulting Output** | +| ------------ | ---------------------------------- | -------------------- | +| `sum` | `Option`, `Option` | `Option` | +| `multiply` | `Option`, `Option` | `Option` | +| `subtract` | `Option`, `Option` | `Option` | +| `divide` | `Option`, `Option` | `Option` | diff --git a/src/Either.ts b/src/Either.ts index cb1fba13b..c191e4e48 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -525,7 +525,22 @@ export const appendElement: { ): >(self: Either) => Either } = semiProduct.appendElement(SemiProduct) -const productAll = ( +/** + * Flattens a collection of `Either`s into a single `Either` that contains a list of all the `Right` values. + * If there is a `Left` value in the collection, it returns `Left` as the result. + * + * @param collection - An iterable collection of `Either`s to flatten. + * + * @example + * import * as E from "@fp-ts/core/Either" + * + * assert.deepStrictEqual(E.productAll([E.right(1), E.right(2), E.right(3)]), E.right([1, 2, 3])) + * assert.deepStrictEqual(E.productAll([E.right(1), E.left("error"), E.right(3)]), E.left("error")) + * + * @category sequencing + * @since 1.0.0 + */ +export const productAll = ( collection: Iterable> ): Either> => { const out: Array = [] @@ -554,7 +569,7 @@ export const Product: product_.Product = { * @since 1.0.0 */ export const tuple: >>( - ...tuple: T + ...elements: T ) => Either< [T[number]] extends [Either] ? E : never, { [I in keyof T]: [T[I]] extends [Either] ? A : never } @@ -564,7 +579,7 @@ export const tuple: >>( * @since 1.0.0 */ export const struct: >>( - r: R + fields: R ) => Either< [R[keyof R]] extends [Either] ? E : never, { [K in keyof R]: [R[K]] extends [Either] ? A : never } diff --git a/src/Option.ts b/src/Option.ts index a51cb4b1b..35aa6c8db 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -37,10 +37,6 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" -// ------------------------------------------------------------------------------------- -// models -// ------------------------------------------------------------------------------------- - /** * @category models * @since 1.0.0 @@ -72,16 +68,9 @@ export interface OptionTypeLambda extends TypeLambda { readonly type: Option } -// ------------------------------------------------------------------------------------- -// constructors -// ------------------------------------------------------------------------------------- - /** * Creates a new `Option` that represents the absence of a value. * - * This can be useful when working with optional values or to represent a computation that failed. - * It returns a new `Option` object that does not contain any value. - * * @category constructors * @since 1.0.0 */ @@ -90,8 +79,6 @@ export const none = (): Option => option.none /** * Creates a new `Option` that wraps the given value. * - * This can be useful when working with optional values or to represent a computation that succeeded with a value. - * * @param value - The value to wrap. * * @category constructors @@ -107,10 +94,6 @@ export const some: (value: A) => Option = option.some */ export const of: (value: A) => Option = some -// ------------------------------------------------------------------------------------- -// guards -// ------------------------------------------------------------------------------------- - /** * Tests if a value is a `Option`. * @@ -162,10 +145,6 @@ export const isNone: (self: Option) => self is None = option.isNone */ export const isSome: (self: Option) => self is Some = option.isSome -// ------------------------------------------------------------------------------------- -// pattern matching -// ------------------------------------------------------------------------------------- - /** * Matches the given `Option` and returns either the provided `onNone` value or the result of the provided `onSome` * function when passed the `Option`'s value. @@ -176,7 +155,7 @@ export const isSome: (self: Option) => self is Some = option.isSome * * @example * import { some, none, match } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' + * import { pipe } from "@fp-ts/core/Function" * * assert.deepStrictEqual( * pipe( @@ -206,18 +185,25 @@ export const match: { isNone(self) ? onNone() : onSome(self.value) ) -// ------------------------------------------------------------------------------------- -// conversions -// ------------------------------------------------------------------------------------- - /** - * Returns a `Refinement` from a `Option` returning function. - * This function ensures that a `Refinement` definition is type-safe. + * Returns a type guard from a `Option` returning function. + * This function ensures that a type guard definition is type-safe. + * + * @example + * import * as O from "@fp-ts/core/Option" + * + * const parsePositive = (n: number): O.Option => + * n > 0 ? O.some(n) : O.none() + * + * const isPositive = O.toRefinement(parsePositive) + * + * assert.deepStrictEqual(isPositive(1), true) + * assert.deepStrictEqual(isPositive(-1), false) * * @category conversions * @since 1.0.0 */ -export const toRefinement = (f: (a: A) => Option): Refinement => +export const toRefinement = (f: (a: A) => Option): (a: A) => a is B => (a: A): a is B => isSome(f(a)) /** @@ -229,8 +215,7 @@ export const toRefinement = (f: (a: A) => Option): Refinement * @example * import { fromIterable, some, none } from '@fp-ts/core/Option' * - * const collection = [1, 2, 3] - * assert.deepStrictEqual(fromIterable(collection), some(1)) + * assert.deepStrictEqual(fromIterable([1, 2, 3]), some(1)) * assert.deepStrictEqual(fromIterable([]), none()) * * @category conversions @@ -249,11 +234,11 @@ export const fromIterable = (collection: Iterable): Option => { * @param self - The `Either` to convert to an `Option`. * * @example - * import * as O from '@fp-ts/core/Option' - * import * as E from '@fp-ts/core/Either' + * import * as O from "@fp-ts/core/Option" + * import * as E from "@fp-ts/core/Either" * * assert.deepStrictEqual(O.fromEither(E.right(1)), O.some(1)) - * assert.deepStrictEqual(O.fromEither(E.left('a')), O.none()) + * assert.deepStrictEqual(O.fromEither(E.left('error message')), O.none()) * * @category conversions * @since 1.0.0 @@ -266,8 +251,8 @@ export const fromEither: (self: Either) => Option = either.getRig * Alias of {@link fromEither}. * * @example - * import * as O from '@fp-ts/core/Option' - * import * as E from '@fp-ts/core/Either' + * import * as O from "@fp-ts/core/Option" + * import * as E from "@fp-ts/core/Either" * * assert.deepStrictEqual(O.getRight(E.right('ok')), O.some('ok')) * assert.deepStrictEqual(O.getRight(E.left('err')), O.none()) @@ -281,11 +266,11 @@ export const getRight: (self: Either) => Option = fromEither * Converts a `Either` to an `Option` discarding the value. * * @example - * import * as O from '@fp-ts/core/Option' - * import * as E from '@fp-ts/core/Either' + * import * as O from "@fp-ts/core/Option" + * import * as E from "@fp-ts/core/Either" * - * assert.deepStrictEqual(O.getLeft(E.right('ok')), O.none()) - * assert.deepStrictEqual(O.getLeft(E.left('err')), O.some('err')) + * assert.deepStrictEqual(O.getLeft(E.right("ok")), O.none()) + * assert.deepStrictEqual(O.getLeft(E.left("error")), O.some("error")) * * @category conversions * @since 1.0.0 @@ -299,9 +284,9 @@ export const getLeft: (self: Either) => Option = either.getLeft * @param onNone - a function that produces an error value when the `Option` is `None`. * * @example - * import { pipe } from '@fp-ts/core/Function' - * import * as O from '@fp-ts/core/Option' - * import * as E from '@fp-ts/core/Either' + * import { pipe } from "@fp-ts/core/Function" + * import * as O from "@fp-ts/core/Option" + * import * as E from "@fp-ts/core/Either" * * const onNone = () => 'error' * assert.deepStrictEqual(pipe(O.some(1), O.toEither(onNone)), E.right(1)) @@ -315,10 +300,6 @@ export const toEither: { (onNone: () => E): (self: Option) => Either } = either.fromOption -// ------------------------------------------------------------------------------------- -// error handling -// ------------------------------------------------------------------------------------- - /** * Returns the value of the `Option` if it is `Some`, otherwise returns `onNone` * @@ -327,12 +308,12 @@ export const toEither: { * * @example * import { some, none, getOrElse } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' + * import { pipe } from "@fp-ts/core/Function" * * assert.deepStrictEqual(pipe(some(1), getOrElse(() => 0)), 1) * assert.deepStrictEqual(pipe(none(), getOrElse(() => 0)), 0) * - * @category error handling + * @category getters * @since 1.0.0 */ export const getOrElse: { @@ -350,8 +331,8 @@ export const getOrElse: { * @param that - The `Option` to return if `self` is `None`. * * @example - * import * as O from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' + * import * as O from "@fp-ts/core/Option" + * import { pipe } from "@fp-ts/core/Function" * * assert.deepStrictEqual( * pipe( @@ -415,10 +396,15 @@ export const orElseEither: { ) /** - * Given an `Iterable` collection of `Option`s, the function returns the first `Some` found in the collection. + * Given an `Iterable` collection of `Option`s, returns the first `Some` found in the collection. * * @param collection - An iterable collection of `Option` to be searched. * + * @example + * import * as O from "@fp-ts/core/Option" + * + * assert.deepStrictEqual(O.firstSomeOf([O.none(), O.some(1), O.some(2)]), O.some(1)) + * * @category error handling * @since 1.0.0 */ @@ -432,9 +418,31 @@ export const firstSomeOf = (collection: Iterable>): Option => { return out } -// ------------------------------------------------------------------------------------- -// interop -// ------------------------------------------------------------------------------------- +/** + * Flattens a collection of `Option`s into a single `Option` that contains a list of all the `Some` values. + * If there is a `None` value in the collection, it returns `None` as the result. + * + * @param collection - An iterable collection of `Option`s to flatten. + * + * @example + * import * as O from "@fp-ts/core/Option" + * + * assert.deepStrictEqual(O.productAll([O.some(1), O.some(2), O.some(3)]), O.some([1, 2, 3])) + * assert.deepStrictEqual(O.productAll([O.some(1), O.none(), O.some(3)]), O.none()) + * + * @category sequencing + * @since 1.0.0 + */ +export const productAll = (collection: Iterable>): Option> => { + const out: Array = [] + for (const o of collection) { + if (isNone(o)) { + return none() + } + out.push(o.value) + } + return some(out) +} /** * Constructs a new `Option` from a nullable type. If the value is `null` or `undefined`, returns `None`, otherwise @@ -443,13 +451,13 @@ export const firstSomeOf = (collection: Iterable>): Option => { * @param nullableValue - The nullable value to be converted to an `Option`. * * @example - * import { none, some, fromNullable } from '@fp-ts/core/Option' + * import * as O from "@fp-ts/core/Option" * - * assert.deepStrictEqual(fromNullable(undefined), none()) - * assert.deepStrictEqual(fromNullable(null), none()) - * assert.deepStrictEqual(fromNullable(1), some(1)) + * assert.deepStrictEqual(O.fromNullable(undefined), O.none()) + * assert.deepStrictEqual(O.fromNullable(null), O.none()) + * assert.deepStrictEqual(O.fromNullable(1), O.some(1)) * - * @category interop + * @category conversions * @since 1.0.0 */ export const fromNullable = ( @@ -462,19 +470,19 @@ export const fromNullable = ( * This API is useful for lifting a function that returns `null` or `undefined` into the `Option` context. * * @example - * import { liftNullable, none, some } from '@fp-ts/core/Option' + * import * as O from "@fp-ts/core/Option" * * const parse = (s: string): number | undefined => { * const n = parseFloat(s) * return isNaN(n) ? undefined : n * } * - * const parseOption = liftNullable(parse) + * const parseOption = O.liftNullable(parse) * - * assert.deepStrictEqual(parseOption('1'), some(1)) - * assert.deepStrictEqual(parseOption('not a number'), none()) + * assert.deepStrictEqual(parseOption('1'), O.some(1)) + * assert.deepStrictEqual(parseOption('not a number'), O.none()) * - * @category interop + * @category conversions * @since 1.0.0 */ export const liftNullable = , B>( @@ -487,13 +495,12 @@ export const liftNullable = , B>( * @param self - The `Option` to extract the value from. * * @example - * import { some, none, getOrNull } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' + * import * as O from "@fp-ts/core/Option" * - * assert.deepStrictEqual(pipe(some(1), getOrNull), 1) - * assert.deepStrictEqual(pipe(none(), getOrNull), null) + * assert.deepStrictEqual(O.getOrNull(O.some(1)), 1) + * assert.deepStrictEqual(O.getOrNull(O.none()), null) * - * @category interop + * @category getters * @since 1.0.0 */ export const getOrNull: (self: Option) => A | null = getOrElse(constNull) @@ -504,13 +511,12 @@ export const getOrNull: (self: Option) => A | null = getOrElse(constNull) * @param self - The `Option` to extract the value from. * * @example - * import { some, none, getOrUndefined } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' + * import * as O from "@fp-ts/core/Option" * - * assert.deepStrictEqual(pipe(some(1), getOrUndefined), 1) - * assert.deepStrictEqual(pipe(none(), getOrUndefined), undefined) + * assert.deepStrictEqual(O.getOrUndefined(O.some(1)), 1) + * assert.deepStrictEqual(O.getOrUndefined(O.none()), undefined) * - * @category interop + * @category getters * @since 1.0.0 */ export const getOrUndefined: (self: Option) => A | undefined = getOrElse(constUndefined) @@ -524,14 +530,14 @@ export const getOrUndefined: (self: Option) => A | undefined = getOrElse(c * @param f - the function that can throw exceptions. * * @example - * import { liftThrowable, some, none } from "@fp-ts/core/Option"; + * import * as O from "@fp-ts/core/Option" * - * const parse = liftThrowable(JSON.parse) + * const parse = O.liftThrowable(JSON.parse) * - * assert.deepStrictEqual(parse("1"), some(1)) - * assert.deepStrictEqual(parse(""), none()) + * assert.deepStrictEqual(parse("1"), O.some(1)) + * assert.deepStrictEqual(parse(""), O.none()) * - * @category interop + * @category conversions * @since 1.0.0 */ export const liftThrowable = , B>( @@ -554,7 +560,7 @@ export const liftThrowable = , B>( * @param onNone - A function that will be called if the `Option` is `None`. It returns the error to be thrown. * * @example - * import * as O from '@fp-ts/core/Option' + * import * as O from "@fp-ts/core/Option" * * assert.deepStrictEqual( * O.getOrThrowWith(O.some(1), () => new Error('Unexpected None')), @@ -562,7 +568,7 @@ export const liftThrowable = , B>( * ) * assert.throws(() => O.getOrThrowWith(O.none(), () => new Error('Unexpected None'))) * - * @category interop + * @category conversions * @since 1.0.0 */ export const getOrThrowWith: { @@ -584,29 +590,25 @@ export const getOrThrowWith: { * @throws `Error("getOrThrow called on a None")` * * @example - * import * as O from '@fp-ts/core/Option' + * import * as O from "@fp-ts/core/Option" * * assert.deepStrictEqual(O.getOrThrow(O.some(1)), 1) * assert.throws(() => O.getOrThrow(O.none())) * - * @category interop + * @category conversions * @since 1.0.0 */ export const getOrThrow: (self: Option) => A = getOrThrowWith(() => new Error("getOrThrow called on a None") ) -// ------------------------------------------------------------------------------------- -// mapping -// ------------------------------------------------------------------------------------- - /** * Maps the `Some` side of an `Option` value to a new `Option` value. * * @param self - An `Option` to map * @param f - The function to map over the value of the `Option` * - * @category mapping + * @category transforming * @since 1.0.0 */ export const map: { @@ -620,7 +622,6 @@ export const map: { const imap = covariant.imap(map) /** - * @category mapping * @since 1.0.0 */ export const Covariant: covariant.Covariant = { @@ -629,7 +630,6 @@ export const Covariant: covariant.Covariant = { } /** - * @category mapping * @since 1.0.0 */ export const Invariant: invariant.Invariant = { @@ -637,13 +637,13 @@ export const Invariant: invariant.Invariant = { } /** - * @category mapping + * @category transforming * @since 1.0.0 */ export const tupled: (self: Option) => Option<[A]> = invariant.tupled(Invariant) /** - * @category mapping + * @category transforming * @since 1.0.0 */ export const flap: { @@ -654,7 +654,7 @@ export const flap: { /** * Maps the `Some` value of this `Option` to the specified constant value. * - * @category mapping + * @category transforming * @since 1.0.0 */ export const as: { @@ -667,7 +667,7 @@ export const as: { * * This is useful when the value of the `Option` is not needed, but the presence or absence of the value is important. * - * @category mapping + * @category transforming * @since 1.0.0 */ export const asUnit: <_>(self: Option<_>) => Option = covariant.asUnit(Covariant) @@ -693,14 +693,10 @@ export const Pointed: pointed.Pointed = { map } -// ------------------------------------------------------------------------------------- -// sequencing -// ------------------------------------------------------------------------------------- - /** * Applies a function to the value of an `Option` and flattens the result, if the input is `Some`. * - * @category sequencing + * @category transforming * @since 1.0.0 */ export const flatMap: { @@ -719,16 +715,16 @@ export const flatMap: { * @param f - The function to be applied to the contents of the `Option`. * * @example - * import * as O from '@fp-ts/core/Option' - * import * as E from '@fp-ts/core/Either' - * import { pipe } from '@fp-ts/core/Function' + * import * as O from "@fp-ts/core/Option" + * import * as E from "@fp-ts/core/Either" + * import { pipe } from "@fp-ts/core/Function" * * const f = (n: number) => (n > 2 ? E.left('Too big') : E.right(n + 1)) * * assert.deepStrictEqual(pipe(O.some(1), O.flatMapEither(f)), O.some(2)) * assert.deepStrictEqual(pipe(O.some(3), O.flatMapEither(f)), O.none()) * - * @category sequencing + * @category transforming * @since 1.0.0 */ export const flatMapEither: { @@ -744,7 +740,7 @@ export const flatMapEither: { * * @example * import { some, none, flatMapNullable } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' + * import { pipe } from "@fp-ts/core/Function" * * interface Employee { * company?: { @@ -776,7 +772,7 @@ export const flatMapEither: { * none() * ) * - * @category sequencing + * @category transforming * @since 1.0.0 */ export const flatMapNullable: { @@ -789,7 +785,6 @@ export const flatMapNullable: { ) /** - * @category sequencing * @since 1.0.0 */ export const FlatMap: flatMap_.FlatMap = { @@ -797,13 +792,13 @@ export const FlatMap: flatMap_.FlatMap = { } /** - * @category sequencing + * @category transforming * @since 1.0.0 */ export const flatten: (self: Option>) => Option = flatMap_.flatten(FlatMap) /** - * @category sequencing + * @category transforming * @since 1.0.0 */ export const andThen: { @@ -812,7 +807,7 @@ export const andThen: { } = flatMap_.andThen(FlatMap) /** - * @category sequencing + * @category transforming * @since 1.0.0 */ export const composeKleisliArrow: { @@ -821,7 +816,6 @@ export const composeKleisliArrow: { } = flatMap_.composeKleisliArrow(FlatMap) /** - * @category sequencing * @since 1.0.0 */ export const Chainable: chainable.Chainable = { @@ -838,7 +832,7 @@ export const Chainable: chainable.Chainable = { * @param that - The `Option` that will be ignored in the chain and discarded * @param self - The `Option` we care about * - * @category sequencing + * @category transforming * @since 1.0.0 */ export const andThenDiscard: { @@ -855,7 +849,7 @@ export const andThenDiscard: { * @param f - Function to apply to the value of the `Option` if it is `Some` * @param self - The `Option` to apply the function to * - * @category sequencing + * @category transforming * @since 1.0.0 */ export const tap: { @@ -906,7 +900,6 @@ export const inspectNone: { }) /** - * @category instances * @since 1.0.0 */ export const Monad: monad.Monad = { @@ -937,7 +930,6 @@ const productMany = ( } /** - * @category instances * @since 1.0.0 */ export const SemiProduct: semiProduct.SemiProduct = { @@ -956,19 +948,7 @@ export const appendElement: { (that: Option): >(self: Option) => Option<[...A, B]> } = semiProduct.appendElement(SemiProduct) -const productAll = (collection: Iterable>): Option> => { - const out: Array = [] - for (const o of collection) { - if (isNone(o)) { - return none() - } - out.push(o.value) - } - return some(out) -} - /** - * @category instances * @since 1.0.0 */ export const Product: product_.Product = { @@ -980,25 +960,45 @@ export const Product: product_.Product = { } /** + * Takes a tuple of `Option`s and returns an `Option` of a tuple of values. + * + * @param elements - the tuple of `Option`s to be sequenced. + * + * @example + * import * as O from "@fp-ts/core/Option" + * + * assert.deepStrictEqual(O.tuple(O.some(1), O.some("hello")), O.some([1, "hello"])) + * assert.deepStrictEqual(O.tuple(O.some(1), O.none()), O.none()) + * + * @category sequencing * @since 1.0.0 */ export const tuple: >>( - ...tuple: T + ...elements: T ) => Option<{ [I in keyof T]: [T[I]] extends [Option] ? A : never }> = product_.tuple( Product ) /** + * Takes a struct of `Option`s and returns an `Option` of a struct of values. + * + * @param fields - the struct of `Option`s to be sequenced. + * + * @example + * import * as O from "@fp-ts/core/Option" + * + * assert.deepStrictEqual(O.struct({ a: O.some(1), b: O.some("hello") }), O.some({ a: 1, b: "hello" })) + * assert.deepStrictEqual(O.struct({ a: O.some(1), b: O.none() }), O.none()) + * + * @category sequencing * @since 1.0.0 */ export const struct: >>( - r: R -) => Option<{ [K in keyof R]: [R[K]] extends [Option] ? A : never }> = product_.struct( - Product -) + fields: R +) => Option<{ [K in keyof R]: [R[K]] extends [Option] ? A : never }> = product_ + .struct(Product) /** - * @category instances * @since 1.0.0 */ export const SemiApplicative: semiApplicative.SemiApplicative = { @@ -1012,18 +1012,22 @@ export const SemiApplicative: semiApplicative.SemiApplicative * Monoid that models the combination of values that may be absent, elements that are `None` are ignored * while elements that are `Some` are combined using the provided `Semigroup`. * + * The `empty` value is `none()`. + * + * @param Semigroup - The `Semigroup` used to combine two values of type `A`. + * * @example - * import { getOptionalMonoid, some, none } from '@fp-ts/core/Option' + * import * as O from "@fp-ts/core/Option" * import * as N from '@fp-ts/core/Number' - * import { pipe } from '@fp-ts/core/Function' + * import { pipe } from "@fp-ts/core/Function" * - * const M = getOptionalMonoid(N.SemigroupSum) - * assert.deepStrictEqual(M.combine(none(), none()), none()) - * assert.deepStrictEqual(M.combine(some(1), none()), some(1)) - * assert.deepStrictEqual(M.combine(none(), some(1)), some(1)) - * assert.deepStrictEqual(M.combine(some(1), some(2)), some(3)) + * const M = O.getOptionalMonoid(N.SemigroupSum) + * + * assert.deepStrictEqual(M.combine(O.none(), O.none()), O.none()) + * assert.deepStrictEqual(M.combine(O.some(1), O.none()), O.some(1)) + * assert.deepStrictEqual(M.combine(O.none(), O.some(1)), O.some(1)) + * assert.deepStrictEqual(M.combine(O.some(1), O.some(2)), O.some(3)) * - * @category instances * @since 1.0.0 */ export const getOptionalMonoid = ( @@ -1036,10 +1040,6 @@ export const getOptionalMonoid = ( none() ) -// ------------------------------------------------------------------------------------- -// combining -// ------------------------------------------------------------------------------------- - /** * Zips two `Option` values together using a provided function, returning a new `Option` of the result. * @@ -1078,7 +1078,6 @@ export const getFailureSemigroup: (S: Semigroup) => Semigroup> = .getSemigroup(SemiApplicative) /** - * @category instances * @since 1.0.0 */ export const Applicative: applicative.Applicative = { @@ -1109,21 +1108,10 @@ export const getFailureMonoid: (M: Monoid) => Monoid> = applicat const coproduct = (self: Option, that: Option): Option => isSome(self) ? self : that -const coproductMany = (self: Option, collection: Iterable>): Option => { - let out = self - if (isSome(out)) { - return out - } - for (out of collection) { - if (isSome(out)) { - return out - } - } - return out -} +const coproductMany = (self: Option, collection: Iterable>): Option => + isSome(self) ? self : firstSomeOf(collection) /** - * @category instances * @since 1.0.0 */ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { @@ -1138,11 +1126,11 @@ export const SemiCoproduct: semiCoproduct.SemiCoproduct = { * @category combining * @since 1.0.0 */ -export const getFirstSomeSemigroup: () => Semigroup> = semiCoproduct - .getSemigroup(SemiCoproduct) +export const getFirstSomeSemigroup: () => Semigroup> = semiCoproduct.getSemigroup( + SemiCoproduct +) /** - * @category instances * @since 1.0.0 */ export const Coproduct: coproduct_.Coproduct = { @@ -1154,7 +1142,6 @@ export const Coproduct: coproduct_.Coproduct = { } /** - * @category instances * @since 1.0.0 */ export const SemiAlternative: semiAlternative.SemiAlternative = { @@ -1165,7 +1152,6 @@ export const SemiAlternative: semiAlternative.SemiAlternative } /** - * @category instances * @since 1.0.0 */ export const Alternative: alternative.Alternative = { @@ -1177,10 +1163,6 @@ export const Alternative: alternative.Alternative = { zero: none } -// ------------------------------------------------------------------------------------- -// folding -// ------------------------------------------------------------------------------------- - /** * Reduces an `Iterable` of `Option` to a single value of type `B`, elements that are `None` are ignored. * @@ -1190,7 +1172,7 @@ export const Alternative: alternative.Alternative = { * * @example * import { some, none, reduceCompact } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' + * import { pipe } from "@fp-ts/core/Function" * * const iterable = [some(1), none(), some(2), none()] * assert.deepStrictEqual(pipe(iterable, reduceCompact(0, (b, a) => b + a)), 3) @@ -1215,7 +1197,6 @@ export const reduceCompact: { ) /** - * @category folding * @since 1.0.0 */ export const Foldable: foldable.Foldable = { @@ -1233,20 +1214,16 @@ export const Foldable: foldable.Foldable = { * @param self - The `Option` to convert to an array. * * @example - * import { some, none, toArray } from '@fp-ts/core/Option' + * import * as O from "@fp-ts/core/Option" * - * assert.deepStrictEqual(toArray(some(1)), [1]) - * assert.deepStrictEqual(toArray(none()), []) + * assert.deepStrictEqual(O.toArray(O.some(1)), [1]) + * assert.deepStrictEqual(O.toArray(O.none()), []) * * @category conversions * @since 1.0.0 */ export const toArray: (self: Option) => Array = foldable.toArray(Foldable) -// ------------------------------------------------------------------------------------- -// filtering -// ------------------------------------------------------------------------------------- - /** * @category filtering * @since 1.0.0 @@ -1286,7 +1263,6 @@ export const filterMap: { ) /** - * @category instances * @since 1.0.0 */ export const Filterable: filterable.Filterable = { @@ -1312,12 +1288,25 @@ export const filter: { (predicate: (a: A) => boolean): (self: Option) => Option } = filterable.filter(Filterable) -// ------------------------------------------------------------------------------------- -// traversing -// ------------------------------------------------------------------------------------- - /** - * @category traversing + * Applies an `Option` value to an effectful function that returns an `F` value. + * + * @param F - {@link applicative.Applicative} instance + * @param self - The `Option` value. + * @param f - An effectful function that returns an `F` value. + * + * @example + * import * as O from "@fp-ts/core/Option" + * import * as E from "@fp-ts/core/Either" + * + * const traverse = O.traverse(E.Applicative) + * const f = (n: number) => n >= 0 ? E.right(1) : E.left("negative") + * + * assert.deepStrictEqual(traverse(O.some(1), f), E.right(O.some(1))) + * assert.deepStrictEqual(traverse(O.some(-1), f), E.left("negative")) + * assert.deepStrictEqual(traverse(O.none(), f), E.right(O.none())) + * + * @category sequencing * @since 1.0.0 */ export const traverse = ( @@ -1337,7 +1326,6 @@ export const traverse = ( ) /** - * @category instances * @since 1.0.0 */ export const Traversable: traversable.Traversable = { @@ -1345,7 +1333,22 @@ export const Traversable: traversable.Traversable = { } /** - * @category traversing + * Combines an `Option` of an `F`-structure to an `F`-structure of an `Option` with the same inner type. + * + * @param F - {@link applicative.Applicative} instance + * @param self - `Option` of Kind `F` + * + * @example + * import * as O from "@fp-ts/core/Option" + * import * as E from "@fp-ts/core/Either" + * + * const sequence = O.sequence(E.Applicative) + * + * assert.deepStrictEqual(sequence(O.some(E.right(1))), E.right(O.some(1))) + * assert.deepStrictEqual(sequence(O.some(E.left("error"))), E.left("error")) + * assert.deepStrictEqual(sequence(O.none()), E.right(O.none())) + * + * @category sequencing * @since 1.0.0 */ export const sequence: ( @@ -1354,7 +1357,7 @@ export const sequence: ( .sequence(Traversable) /** - * @category traversing + * @category sequencing * @since 1.0.0 */ export const traverseTap: ( @@ -1369,10 +1372,6 @@ export const traverseTap: ( ): (self: Option) => Kind> } = traversable.traverseTap(Traversable) -// ------------------------------------------------------------------------------------- -// equivalence -// ------------------------------------------------------------------------------------- - /** * @example * import { none, some, getEquivalence } from '@fp-ts/core/Option' @@ -1393,10 +1392,6 @@ export const getEquivalence = (E: Equivalence): Equivalence> => x === y || (isNone(x) ? isNone(y) : isNone(y) ? false : E(x.value, y.value)) ) -// ------------------------------------------------------------------------------------- -// sorting -// ------------------------------------------------------------------------------------- - /** * The `Order` instance allows `Option` values to be compared with * `compare`, whenever there is an `Order` instance for @@ -1407,7 +1402,7 @@ export const getEquivalence = (E: Equivalence): Equivalence> => * @example * import { none, some, getOrder } from '@fp-ts/core/Option' * import * as N from '@fp-ts/core/Number' - * import { pipe } from '@fp-ts/core/Function' + * import { pipe } from "@fp-ts/core/Function" * * const O = getOrder(N.Order) * assert.deepStrictEqual(O.compare(none(), none()), 0) @@ -1424,10 +1419,6 @@ export const getOrder = (O: Order): Order> => isSome(self) ? (isSome(that) ? O.compare(self.value, that.value) : 1) : -1 ) -// ------------------------------------------------------------------------------------- -// lifting -// ------------------------------------------------------------------------------------- - /** * Lifts a binary function into `Option`. * @@ -1448,7 +1439,7 @@ export const lift2: (f: (a: A, b: B) => C) => { * @param predicate - A `Predicate` function that takes in a value of type `A` and returns a boolean. * * @example - * import * as O from '@fp-ts/core/Option' + * import * as O from "@fp-ts/core/Option" * * const getOption = O.liftPredicate((n: number) => n >= 0) * @@ -1469,8 +1460,8 @@ export const liftPredicate: { * @param f - Any variadic function that returns an `Either`. * * @example - * import * as O from '@fp-ts/core/Option' - * import * as E from '@fp-ts/core/Either' + * import * as O from "@fp-ts/core/Option" + * import * as E from "@fp-ts/core/Either" * * const parse = (s: string) => * isNaN(+s) ? E.left(`Error: ${s} is not a number`) : E.right(+s) @@ -1487,10 +1478,6 @@ export const liftEither = , E, B>( f: (...a: A) => Either ) => (...a: A): Option => fromEither(f(...a)) -// ------------------------------------------------------------------------------------- -// utils -// ------------------------------------------------------------------------------------- - /** * Returns a function that checks if an `Option` contains a given value using a provided `Equivalence` instance. * @@ -1501,7 +1488,7 @@ export const liftEither = , E, B>( * @example * import { some, none, contains } from '@fp-ts/core/Option' * import { Equivalence } from '@fp-ts/core/Number' - * import { pipe } from '@fp-ts/core/Function' + * import { pipe } from "@fp-ts/core/Function" * * assert.deepStrictEqual(pipe(some(2), contains(Equivalence)(2)), true) * assert.deepStrictEqual(pipe(some(1), contains(Equivalence)(2)), false) @@ -1522,7 +1509,7 @@ export const contains = (isEquivalent: (self: A, that: A) => boolean): { * * @example * import { some, none, exists } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' + * import { pipe } from "@fp-ts/core/Function" * * const isEven = (n: number) => n % 2 === 0 * diff --git a/src/Predicate.ts b/src/Predicate.ts index 35d726721..58cb9f1be 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -454,26 +454,38 @@ export const Of: of_.Of = { */ export const unit: Predicate = of_.unit(Of) -const product = (self: Predicate, that: Predicate): Predicate<[A, B]> => +const product = (self: Predicate, that: Predicate): Predicate => ([a, b]) => self(a) && that(b) -const productMany = ( - self: Predicate, +/** + * Flattens a collection of `Predicate`s into a single `Predicate` that tests a `ReadonlyArray` of values. + * + * @param collection - An iterable collection of `Predicate`s to flatten. + * + * @category sequencing + * @since 1.0.0 + */ +const productAll = ( collection: Iterable> -): Predicate<[A, ...Array]> => - ([head, ...tail]) => { - if (self(head) === false) { - return false - } +): Predicate> => + (as) => { const predicates = readonlyArray.fromIterable(collection) for (let i = 0; i < predicates.length; i++) { - if (predicates[i](tail[i]) === false) { + if (predicates[i](as[i]) === false) { return false } } return true } +const productMany = ( + self: Predicate, + collection: Iterable> +): Predicate]> => { + const rest = productAll(collection) + return ([head, ...tail]) => self(head) === false ? false : rest(tail) +} + /** * @category instances * @since 1.0.0 @@ -484,19 +496,6 @@ export const SemiProduct: semiProduct.SemiProduct = { productMany } -const productAll = ( - collection: Iterable> -): Predicate> => - (as) => { - const predicates = readonlyArray.fromIterable(collection) - for (let i = 0; i < predicates.length; i++) { - if (predicates[i](as[i]) === false) { - return false - } - } - return true - } - /** * @category instances * @since 1.0.0 diff --git a/test/Either.ts b/test/Either.ts index a1efc061d..ece347dd1 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -50,6 +50,7 @@ describe.concurrent("Either", () => { expect(E.SemiProduct).exist expect(E.Product).exist + expect(E.productAll).exist expect(E.tuple).exist expect(E.struct).exist diff --git a/test/Option.ts b/test/Option.ts index a6dda11ab..6db47ba5a 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -49,6 +49,7 @@ describe.concurrent("Option", () => { expect(_.SemiProduct).exist expect(_.Product).exist + expect(_.productAll).exist expect(_.tuple).exist expect(_.struct).exist From c12a29a6453e03d08cb3d54c44ccaeb959680cf4 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 12 Feb 2023 08:58:15 +0100 Subject: [PATCH 240/255] docs: Boolean module --- docs/modules/Boolean.ts.md | 153 ++++++++++++++++++++++++++++++++----- src/Boolean.ts | 125 ++++++++++++++++++++++++++---- 2 files changed, 246 insertions(+), 32 deletions(-) diff --git a/docs/modules/Boolean.ts.md b/docs/modules/Boolean.ts.md index c3f014c8f..ca0c77463 100644 --- a/docs/modules/Boolean.ts.md +++ b/docs/modules/Boolean.ts.md @@ -50,82 +50,184 @@ Added in v1.0.0 ## and +Combines two boolean using AND: `self && that`. + **Signature** ```ts export declare const and: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } ``` +**Example** + +```ts +import { and } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(and(true, true), true) +assert.deepStrictEqual(and(true, false), false) +assert.deepStrictEqual(and(false, true), false) +assert.deepStrictEqual(and(false, false), false) +``` + Added in v1.0.0 ## eqv +Combines two booleans using EQV (aka XNOR): `!xor(self, that)`. + **Signature** ```ts export declare const eqv: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } ``` +**Example** + +```ts +import { eqv } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(eqv(true, true), true) +assert.deepStrictEqual(eqv(true, false), false) +assert.deepStrictEqual(eqv(false, true), false) +assert.deepStrictEqual(eqv(false, false), true) +``` + Added in v1.0.0 ## implies +Combines two booleans using an implication: `(!self || that)`. + **Signature** ```ts export declare const implies: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } ``` +**Example** + +```ts +import { implies } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(implies(true, true), true) +assert.deepStrictEqual(implies(true, false), false) +assert.deepStrictEqual(implies(false, true), true) +assert.deepStrictEqual(implies(false, false), true) +``` + Added in v1.0.0 ## nand +Combines two boolean using NAND: `!(self && that)`. + **Signature** ```ts export declare const nand: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } ``` +**Example** + +```ts +import { nand } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(nand(true, true), false) +assert.deepStrictEqual(nand(true, false), true) +assert.deepStrictEqual(nand(false, true), true) +assert.deepStrictEqual(nand(false, false), true) +``` + Added in v1.0.0 ## nor +Combines two booleans using NOR: `!(self || that)`. + **Signature** ```ts export declare const nor: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } ``` +**Example** + +```ts +import { nor } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(nor(true, true), false) +assert.deepStrictEqual(nor(true, false), false) +assert.deepStrictEqual(nor(false, true), false) +assert.deepStrictEqual(nor(false, false), true) +``` + Added in v1.0.0 ## not +Negates the given boolean: `!self` + **Signature** ```ts export declare const not: (self: boolean) => boolean ``` +**Example** + +```ts +import { not } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(not(true), false) +assert.deepStrictEqual(not(false), true) +``` + Added in v1.0.0 ## or +Combines two boolean using OR: `self || that`. + **Signature** ```ts export declare const or: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } ``` +**Example** + +```ts +import { or } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(or(true, true), true) +assert.deepStrictEqual(or(true, false), true) +assert.deepStrictEqual(or(false, true), true) +assert.deepStrictEqual(or(false, false), false) +``` + Added in v1.0.0 ## xor +Combines two booleans using XOR: `(!self && that) || (self && !that)`. + **Signature** ```ts export declare const xor: { (that: boolean): (self: boolean) => boolean; (self: boolean, that: boolean): boolean } ``` +**Example** + +```ts +import { xor } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(xor(true, true), false) +assert.deepStrictEqual(xor(true, false), true) +assert.deepStrictEqual(xor(false, true), true) +assert.deepStrictEqual(xor(false, false), false) +``` + Added in v1.0.0 # guards @@ -165,7 +267,7 @@ Added in v1.0.0 ## MonoidAll -`boolean` monoid under conjunction. +`boolean` monoid under conjunction, see also {@link SemigroupAll}. The `empty` value is `true`. @@ -179,7 +281,7 @@ Added in v1.0.0 ## MonoidAny -`boolean` monoid under disjunction. +`boolean` monoid under disjunction, see also {@link SemigroupAny}. The `empty` value is `false`. @@ -207,7 +309,7 @@ Added in v1.0.0 ## MonoidXor -`boolean` monoid under exclusive disjunction. +`boolean` monoid under exclusive disjunction, see also {@link SemigroupXor}. The `empty` value is `false`. @@ -325,9 +427,8 @@ Added in v1.0.0 ## match -Defines the match over a boolean value. -Takes two thunks `onTrue`, `onFalse` and a `boolean` value. -If `value` is `false`, `onFalse()` is returned, otherwise `onTrue()`. +This function returns the result of either of the given functions depending on the value of the boolean parameter. +It is useful when you have to run one of two functions depending on the boolean value. **Signature** @@ -341,21 +442,15 @@ export declare const match: { **Example** ```ts -import { some, map } from '@fp-ts/core/Option' -import { pipe } from '@fp-ts/core/Function' -import { match } from '@fp-ts/core/Boolean' +import * as B from '@fp-ts/core/Boolean' assert.deepStrictEqual( - pipe( - some(true), - map( - match( - () => 'false', - () => 'true' - ) - ) + B.match( + true, + () => "It's false!", + () => "It's true!" ), - some('true') + "It's true!" ) ``` @@ -365,20 +460,42 @@ Added in v1.0.0 ## all +This utility function is used to check if all the elements in a collection of boolean values are `true`. + **Signature** ```ts export declare const all: (collection: Iterable) => boolean ``` +**Example** + +```ts +import { all } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(all([true, true, true]), true) +assert.deepStrictEqual(all([true, false, true]), false) +``` + Added in v1.0.0 ## any +This utility function is used to check if at least one of the elements in a collection of boolean values is `true`. + **Signature** ```ts export declare const any: (collection: Iterable) => boolean ``` +**Example** + +```ts +import { any } from '@fp-ts/core/Boolean' + +assert.deepStrictEqual(any([true, false, true]), true) +assert.deepStrictEqual(any([false, false, false]), false) +``` + Added in v1.0.0 diff --git a/src/Boolean.ts b/src/Boolean.ts index 6d7c4b084..2b432317d 100644 --- a/src/Boolean.ts +++ b/src/Boolean.ts @@ -30,21 +30,19 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" export const isBoolean: (input: unknown) => input is boolean = predicate.isBoolean /** - * Defines the match over a boolean value. - * Takes two thunks `onTrue`, `onFalse` and a `boolean` value. - * If `value` is `false`, `onFalse()` is returned, otherwise `onTrue()`. + * This function returns the result of either of the given functions depending on the value of the boolean parameter. + * It is useful when you have to run one of two functions depending on the boolean value. + * + * @param value - the boolean value that decides which function will be executed. + * @param onFalse - a lazy evaluation function that will be executed when the `value` is `false`. + * @param onTrue - a lazy evaluation function that will be executed when the `value` is `true`. * * @example - * import { some, map } from '@fp-ts/core/Option' - * import { pipe } from '@fp-ts/core/Function' - * import { match } from '@fp-ts/core/Boolean' + * import * as B from "@fp-ts/core/Boolean" * * assert.deepStrictEqual( - * pipe( - * some(true), - * map(match(() => 'false', () => 'true')) - * ), - * some('true') + * B.match(true, () => "It's false!", () => "It's true!"), + * "It's true!" * ) * * @category pattern matching @@ -118,6 +116,7 @@ export const SemigroupAny: semigroup.Semigroup = semigroup.booleanAny * @since 1.0.0 */ export const SemigroupXor: semigroup.Semigroup = semigroup.booleanXor + /** * `boolean` semigroup under equivalence. * @@ -135,7 +134,7 @@ export const SemigroupXor: semigroup.Semigroup = semigroup.booleanXor export const SemigroupEqv: semigroup.Semigroup = semigroup.booleanEqv /** - * `boolean` monoid under conjunction. + * `boolean` monoid under conjunction, see also {@link SemigroupAll}. * * The `empty` value is `true`. * @@ -145,7 +144,7 @@ export const SemigroupEqv: semigroup.Semigroup = semigroup.booleanEqv export const MonoidAll: monoid.Monoid = monoid.booleanAll /** - * `boolean` monoid under disjunction. + * `boolean` monoid under disjunction, see also {@link SemigroupAny}. * * The `empty` value is `false`. * @@ -155,7 +154,7 @@ export const MonoidAll: monoid.Monoid = monoid.booleanAll export const MonoidAny: monoid.Monoid = monoid.booleanAny /** - * `boolean` monoid under exclusive disjunction. + * `boolean` monoid under exclusive disjunction, see also {@link SemigroupXor}. * * The `empty` value is `false`. * @@ -175,12 +174,30 @@ export const MonoidXor: monoid.Monoid = monoid.booleanXor export const MonoidEqv: monoid.Monoid = monoid.booleanEqv /** + * Negates the given boolean: `!self` + * + * @example + * import { not } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(not(true), false) + * assert.deepStrictEqual(not(false), true) + * * @category combinators * @since 1.0.0 */ export const not = (self: boolean): boolean => !self /** + * Combines two boolean using AND: `self && that`. + * + * @example + * import { and } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(and(true, true), true) + * assert.deepStrictEqual(and(true, false), false) + * assert.deepStrictEqual(and(false, true), false) + * assert.deepStrictEqual(and(false, false), false) + * * @category combinators * @since 1.0.0 */ @@ -190,6 +207,16 @@ export const and: { } = dual(2, semigroup.booleanAll.combine) /** + * Combines two boolean using NAND: `!(self && that)`. + * + * @example + * import { nand } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(nand(true, true), false) + * assert.deepStrictEqual(nand(true, false), true) + * assert.deepStrictEqual(nand(false, true), true) + * assert.deepStrictEqual(nand(false, false), true) + * * @category combinators * @since 1.0.0 */ @@ -199,6 +226,16 @@ export const nand: { } = dual(2, flow(semigroup.booleanAll.combine, not)) /** + * Combines two boolean using OR: `self || that`. + * + * @example + * import { or } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(or(true, true), true) + * assert.deepStrictEqual(or(true, false), true) + * assert.deepStrictEqual(or(false, true), true) + * assert.deepStrictEqual(or(false, false), false) + * * @category combinators * @since 1.0.0 */ @@ -208,6 +245,16 @@ export const or: { } = dual(2, semigroup.booleanAny.combine) /** + * Combines two booleans using NOR: `!(self || that)`. + * + * @example + * import { nor } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(nor(true, true), false) + * assert.deepStrictEqual(nor(true, false), false) + * assert.deepStrictEqual(nor(false, true), false) + * assert.deepStrictEqual(nor(false, false), true) + * * @category combinators * @since 1.0.0 */ @@ -217,6 +264,16 @@ export const nor: { } = dual(2, flow(semigroup.booleanAny.combine, not)) /** + * Combines two booleans using XOR: `(!self && that) || (self && !that)`. + * + * @example + * import { xor } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(xor(true, true), false) + * assert.deepStrictEqual(xor(true, false), true) + * assert.deepStrictEqual(xor(false, true), true) + * assert.deepStrictEqual(xor(false, false), false) + * * @category combinators * @since 1.0.0 */ @@ -226,6 +283,16 @@ export const xor: { } = dual(2, semigroup.booleanXor.combine) /** + * Combines two booleans using EQV (aka XNOR): `!xor(self, that)`. + * + * @example + * import { eqv } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(eqv(true, true), true) + * assert.deepStrictEqual(eqv(true, false), false) + * assert.deepStrictEqual(eqv(false, true), false) + * assert.deepStrictEqual(eqv(false, false), true) + * * @category combinators * @since 1.0.0 */ @@ -235,6 +302,16 @@ export const eqv: { } = dual(2, semigroup.booleanEqv.combine) /** + * Combines two booleans using an implication: `(!self || that)`. + * + * @example + * import { implies } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(implies(true, true), true) + * assert.deepStrictEqual(implies(true, false), false) + * assert.deepStrictEqual(implies(false, true), true) + * assert.deepStrictEqual(implies(false, false), true) + * * @category combinators * @since 1.0.0 */ @@ -244,11 +321,31 @@ export const implies: { } = dual(2, (self, that) => self ? that : true) /** + * This utility function is used to check if all the elements in a collection of boolean values are `true`. + * + * @param collection - An iterable collection of booleans. + * + * @example + * import { all } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(all([true, true, true]), true) + * assert.deepStrictEqual(all([true, false, true]), false) + * * @since 1.0.0 */ export const all: (collection: Iterable) => boolean = MonoidAll.combineAll /** + * This utility function is used to check if at least one of the elements in a collection of boolean values is `true`. + * + * @param collection - An iterable collection of booleans. + * + * @example + * import { any } from '@fp-ts/core/Boolean' + * + * assert.deepStrictEqual(any([true, false, true]), true) + * assert.deepStrictEqual(any([false, false, false]), false) + * * @since 1.0.0 */ export const any: (collection: Iterable) => boolean = MonoidAny.combineAll From d2e665d7d98bf64765aff227f8420616dfb73a8e Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 12 Feb 2023 12:17:40 +0100 Subject: [PATCH 241/255] refactor tuple, struct --- docs/modules/Either.ts.md | 185 ++++++------ docs/modules/Option.ts.md | 346 ++++++++++++----------- docs/modules/Predicate.ts.md | 28 +- docs/modules/ReadonlyArray.ts.md | 158 +++++------ docs/modules/Symbol.ts.md | 14 + docs/modules/These.ts.md | 241 ++++++++-------- docs/modules/Tuple.ts.md | 20 +- docs/modules/typeclass/Chainable.ts.md | 60 ++-- docs/modules/typeclass/Equivalence.ts.md | 50 ++-- docs/modules/typeclass/Invariant.ts.md | 7 + docs/modules/typeclass/Monoid.ts.md | 2 + docs/modules/typeclass/Order.ts.md | 37 ++- docs/modules/typeclass/Semigroup.ts.md | 34 ++- guides/Either.md | 13 +- guides/Option.md | 13 +- src/Either.ts | 30 +- src/Option.ts | 46 +-- src/Predicate.ts | 31 +- src/ReadonlyArray.ts | 14 +- src/Symbol.ts | 7 + src/These.ts | 33 ++- src/Tuple.ts | 15 +- src/typeclass/Chainable.ts | 2 +- src/typeclass/Equivalence.ts | 155 +++++----- src/typeclass/Invariant.ts | 7 + src/typeclass/Monoid.ts | 2 + src/typeclass/Order.ts | 176 +++++++----- src/typeclass/Semigroup.ts | 141 +++++---- test/Either.ts | 2 +- test/Option.ts | 2 +- test/Predicate.ts | 4 +- test/Symbol.ts | 6 + test/typeclass/Equivalence.ts | 121 ++------ test/typeclass/Order.ts | 39 +-- test/typeclass/Semigroup.ts | 43 +-- 35 files changed, 1105 insertions(+), 979 deletions(-) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 53a643b36..f12f4dcd7 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -20,6 +20,11 @@ Added in v1.0.0 - [combinators](#combinators) - [tap](#tap) - [combining](#combining) + - [all](#all) + - [andThenDiscard](#andthendiscard) + - [flatMap](#flatmap) + - [flatMapNullable](#flatmapnullable) + - [flatMapOption](#flatmapoption) - [getFirstLeftMonoid](#getfirstleftmonoid) - [getFirstLeftSemigroup](#getfirstleftsemigroup) - [getFirstRightSemigroup](#getfirstrightsemigroup) @@ -110,12 +115,6 @@ Added in v1.0.0 - [Right (interface)](#right-interface) - [pattern matching](#pattern-matching) - [match](#match) -- [sequencing](#sequencing) - - [andThenDiscard](#andthendiscard) - - [flatMap](#flatmap) - - [flatMapNullable](#flatmapnullable) - - [flatMapOption](#flatmapoption) - - [productAll](#productall) - [traversing](#traversing) - [sequence](#sequence) - [traverse](#traverse) @@ -210,6 +209,94 @@ Added in v1.0.0 # combining +## all + +Similar to `Promise.all` but operates on `Either`s. + +``` +Iterable> -> Either +``` + +Flattens a collection of `Either`s into a single `Either` that contains a list of all the `Right` values. +If there is a `Left` value in the collection, it returns the first `Left` found as the result. + +**Signature** + +```ts +export declare const all: (collection: Iterable>) => Either +``` + +**Example** + +```ts +import * as E from '@fp-ts/core/Either' + +assert.deepStrictEqual(E.all([E.right(1), E.right(2), E.right(3)]), E.right([1, 2, 3])) +assert.deepStrictEqual(E.all([E.right(1), E.left('error'), E.right(3)]), E.left('error')) +``` + +Added in v1.0.0 + +## andThenDiscard + +Sequences the specified effect after this effect, but ignores the value +produced by the effect. + +**Signature** + +```ts +export declare const andThenDiscard: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} +``` + +Added in v1.0.0 + +## flatMap + +**Signature** + +```ts +export declare const flatMap: { + (f: (a: A) => Either): (self: Either) => Either + (self: Either, f: (a: A) => Either): Either +} +``` + +Added in v1.0.0 + +## flatMapNullable + +**Signature** + +```ts +export declare const flatMapNullable: { + (f: (a: A) => B | null | undefined, onNullable: (a: A) => E2): ( + self: Either + ) => Either> + (self: Either, f: (a: A) => B | null | undefined, onNullable: (a: A) => E2): Either< + E1 | E2, + NonNullable + > +} +``` + +Added in v1.0.0 + +## flatMapOption + +**Signature** + +```ts +export declare const flatMapOption: { + (f: (a: A) => Option, onNone: (a: A) => E2): (self: Either) => Either + (self: Either, f: (a: A) => Option, onNone: (a: A) => E2): Either +} +``` + +Added in v1.0.0 + ## getFirstLeftMonoid `Monoid` returning the left-most `Left` value. If both operands are `Right`s then the inner values @@ -1414,90 +1501,6 @@ assert.deepStrictEqual(pipe(E.left(['error 1', 'error 2']), E.match(onLeft, onRi Added in v1.0.0 -# sequencing - -## andThenDiscard - -Sequences the specified effect after this effect, but ignores the value -produced by the effect. - -**Signature** - -```ts -export declare const andThenDiscard: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} -``` - -Added in v1.0.0 - -## flatMap - -**Signature** - -```ts -export declare const flatMap: { - (f: (a: A) => Either): (self: Either) => Either - (self: Either, f: (a: A) => Either): Either -} -``` - -Added in v1.0.0 - -## flatMapNullable - -**Signature** - -```ts -export declare const flatMapNullable: { - (f: (a: A) => B | null | undefined, onNullable: (a: A) => E2): ( - self: Either - ) => Either> - (self: Either, f: (a: A) => B | null | undefined, onNullable: (a: A) => E2): Either< - E1 | E2, - NonNullable - > -} -``` - -Added in v1.0.0 - -## flatMapOption - -**Signature** - -```ts -export declare const flatMapOption: { - (f: (a: A) => Option, onNone: (a: A) => E2): (self: Either) => Either - (self: Either, f: (a: A) => Option, onNone: (a: A) => E2): Either -} -``` - -Added in v1.0.0 - -## productAll - -Flattens a collection of `Either`s into a single `Either` that contains a list of all the `Right` values. -If there is a `Left` value in the collection, it returns `Left` as the result. - -**Signature** - -```ts -export declare const productAll: (collection: Iterable>) => Either -``` - -**Example** - -```ts -import * as E from '@fp-ts/core/Either' - -assert.deepStrictEqual(E.productAll([E.right(1), E.right(2), E.right(3)]), E.right([1, 2, 3])) -assert.deepStrictEqual(E.productAll([E.right(1), E.left('error'), E.right(3)]), E.left('error')) -``` - -Added in v1.0.0 - # traversing ## sequence @@ -1691,6 +1694,8 @@ Added in v1.0.0 ## tuple +Similar to `Promise.all` but operates on `Either`s. + **Signature** ```ts diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index aadaf7d80..efe61026b 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -20,10 +20,17 @@ Added in v1.0.0 - [sum](#sum) - [sumCompact](#sumcompact) - [combining](#combining) + - [all](#all) - [ap](#ap) + - [appendElement](#appendelement) - [getFailureMonoid](#getfailuremonoid) - [getFailureSemigroup](#getfailuresemigroup) - [getFirstSomeSemigroup](#getfirstsomesemigroup) + - [sequence](#sequence) + - [struct](#struct) + - [traverse](#traverse) + - [traverseTap](#traversetap) + - [tuple](#tuple) - [zipWith](#zipwith) - [constructors](#constructors) - [none](#none) @@ -81,13 +88,6 @@ Added in v1.0.0 - [Some (interface)](#some-interface) - [pattern matching](#pattern-matching) - [match](#match) -- [sequencing](#sequencing) - - [productAll](#productall) - - [sequence](#sequence) - - [struct](#struct) - - [traverse](#traverse) - - [traverseTap](#traversetap) - - [tuple](#tuple) - [sorting](#sorting) - [getOrder](#getorder) - [transforming](#transforming) @@ -125,7 +125,6 @@ Added in v1.0.0 - [SemiCoproduct](#semicoproduct) - [SemiProduct](#semiproduct) - [Traversable](#traversable) - - [appendElement](#appendelement) - [contains](#contains) - [exists](#exists) - [getOptionalMonoid](#getoptionalmonoid) @@ -231,6 +230,34 @@ Added in v1.0.0 # combining +## all + +Similar to `Promise.all` but operates on `Option`s. + +``` +Iterable> -> Option +``` + +Flattens a collection of `Option`s into a single `Option` that contains a list of all the `Some` values. +If there is a `None` value in the collection, it returns `None` as the result. + +**Signature** + +```ts +export declare const all: (collection: Iterable>) => Option +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual(O.all([O.some(1), O.some(2), O.some(3)]), O.some([1, 2, 3])) +assert.deepStrictEqual(O.all([O.some(1), O.none(), O.some(3)]), O.none()) +``` + +Added in v1.0.0 + ## ap **Signature** @@ -244,6 +271,30 @@ export declare const ap: { Added in v1.0.0 +## appendElement + +Appends an element to the end of a tuple wrapped in an `Option` type. + +**Signature** + +```ts +export declare const appendElement: { + (self: Option, that: Option): Option<[...A, B]> + (that: Option): (self: Option) => Option<[...A, B]> +} +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual(O.appendElement(O.some([1, 2]), O.some(3)), O.some([1, 2, 3])) +assert.deepStrictEqual(O.appendElement(O.some([1, 2]), O.none()), O.none()) +``` + +Added in v1.0.0 + ## getFailureMonoid Monoid that models the combination of computations that can fail, if at least one element is `None` @@ -290,6 +341,127 @@ export declare const getFirstSomeSemigroup: () => Semigroup> Added in v1.0.0 +## sequence + +Combines an `Option` of an `F`-structure to an `F`-structure of an `Option` with the same inner type. + +**Signature** + +```ts +export declare const sequence: ( + F: applicative.Applicative +) => (self: Option>) => Kind> +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +const sequence = O.sequence(E.Applicative) + +assert.deepStrictEqual(sequence(O.some(E.right(1))), E.right(O.some(1))) +assert.deepStrictEqual(sequence(O.some(E.left('error'))), E.left('error')) +assert.deepStrictEqual(sequence(O.none()), E.right(O.none())) +``` + +Added in v1.0.0 + +## struct + +Takes a struct of `Option`s and returns an `Option` of a struct of values. + +**Signature** + +```ts +export declare const struct: >>( + fields: R +) => Option<{ [K in keyof R]: [R[K]] extends [Option] ? A : never }> +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual(O.struct({ a: O.some(1), b: O.some('hello') }), O.some({ a: 1, b: 'hello' })) +assert.deepStrictEqual(O.struct({ a: O.some(1), b: O.none() }), O.none()) +``` + +Added in v1.0.0 + +## traverse + +Applies an `Option` value to an effectful function that returns an `F` value. + +**Signature** + +```ts +export declare const traverse: ( + F: applicative.Applicative +) => { + (f: (a: A) => Kind): (self: Option) => Kind> + (self: Option, f: (a: A) => Kind): Kind> +} +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' +import * as E from '@fp-ts/core/Either' + +const traverse = O.traverse(E.Applicative) +const f = (n: number) => (n >= 0 ? E.right(1) : E.left('negative')) + +assert.deepStrictEqual(traverse(O.some(1), f), E.right(O.some(1))) +assert.deepStrictEqual(traverse(O.some(-1), f), E.left('negative')) +assert.deepStrictEqual(traverse(O.none(), f), E.right(O.none())) +``` + +Added in v1.0.0 + +## traverseTap + +**Signature** + +```ts +export declare const traverseTap: ( + F: applicative.Applicative +) => { + (self: Option, f: (a: A) => Kind): Kind> + (f: (a: A) => Kind): (self: Option) => Kind> +} +``` + +Added in v1.0.0 + +## tuple + +Similar to `Promise.all` but operates on `Option`s. + +Takes a tuple of `Option`s and returns an `Option` of a tuple of values. + +**Signature** + +```ts +export declare const tuple: []>( + ...elements: T +) => Option<{ [I in keyof T]: [T[I]] extends [Option] ? A : never }> +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual(O.tuple(O.some(1), O.some('hello')), O.some([1, 'hello'])) +assert.deepStrictEqual(O.tuple(O.some(1), O.none()), O.none()) +``` + +Added in v1.0.0 + ## zipWith Zips two `Option` values together using a provided function, returning a new `Option` of the result. @@ -1255,149 +1427,6 @@ assert.deepStrictEqual( Added in v1.0.0 -# sequencing - -## productAll - -Flattens a collection of `Option`s into a single `Option` that contains a list of all the `Some` values. -If there is a `None` value in the collection, it returns `None` as the result. - -**Signature** - -```ts -export declare const productAll: (collection: Iterable>) => Option -``` - -**Example** - -```ts -import * as O from '@fp-ts/core/Option' - -assert.deepStrictEqual(O.productAll([O.some(1), O.some(2), O.some(3)]), O.some([1, 2, 3])) -assert.deepStrictEqual(O.productAll([O.some(1), O.none(), O.some(3)]), O.none()) -``` - -Added in v1.0.0 - -## sequence - -Combines an `Option` of an `F`-structure to an `F`-structure of an `Option` with the same inner type. - -**Signature** - -```ts -export declare const sequence: ( - F: applicative.Applicative -) => (self: Option>) => Kind> -``` - -**Example** - -```ts -import * as O from '@fp-ts/core/Option' -import * as E from '@fp-ts/core/Either' - -const sequence = O.sequence(E.Applicative) - -assert.deepStrictEqual(sequence(O.some(E.right(1))), E.right(O.some(1))) -assert.deepStrictEqual(sequence(O.some(E.left('error'))), E.left('error')) -assert.deepStrictEqual(sequence(O.none()), E.right(O.none())) -``` - -Added in v1.0.0 - -## struct - -Takes a struct of `Option`s and returns an `Option` of a struct of values. - -**Signature** - -```ts -export declare const struct: >>( - fields: R -) => Option<{ [K in keyof R]: [R[K]] extends [Option] ? A : never }> -``` - -**Example** - -```ts -import * as O from '@fp-ts/core/Option' - -assert.deepStrictEqual(O.struct({ a: O.some(1), b: O.some('hello') }), O.some({ a: 1, b: 'hello' })) -assert.deepStrictEqual(O.struct({ a: O.some(1), b: O.none() }), O.none()) -``` - -Added in v1.0.0 - -## traverse - -Applies an `Option` value to an effectful function that returns an `F` value. - -**Signature** - -```ts -export declare const traverse: ( - F: applicative.Applicative -) => { - (f: (a: A) => Kind): (self: Option) => Kind> - (self: Option, f: (a: A) => Kind): Kind> -} -``` - -**Example** - -```ts -import * as O from '@fp-ts/core/Option' -import * as E from '@fp-ts/core/Either' - -const traverse = O.traverse(E.Applicative) -const f = (n: number) => (n >= 0 ? E.right(1) : E.left('negative')) - -assert.deepStrictEqual(traverse(O.some(1), f), E.right(O.some(1))) -assert.deepStrictEqual(traverse(O.some(-1), f), E.left('negative')) -assert.deepStrictEqual(traverse(O.none(), f), E.right(O.none())) -``` - -Added in v1.0.0 - -## traverseTap - -**Signature** - -```ts -export declare const traverseTap: ( - F: applicative.Applicative -) => { - (self: Option, f: (a: A) => Kind): Kind> - (f: (a: A) => Kind): (self: Option) => Kind> -} -``` - -Added in v1.0.0 - -## tuple - -Takes a tuple of `Option`s and returns an `Option` of a tuple of values. - -**Signature** - -```ts -export declare const tuple: []>( - ...elements: T -) => Option<{ [I in keyof T]: [T[I]] extends [Option] ? A : never }> -``` - -**Example** - -```ts -import * as O from '@fp-ts/core/Option' - -assert.deepStrictEqual(O.tuple(O.some(1), O.some('hello')), O.some([1, 'hello'])) -assert.deepStrictEqual(O.tuple(O.some(1), O.none()), O.none()) -``` - -Added in v1.0.0 - # sorting ## getOrder @@ -1859,21 +1888,6 @@ export declare const Traversable: traversable.Traversable Added in v1.0.0 -## appendElement - -Appends an element to the end of a tuple. - -**Signature** - -```ts -export declare const appendElement: { - (self: Option, that: Option): Option<[...A, B]> - (that: Option): (self: Option) => Option<[...A, B]> -} -``` - -Added in v1.0.0 - ## contains Returns a function that checks if an `Option` contains a given value using a provided `Equivalence` instance. diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index 0b9fbddda..3a9fab85c 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -14,6 +14,8 @@ Added in v1.0.0 - [combinators](#combinators) - [contramap](#contramap) +- [combining](#combining) + - [productAll](#productall) - [do notation](#do-notation) - [Do](#do) - [andThenBind](#andthenbind) @@ -84,6 +86,27 @@ export declare const contramap: { Added in v1.0.0 +# combining + +## productAll + +Similar to `Promise.all` but operates on `Predicate`s. + +``` +Iterable> -> Predicate +``` + +Given an iterable of `Predicate` returns an `Predicate>` that operates on arrays +by applying each predicate in the iterable in order until a predicate fails. + +**Signature** + +```ts +export declare const productAll: (collection: Iterable>) => Predicate +``` + +Added in v1.0.0 + # do notation ## Do @@ -742,7 +765,8 @@ Added in v1.0.0 ## appendElement -Appends an element to the end of a tuple. +This function appends a predicate to a tuple-like predicate, allowing you to create a new predicate that includes +the original elements and the new one. **Signature** @@ -815,6 +839,8 @@ Added in v1.0.0 ## tuple +Similar to `Promise.all` but operates on `Predicate`s. + **Signature** ```ts diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index fd2927a9d..2d0e2b014 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -14,6 +14,12 @@ Added in v1.0.0

Table of contents

+- [combining](#combining) + - [flatMap](#flatmap) + - [flatMapNonEmpty](#flatmapnonempty) + - [flatMapNullable](#flatmapnullable) + - [flatten](#flatten) + - [flattenNonEmpty](#flattennonempty) - [constructors](#constructors) - [empty](#empty) - [make](#make) @@ -109,7 +115,6 @@ Added in v1.0.0 - [getUnionMonoid](#getunionmonoid) - [getUnionSemigroup](#getunionsemigroup) - [lifting](#lifting) - - [every](#every) - [getOrder](#getorder) - [lift2](#lift2) - [liftEither](#lifteither) @@ -132,13 +137,8 @@ Added in v1.0.0 - [matchRight](#matchright) - [predicates](#predicates) - [contains](#contains) + - [every](#every) - [some](#some) -- [sequencing](#sequencing) - - [flatMap](#flatmap) - - [flatMapNonEmpty](#flatmapnonempty) - - [flatMapNullable](#flatmapnullable) - - [flatten](#flatten) - - [flattenNonEmpty](#flattennonempty) - [sorting](#sorting) - [sort](#sort) - [sortBy](#sortby) @@ -205,6 +205,69 @@ Added in v1.0.0 --- +# combining + +## flatMap + +**Signature** + +```ts +export declare const flatMap: { + (f: (a: A, i: number) => readonly B[]): (self: readonly A[]) => B[] + (self: readonly A[], f: (a: A, i: number) => readonly B[]): B[] +} +``` + +Added in v1.0.0 + +## flatMapNonEmpty + +**Signature** + +```ts +export declare const flatMapNonEmpty: { + (f: (a: A, i: number) => readonly [B, ...B[]]): (self: readonly [A, ...A[]]) => [B, ...B[]] + (self: readonly [A, ...A[]], f: (a: A, i: number) => readonly [B, ...B[]]): [B, ...B[]] +} +``` + +Added in v1.0.0 + +## flatMapNullable + +**Signature** + +```ts +export declare const flatMapNullable: { + (f: (a: A) => B | null | undefined): (self: readonly A[]) => NonNullable[] + (self: readonly A[], f: (a: A) => B | null | undefined): NonNullable[] +} +``` + +Added in v1.0.0 + +## flatten + +**Signature** + +```ts +export declare const flatten:
(self: readonly (readonly A[])[]) => A[] +``` + +Added in v1.0.0 + +## flattenNonEmpty + +**Signature** + +```ts +export declare const flattenNonEmpty: ( + self: readonly [readonly [A, ...A[]], ...(readonly [A, ...A[]])[]] +) => [A, ...A[]] +``` + +Added in v1.0.0 + # constructors ## empty @@ -1362,21 +1425,6 @@ Added in v1.0.0 # lifting -## every - -Check if a predicate holds true for every `ReadonlyArray` member. - -**Signature** - -```ts -export declare function every( - refinement: Refinement -): Refinement, ReadonlyArray> -export declare function every(predicate: Predicate): Predicate> -``` - -Added in v1.0.0 - ## getOrder This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. @@ -1604,77 +1652,29 @@ export declare const contains: (isEquivalent: (self: A, that: A) => boolean) Added in v1.0.0 -## some - -Check if a predicate holds true for any `ReadonlyArray` member. - -**Signature** - -```ts -export declare const some: (predicate: Predicate) => (self: readonly A[]) => self is readonly [A, ...A[]] -``` - -Added in v1.0.0 - -# sequencing - -## flatMap - -**Signature** - -```ts -export declare const flatMap: { - (f: (a: A, i: number) => readonly B[]): (self: readonly A[]) => B[] - (self: readonly A[], f: (a: A, i: number) => readonly B[]): B[] -} -``` - -Added in v1.0.0 - -## flatMapNonEmpty - -**Signature** - -```ts -export declare const flatMapNonEmpty: { - (f: (a: A, i: number) => readonly [B, ...B[]]): (self: readonly [A, ...A[]]) => [B, ...B[]] - (self: readonly [A, ...A[]], f: (a: A, i: number) => readonly [B, ...B[]]): [B, ...B[]] -} -``` - -Added in v1.0.0 +## every -## flatMapNullable +Check if a predicate holds true for every `ReadonlyArray` member. **Signature** ```ts -export declare const flatMapNullable: { - (f: (a: A) => B | null | undefined): (self: readonly A[]) => NonNullable[] - (self: readonly A[], f: (a: A) => B | null | undefined): NonNullable[] -} +export declare function every( + refinement: Refinement +): Refinement, ReadonlyArray> +export declare function every(predicate: Predicate): Predicate> ``` Added in v1.0.0 -## flatten - -**Signature** - -```ts -export declare const flatten: (self: readonly (readonly A[])[]) => A[] -``` - -Added in v1.0.0 +## some -## flattenNonEmpty +Check if a predicate holds true for some `ReadonlyArray` member. **Signature** ```ts -export declare const flattenNonEmpty: ( - self: readonly [readonly [A, ...A[]], ...(readonly [A, ...A[]])[]] -) => [A, ...A[]] +export declare const some: (predicate: Predicate) => (self: readonly A[]) => self is readonly [A, ...A[]] ``` Added in v1.0.0 diff --git a/docs/modules/Symbol.ts.md b/docs/modules/Symbol.ts.md index 15df595cc..848b1ef4c 100644 --- a/docs/modules/Symbol.ts.md +++ b/docs/modules/Symbol.ts.md @@ -14,6 +14,8 @@ Added in v1.0.0 - [guards](#guards) - [isSymbol](#issymbol) +- [instances](#instances) + - [Equivalence](#equivalence) --- @@ -39,3 +41,15 @@ assert.deepStrictEqual(isSymbol('a'), false) ``` Added in v1.0.0 + +# instances + +## Equivalence + +**Signature** + +```ts +export declare const Equivalence: equivalence.Equivalence +``` + +Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index 247638397..c15660b7c 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -20,6 +20,12 @@ Added in v1.0.0 - [combinators](#combinators) - [tap](#tap) - [combining](#combining) + - [andThenDiscard](#andthendiscard) + - [flatMap](#flatmap) + - [flatMapEither](#flatmapeither) + - [flatMapNullable](#flatmapnullable) + - [flatMapOption](#flatmapoption) + - [flatMapThese](#flatmapthese) - [getFirstLeftMonoid](#getfirstleftmonoid) - [getFirstLeftSemigroup](#getfirstleftsemigroup) - [getFirstRightOrBothSemigroup](#getfirstrightorbothsemigroup) @@ -130,13 +136,6 @@ Added in v1.0.0 - [match](#match) - [predicates](#predicates) - [exists](#exists) -- [sequencing](#sequencing) - - [andThenDiscard](#andthendiscard) - - [flatMap](#flatmap) - - [flatMapEither](#flatmapeither) - - [flatMapNullable](#flatmapnullable) - - [flatMapOption](#flatmapoption) - - [flatMapThese](#flatmapthese) - [traversing](#traversing) - [sequence](#sequence) - [traverse](#traverse) @@ -256,6 +255,118 @@ Added in v1.0.0 # combining +## andThenDiscard + +Sequences the specified effect after this effect, but ignores the value +produced by the effect. + +**Signature** + +```ts +export declare const andThenDiscard: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + A + > + (that: These): ( + self: These + ) => These +} +``` + +Added in v1.0.0 + +## flatMap + +**Signature** + +```ts +export declare const flatMap: { + (f: (a: A) => These): ( + self: These + ) => These + (self: These, f: (a: A) => These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + B + > +} +``` + +Added in v1.0.0 + +## flatMapEither + +**Signature** + +```ts +export declare const flatMapEither: { + (f: (a: A) => Either): ( + self: These + ) => These + (self: These, f: (a: A) => Either): These< + readonly [E1 | E2, ...(E1 | E2)[]], + B + > +} +``` + +Added in v1.0.0 + +## flatMapNullable + +**Signature** + +```ts +export declare const flatMapNullable: { + (f: (a: A) => B | null | undefined, onNullable: (a: A) => E2): ( + self: These + ) => These> + ( + self: These, + f: (a: A) => B | null | undefined, + onNullable: (a: A) => E2 + ): These> +} +``` + +Added in v1.0.0 + +## flatMapOption + +**Signature** + +```ts +export declare const flatMapOption: { + (f: (a: A) => O.Option, onNone: (a: A) => E2): ( + self: These + ) => These + (self: These, f: (a: A) => O.Option, onNone: (a: A) => E2): These< + readonly [E1 | E2, ...(E1 | E2)[]], + B + > +} +``` + +Added in v1.0.0 + +## flatMapThese + +**Signature** + +```ts +export declare const flatMapThese: { + (f: (a: A) => These): ( + self: These + ) => These + (self: These, f: (a: A) => These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + B + > +} +``` + +Added in v1.0.0 + ## getFirstLeftMonoid **Signature** @@ -1572,120 +1683,6 @@ export declare const exists: { Added in v1.0.0 -# sequencing - -## andThenDiscard - -Sequences the specified effect after this effect, but ignores the value -produced by the effect. - -**Signature** - -```ts -export declare const andThenDiscard: { - (self: These, that: These): These< - readonly [E1 | E2, ...(E1 | E2)[]], - A - > - (that: These): ( - self: These - ) => These -} -``` - -Added in v1.0.0 - -## flatMap - -**Signature** - -```ts -export declare const flatMap: { - (f: (a: A) => These): ( - self: These - ) => These - (self: These, f: (a: A) => These): These< - readonly [E1 | E2, ...(E1 | E2)[]], - B - > -} -``` - -Added in v1.0.0 - -## flatMapEither - -**Signature** - -```ts -export declare const flatMapEither: { - (f: (a: A) => Either): ( - self: These - ) => These - (self: These, f: (a: A) => Either): These< - readonly [E1 | E2, ...(E1 | E2)[]], - B - > -} -``` - -Added in v1.0.0 - -## flatMapNullable - -**Signature** - -```ts -export declare const flatMapNullable: { - (f: (a: A) => B | null | undefined, onNullable: (a: A) => E2): ( - self: These - ) => These> - ( - self: These, - f: (a: A) => B | null | undefined, - onNullable: (a: A) => E2 - ): These> -} -``` - -Added in v1.0.0 - -## flatMapOption - -**Signature** - -```ts -export declare const flatMapOption: { - (f: (a: A) => O.Option, onNone: (a: A) => E2): ( - self: These - ) => These - (self: These, f: (a: A) => O.Option, onNone: (a: A) => E2): These< - readonly [E1 | E2, ...(E1 | E2)[]], - B - > -} -``` - -Added in v1.0.0 - -## flatMapThese - -**Signature** - -```ts -export declare const flatMapThese: { - (f: (a: A) => These): ( - self: These - ) => These - (self: These, f: (a: A) => These): These< - readonly [E1 | E2, ...(E1 | E2)[]], - B - > -} -``` - -Added in v1.0.0 - # traversing ## sequence @@ -1888,6 +1885,8 @@ Added in v1.0.0 ## tuple +Similar to `Promise.all` but operates on `These`s. + **Signature** ```ts diff --git a/docs/modules/Tuple.ts.md b/docs/modules/Tuple.ts.md index 7992f7396..f18666e52 100644 --- a/docs/modules/Tuple.ts.md +++ b/docs/modules/Tuple.ts.md @@ -36,9 +36,11 @@ by applying each `Equivalence` to the corresponding element of the tuple. **Signature** ```ts -export declare const getEquivalence: ( - ...equivalences: { readonly [K in keyof A]: equivalence.Equivalence } -) => equivalence.Equivalence> +export declare const getEquivalence: []>( + ...predicates: T +) => equivalence.Equivalence< + Readonly<{ [I in keyof T]: [T[I]] extends [equivalence.Equivalence] ? A : never }> +> ``` Added in v1.0.0 @@ -72,9 +74,9 @@ of the tuple. **Signature** ```ts -export declare const getOrder: ( - ...orders: { readonly [K in keyof A]: order.Order } -) => order.Order> +export declare const getOrder: []>( + ...elements: T +) => order.Order<{ [I in keyof T]: [T[I]] extends [order.Order] ? A : never }> ``` Added in v1.0.0 @@ -89,9 +91,9 @@ It is useful when you need to combine two tuples of the same type and you have a **Signature** ```ts -export declare const getSemigroup: ( - ...semigroups: { readonly [K in keyof A]: semigroup.Semigroup } -) => semigroup.Semigroup +export declare const getSemigroup: []>( + ...elements: T +) => semigroup.Semigroup<{ [I in keyof T]: [T[I]] extends [semigroup.Semigroup] ? A : never }> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Chainable.ts.md b/docs/modules/typeclass/Chainable.ts.md index 311a635dc..6b1a4793f 100644 --- a/docs/modules/typeclass/Chainable.ts.md +++ b/docs/modules/typeclass/Chainable.ts.md @@ -12,10 +12,10 @@ Added in v1.0.0

Table of contents

+- [combining](#combining) + - [andThenDiscard](#andthendiscard) - [do notation](#do-notation) - [bind](#bind) -- [sequencing](#sequencing) - - [andThenDiscard](#andthendiscard) - [type class](#type-class) - [Chainable (interface)](#chainable-interface) - [utils](#utils) @@ -23,34 +23,7 @@ Added in v1.0.0 --- -# do notation - -## bind - -**Signature** - -```ts -export declare const bind: ( - F: Chainable -) => { - (name: Exclude, f: (a: A) => Kind): < - R1, - O1, - E1 - >( - self: Kind - ) => Kind - ( - self: Kind, - name: Exclude, - f: (a: A) => Kind - ): Kind -} -``` - -Added in v1.0.0 - -# sequencing +# combining ## andThenDiscard @@ -78,6 +51,33 @@ export declare const andThenDiscard: ( Added in v1.0.0 +# do notation + +## bind + +**Signature** + +```ts +export declare const bind: ( + F: Chainable +) => { + (name: Exclude, f: (a: A) => Kind): < + R1, + O1, + E1 + >( + self: Kind + ) => Kind + ( + self: Kind, + name: Exclude, + f: (a: A) => Kind + ): Kind +} +``` + +Added in v1.0.0 + # type class ## Chainable (interface) diff --git a/docs/modules/typeclass/Equivalence.ts.md b/docs/modules/typeclass/Equivalence.ts.md index 24453aec6..513c2eb8d 100644 --- a/docs/modules/typeclass/Equivalence.ts.md +++ b/docs/modules/typeclass/Equivalence.ts.md @@ -19,9 +19,10 @@ Added in v1.0.0 - [combinators](#combinators) - [array](#array) - [contramap](#contramap) - - [record](#record) - [struct](#struct) - [tuple](#tuple) +- [combining](#combining) + - [all](#all) - [constructors](#constructors) - [make](#make) - [strict](#strict) @@ -48,10 +49,6 @@ Added in v1.0.0 ## array -Given an `Equivalence` of type `A`, returns a new `Equivalence` of type `ReadonlyArray
`. -The returned `Equivalence` compares arrays by first checking their length and then applying the provided `Equivalence` to each element. -If all comparisons return true, the arrays are considered equal. - **Signature** ```ts @@ -73,46 +70,55 @@ export declare const contramap: { Added in v1.0.0 -## record +## struct -Given an `Equivalence` of type `A`, returns a new `Equivalence` of type `{ readonly [x: string]: A }`. -The returned `Equivalence` compares records by first checking their number of keys and then applying the provided `Equivalence` to each value. -If all comparisons return true, the records are considered equal. +Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct +by applying each `Equivalence` to the corresponding property of the struct. **Signature** ```ts -export declare const record: (equivalence: Equivalence) => Equivalence> +export declare const struct: >>( + predicates: R +) => Equivalence<{ readonly [K in keyof R]: [R[K]] extends [Equivalence] ? A : never }> ``` Added in v1.0.0 -## struct +## tuple -Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct -by applying each `Equivalence` to the corresponding property of the struct. +Similar to `Promise.all` but operates on `Equivalence`s. + +Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple +by applying each `Equivalence` to the corresponding element of the tuple. **Signature** ```ts -export declare const struct: (equivalences: { [K in keyof A]: Equivalence }) => Equivalence<{ - readonly [K in keyof A]: A[K] -}> +export declare const tuple: []>( + ...predicates: T +) => Equivalence] ? A : never }>> ``` Added in v1.0.0 -## tuple +# combining -Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple -by applying each `Equivalence` to the corresponding element of the tuple. +## all + +Similar to `Promise.all` but operates on `Equivalence`s. + +``` +Iterable> -> Equivalence +``` + +Given an iterable of `Equivalence` returns an `Equivalence>` that operates on arrays +by applying each equivalence in the iterable in order until a difference is found. **Signature** ```ts -export declare const tuple: ( - ...equivalences: { readonly [K in keyof A]: Equivalence } -) => Equivalence> +export declare const all: (collection: Iterable>) => Equivalence ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Invariant.ts.md b/docs/modules/typeclass/Invariant.ts.md index 914d3ffce..fa6c6d712 100644 --- a/docs/modules/typeclass/Invariant.ts.md +++ b/docs/modules/typeclass/Invariant.ts.md @@ -6,6 +6,11 @@ parent: Modules ## Invariant overview +The `Invariant` typeclass is a higher-order abstraction over types that allow mapping the contents of a type in both directions. +It is similar to the `Covariant` typeclass but provides an `imap` opration, which allows transforming a value in both directions. +This typeclass is useful when dealing with data types that can be converted to and from some other types. +The `imap` operation provides a way to convert such data types to other types that they can interact with while preserving their invariants. + Added in v1.0.0 --- @@ -79,6 +84,8 @@ Added in v1.0.0 ## tupled +Convert a value in a singleton array in a given effect. + **Signature** ```ts diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index 3fb15fc44..c1f64d49a 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -98,6 +98,8 @@ Added in v1.0.0 ## tuple +Similar to `Promise.all` but operates on `Monoid`s. + This function creates and returns a new `Monoid` for a tuple of values based on the given `Monoid`s for each element in the tuple. The returned `Monoid` combines two tuples of the same type by applying the corresponding `Monoid` passed as arguments to each element in the tuple. diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index 268baebed..ee9046440 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -17,6 +17,8 @@ Added in v1.0.0 - [contramap](#contramap) - [struct](#struct) - [tuple](#tuple) +- [combining](#combining) + - [all](#all) - [constructors](#constructors) - [make](#make) - [instances](#instances) @@ -85,15 +87,17 @@ for each property in the struct. **Signature** ```ts -export declare const struct: (orders: { readonly [K in keyof A]: Order }) => Order<{ - readonly [K in keyof A]: A[K] -}> +export declare const struct: }>( + fields: R +) => Order<{ [K in keyof R]: [R[K]] extends [Order] ? A : never }> ``` Added in v1.0.0 ## tuple +Similar to `Promise.all` but operates on `Order`s. + This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. The returned `Order` compares two tuples of the same type by applying the corresponding `Order` to each element in the tuple. It is useful when you need to compare two tuples of the same type and you have a specific way of comparing each element @@ -102,9 +106,30 @@ of the tuple. **Signature** ```ts -export declare const tuple: ( - ...orders: { readonly [K in keyof A]: Order } -) => Order> +export declare const tuple: []>( + ...elements: T +) => Order<{ [I in keyof T]: [T[I]] extends [Order] ? A : never }> +``` + +Added in v1.0.0 + +# combining + +## all + +Similar to `Promise.all` but operates on `Order`s. + +``` +Iterable> -> Order +``` + +Given an iterable of `Order` returns an `Order>` that operates on arrays +by applying each order in the iterable in order until a difference is found. + +**Signature** + +```ts +export declare const all: (collection: Iterable>) => Order ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index be1e901f8..8dc71b4d3 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -17,6 +17,8 @@ Added in v1.0.0 - [mutableArray](#mutablearray) - [struct](#struct) - [tuple](#tuple) +- [combining](#combining) + - [all](#all) - [constructors](#constructors) - [constant](#constant) - [make](#make) @@ -86,15 +88,17 @@ It is useful when you need to combine two structs of the same type and you have **Signature** ```ts -export declare const struct: (semigroups: { readonly [K in keyof A]: Semigroup }) => Semigroup<{ - readonly [K in keyof A]: A[K] -}> +export declare const struct: }>( + fields: R +) => Semigroup<{ [K in keyof R]: [R[K]] extends [Semigroup] ? A : never }> ``` Added in v1.0.0 ## tuple +Similar to `Promise.all` but operates on `Semigroup`s. + This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. @@ -103,9 +107,27 @@ It is useful when you need to combine two tuples of the same type and you have a **Signature** ```ts -export declare const tuple: ( - ...semigroups: { readonly [K in keyof A]: Semigroup } -) => Semigroup +export declare const tuple: []>( + ...elements: T +) => Semigroup<{ [I in keyof T]: [T[I]] extends [Semigroup] ? A : never }> +``` + +Added in v1.0.0 + +# combining + +## all + +Similar to `Promise.all` but operates on `Semigroup`s. + +``` +Iterable> -> Semigroup +``` + +**Signature** + +```ts +export declare const all: (collection: Iterable>) => Semigroup ``` Added in v1.0.0 diff --git a/guides/Either.md b/guides/Either.md index a37855a80..5f6bb7808 100644 --- a/guides/Either.md +++ b/guides/Either.md @@ -578,11 +578,14 @@ This is because the `zipWith` function only combines the values if both `Either` **Cheat sheet** (combining) -| Name | Given | To | -| ------------ | ----------------------------------------------- | --------------------- | -| `zipWith` | `Either`, `Either`, `(A, B) => C` | `Either` | -| `productAll` | `Iterable>` | `Either` | -| `ap` | `Either B>`, `Either` | `Either` | +| Name | Given | To | +| --------------- | ----------------------------------------------- | ---------------------------------------------- | +| `zipWith` | `Either`, `Either`, `(A, B) => C` | `Either` | +| `tuple` | `[Either, Either, ...]` | `Either` | +| `struct` | `{ a: Either, b: Either, ... }` | `Either` | +| `all` | `Iterable>` | `Either` | +| `appendElement` | `Either`, `Either` | `Either` | +| `ap` | `Either B>`, `Either` | `Either` | For convenience, a series of algebraic operations such as sums and products are exported. diff --git a/guides/Option.md b/guides/Option.md index 378580d21..6e7dd8ae9 100644 --- a/guides/Option.md +++ b/guides/Option.md @@ -708,11 +708,14 @@ console.log(combine); // none() **Cheat sheet** (combining) -| **Function** | **Given input** | **Resulting Output** | -| ------------ | --------------------------------------- | -------------------- | -| `zipWith` | `Option`, `Option`, `(A, B) => C` | `Option` | -| `productAll` | `Iterable>` | `Option` | -| `ap` | `Option<(a: A) => B>`, `Option` | `Option` | +| **Function** | **Given input** | **Resulting Output** | +| --------------- | --------------------------------------- | ----------------------------- | +| `zipWith` | `Option`, `Option`, `(A, B) => C` | `Option` | +| `tuple` | `[Option, Option, ...]` | `Option<[A, B, ...]>` | +| `struct` | `{ a: Option, b: Option, ... }` | `Option<{ a: A, b: B, ... }>` | +| `all` | `Iterable>` | `Option` | +| `appendElement` | `Option<[A, B, ...]>`, `Option` | `Option<[A, B, ..., C]>` | +| `ap` | `Option<(a: A) => B>`, `Option` | `Option` | ## Algebraic operations with `Option`s diff --git a/src/Either.ts b/src/Either.ts index c191e4e48..2f4895bd4 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -400,7 +400,7 @@ export const Pointed: pointed.Pointed = { } /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flatMap: { @@ -461,7 +461,7 @@ export const Chainable: chainable.Chainable = { * Sequences the specified effect after this effect, but ignores the value * produced by the effect. * - * @category sequencing + * @category combining * @since 1.0.0 */ export const andThenDiscard: { @@ -526,21 +526,27 @@ export const appendElement: { } = semiProduct.appendElement(SemiProduct) /** + * Similar to `Promise.all` but operates on `Either`s. + * + * ``` + * Iterable> -> Either + * ``` + * * Flattens a collection of `Either`s into a single `Either` that contains a list of all the `Right` values. - * If there is a `Left` value in the collection, it returns `Left` as the result. + * If there is a `Left` value in the collection, it returns the first `Left` found as the result. * * @param collection - An iterable collection of `Either`s to flatten. * * @example * import * as E from "@fp-ts/core/Either" * - * assert.deepStrictEqual(E.productAll([E.right(1), E.right(2), E.right(3)]), E.right([1, 2, 3])) - * assert.deepStrictEqual(E.productAll([E.right(1), E.left("error"), E.right(3)]), E.left("error")) + * assert.deepStrictEqual(E.all([E.right(1), E.right(2), E.right(3)]), E.right([1, 2, 3])) + * assert.deepStrictEqual(E.all([E.right(1), E.left("error"), E.right(3)]), E.left("error")) * - * @category sequencing + * @category combining * @since 1.0.0 */ -export const productAll = ( +export const all = ( collection: Iterable> ): Either> => { const out: Array = [] @@ -562,10 +568,12 @@ export const Product: product_.Product = { imap, product, productMany, - productAll + productAll: all } /** + * Similar to `Promise.all` but operates on `Either`s. + * * @since 1.0.0 */ export const tuple: >>( @@ -643,7 +651,7 @@ export const Applicative: applicative.Applicative = { map, product, productMany, - productAll + productAll: all } /** @@ -938,7 +946,7 @@ export const liftNullable = , B, E>( export const merge: (self: Either) => E | A = match(identity, identity) /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flatMapNullable: { @@ -1271,7 +1279,7 @@ export const liftOption = , B, E>( ) => (...a: A): Either => fromOption(() => onNone(...a))(f(...a)) /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flatMapOption: { diff --git a/src/Option.ts b/src/Option.ts index 35aa6c8db..445b17403 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -419,6 +419,12 @@ export const firstSomeOf = (collection: Iterable>): Option => { } /** + * Similar to `Promise.all` but operates on `Option`s. + * + * ``` + * Iterable> -> Option + * ``` + * * Flattens a collection of `Option`s into a single `Option` that contains a list of all the `Some` values. * If there is a `None` value in the collection, it returns `None` as the result. * @@ -427,13 +433,13 @@ export const firstSomeOf = (collection: Iterable>): Option => { * @example * import * as O from "@fp-ts/core/Option" * - * assert.deepStrictEqual(O.productAll([O.some(1), O.some(2), O.some(3)]), O.some([1, 2, 3])) - * assert.deepStrictEqual(O.productAll([O.some(1), O.none(), O.some(3)]), O.none()) + * assert.deepStrictEqual(O.all([O.some(1), O.some(2), O.some(3)]), O.some([1, 2, 3])) + * assert.deepStrictEqual(O.all([O.some(1), O.none(), O.some(3)]), O.none()) * - * @category sequencing + * @category combining * @since 1.0.0 */ -export const productAll = (collection: Iterable>): Option> => { +export const all = (collection: Iterable>): Option> => { const out: Array = [] for (const o of collection) { if (isNone(o)) { @@ -857,10 +863,6 @@ export const tap: { (f: (a: A) => Option<_>): (self: Option) => Option } = chainable.tap(Chainable) -// ------------------------------------------------------------------------------------- -// debugging -// ------------------------------------------------------------------------------------- - /** * Useful for debugging purposes, the `onSome` callback is called with the value of `self` if it is a `Some`. * @@ -939,8 +941,18 @@ export const SemiProduct: semiProduct.SemiProduct = { } /** - * Appends an element to the end of a tuple. + * Appends an element to the end of a tuple wrapped in an `Option` type. + * + * @param self - The option of a tuple to which an element needs to be added. + * @param that - The element which needs to be added to the tuple. + * + * @example + * import * as O from "@fp-ts/core/Option" + * + * assert.deepStrictEqual(O.appendElement(O.some([1, 2]), O.some(3)), O.some([1, 2, 3])) + * assert.deepStrictEqual(O.appendElement(O.some([1, 2]), O.none()), O.none()) * + * @category combining * @since 1.0.0 */ export const appendElement: { @@ -956,10 +968,12 @@ export const Product: product_.Product = { imap, product, productMany, - productAll + productAll: all } /** + * Similar to `Promise.all` but operates on `Option`s. + * * Takes a tuple of `Option`s and returns an `Option` of a tuple of values. * * @param elements - the tuple of `Option`s to be sequenced. @@ -970,7 +984,7 @@ export const Product: product_.Product = { * assert.deepStrictEqual(O.tuple(O.some(1), O.some("hello")), O.some([1, "hello"])) * assert.deepStrictEqual(O.tuple(O.some(1), O.none()), O.none()) * - * @category sequencing + * @category combining * @since 1.0.0 */ export const tuple: >>( @@ -990,7 +1004,7 @@ export const tuple: >>( * assert.deepStrictEqual(O.struct({ a: O.some(1), b: O.some("hello") }), O.some({ a: 1, b: "hello" })) * assert.deepStrictEqual(O.struct({ a: O.some(1), b: O.none() }), O.none()) * - * @category sequencing + * @category combining * @since 1.0.0 */ export const struct: >>( @@ -1086,7 +1100,7 @@ export const Applicative: applicative.Applicative = { map, product, productMany, - productAll + productAll: all } /** @@ -1306,7 +1320,7 @@ export const filter: { * assert.deepStrictEqual(traverse(O.some(-1), f), E.left("negative")) * assert.deepStrictEqual(traverse(O.none(), f), E.right(O.none())) * - * @category sequencing + * @category combining * @since 1.0.0 */ export const traverse = ( @@ -1348,7 +1362,7 @@ export const Traversable: traversable.Traversable = { * assert.deepStrictEqual(sequence(O.some(E.left("error"))), E.left("error")) * assert.deepStrictEqual(sequence(O.none()), E.right(O.none())) * - * @category sequencing + * @category combining * @since 1.0.0 */ export const sequence: ( @@ -1357,7 +1371,7 @@ export const sequence: ( .sequence(Traversable) /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const traverseTap: ( diff --git a/src/Predicate.ts b/src/Predicate.ts index 58cb9f1be..5cc4dc146 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -458,25 +458,34 @@ const product = (self: Predicate, that: Predicate): Predicate self(a) && that(b) /** - * Flattens a collection of `Predicate`s into a single `Predicate` that tests a `ReadonlyArray` of values. + * Similar to `Promise.all` but operates on `Predicate`s. + * + * ``` + * Iterable> -> Predicate + * ``` + * + * Given an iterable of `Predicate` returns an `Predicate>` that operates on arrays + * by applying each predicate in the iterable in order until a predicate fails. * * @param collection - An iterable collection of `Predicate`s to flatten. * - * @category sequencing + * @category combining * @since 1.0.0 */ -const productAll = ( +export const productAll = ( collection: Iterable> -): Predicate> => - (as) => { - const predicates = readonlyArray.fromIterable(collection) - for (let i = 0; i < predicates.length; i++) { +): Predicate> => { + const predicates = readonlyArray.fromIterable(collection) + return (as) => { + const len = Math.min(as.length, predicates.length) + for (let i = 0; i < len; i++) { if (predicates[i](as[i]) === false) { return false } } return true } +} const productMany = ( self: Predicate, @@ -509,7 +518,11 @@ export const Product: product_.Product = { } /** - * Appends an element to the end of a tuple. + * This function appends a predicate to a tuple-like predicate, allowing you to create a new predicate that includes + * the original elements and the new one. + * + * @param self - The tuple-like predicate to append to. + * @param that - The predicate to append. * * @since 1.0.0 */ @@ -524,6 +537,8 @@ export const appendElement: { } = semiProduct.appendElement(SemiProduct) as any /** + * Similar to `Promise.all` but operates on `Predicate`s. + * * @since 1.0.0 */ export const tuple: >>( diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index d8902c488..1e76360d4 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -1478,7 +1478,7 @@ export const Pointed: pointed.Pointed = { } /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flatMap: { @@ -1499,7 +1499,7 @@ export const flatMap: { ) /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flatMapNonEmpty: { @@ -1521,14 +1521,14 @@ export const FlatMap: flatMap_.FlatMap = { } /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flatten: (self: ReadonlyArray>) => Array = flatMap_ .flatten(FlatMap) as any /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flattenNonEmpty: ( @@ -2101,7 +2101,7 @@ export const liftNullable = , B>( ): (...a: A) => Array> => (...a) => fromNullable(f(...a)) /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flatMapNullable: { @@ -2128,7 +2128,7 @@ export const liftEither = , E, B>( /** * Check if a predicate holds true for every `ReadonlyArray` member. * - * @category lifting + * @category predicates * @since 1.0.0 */ export function every( @@ -2140,7 +2140,7 @@ export function every(predicate: Predicate): Predicate> { } /** - * Check if a predicate holds true for any `ReadonlyArray` member. + * Check if a predicate holds true for some `ReadonlyArray` member. * * @category predicates * @since 1.0.0 diff --git a/src/Symbol.ts b/src/Symbol.ts index 0bd198ac5..82d3781be 100644 --- a/src/Symbol.ts +++ b/src/Symbol.ts @@ -3,6 +3,7 @@ */ import * as predicate from "@fp-ts/core/Predicate" +import * as equivalence from "@fp-ts/core/typeclass/Equivalence" /** * Tests if a value is a `symbol`. @@ -19,3 +20,9 @@ import * as predicate from "@fp-ts/core/Predicate" * @since 1.0.0 */ export const isSymbol: (u: unknown) => u is symbol = predicate.isSymbol + +/** + * @category instances + * @since 1.0.0 + */ +export const Equivalence: equivalence.Equivalence = equivalence.symbol diff --git a/src/These.ts b/src/These.ts index c9b1d8445..33e830ed6 100644 --- a/src/These.ts +++ b/src/These.ts @@ -486,7 +486,7 @@ export const liftNullable = , B, E>( ) => (...a: A): These> => fromNullable(() => onNullable(...a))(f(...a)) /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flatMapNullable: { @@ -577,7 +577,7 @@ export const liftThese = , E, B>( ) => (...a: A): Validated => toValidated(f(...a)) /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flatMapOption: { @@ -597,7 +597,7 @@ export const flatMapOption: { ): Validated => flatMap(self, liftOption(f, (a) => [onNone(a)]))) /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flatMapEither: { @@ -610,7 +610,7 @@ export const flatMapEither: { ) /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flatMapThese: { @@ -1203,7 +1203,17 @@ const product = ( return both(RA.appendAllNonEmpty(self.left, that.left), [self.right, that.right]) } -const productAll = ( +/** + * Similar to `Promise.all` but operates on `These`s. + * + * ``` + * Iterable> -> These + * ``` + * + * @category combining + * @since 1.0.0 + */ +const all = ( collection: Iterable> ): Validated> => { const rights: Array = [] @@ -1230,8 +1240,7 @@ const productAll = ( const productMany = ( self: Validated, collection: Iterable> -): Validated]> => - map(product(self, productAll(collection)), ([a, as]) => [a, ...as]) +): Validated]> => map(product(self, all(collection)), ([a, as]) => [a, ...as]) /** * @category instances @@ -1324,10 +1333,12 @@ export const Product: product_.Product = { imap, product, productMany, - productAll + productAll: all } /** + * Similar to `Promise.all` but operates on `These`s. + * * @since 1.0.0 */ export const tuple: >>(...tuple: T) => Validated< @@ -1347,7 +1358,7 @@ export const struct: >>( .struct(Product) /** - * @category sequencing + * @category combining * @since 1.0.0 */ export const flatMap: { @@ -1383,7 +1394,7 @@ export const Applicative: applicative.Applicative = { map, product, productMany, - productAll + productAll: all } /** @@ -1445,7 +1456,7 @@ export const Chainable: chainable.Chainable = { * Sequences the specified effect after this effect, but ignores the value * produced by the effect. * - * @category sequencing + * @category combining * @since 1.0.0 */ export const andThenDiscard: { diff --git a/src/Tuple.ts b/src/Tuple.ts index 0725bcf65..83e1b8557 100644 --- a/src/Tuple.ts +++ b/src/Tuple.ts @@ -22,9 +22,11 @@ export const tuple = >(...elements: A): A => elemen * @category combinators * @since 1.0.0 */ -export const getEquivalence: >( - ...equivalences: { readonly [K in keyof A]: equivalence.Equivalence } -) => equivalence.Equivalence> = equivalence.tuple +export const getEquivalence: >>( + ...predicates: T +) => equivalence.Equivalence< + Readonly<{ [I in keyof T]: [T[I]] extends [equivalence.Equivalence] ? A : never }> +> = equivalence.tuple /** * This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. @@ -35,9 +37,10 @@ export const getEquivalence: >( * @category combinators * @since 1.0.0 */ -export const getOrder: >( - ...orders: { readonly [K in keyof A]: order.Order } -) => order.Order> = order.tuple +export const getOrder: >>( + ...elements: T +) => order.Order<{ [I in keyof T]: [T[I]] extends [order.Order] ? A : never }> = + order.tuple /** * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. diff --git a/src/typeclass/Chainable.ts b/src/typeclass/Chainable.ts index 79ee02aee..a10bbf3da 100644 --- a/src/typeclass/Chainable.ts +++ b/src/typeclass/Chainable.ts @@ -16,7 +16,7 @@ export interface Chainable extends FlatMap, Covariant(F: Chainable): { diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 77c2fd593..8f9474df2 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -7,12 +7,12 @@ */ import { dual } from "@fp-ts/core/Function" import type { TypeLambda } from "@fp-ts/core/HKT" -import type { ReadonlyRecord } from "@fp-ts/core/ReadonlyRecord" +import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" import * as monoid from "@fp-ts/core/typeclass/Monoid" -import type * as product_ from "@fp-ts/core/typeclass/Product" +import * as product_ from "@fp-ts/core/typeclass/Product" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" @@ -80,74 +80,6 @@ export const bigint: Equivalence = strict() */ export const symbol: Equivalence = strict() -/** - * Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple - * by applying each `Equivalence` to the corresponding element of the tuple. - * - * @category combinators - * @since 1.0.0 - */ -export const tuple = >( - ...equivalences: { readonly [K in keyof A]: Equivalence } -): Equivalence> => - make((x, y) => equivalences.every((equivalence, i) => equivalence(x[i], y[i]))) - -/** - * Given an `Equivalence` of type `A`, returns a new `Equivalence` of type `ReadonlyArray`. - * The returned `Equivalence` compares arrays by first checking their length and then applying the provided `Equivalence` to each element. - * If all comparisons return true, the arrays are considered equal. - * - * @category combinators - * @since 1.0.0 - */ -export const array = ( - equivalence: Equivalence -): Equivalence> => - make((x, y) => x.length === y.length && x.every((a, i) => equivalence(a, y[i]))) - -/** - * Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct - * by applying each `Equivalence` to the corresponding property of the struct. - * - * @category combinators - * @since 1.0.0 - */ -export const struct = ( - equivalences: { [K in keyof A]: Equivalence } -): Equivalence<{ readonly [K in keyof A]: A[K] }> => - make((x, y) => { - for (const key in equivalences) { - if (!equivalences[key](x[key], y[key])) { - return false - } - } - return true - }) - -/** - * Given an `Equivalence` of type `A`, returns a new `Equivalence` of type `{ readonly [x: string]: A }`. - * The returned `Equivalence` compares records by first checking their number of keys and then applying the provided `Equivalence` to each value. - * If all comparisons return true, the records are considered equal. - * - * @category combinators - * @since 1.0.0 - */ -export const record = ( - equivalence: Equivalence -): Equivalence> => - make((x, y) => { - const keys = Object.keys(x) - if (Object.keys(y).length !== keys.length) { - return false - } - for (const key of keys) { - if (!equivalence(x[key], y[key])) { - return false - } - } - return true - }) - /** * @category instances * @since 1.0.0 @@ -210,12 +142,41 @@ export const Invariant: invariant.Invariant = { } const product = (self: Equivalence, that: Equivalence): Equivalence<[A, B]> => - tuple(self, that) + make(([xa, xb], [ya, yb]) => self(xa, ya) && that(xb, yb)) + +/** + * Similar to `Promise.all` but operates on `Equivalence`s. + * + * ``` + * Iterable> -> Equivalence + * ``` + * + * Given an iterable of `Equivalence` returns an `Equivalence>` that operates on arrays + * by applying each equivalence in the iterable in order until a difference is found. + * + * @category combining + * @since 1.0.0 + */ +export const all = (collection: Iterable>): Equivalence> => { + const equivalences = readonlyArray.fromIterable(collection) + return make((x, y) => { + const len = Math.min(x.length, y.length, equivalences.length) + for (let i = 0; i < len; i++) { + if (!equivalences[i](x[i], y[i])) { + return false + } + } + return true + }) +} const productMany = ( self: Equivalence, collection: Iterable> -): Equivalence<[A, ...Array]> => tuple(self, ...collection) +): Equivalence<[A, ...Array]> => { + const equivalence = all(collection) + return make((x, y) => !self(x[0], y[0]) ? false : equivalence(x.slice(1), y.slice(1))) +} /** * @category instances @@ -229,17 +190,57 @@ export const SemiProduct: semiProduct.SemiProduct = { const of: (a: A) => Equivalence = () => isAlwaysEquivalent -const productAll = (collection: Iterable>): Equivalence> => - tuple>(...collection) - /** * @category instances * @since 1.0.0 */ export const Product: product_.Product = { of, - imap: Invariant.imap, + imap, product, productMany, - productAll + productAll: all } + +/** + * Similar to `Promise.all` but operates on `Equivalence`s. + * + * Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple + * by applying each `Equivalence` to the corresponding element of the tuple. + * + * @category combinators + * @since 1.0.0 + */ +export const tuple: >>( + ...predicates: T +) => Equivalence] ? A : never }>> = + product_.tuple(Product) + +/** + * @category combinators + * @since 1.0.0 + */ +export const array = ( + equivalence: Equivalence +): Equivalence> => + make((x, y) => { + const len = Math.min(x.length, y.length) + for (let i = 0; i < len; i++) { + if (!equivalence(x[i], y[i])) { + return false + } + } + return true + }) + +/** + * Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct + * by applying each `Equivalence` to the corresponding property of the struct. + * + * @category combinators + * @since 1.0.0 + */ +export const struct: >>( + predicates: R +) => Equivalence<{ readonly [K in keyof R]: [R[K]] extends [Equivalence] ? A : never }> = + product_.struct(Product) diff --git a/src/typeclass/Invariant.ts b/src/typeclass/Invariant.ts index 738621cf7..5fe81b80b 100644 --- a/src/typeclass/Invariant.ts +++ b/src/typeclass/Invariant.ts @@ -1,4 +1,9 @@ /** + * The `Invariant` typeclass is a higher-order abstraction over types that allow mapping the contents of a type in both directions. + * It is similar to the `Covariant` typeclass but provides an `imap` opration, which allows transforming a value in both directions. + * This typeclass is useful when dealing with data types that can be converted to and from some other types. + * The `imap` operation provides a way to convert such data types to other types that they can interact with while preserving their invariants. + * * @since 1.0.0 */ import { dual } from "@fp-ts/core/Function" @@ -57,6 +62,8 @@ export const bindTo = (F: Invariant): { F.imap(self, a => ({ [name]: a } as any), ({ [name]: a }) => a)) /** + * Convert a value in a singleton array in a given effect. + * * @since 1.0.0 */ export const tupled = ( diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index 85eb51462..5e6399a1b 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -140,6 +140,8 @@ export const booleanXor: Monoid = fromSemigroup(semigroup.booleanXor, f export const booleanEqv: Monoid = fromSemigroup(semigroup.booleanEqv, true) /** + * Similar to `Promise.all` but operates on `Monoid`s. + * * This function creates and returns a new `Monoid` for a tuple of values based on the given `Monoid`s for each element in the tuple. * The returned `Monoid` combines two tuples of the same type by applying the corresponding `Monoid` passed as arguments to each element in the tuple. * diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index cbcbafb2d..8f94cf1a5 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -3,11 +3,12 @@ */ import { dual } from "@fp-ts/core/Function" import type { TypeLambda } from "@fp-ts/core/HKT" +import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import * as contravariant from "@fp-ts/core/typeclass/Contravariant" import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Monoid } from "@fp-ts/core/typeclass/Monoid" import * as monoid from "@fp-ts/core/typeclass/Monoid" -import type * as product_ from "@fp-ts/core/typeclass/Product" +import * as product_ from "@fp-ts/core/typeclass/Product" import type { Semigroup } from "@fp-ts/core/typeclass/Semigroup" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" @@ -62,72 +63,6 @@ export const boolean: Order = make((self, that) => self < that ? -1 : 1 */ export const bigint: Order = make((self, that) => self < that ? -1 : 1) -/** - * This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. - * The returned `Order` compares two tuples of the same type by applying the corresponding `Order` to each element in the tuple. - * It is useful when you need to compare two tuples of the same type and you have a specific way of comparing each element - * of the tuple. - * - * @category combinators - * @since 1.0.0 - */ -export const tuple = >( - ...orders: { readonly [K in keyof A]: Order } -): Order> => - make((self, that) => { - let i = 0 - for (; i < orders.length - 1; i++) { - const r = orders[i].compare(self[i], that[i]) - if (r !== 0) { - return r - } - } - return orders[i].compare(self[i], that[i]) - }) - -/** - * This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. - * The returned `Order` compares two arrays by applying the given `Order` to each element in the arrays. - * If all elements are equal, the arrays are then compared based on their length. - * It is useful when you need to compare two arrays of the same type and you have a specific way of comparing each element of the array. - * - * @category combinators - * @since 1.0.0 - */ -export const array = (O: Order): Order> => - make((self, that) => { - const aLen = self.length - const bLen = that.length - const len = Math.min(aLen, bLen) - for (let i = 0; i < len; i++) { - const o = O.compare(self[i], that[i]) - if (o !== 0) { - return o - } - } - return number.compare(aLen, bLen) - }) - -/** - * This function creates and returns a new `Order` for a struct of values based on the given `Order`s - * for each property in the struct. - * - * @category combinators - * @since 1.0.0 - */ -export const struct = (orders: { readonly [K in keyof A]: Order }): Order< - { readonly [K in keyof A]: A[K] } -> => - make((self, that) => { - for (const key of Object.keys(orders)) { - const o = orders[key].compare(self[key], that[key]) - if (o !== 0) { - return o - } - } - return 0 - }) - /** * @since 1.0.0 */ @@ -202,10 +137,49 @@ export const Invariant: invariant.Invariant = { imap } -const product = (self: Order, that: Order): Order<[A, B]> => tuple(self, that) +const product = (self: Order, that: Order): Order<[A, B]> => + make(([xa, xb], [ya, yb]) => { + const o = self.compare(xa, ya) + return o !== 0 ? o : that.compare(xb, yb) + }) + +/** + * Similar to `Promise.all` but operates on `Order`s. + * + * ``` + * Iterable> -> Order + * ``` + * + * Given an iterable of `Order` returns an `Order>` that operates on arrays + * by applying each order in the iterable in order until a difference is found. + * + * @category combining + * @since 1.0.0 + */ +export const all = (collection: Iterable>): Order> => { + const orders = readonlyArray.fromIterable(collection) + return make((x, y) => { + const len = Math.min(x.length, y.length, orders.length) + for (let i = 0; i < len; i++) { + const o = orders[i].compare(x[i], y[i]) + if (o !== 0) { + return o + } + } + return 0 + }) +} -const productMany = (self: Order, collection: Iterable>): Order<[A, ...Array]> => - tuple(self, ...collection) +const productMany = ( + self: Order, + collection: Iterable> +): Order<[A, ...Array]> => { + const order = all(collection) + return make((x, y) => { + const o = self.compare(x[0], y[0]) + return o !== 0 ? o : order.compare(x.slice(1), y.slice(1)) + }) +} /** * @category instances @@ -219,9 +193,6 @@ export const SemiProduct: semiProduct.SemiProduct = { const of: (a: A) => Order = () => empty -const productAll = (collection: Iterable>): Order> => - tuple>(...collection) - /** * @category instances * @since 1.0.0 @@ -229,11 +200,64 @@ const productAll = (collection: Iterable>): Order> => export const Product: product_.Product = { of, imap, - product: SemiProduct.product, - productMany: SemiProduct.productMany, - productAll + product, + productMany, + productAll: all } +/** + * Similar to `Promise.all` but operates on `Order`s. + * + * This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. + * The returned `Order` compares two tuples of the same type by applying the corresponding `Order` to each element in the tuple. + * It is useful when you need to compare two tuples of the same type and you have a specific way of comparing each element + * of the tuple. + * + * @category combinators + * @since 1.0.0 + */ +export const tuple: >>( + ...elements: T +) => Order<{ [I in keyof T]: [T[I]] extends [Order] ? A : never }> = product_.tuple( + Product +) + +/** + * This function creates and returns a new `Order` for an array of values based on a given `Order` for the elements of the array. + * The returned `Order` compares two arrays by applying the given `Order` to each element in the arrays. + * If all elements are equal, the arrays are then compared based on their length. + * It is useful when you need to compare two arrays of the same type and you have a specific way of comparing each element of the array. + * + * @category combinators + * @since 1.0.0 + */ +export const array = (O: Order): Order> => + make((self, that) => { + const aLen = self.length + const bLen = that.length + const len = Math.min(aLen, bLen) + for (let i = 0; i < len; i++) { + const o = O.compare(self[i], that[i]) + if (o !== 0) { + return o + } + } + return number.compare(aLen, bLen) + }) + +/** + * This function creates and returns a new `Order` for a struct of values based on the given `Order`s + * for each property in the struct. + * + * @category combinators + * @since 1.0.0 + */ +export const struct: }>( + fields: R +) => Order<{ [K in keyof R]: [R[K]] extends [Order] ? A : never }> = product_.struct( + Product +) + /** * Test whether one value is _strictly less than_ another. * diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 8679fbbee..547267294 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -4,9 +4,10 @@ import { dual } from "@fp-ts/core/Function" import type { TypeLambda } from "@fp-ts/core/HKT" import { fromIterable } from "@fp-ts/core/internal/ReadonlyArray" +import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type * as invariant from "@fp-ts/core/typeclass/Invariant" import type { Order } from "@fp-ts/core/typeclass/Order" -import type * as product_ from "@fp-ts/core/typeclass/Product" +import * as product_ from "@fp-ts/core/typeclass/Product" import type * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" /** @@ -167,60 +168,6 @@ export const booleanXor: Semigroup = make((self, that) => self !== that */ export const booleanEqv: Semigroup = make((self, that) => self === that) -/** - * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. - * The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. - * - * It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. - * - * @category combinators - * @since 1.0.0 - */ -export const tuple = >( - ...semigroups: { readonly [K in keyof A]: Semigroup } -): Semigroup => - make((self, that) => semigroups.map((S, i) => S.combine(self[i], that[i])) as any) - -/** - * Given a type `A`, this function creates and returns a `Semigroup` for `Array`. - * The returned `Semigroup` combines two arrays by concatenating them. - * - * @category combinators - * @since 1.0.0 - */ -export const mutableArray = (): Semigroup> => make((self, that) => self.concat(that)) - -/** - * Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. - * The returned `Semigroup` combines two arrays by concatenating them. - * - * @category combinators - * @since 1.0.0 - */ -export const array: () => Semigroup> = mutableArray as any - -/** - * This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. - * The returned `Semigroup` combines two structs of the same type by applying the corresponding `Semigroup` passed as arguments to each property in the struct. - * - * It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. - * - * @category combinators - * @since 1.0.0 - */ -export const struct = (semigroups: { readonly [K in keyof A]: Semigroup }): Semigroup< - { readonly [K in keyof A]: A[K] } -> => - make((self, that) => { - const r = {} as any - for (const k in semigroups) { - if (Object.prototype.hasOwnProperty.call(semigroups, k)) { - r[k] = semigroups[k].combine(self[k], that[k]) - } - } - return r - }) - /** * `Semigroup` that returns last minimum of elements. * @@ -319,12 +266,37 @@ export const Invariant: invariant.Invariant = { } const product = (self: Semigroup, that: Semigroup): Semigroup<[A, B]> => - tuple(self, that) + make(([xa, xb], [ya, yb]) => [self.combine(xa, ya), that.combine(xb, yb)]) + +/** + * Similar to `Promise.all` but operates on `Semigroup`s. + * + * ``` + * Iterable> -> Semigroup + * ``` + * + * @category combining + * @since 1.0.0 + */ +export const all = (collection: Iterable>): Semigroup> => { + const semigroups = readonlyArray.fromIterable(collection) + return make((x, y) => { + const len = Math.min(x.length, y.length, semigroups.length) + const out = [] + for (let i = 0; i < len; i++) { + out.push(semigroups[i].combine(x[i], y[i])) + } + return out + }) +} const productMany = ( self: Semigroup, collection: Iterable> -): Semigroup<[A, ...Array]> => tuple(self, ...collection) +): Semigroup<[A, ...Array]> => { + const semigroup = all(collection) + return make((x, y) => [self.combine(x[0], y[0]), ...semigroup.combine(x.slice(1), y.slice(1))]) +} /** * @category instances @@ -338,17 +310,62 @@ export const SemiProduct: semiProduct.SemiProduct = { const of: (a: A) => Semigroup = constant -const productAll = (collection: Iterable>): Semigroup> => - tuple>(...collection) - /** * @category instances * @since 1.0.0 */ export const Product: product_.Product = { of, - imap: Invariant.imap, + imap, product, productMany, - productAll + productAll: all } + +/** + * Similar to `Promise.all` but operates on `Semigroup`s. + * + * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. + * The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. + * + * It is useful when you need to combine two tuples of the same type and you have a specific way of combining each element of the tuple. + * + * @category combinators + * @since 1.0.0 + */ +export const tuple: >>( + ...elements: T +) => Semigroup<{ [I in keyof T]: [T[I]] extends [Semigroup] ? A : never }> = product_ + .tuple(Product) + +/** + * Given a type `A`, this function creates and returns a `Semigroup` for `Array`. + * The returned `Semigroup` combines two arrays by concatenating them. + * + * @category combinators + * @since 1.0.0 + */ +export const mutableArray = (): Semigroup> => make((self, that) => self.concat(that)) + +/** + * Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. + * The returned `Semigroup` combines two arrays by concatenating them. + * + * @category combinators + * @since 1.0.0 + */ +export const array: () => Semigroup> = mutableArray as any + +/** + * This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. + * The returned `Semigroup` combines two structs of the same type by applying the corresponding `Semigroup` passed as arguments to each property in the struct. + * + * It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. + * + * @category combinators + * @since 1.0.0 + */ +export const struct: }>( + fields: R +) => Semigroup<{ [K in keyof R]: [R[K]] extends [Semigroup] ? A : never }> = product_ + .struct(Product) diff --git a/test/Either.ts b/test/Either.ts index ece347dd1..ccbbdda5f 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -50,7 +50,7 @@ describe.concurrent("Either", () => { expect(E.SemiProduct).exist expect(E.Product).exist - expect(E.productAll).exist + expect(E.all).exist expect(E.tuple).exist expect(E.struct).exist diff --git a/test/Option.ts b/test/Option.ts index 6db47ba5a..dca618056 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -49,7 +49,7 @@ describe.concurrent("Option", () => { expect(_.SemiProduct).exist expect(_.Product).exist - expect(_.productAll).exist + expect(_.all).exist expect(_.tuple).exist expect(_.struct).exist diff --git a/test/Predicate.ts b/test/Predicate.ts index 0dc009046..ecf1e81da 100644 --- a/test/Predicate.ts +++ b/test/Predicate.ts @@ -78,8 +78,8 @@ describe.concurrent("Predicate", () => { }) it("productAll", () => { - const productAll = _.Product.productAll - const p = productAll([isPositive, isNegative]) + const p = _.productAll([isPositive, isNegative]) + deepStrictEqual(p([1]), true) deepStrictEqual(p([1, -1]), true) deepStrictEqual(p([1, 1]), false) deepStrictEqual(p([-1, -1]), false) diff --git a/test/Symbol.ts b/test/Symbol.ts index 85b8cecd2..ad271c9a2 100644 --- a/test/Symbol.ts +++ b/test/Symbol.ts @@ -8,4 +8,10 @@ describe.concurrent("Symbol", () => { expect(S.isSymbol("a")).toEqual(false) expect(S.isSymbol(true)).toEqual(false) }) + + it("Equivalence", () => { + const eq = S.Equivalence + expect(eq(Symbol.for("@fp-ts/core/test/a"), Symbol.for("@fp-ts/core/test/a"))).toBe(true) + expect(eq(Symbol.for("@fp-ts/core/test/a"), Symbol.for("@fp-ts/core/test/b"))).toBe(false) + }) }) diff --git a/test/typeclass/Equivalence.ts b/test/typeclass/Equivalence.ts index 8bef6a0b1..dcb6b3086 100644 --- a/test/typeclass/Equivalence.ts +++ b/test/typeclass/Equivalence.ts @@ -3,7 +3,12 @@ import * as _ from "@fp-ts/core/typeclass/Equivalence" describe("Equivalence", () => { it("exports", () => { + expect(_.Invariant).exists expect(_.Contravariant).exists + expect(_.SemiProduct).exists + expect(_.Product).exists + expect(_.tuple).exists + expect(_.struct).exists }) test("strict returns an Equivalence that uses strict equality (===) to compare values", () => { @@ -13,78 +18,6 @@ describe("Equivalence", () => { expect(eq({ a: 1 }, { a: 1 })).toBe(false) }) - it("bigint", () => { - const eq = _.bigint - expect(eq(1n, 1n)).toBe(true) - expect(eq(1n, 2n)).toBe(false) - }) - - it("symbol", () => { - const eq = _.symbol - expect(eq(Symbol.for("@fp-ts/core/test/a"), Symbol.for("@fp-ts/core/test/a"))).toBe(true) - expect(eq(Symbol.for("@fp-ts/core/test/a"), Symbol.for("@fp-ts/core/test/b"))).toBe(false) - }) - - it("tuple", () => { - const eqTuple = _.tuple(_.string, _.number, _.boolean) - expect(eqTuple(["a", 1, true], ["a", 1, true])).toEqual(true) - expect(eqTuple(["a", 1, true], ["b", 1, true])).toEqual(false) - expect(eqTuple(["a", 1, true], ["a", 2, true])).toEqual(false) - expect(eqTuple(["a", 1, true], ["a", 1, false])).toEqual(false) - }) - - describe("array", () => { - it("returns true when all the elements of the arrays are equal according to the provided Equivalence", () => { - const eqA = _.string - const eqArray = _.array(eqA) - expect(eqArray(["a", "b"], ["a", "b"])).toBe(true) - }) - - it("returns false when at least one element of the arrays is not equal according to the provided Equivalence", () => { - const eqA = _.string - const eqArray = _.array(eqA) - expect(eqArray(["a", "b"], ["b", "b"])).toBe(false) - expect(eqArray(["a", "b"], ["a", "c"])).toBe(false) - }) - - it("returns false when comparing arrays of different length", () => { - const eqA = _.string - const eqArray = _.array(eqA) - expect(eqArray(["a"], ["a", "b"])).toBe(false) - expect(eqArray(["a", "b"], ["a"])).toBe(false) - }) - }) - - describe("record", () => { - it("returns true when all the values of the records are equal according to the provided Equivalence", () => { - const eqA = _.string - const eqRecord = _.record(eqA) - expect(eqRecord({ a: "a", b: "b" }, { a: "a", b: "b" })).toBe(true) - }) - - it("returns false when at least one value of the records is not equal according to the provided Equivalence", () => { - const eqA = _.string - const eqRecord = _.record(eqA) - expect(eqRecord({ a: "a", b: "b" }, { a: "b", b: "b" })).toBe(false) - expect(eqRecord({ a: "a", b: "b" }, { a: "a", b: "c" })).toBe(false) - }) - - it("returns false when comparing records with a different number of keys", () => { - const eqA = _.string - const eqRecord = _.record(eqA) - expect(eqRecord({ a: "a" }, { a: "a", b: "b" })).toBe(false) - expect(eqRecord({ a: "a", b: "b" }, { a: "a" })).toBe(false) - }) - }) - - it("struct", () => { - const eqStruct = _.struct({ a: _.string, b: _.number, c: _.boolean }) - expect(eqStruct({ a: "a", b: 1, c: true }, { a: "a", b: 1, c: true })).toEqual(true) - expect(eqStruct({ a: "a", b: 1, c: true }, { a: "b", b: 1, c: true })).toEqual(false) - expect(eqStruct({ a: "a", b: 1, c: true }, { a: "a", b: 2, c: true })).toEqual(false) - expect(eqStruct({ a: "a", b: 1, c: true }, { a: "a", b: 1, c: false })).toEqual(false) - }) - it("contramap", () => { interface Person { readonly name: string @@ -128,38 +61,40 @@ describe("Equivalence", () => { expect(eqE0E1E2(["a", 1, true], ["a", 1, false])).toEqual(false) }) - it("Invariant", () => { - const eq = _.Invariant.imap((s: string) => [s], ([s]) => s)( - _.string - ) - expect(eq(["a"], ["a"])).toEqual(true) - expect(eq(["a"], ["b"])).toEqual(false) + it("of", () => { + const eq = _.Product.of([]) + expect(eq([], [])).toEqual(true) }) - it("SemiProduct/product", () => { - const eq = _.SemiProduct.product( - _.string, - _.string - ) + it("product", () => { + const eq = _.Product.product(_.string, _.string) expect(eq(["a", "b"], ["a", "b"])).toEqual(true) + expect(eq(["a", "b"], ["c", "b"])).toEqual(false) expect(eq(["a", "b"], ["a", "c"])).toEqual(false) }) - it("SemiProduct/productMany", () => { - const eq = _.SemiProduct.productMany(_.string, [_.string]) + it("productMany", () => { + const eq = _.Product.productMany(_.string, [_.string]) + expect(eq(["a", "b"], ["a", "b"])).toEqual(true) + expect(eq(["a", "b"], ["a", "b", "c"])).toEqual(true) + expect(eq(["a", "b", "c"], ["a", "b"])).toEqual(true) + expect(eq(["a", "b"], ["c", "b"])).toEqual(false) + expect(eq(["a", "b"], ["a", "c"])).toEqual(false) + }) + + it("all", () => { + const eq = _.all([_.string, _.string]) expect(eq(["a"], ["a"])).toEqual(true) expect(eq(["a"], ["b"])).toEqual(false) - expect(eq(["a"], ["a", "b"])).toEqual(false) expect(eq(["a", "b"], ["a", "b"])).toEqual(true) - expect(eq(["a", "b"], ["a", "b", "d"])).toEqual(true) - expect(eq(["a", "b", "c"], ["a", "b", "d"])).toEqual(true) + expect(eq(["a", "b"], ["a", "c"])).toEqual(false) }) - it("SemiProduct/productAll", () => { - const eq = _.Product.productAll([_.Product.of(""), _.string, _.string]) + it("array", () => { + const eq = _.array(_.string) expect(eq(["a"], ["a"])).toEqual(true) - expect(eq(["a"], ["b"])).toEqual(true) - expect(eq(["a", "c"], ["b", "c"])).toEqual(true) - expect(eq(["a", "c"], ["b", "d"])).toEqual(false) + expect(eq(["a"], ["b"])).toEqual(false) + expect(eq(["a", "b"], ["a", "b"])).toEqual(true) + expect(eq(["a", "b"], ["a", "c"])).toEqual(false) }) }) diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index 5ee002070..ae978ac1c 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -5,6 +5,7 @@ import * as U from "../util" describe("Order", () => { it("exports", () => { + expect(_.Invariant).exist expect(_.Contravariant).exist expect(_.string).exist expect(_.number).exist @@ -12,27 +13,14 @@ describe("Order", () => { expect(_.bigint).exist }) - it("bigint", () => { - const O = _.bigint - expect(pipe(1n, _.lessThanOrEqualTo(O)(2n))).toBe(true) - expect(pipe(1n, _.lessThanOrEqualTo(O)(1n))).toBe(true) - expect(pipe(1n, _.lessThan(O)(1n))).toBe(false) - expect(pipe(1n, _.lessThanOrEqualTo(O)(0n))).toBe(false) - }) - - it("tuple", () => { - const O = _.tuple(_.string, _.number, _.boolean) - U.deepStrictEqual(O.compare(["a", 1, true], ["b", 2, true]), -1) - U.deepStrictEqual(O.compare(["a", 1, true], ["a", 2, true]), -1) - U.deepStrictEqual(O.compare(["a", 1, true], ["a", 1, false]), 1) - }) - - it("struct", () => { - const O = _.struct({ a: _.string, b: _.number, c: _.boolean }) - U.deepStrictEqual(O.compare({ a: "a", b: 1, c: true }, { a: "b", b: 2, c: true }), -1) - U.deepStrictEqual(O.compare({ a: "a", b: 1, c: true }, { a: "a", b: 2, c: true }), -1) - U.deepStrictEqual(O.compare({ a: "a", b: 1, c: true }, { a: "a", b: 1, c: false }), 1) - U.deepStrictEqual(O.compare({ a: "a", b: 1, c: true }, { a: "a", b: 1, c: true }), 0) + it("all", () => { + const O = _.all([_.string, _.string]) + U.deepStrictEqual(O.compare(["a"], ["b"]), -1) + U.deepStrictEqual(O.compare(["a"], ["a"]), 0) + U.deepStrictEqual(O.compare(["b"], ["a"]), 1) + U.deepStrictEqual(O.compare(["a", "b"], ["a", "c"]), -1) + U.deepStrictEqual(O.compare(["a", "b"], ["a", "b"]), 0) + U.deepStrictEqual(O.compare(["a", "c"], ["a", "b"]), 1) }) it("contramap", () => { @@ -42,15 +30,6 @@ describe("Order", () => { U.deepStrictEqual(O.compare("aa", "b"), 1) }) - it("Invariant", () => { - const O = _.Invariant.imap((s: string) => [s], ([s]) => s)( - _.string - ) - U.deepStrictEqual(O.compare(["a"], ["b"]), -1) - U.deepStrictEqual(O.compare(["a"], ["a"]), 0) - U.deepStrictEqual(O.compare(["b"], ["a"]), 1) - }) - it("getSemigroup", () => { type T = [number, string] const tuples: Array = [ diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index ae381c20d..73f432725 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -7,6 +7,7 @@ import * as U from "../util" describe("Semigroup", () => { it("exports", () => { + expect(_.Invariant).exist expect(_.mutableArray).exists }) @@ -65,43 +66,6 @@ describe("Semigroup", () => { }) }) - it("struct", () => { - const S = _.struct({ - name: String.Semigroup, - age: Number.SemigroupSum - }) - U.deepStrictEqual(S.combine({ name: "a", age: 10 }, { name: "b", age: 20 }), { - name: "ab", - age: 30 - }) - U.deepStrictEqual(S.combineMany({ name: "a", age: 10 }, []), { - name: "a", - age: 10 - }) - U.deepStrictEqual(S.combineMany({ name: "a", age: 10 }, [{ name: "b", age: 20 }]), { - name: "ab", - age: 30 - }) - U.deepStrictEqual( - S.combineMany({ name: "a", age: 10 }, [{ name: "b", age: 20 }, { name: "c", age: 30 }]), - { - name: "abc", - age: 60 - } - ) - }) - - it("tuple", () => { - const S = _.tuple( - String.Semigroup, - Number.SemigroupSum - ) - U.deepStrictEqual(S.combine(["a", 10], ["b", 20]), ["ab", 30]) - U.deepStrictEqual(S.combineMany(["a", 10], []), ["a", 10]) - U.deepStrictEqual(S.combineMany(["a", 10], [["b", 20]]), ["ab", 30]) - U.deepStrictEqual(S.combineMany(["a", 10], [["b", 20], ["c", 30]]), ["abc", 60]) - }) - it("first", () => { const S = _.first() U.deepStrictEqual(S.combine(1, 2), 1) @@ -148,4 +112,9 @@ describe("Semigroup", () => { const S = _.SemiProduct.productMany(String.Semigroup, [String.Semigroup, String.Semigroup]) U.deepStrictEqual(S.combine(["a", "b", "c"], ["d", "e", "f"]), ["ad", "be", "cf"]) }) + + it("all", () => { + const S = _.all([String.Semigroup, String.Semigroup]) + U.deepStrictEqual(S.combine(["a1", "b1"], ["a2", "b2"]), ["a1a2", "b1b2"]) + }) }) From d732ea1fad36fd363ddffe9fb593b3400efb2369 Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 12 Feb 2023 14:49:51 +0100 Subject: [PATCH 242/255] Number: add missing functions (derivable from Order) --- .changeset/sour-suits-press.md | 5 + benchmark/Number/lessThan.ts | 28 +++ docs/modules/Either.ts.md | 4 + docs/modules/Number.ts.md | 235 +++++++++++++++++++++-- docs/modules/Option.ts.md | 4 + docs/modules/Predicate.ts.md | 158 ++++++++++----- docs/modules/Struct.ts.md | 24 +-- docs/modules/These.ts.md | 4 + docs/modules/Tuple.ts.md | 6 +- docs/modules/typeclass/Equivalence.ts.md | 4 + docs/modules/typeclass/Monoid.ts.md | 14 +- docs/modules/typeclass/Order.ts.md | 12 +- docs/modules/typeclass/Semigroup.ts.md | 4 + src/Either.ts | 4 + src/Number.ts | 219 +++++++++++++++++++-- src/Option.ts | 4 + src/Predicate.ts | 95 +++++++-- src/Struct.ts | 30 +-- src/These.ts | 4 + src/typeclass/Equivalence.ts | 4 + src/typeclass/Monoid.ts | 30 +-- src/typeclass/Order.ts | 18 +- src/typeclass/Semigroup.ts | 4 + test/Number.ts | 8 + 24 files changed, 782 insertions(+), 140 deletions(-) create mode 100644 .changeset/sour-suits-press.md create mode 100644 benchmark/Number/lessThan.ts diff --git a/.changeset/sour-suits-press.md b/.changeset/sour-suits-press.md new file mode 100644 index 000000000..7357042be --- /dev/null +++ b/.changeset/sour-suits-press.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Number: add missing functions (derivable from Order) diff --git a/benchmark/Number/lessThan.ts b/benchmark/Number/lessThan.ts new file mode 100644 index 000000000..bbc06584c --- /dev/null +++ b/benchmark/Number/lessThan.ts @@ -0,0 +1,28 @@ +import { dual } from "@fp-ts/core/Function"; +import { lessThan } from "@fp-ts/core/Number" +import * as Benchmark from "benchmark" + +/* +*/ + +const suite = new Benchmark.Suite() + +const lessThanBaseline: { + (that: number): (self: number) => boolean; + (self: number, that: number): boolean; +} = dual(2, (self: number, that: number): boolean => self < that) + +suite + .add("lessThanBaseline", function() { + lessThanBaseline(2, 1) + }) + .add("lessThan", function() { + lessThan(2, 1) + }) + .on("cycle", function(event: any) { + console.log(String(event.target)) + }) + .on("complete", function(this: any) { + console.log("Fastest is " + this.filter("fastest").map("name")) + }) + .run({ async: true }) diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index f12f4dcd7..76e011dff 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -1696,6 +1696,10 @@ Added in v1.0.0 Similar to `Promise.all` but operates on `Either`s. +``` +[Either, Either, ...] -> Either +``` + **Signature** ```ts diff --git a/docs/modules/Number.ts.md b/docs/modules/Number.ts.md index cb381fc4a..29a037fe3 100644 --- a/docs/modules/Number.ts.md +++ b/docs/modules/Number.ts.md @@ -38,9 +38,18 @@ Added in v1.0.0 - [SemigroupMin](#semigroupmin) - [SemigroupMultiply](#semigroupmultiply) - [SemigroupSum](#semigroupsum) +- [predicates](#predicates) + - [between](#between) + - [greaterThan](#greaterthan) + - [greaterThanOrEqualTo](#greaterthanorequalto) + - [lessThan](#lessthan) + - [lessThanOrEqualTo](#lessthanorequalto) - [utils](#utils) + - [clamp](#clamp) - [decrement](#decrement) - [increment](#increment) + - [max](#max) + - [min](#min) - [sign](#sign) --- @@ -49,6 +58,9 @@ Added in v1.0.0 ## divide +Provides a division operation on numbers. +It can be used as a binary function or a curried function. + **Signature** ```ts @@ -59,15 +71,17 @@ export declare const divide: { (that: number): (self: number) => number; (self: ```ts import { divide } from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe(6, divide(3)), 2) +assert.deepStrictEqual(divide(6, 3), 2) ``` Added in v1.0.0 ## multiply +Provides a multiplication operation on numbers. +It can be used as a binary function or a curried function. + **Signature** ```ts @@ -78,9 +92,8 @@ export declare const multiply: { (that: number): (self: number) => number; (self ```ts import { multiply } from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe(2, multiply(3)), 6) +assert.deepStrictEqual(multiply(2, 3), 6) ``` Added in v1.0.0 @@ -121,6 +134,9 @@ Added in v1.0.0 ## subtract +Provides a subtraction operation on numbers. +It can be used as a binary function or a curried function. + **Signature** ```ts @@ -131,15 +147,17 @@ export declare const subtract: { (that: number): (self: number) => number; (self ```ts import { subtract } from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe(2, subtract(3)), -1) +assert.deepStrictEqual(subtract(2, 3), -1) ``` Added in v1.0.0 ## sum +Provides an addition operation on numbers. +It can be used as a binary function or a curried function. + **Signature** ```ts @@ -150,9 +168,8 @@ export declare const sum: { (that: number): (self: number) => number; (self: num ```ts import { sum } from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe(2, sum(3)), 5) +assert.deepStrictEqual(sum(2, 3), 5) ``` Added in v1.0.0 @@ -304,7 +321,6 @@ export declare const SemigroupMultiply: semigroup.Semigroup ```ts import { SemigroupMultiply } from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' assert.deepStrictEqual(SemigroupMultiply.combine(2, 3), 6) ``` @@ -325,17 +341,168 @@ export declare const SemigroupSum: semigroup.Semigroup ```ts import { SemigroupSum } from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' assert.deepStrictEqual(SemigroupSum.combine(2, 3), 5) ``` Added in v1.0.0 +# predicates + +## between + +Checks if a number is between a minimum and maximum value (inclusive). + +**Signature** + +```ts +export declare const between: { + (minimum: number, maximum: number): (self: number) => boolean + (self: number, minimum: number, maximum: number): boolean +} +``` + +**Example** + +```ts +import { between } from '@fp-ts/core/Number' + +assert.deepStrictEqual(between(0, 5)(3), true) +assert.deepStrictEqual(between(0, 5)(-1), false) +assert.deepStrictEqual(between(0, 5)(6), false) +``` + +Added in v1.0.0 + +## greaterThan + +Returns `true` if the first argument is greater than the second, otherwise `false`. + +**Signature** + +```ts +export declare const greaterThan: { (that: number): (self: number) => boolean; (self: number, that: number): boolean } +``` + +**Example** + +```ts +import { greaterThan } from '@fp-ts/core/Number' + +assert.deepStrictEqual(greaterThan(2, 3), false) +assert.deepStrictEqual(greaterThan(3, 3), false) +assert.deepStrictEqual(greaterThan(4, 3), true) +``` + +Added in v1.0.0 + +## greaterThanOrEqualTo + +Returns a function that checks if a given number is greater than or equal to the provided one. + +**Signature** + +```ts +export declare const greaterThanOrEqualTo: { + (that: number): (self: number) => boolean + (self: number, that: number): boolean +} +``` + +**Example** + +```ts +import { greaterThanOrEqualTo } from '@fp-ts/core/Number' + +assert.deepStrictEqual(greaterThanOrEqualTo(2, 3), false) +assert.deepStrictEqual(greaterThanOrEqualTo(3, 3), true) +assert.deepStrictEqual(greaterThanOrEqualTo(4, 3), true) +``` + +Added in v1.0.0 + +## lessThan + +Returns `true` if the first argument is less than the second, otherwise `false`. + +**Signature** + +```ts +export declare const lessThan: { (that: number): (self: number) => boolean; (self: number, that: number): boolean } +``` + +**Example** + +```ts +import { lessThan } from '@fp-ts/core/Number' + +assert.deepStrictEqual(lessThan(2, 3), true) +assert.deepStrictEqual(lessThan(3, 3), false) +assert.deepStrictEqual(lessThan(4, 3), false) +``` + +Added in v1.0.0 + +## lessThanOrEqualTo + +Returns a function that checks if a given number is less than or equal to the provided one. + +**Signature** + +```ts +export declare const lessThanOrEqualTo: { + (that: number): (self: number) => boolean + (self: number, that: number): boolean +} +``` + +**Example** + +```ts +import { lessThanOrEqualTo } from '@fp-ts/core/Number' + +assert.deepStrictEqual(lessThanOrEqualTo(2, 3), true) +assert.deepStrictEqual(lessThanOrEqualTo(3, 3), true) +assert.deepStrictEqual(lessThanOrEqualTo(4, 3), false) +``` + +Added in v1.0.0 + # utils +## clamp + +Restricts the given number to be within the range specified by the minimum and maximum values. + +- If the number is less than the minimum value, the function returns the minimum value. +- If the number is greater than the maximum value, the function returns the maximum value. +- Otherwise, it returns the original number. + +**Signature** + +```ts +export declare const clamp: { + (minimum: number, maximum: number): (self: number) => number + (self: number, minimum: number, maximum: number): number +} +``` + +**Example** + +```ts +import { clamp } from '@fp-ts/core/Number' + +assert.deepStrictEqual(clamp(0, 5)(3), 3) +assert.deepStrictEqual(clamp(0, 5)(-1), 0) +assert.deepStrictEqual(clamp(0, 5)(6), 5) +``` + +Added in v1.0.0 + ## decrement +Decrements a number by `1`. + **Signature** ```ts @@ -346,15 +513,16 @@ export declare const decrement: (n: number) => number ```ts import { decrement } from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe(3, decrement), 2) +assert.deepStrictEqual(decrement(3), 2) ``` Added in v1.0.0 ## increment +Returns the result of adding `1` to a given number. + **Signature** ```ts @@ -365,9 +533,48 @@ export declare const increment: (n: number) => number ```ts import { increment } from '@fp-ts/core/Number' -import { pipe } from '@fp-ts/core/Function' -assert.deepStrictEqual(pipe(2, increment), 3) +assert.deepStrictEqual(increment(2), 3) +``` + +Added in v1.0.0 + +## max + +Returns the maximum between two numbers. + +**Signature** + +```ts +export declare const max: { (that: number): (self: number) => number; (self: number, that: number): number } +``` + +**Example** + +```ts +import { max } from '@fp-ts/core/Number' + +assert.deepStrictEqual(max(2, 3), 3) +``` + +Added in v1.0.0 + +## min + +Returns the minimum between two numbers. + +**Signature** + +```ts +export declare const min: { (that: number): (self: number) => number; (self: number, that: number): number } +``` + +**Example** + +```ts +import { min } from '@fp-ts/core/Number' + +assert.deepStrictEqual(min(2, 3), 2) ``` Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index efe61026b..17b8d6495 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -441,6 +441,10 @@ Added in v1.0.0 Similar to `Promise.all` but operates on `Option`s. +``` +[Option, Option, ...] -> Option<[A, B, ...]> +``` + Takes a tuple of `Option`s and returns an `Option` of a tuple of values. **Signature** diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index 3a9fab85c..ddd8296b9 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -13,9 +13,13 @@ Added in v1.0.0

Table of contents

- [combinators](#combinators) - - [contramap](#contramap) + - [and](#and) + - [not](#not) + - [or](#or) - [combining](#combining) - [productAll](#productall) +- [constructors](#constructors) + - [contramap](#contramap) - [do notation](#do-notation) - [Do](#do) - [andThenBind](#andthenbind) @@ -57,13 +61,10 @@ Added in v1.0.0 - [PredicateTypeLambda (interface)](#predicatetypelambda-interface) - [utils](#utils) - [all](#all) - - [and](#and) - [any](#any) - [appendElement](#appendelement) - [compose](#compose) - - [not](#not) - [of](#of) - - [or](#or) - [struct](#struct) - [tuple](#tuple) - [tupled](#tupled) @@ -73,17 +74,87 @@ Added in v1.0.0 # combinators -## contramap +## and + +Combines two predicates into a new predicate that returns `true` if both of the predicates returns `true`. **Signature** ```ts -export declare const contramap: { - (f: (b: B) => A): (self: Predicate
) => Predicate - (self: Predicate, f: (b: B) => A): Predicate +export declare const and: { + (that: Predicate): (self: Predicate) => Predicate + (self: Predicate, that: Predicate): Predicate } ``` +**Example** + +```ts +import * as P from '@fp-ts/core/Predicate' + +const minLength = (n: number) => (s: string) => s.length >= n +const maxLength = (n: number) => (s: string) => s.length <= n + +const length = (n: number) => P.and(minLength(n), maxLength(n)) + +assert.deepStrictEqual(length(2)('aa'), true) +assert.deepStrictEqual(length(2)('a'), false) +assert.deepStrictEqual(length(2)('aaa'), false) +``` + +Added in v1.0.0 + +## not + +Negates the result of a given predicate. + +**Signature** + +```ts +export declare const not: (self: Predicate) => Predicate +``` + +**Example** + +```ts +import * as P from '@fp-ts/core/Predicate' +import * as N from '@fp-ts/core/Number' + +const isPositive = P.not(N.lessThan(0)) + +assert.deepStrictEqual(isPositive(-1), false) +assert.deepStrictEqual(isPositive(0), true) +assert.deepStrictEqual(isPositive(1), true) +``` + +Added in v1.0.0 + +## or + +Combines two predicates into a new predicate that returns `true` if at least one of the predicates returns `true`. + +**Signature** + +```ts +export declare const or: { + (that: Predicate): (self: Predicate) => Predicate + (self: Predicate, that: Predicate): Predicate +} +``` + +**Example** + +```ts +import * as P from '@fp-ts/core/Predicate' +import * as N from '@fp-ts/core/Number' + +const nonZero = P.or(N.lessThan(0), N.greaterThan(0)) + +assert.deepStrictEqual(nonZero(-1), true) +assert.deepStrictEqual(nonZero(0), false) +assert.deepStrictEqual(nonZero(1), true) +``` + Added in v1.0.0 # combining @@ -107,6 +178,37 @@ export declare const productAll: (collection: Iterable>) => Pred Added in v1.0.0 +# constructors + +## contramap + +Given a `Predicate` returns a `Predicate` + +**Signature** + +```ts +export declare const contramap: { + (f: (b: B) => A): (self: Predicate) => Predicate + (self: Predicate, f: (b: B) => A): Predicate +} +``` + +**Example** + +```ts +import * as P from '@fp-ts/core/Predicate' +import * as N from '@fp-ts/core/Number' + +const minLength3 = P.contramap(N.greaterThan(2), (s: string) => s.length) + +assert.deepStrictEqual(minLength3('a'), false) +assert.deepStrictEqual(minLength3('aa'), false) +assert.deepStrictEqual(minLength3('aaa'), true) +assert.deepStrictEqual(minLength3('aaaa'), true) +``` + +Added in v1.0.0 + # do notation ## Do @@ -740,19 +842,6 @@ export declare const all: (collection: Iterable>) => Predicate(that: Predicate): (self: Predicate) => Predicate - (self: Predicate, that: Predicate): Predicate -} -``` - -Added in v1.0.0 - ## any **Signature** @@ -792,16 +881,6 @@ export declare const compose: { Added in v1.0.0 -## not - -**Signature** - -```ts -export declare const not: (self: Predicate) => Predicate -``` - -Added in v1.0.0 - ## of **Signature** @@ -812,19 +891,6 @@ export declare const of: (_: A) => Predicate Added in v1.0.0 -## or - -**Signature** - -```ts -export declare const or: { - (that: Predicate): (self: Predicate) => Predicate - (self: Predicate, that: Predicate): Predicate -} -``` - -Added in v1.0.0 - ## struct **Signature** @@ -841,6 +907,10 @@ Added in v1.0.0 Similar to `Promise.all` but operates on `Predicate`s. +``` +[Predicate, Predicate, ...] -> Predicate<[A, B, ...]> +``` + **Signature** ```ts diff --git a/docs/modules/Struct.ts.md b/docs/modules/Struct.ts.md index de0267e42..4887a2642 100644 --- a/docs/modules/Struct.ts.md +++ b/docs/modules/Struct.ts.md @@ -35,9 +35,9 @@ by applying each `Equivalence` to the corresponding property of the struct. **Signature** ```ts -export declare const getEquivalence: (equivalences: { - [K in keyof A]: equivalence.Equivalence -}) => equivalence.Equivalence<{ readonly [K in keyof A]: A[K] }> +export declare const getEquivalence: >>( + predicates: R +) => equivalence.Equivalence<{ readonly [K in keyof R]: [R[K]] extends [equivalence.Equivalence] ? A : never }> ``` Added in v1.0.0 @@ -54,9 +54,9 @@ It is useful when you need to combine two structs of the same type and you have **Signature** ```ts -export declare const getMonoid: (monoids: { readonly [K in keyof A]: monoid.Monoid }) => monoid.Monoid<{ - readonly [K in keyof A]: A[K] -}> +export declare const getMonoid: }>( + fields: R +) => monoid.Monoid<{ [K in keyof R]: [R[K]] extends [monoid.Monoid] ? A : never }> ``` Added in v1.0.0 @@ -69,9 +69,9 @@ for each property in the struct. **Signature** ```ts -export declare const getOrder: (orders: { readonly [K in keyof A]: order.Order }) => order.Order<{ - readonly [K in keyof A]: A[K] -}> +export declare const getOrder: }>( + fields: R +) => order.Order<{ [K in keyof R]: [R[K]] extends [order.Order] ? A : never }> ``` Added in v1.0.0 @@ -86,9 +86,9 @@ It is useful when you need to combine two structs of the same type and you have **Signature** ```ts -export declare const getSemigroup: (semigroups: { - readonly [K in keyof A]: semigroup.Semigroup -}) => semigroup.Semigroup<{ readonly [K in keyof A]: A[K] }> +export declare const getSemigroup: }>( + fields: R +) => semigroup.Semigroup<{ [K in keyof R]: [R[K]] extends [semigroup.Semigroup] ? A : never }> ``` Added in v1.0.0 diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index c15660b7c..cdc6de92c 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -1887,6 +1887,10 @@ Added in v1.0.0 Similar to `Promise.all` but operates on `These`s. +``` +[These, These, ...] -> These +``` + **Signature** ```ts diff --git a/docs/modules/Tuple.ts.md b/docs/modules/Tuple.ts.md index f18666e52..24a802bdd 100644 --- a/docs/modules/Tuple.ts.md +++ b/docs/modules/Tuple.ts.md @@ -57,9 +57,9 @@ It is useful when you need to combine two tuples of the same type and you have a **Signature** ```ts -export declare const getMonoid: ( - ...monoids: { [K in keyof A]: monoid.Monoid } -) => monoid.Monoid +export declare const getMonoid: []>( + ...elements: T +) => monoid.Monoid<{ [I in keyof T]: [T[I]] extends [monoid.Monoid] ? A : never }> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Equivalence.ts.md b/docs/modules/typeclass/Equivalence.ts.md index 513c2eb8d..06700caa9 100644 --- a/docs/modules/typeclass/Equivalence.ts.md +++ b/docs/modules/typeclass/Equivalence.ts.md @@ -89,6 +89,10 @@ Added in v1.0.0 Similar to `Promise.all` but operates on `Equivalence`s. +``` +[Equivalence, Equivalence, ...] -> Equivalence<[A, B, ...]> +``` + Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple by applying each `Equivalence` to the corresponding element of the tuple. diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index c1f64d49a..94447b8f3 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -89,9 +89,9 @@ It is useful when you need to combine two structs of the same type and you have **Signature** ```ts -export declare const struct: (monoids: { readonly [K in keyof A]: Monoid }) => Monoid<{ - readonly [K in keyof A]: A[K] -}> +export declare const struct: }>( + fields: R +) => Monoid<{ [K in keyof R]: [R[K]] extends [Monoid] ? A : never }> ``` Added in v1.0.0 @@ -100,6 +100,10 @@ Added in v1.0.0 Similar to `Promise.all` but operates on `Monoid`s. +``` +[Monoid, Monoid, ...] -> Monoid<[A, B, ...]> +``` + This function creates and returns a new `Monoid` for a tuple of values based on the given `Monoid`s for each element in the tuple. The returned `Monoid` combines two tuples of the same type by applying the corresponding `Monoid` passed as arguments to each element in the tuple. @@ -110,7 +114,9 @@ It is useful when you need to combine two tuples of the same type and you have a **Signature** ```ts -export declare const tuple: (...monoids: { [K in keyof A]: Monoid }) => Monoid +export declare const tuple: []>( + ...elements: T +) => Monoid<{ [I in keyof T]: [T[I]] extends [Monoid] ? A : never }> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index ee9046440..5f996a712 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -98,6 +98,10 @@ Added in v1.0.0 Similar to `Promise.all` but operates on `Order`s. +``` +[Order, Order, ...] -> Order<[A, B, ...]> +``` + This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. The returned `Order` compares two tuples of the same type by applying the corresponding `Order` to each element in the tuple. It is useful when you need to compare two tuples of the same type and you have a specific way of comparing each element @@ -286,8 +290,8 @@ Test whether a value is between a minimum and a maximum (inclusive). ```ts export declare const between: (O: Order) => { - (minimum: A, maximum: A): (a: A) => boolean - (a: A, minimum: A, maximum: A): boolean + (minimum: A, maximum: A): (self: A) => boolean + (self: A, minimum: A, maximum: A): boolean } ``` @@ -301,8 +305,8 @@ Clamp a value between a minimum and a maximum. ```ts export declare const clamp: (O: Order) => { - (minimum: A, maximum: A): (a: A) => A - (a: A, minimum: A, maximum: A): A + (minimum: A, maximum: A): (self: A) => A + (self: A, minimum: A, maximum: A): A } ``` diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index 8dc71b4d3..f28a25d1f 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -99,6 +99,10 @@ Added in v1.0.0 Similar to `Promise.all` but operates on `Semigroup`s. +``` +[Semigroup, Semigroup, ...] -> Semigroup<[A, B, ...]> +``` + This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. diff --git a/src/Either.ts b/src/Either.ts index 2f4895bd4..5ee32f84a 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -574,6 +574,10 @@ export const Product: product_.Product = { /** * Similar to `Promise.all` but operates on `Either`s. * + * ``` + * [Either, Either, ...] -> Either + * ``` + * * @since 1.0.0 */ export const tuple: >>( diff --git a/src/Number.ts b/src/Number.ts index 0cddcacfa..f12f81198 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -31,11 +31,16 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" export const isNumber: (input: unknown) => input is number = predicate.isNumber /** + * Provides an addition operation on numbers. + * It can be used as a binary function or a curried function. + * + * @param self - The first operand. + * @param that - The second operand. + * * @example * import { sum } from '@fp-ts/core/Number' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(2, sum(3)), 5) + * assert.deepStrictEqual(sum(2, 3), 5) * * @category algebraic operations * @since 1.0.0 @@ -46,11 +51,16 @@ export const sum: { } = dual(2, semigroup.numberSum.combine) /** + * Provides a multiplication operation on numbers. + * It can be used as a binary function or a curried function. + * + * @param self - The first operand. + * @param that - The second operand. + * * @example * import { multiply } from '@fp-ts/core/Number' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(2, multiply(3)), 6) + * assert.deepStrictEqual(multiply(2, 3), 6) * * @category algebraic operations * @since 1.0.0 @@ -61,11 +71,16 @@ export const multiply: { } = dual(2, semigroup.numberMultiply.combine) /** + * Provides a subtraction operation on numbers. + * It can be used as a binary function or a curried function. + * + * @param self - The first operand. + * @param that - The second operand. + * * @example * import { subtract } from '@fp-ts/core/Number' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(2, subtract(3)), -1) + * assert.deepStrictEqual(subtract(2, 3), -1) * * @category algebraic operations * @since 1.0.0 @@ -76,11 +91,16 @@ export const subtract: { } = dual(2, (self: number, that: number): number => self - that) /** + * Provides a division operation on numbers. + * It can be used as a binary function or a curried function. + * + * @param self - The first operand. + * @param that - The second operand. + * * @example * import { divide } from '@fp-ts/core/Number' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(6, divide(3)), 2) + * assert.deepStrictEqual(divide(6, 3), 2) * * @category algebraic operations * @since 1.0.0 @@ -91,22 +111,28 @@ export const divide: { } = dual(2, (self: number, that: number): number => self / that) /** + * Returns the result of adding `1` to a given number. + * + * @param n - A number to be incremented. + * * @example * import { increment } from '@fp-ts/core/Number' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(2, increment), 3) + * assert.deepStrictEqual(increment(2), 3) * * @since 1.0.0 */ export const increment = (n: number): number => n + 1 /** + * Decrements a number by `1`. + * + * @param n - A number to be decremented. + * * @example * import { decrement } from '@fp-ts/core/Number' - * import { pipe } from '@fp-ts/core/Function' * - * assert.deepStrictEqual(pipe(3, decrement), 2) + * assert.deepStrictEqual(decrement(3), 2) * * @since 1.0.0 */ @@ -124,6 +150,173 @@ export const Equivalence: equivalence.Equivalence = equivalence.number */ export const Order: order.Order = order.number +/** + * Returns `true` if the first argument is less than the second, otherwise `false`. + * + * @param self - The first argument. + * @param that - The second argument. + * + * @example + * import { lessThan } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(lessThan(2, 3), true) + * assert.deepStrictEqual(lessThan(3, 3), false) + * assert.deepStrictEqual(lessThan(4, 3), false) + * + * @category predicates + * @since 1.0.0 + */ +export const lessThan: { + (that: number): (self: number) => boolean + (self: number, that: number): boolean +} = order.lessThan(Order) + +/** + * Returns a function that checks if a given number is less than or equal to the provided one. + * + * @param self - The first number to compare with. + * @param that - The second number to compare with. + * + * @example + * import { lessThanOrEqualTo } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(lessThanOrEqualTo(2, 3), true) + * assert.deepStrictEqual(lessThanOrEqualTo(3, 3), true) + * assert.deepStrictEqual(lessThanOrEqualTo(4, 3), false) + * + * @category predicates + * @since 1.0.0 + */ +export const lessThanOrEqualTo: { + (that: number): (self: number) => boolean + (self: number, that: number): boolean +} = order.lessThanOrEqualTo(Order) + +/** + * Returns `true` if the first argument is greater than the second, otherwise `false`. + * + * @param self - The first argument. + * @param that - The second argument. + * + * @example + * import { greaterThan } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(greaterThan(2, 3), false) + * assert.deepStrictEqual(greaterThan(3, 3), false) + * assert.deepStrictEqual(greaterThan(4, 3), true) + * + * @category predicates + * @since 1.0.0 + */ +export const greaterThan: { + (that: number): (self: number) => boolean + (self: number, that: number): boolean +} = order.greaterThan(Order) + +/** + * Returns a function that checks if a given number is greater than or equal to the provided one. + * + * @param self - The first number to compare with. + * @param that - The second number to compare with. + * + * @example + * import { greaterThanOrEqualTo } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(greaterThanOrEqualTo(2, 3), false) + * assert.deepStrictEqual(greaterThanOrEqualTo(3, 3), true) + * assert.deepStrictEqual(greaterThanOrEqualTo(4, 3), true) + * + * @category predicates + * @since 1.0.0 + */ +export const greaterThanOrEqualTo: { + (that: number): (self: number) => boolean + (self: number, that: number): boolean +} = order.greaterThanOrEqualTo(Order) + +/** + * Checks if a number is between a minimum and maximum value (inclusive). + * + * @param self - The number to check. + * @param minimum - The minimum value to check. + * @param maximum - The maximum value to check. + * + * @example + * import { between } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(between(0, 5)(3), true) + * assert.deepStrictEqual(between(0, 5)(-1), false) + * assert.deepStrictEqual(between(0, 5)(6), false) + * + * @category predicates + * @since 1.0.0 + */ +export const between: { + (minimum: number, maximum: number): (self: number) => boolean + (self: number, minimum: number, maximum: number): boolean +} = order.between(Order) + +/** + * Restricts the given number to be within the range specified by the minimum and maximum values. + * + * - If the number is less than the minimum value, the function returns the minimum value. + * - If the number is greater than the maximum value, the function returns the maximum value. + * - Otherwise, it returns the original number. + * + * @param self - The number to be clamped. + * @param minimum - The lower end of the range. + * @param maximum - The upper end of the range. + * + * @example + * import { clamp } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(clamp(0, 5)(3), 3) + * assert.deepStrictEqual(clamp(0, 5)(-1), 0) + * assert.deepStrictEqual(clamp(0, 5)(6), 5) + * + * @since 1.0.0 + */ +export const clamp: { + (minimum: number, maximum: number): (self: number) => number + (self: number, minimum: number, maximum: number): number +} = order.clamp(Order) + +/** + * Returns the minimum between two numbers. + * + * @param self - The first number. + * @param that - The second number. + * + * @example + * import { min } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(min(2, 3), 2) + * + * @since 1.0.0 + */ +export const min: { + (that: number): (self: number) => number + (self: number, that: number): number +} = order.min(Order) + +/** + * Returns the maximum between two numbers. + * + * @param self - The first number. + * @param that - The second number. + * + * @example + * import { max } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(max(2, 3), 3) + * + * @since 1.0.0 + */ +export const max: { + (that: number): (self: number) => number + (self: number, that: number): number +} = order.max(Order) + /** * @category instances * @since 1.0.0 @@ -135,7 +328,6 @@ export const Bounded: bounded.Bounded = bounded.number * * @example * import { SemigroupSum } from '@fp-ts/core/Number' - * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(SemigroupSum.combine(2, 3), 5) * @@ -161,7 +353,6 @@ export const SemigroupMin: semigroup.Semigroup = semigroup.min(Order) * * @example * import { SemigroupMultiply } from '@fp-ts/core/Number' - * import { pipe } from '@fp-ts/core/Function' * * assert.deepStrictEqual(SemigroupMultiply.combine(2, 3), 6) * diff --git a/src/Option.ts b/src/Option.ts index 445b17403..326432293 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -974,6 +974,10 @@ export const Product: product_.Product = { /** * Similar to `Promise.all` but operates on `Option`s. * + * ``` + * [Option, Option, ...] -> Option<[A, B, ...]> + * ``` + * * Takes a tuple of `Option`s and returns an `Option` of a tuple of values. * * @param elements - the tuple of `Option`s to be sequenced. diff --git a/src/Predicate.ts b/src/Predicate.ts index 5cc4dc146..2024450f4 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -37,13 +37,38 @@ export interface Refinement { (a: A): a is B } +/** + * Given a `Predicate` returns a `Predicate` + * + * @param self - the `Predicate` to be transformed to `Predicate`. + * @param f - a function to transform `B` to `A`. + * + * @example + * import * as P from "@fp-ts/core/Predicate" + * import * as N from "@fp-ts/core/Number" + * + * const minLength3 = P.contramap(N.greaterThan(2), (s: string) => s.length) + * + * assert.deepStrictEqual(minLength3("a"), false) + * assert.deepStrictEqual(minLength3("aa"), false) + * assert.deepStrictEqual(minLength3("aaa"), true) + * assert.deepStrictEqual(minLength3("aaaa"), true) + * + * @category constructors + * @since 1.0.0 + */ +export const contramap: { + (f: (b: B) => A): (self: Predicate) => Predicate + (self: Predicate, f: (b: B) => A): Predicate +} = dual(2, (self: Predicate, f: (b: B) => A): Predicate => (b) => self(f(b))) + /** * Tests if a value is a `string`. * * @param input - The value to test. * * @example - * import { isString } from '@fp-ts/core/Predicate' + * import { isString } from "@fp-ts/core/Predicate" * * assert.deepStrictEqual(isString("a"), true) * @@ -60,7 +85,7 @@ export const isString = (input: unknown): input is string => typeof input === "s * @param input - The value to test. * * @example - * import { isNumber } from '@fp-ts/core/Predicate' + * import { isNumber } from "@fp-ts/core/Predicate" * * assert.deepStrictEqual(isNumber(2), true) * @@ -77,7 +102,7 @@ export const isNumber = (input: unknown): input is number => typeof input === "n * @param input - The value to test. * * @example - * import { isBoolean } from '@fp-ts/core/Predicate' + * import { isBoolean } from "@fp-ts/core/Predicate" * * assert.deepStrictEqual(isBoolean(true), true) * @@ -128,7 +153,7 @@ export const isSymbol = (input: unknown): input is symbol => typeof input === "s * @param input - The value to test. * * @example - * import { isFunction } from '@fp-ts/core/Predicate' + * import { isFunction } from "@fp-ts/core/Predicate" * * assert.deepStrictEqual(isFunction(isFunction), true) * @@ -401,15 +426,6 @@ export const compose: { (a): a is C => ab(a) && bc(a) ) -/** - * @category combinators - * @since 1.0.0 - */ -export const contramap: { - (f: (b: B) => A): (self: Predicate) => Predicate - (self: Predicate, f: (b: B) => A): Predicate -} = dual(2, (self: Predicate, f: (b: B) => A): Predicate => (b) => self(f(b))) - const imap = contravariant.imap(contramap) /** @@ -539,6 +555,10 @@ export const appendElement: { /** * Similar to `Promise.all` but operates on `Predicate`s. * + * ``` + * [Predicate, Predicate, ...] -> Predicate<[A, B, ...]> + * ``` + * * @since 1.0.0 */ export const tuple: >>( @@ -555,11 +575,42 @@ export const struct: >>( product_.struct(Product) /** + * Negates the result of a given predicate. + * + * @param self - A predicate. + * + * @example + * import * as P from "@fp-ts/core/Predicate" + * import * as N from "@fp-ts/core/Number" + * + * const isPositive = P.not(N.lessThan(0)) + * + * assert.deepStrictEqual(isPositive(-1), false) + * assert.deepStrictEqual(isPositive(0), true) + * assert.deepStrictEqual(isPositive(1), true) + * + * @category combinators * @since 1.0.0 */ export const not = (self: Predicate): Predicate => (a) => !self(a) /** + * Combines two predicates into a new predicate that returns `true` if at least one of the predicates returns `true`. + * + * @param self - A predicate. + * @param that - A predicate. + * + * @example + * import * as P from "@fp-ts/core/Predicate" + * import * as N from "@fp-ts/core/Number" + * + * const nonZero = P.or(N.lessThan(0), N.greaterThan(0)) + * + * assert.deepStrictEqual(nonZero(-1), true) + * assert.deepStrictEqual(nonZero(0), false) + * assert.deepStrictEqual(nonZero(1), true) + * + * @category combinators * @since 1.0.0 */ export const or: { @@ -568,6 +619,24 @@ export const or: { } = dual(2, (self: Predicate, that: Predicate): Predicate => (a) => self(a) || that(a)) /** + * Combines two predicates into a new predicate that returns `true` if both of the predicates returns `true`. + * + * @param self - A predicate. + * @param that - A predicate. + * + * @example + * import * as P from "@fp-ts/core/Predicate" + * + * const minLength = (n: number) => (s: string) => s.length >= n + * const maxLength = (n: number) => (s: string) => s.length <= n + * + * const length = (n: number) => P.and(minLength(n), maxLength(n)) + * + * assert.deepStrictEqual(length(2)("aa"), true) + * assert.deepStrictEqual(length(2)("a"), false) + * assert.deepStrictEqual(length(2)("aaa"), false) + * + * @category combinators * @since 1.0.0 */ export const and: { diff --git a/src/Struct.ts b/src/Struct.ts index 289b13328..c98dcf80f 100644 --- a/src/Struct.ts +++ b/src/Struct.ts @@ -48,9 +48,11 @@ export const omit = ]>( * @category combinators * @since 1.0.0 */ -export const getEquivalence: ( - equivalences: { [K in keyof A]: equivalence.Equivalence } -) => equivalence.Equivalence<{ readonly [K in keyof A]: A[K] }> = equivalence.struct +export const getEquivalence: >>( + predicates: R +) => equivalence.Equivalence< + { readonly [K in keyof R]: [R[K]] extends [equivalence.Equivalence] ? A : never } +> = equivalence.struct /** * This function creates and returns a new `Order` for a struct of values based on the given `Order`s @@ -59,9 +61,10 @@ export const getEquivalence: ( * @category combinators * @since 1.0.0 */ -export const getOrder: ( - orders: { readonly [K in keyof A]: order.Order } -) => order.Order<{ readonly [K in keyof A]: A[K] }> = order.struct +export const getOrder: }>( + fields: R +) => order.Order<{ [K in keyof R]: [R[K]] extends [order.Order] ? A : never }> = + order.struct /** * This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. @@ -72,9 +75,11 @@ export const getOrder: ( * @category combinators * @since 1.0.0 */ -export const getSemigroup: ( - semigroups: { readonly [K in keyof A]: semigroup.Semigroup } -) => semigroup.Semigroup<{ readonly [K in keyof A]: A[K] }> = semigroup.struct +export const getSemigroup: }>( + fields: R +) => semigroup.Semigroup< + { [K in keyof R]: [R[K]] extends [semigroup.Semigroup] ? A : never } +> = semigroup.struct /** * This function creates and returns a new `Monoid` for a struct of values based on the given `Monoid`s for each property in the struct. @@ -87,9 +92,10 @@ export const getSemigroup: ( * @category combinators * @since 1.0.0 */ -export const getMonoid: ( - monoids: { readonly [K in keyof A]: monoid.Monoid } -) => monoid.Monoid<{ readonly [K in keyof A]: A[K] }> = monoid.struct +export const getMonoid: }>( + fields: R +) => monoid.Monoid<{ [K in keyof R]: [R[K]] extends [monoid.Monoid] ? A : never }> = + monoid.struct /* diff --git a/src/These.ts b/src/These.ts index 33e830ed6..ae419bed4 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1339,6 +1339,10 @@ export const Product: product_.Product = { /** * Similar to `Promise.all` but operates on `These`s. * + * ``` + * [These, These, ...] -> These + * ``` + * * @since 1.0.0 */ export const tuple: >>(...tuple: T) => Validated< diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 8f9474df2..158c1affd 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -205,6 +205,10 @@ export const Product: product_.Product = { /** * Similar to `Promise.all` but operates on `Equivalence`s. * + * ``` + * [Equivalence, Equivalence, ...] -> Equivalence<[A, B, ...]> + * ``` + * * Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple * by applying each `Equivalence` to the corresponding element of the tuple. * diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index 5e6399a1b..a6d5237e3 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -142,6 +142,10 @@ export const booleanEqv: Monoid = fromSemigroup(semigroup.booleanEqv, t /** * Similar to `Promise.all` but operates on `Monoid`s. * + * ``` + * [Monoid, Monoid, ...] -> Monoid<[A, B, ...]> + * ``` + * * This function creates and returns a new `Monoid` for a tuple of values based on the given `Monoid`s for each element in the tuple. * The returned `Monoid` combines two tuples of the same type by applying the corresponding `Monoid` passed as arguments to each element in the tuple. * @@ -152,11 +156,11 @@ export const booleanEqv: Monoid = fromSemigroup(semigroup.booleanEqv, t * @category combinators * @since 1.0.0 */ -export const tuple = >( - ...monoids: { [K in keyof A]: Monoid } -): Monoid => { - const empty: A = monoids.map((m) => m.empty) as any - return fromSemigroup(semigroup.tuple(...monoids), empty) +export const tuple = >>( + ...elements: T +): Monoid<{ [I in keyof T]: [T[I]] extends [Monoid] ? A : never }> => { + const empty = elements.map((m) => m.empty) as any + return fromSemigroup(semigroup.tuple(...elements), empty) } /** @@ -189,14 +193,14 @@ export const array: () => Monoid> = mutableArray as any * @category combinators * @since 1.0.0 */ -export const struct = ( - monoids: { readonly [K in keyof A]: Monoid } -): Monoid<{ readonly [K in keyof A]: A[K] }> => { - const empty: A = {} as any - for (const k in monoids) { - if (Object.prototype.hasOwnProperty.call(monoids, k)) { - empty[k] = monoids[k].empty +export const struct = }>( + fields: R +): Monoid<{ [K in keyof R]: [R[K]] extends [Monoid] ? A : never }> => { + const empty = {} as any + for (const k in fields) { + if (Object.prototype.hasOwnProperty.call(fields, k)) { + empty[k] = fields[k].empty } } - return fromSemigroup(semigroup.struct(monoids), empty) + return fromSemigroup(semigroup.struct(fields), empty) } diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 8f94cf1a5..060e4e939 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -208,6 +208,10 @@ export const Product: product_.Product = { /** * Similar to `Promise.all` but operates on `Order`s. * + * ``` + * [Order, Order, ...] -> Order<[A, B, ...]> + * ``` + * * This function creates and returns a new `Order` for a tuple of values based on the given `Order`s for each element in the tuple. * The returned `Order` compares two tuples of the same type by applying the corresponding `Order` to each element in the tuple. * It is useful when you need to compare two tuples of the same type and you have a specific way of comparing each element @@ -324,12 +328,12 @@ export const max = (O: Order): { * @since 1.0.0 */ export const clamp = (O: Order): { - (minimum: A, maximum: A): (a: A) => A - (a: A, minimum: A, maximum: A): A + (minimum: A, maximum: A): (self: A) => A + (self: A, minimum: A, maximum: A): A } => dual( 3, - (a: A, minimum: A, maximum: A): A => min(O)(maximum, max(O)(minimum, a)) + (self: A, minimum: A, maximum: A): A => min(O)(maximum, max(O)(minimum, self)) ) /** @@ -338,11 +342,11 @@ export const clamp = (O: Order): { * @since 1.0.0 */ export const between = (O: Order): { - (minimum: A, maximum: A): (a: A) => boolean - (a: A, minimum: A, maximum: A): boolean + (minimum: A, maximum: A): (self: A) => boolean + (self: A, minimum: A, maximum: A): boolean } => dual( 3, - (a: A, minimum: A, maximum: A): boolean => - !lessThan(O)(a, minimum) && !greaterThan(O)(a, maximum) + (self: A, minimum: A, maximum: A): boolean => + !lessThan(O)(self, minimum) && !greaterThan(O)(self, maximum) ) diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 547267294..6105650ad 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -325,6 +325,10 @@ export const Product: product_.Product = { /** * Similar to `Promise.all` but operates on `Semigroup`s. * + * ``` + * [Semigroup, Semigroup, ...] -> Semigroup<[A, B, ...]> + * ``` + * * This function creates and returns a new `Semigroup` for a tuple of values based on the given `Semigroup`s for each element in the tuple. * The returned `Semigroup` combines two tuples of the same type by applying the corresponding `Semigroup` passed as arguments to each element in the tuple. * diff --git a/test/Number.ts b/test/Number.ts index 067b22705..b5d61d3e9 100644 --- a/test/Number.ts +++ b/test/Number.ts @@ -10,6 +10,14 @@ describe.concurrent("Number", () => { expect(Number.MonoidMin).exists expect(Number.sumAll).exists expect(Number.multiplyAll).exists + expect(Number.lessThan).exists + expect(Number.lessThanOrEqualTo).exists + expect(Number.greaterThan).exists + expect(Number.greaterThanOrEqualTo).exists + expect(Number.between).exists + expect(Number.clamp).exists + expect(Number.min).exists + expect(Number.max).exists }) it("isNumber", () => { From 7088a8e92f17a14d9703ad82c61714122702515e Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 12 Feb 2023 16:14:49 +0100 Subject: [PATCH 243/255] fix CI --- docs/modules/Tuple.ts.md | 4 ++-- docs/modules/typeclass/Monoid.ts.md | 18 ++---------------- docs/modules/typeclass/Semigroup.ts.md | 18 ++---------------- dtslint/ts4.8/Monoid.ts | 16 ++++++++++------ dtslint/ts4.8/Semigroup.ts | 16 ++++++++++------ src/typeclass/Monoid.ts | 16 +++------------- src/typeclass/Semigroup.ts | 21 ++++++--------------- test/typeclass/Monoid.ts | 4 ---- test/typeclass/Semigroup.ts | 1 - 9 files changed, 35 insertions(+), 79 deletions(-) diff --git a/docs/modules/Tuple.ts.md b/docs/modules/Tuple.ts.md index 24a802bdd..9da196763 100644 --- a/docs/modules/Tuple.ts.md +++ b/docs/modules/Tuple.ts.md @@ -59,7 +59,7 @@ It is useful when you need to combine two tuples of the same type and you have a ```ts export declare const getMonoid: []>( ...elements: T -) => monoid.Monoid<{ [I in keyof T]: [T[I]] extends [monoid.Monoid] ? A : never }> +) => monoid.Monoid<{ readonly [I in keyof T]: [T[I]] extends [monoid.Monoid] ? A : never }> ``` Added in v1.0.0 @@ -93,7 +93,7 @@ It is useful when you need to combine two tuples of the same type and you have a ```ts export declare const getSemigroup: []>( ...elements: T -) => semigroup.Semigroup<{ [I in keyof T]: [T[I]] extends [semigroup.Semigroup] ? A : never }> +) => semigroup.Semigroup<{ readonly [I in keyof T]: [T[I]] extends [semigroup.Semigroup] ? A : never }> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index 94447b8f3..b03acba86 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -14,7 +14,6 @@ Added in v1.0.0 - [combinators](#combinators) - [array](#array) - - [mutableArray](#mutablearray) - [reverse](#reverse) - [struct](#struct) - [tuple](#tuple) @@ -52,19 +51,6 @@ export declare const array: () => Monoid Added in v1.0.0 -## mutableArray - -Given a type `A`, this function creates and returns a `Monoid` for `Array`. -The returned `Monoid`'s `empty` value is the empty array. - -**Signature** - -```ts -export declare const mutableArray: () => Monoid -``` - -Added in v1.0.0 - ## reverse The dual of a `Monoid`, obtained by swapping the arguments of `combine`. @@ -91,7 +77,7 @@ It is useful when you need to combine two structs of the same type and you have ```ts export declare const struct: }>( fields: R -) => Monoid<{ [K in keyof R]: [R[K]] extends [Monoid] ? A : never }> +) => Monoid<{ readonly [K in keyof R]: [R[K]] extends [Monoid] ? A : never }> ``` Added in v1.0.0 @@ -116,7 +102,7 @@ It is useful when you need to combine two tuples of the same type and you have a ```ts export declare const tuple: []>( ...elements: T -) => Monoid<{ [I in keyof T]: [T[I]] extends [Monoid] ? A : never }> +) => Monoid<{ readonly [I in keyof T]: [T[I]] extends [Monoid] ? A : never }> ``` Added in v1.0.0 diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index f28a25d1f..3493a0641 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -14,7 +14,6 @@ Added in v1.0.0 - [combinators](#combinators) - [array](#array) - - [mutableArray](#mutablearray) - [struct](#struct) - [tuple](#tuple) - [combining](#combining) @@ -65,19 +64,6 @@ export declare const array: () => Semigroup Added in v1.0.0 -## mutableArray - -Given a type `A`, this function creates and returns a `Semigroup` for `Array`. -The returned `Semigroup` combines two arrays by concatenating them. - -**Signature** - -```ts -export declare const mutableArray: () => Semigroup -``` - -Added in v1.0.0 - ## struct This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. @@ -90,7 +76,7 @@ It is useful when you need to combine two structs of the same type and you have ```ts export declare const struct: }>( fields: R -) => Semigroup<{ [K in keyof R]: [R[K]] extends [Semigroup] ? A : never }> +) => Semigroup<{ readonly [K in keyof R]: [R[K]] extends [Semigroup] ? A : never }> ``` Added in v1.0.0 @@ -113,7 +99,7 @@ It is useful when you need to combine two tuples of the same type and you have a ```ts export declare const tuple: []>( ...elements: T -) => Semigroup<{ [I in keyof T]: [T[I]] extends [Semigroup] ? A : never }> +) => Semigroup<{ readonly [I in keyof T]: [T[I]] extends [Semigroup] ? A : never }> ``` Added in v1.0.0 diff --git a/dtslint/ts4.8/Monoid.ts b/dtslint/ts4.8/Monoid.ts index a8e830cdc..05fd68a52 100644 --- a/dtslint/ts4.8/Monoid.ts +++ b/dtslint/ts4.8/Monoid.ts @@ -6,14 +6,18 @@ import * as String from "@fp-ts/core/String" // tuple // -// $ExpectType Monoid<[string, number]> +// $ExpectType Monoid _.tuple( String.Monoid, Number.MonoidSum ) -// $ExpectType Monoid -_.tuple( - String.Monoid, - Number.MonoidSum -) +// +// struct +// + +// $ExpectType Monoid<{ readonly a: string; readonly b: number; }> +_.struct({ + a: String.Monoid, + b: Number.MonoidSum +}) diff --git a/dtslint/ts4.8/Semigroup.ts b/dtslint/ts4.8/Semigroup.ts index 854f4d468..a94b8c717 100644 --- a/dtslint/ts4.8/Semigroup.ts +++ b/dtslint/ts4.8/Semigroup.ts @@ -6,14 +6,18 @@ import * as String from "@fp-ts/core/String" // tuple // -// $ExpectType Semigroup<[string, number]> +// $ExpectType Semigroup _.tuple( String.Semigroup, Number.SemigroupSum ) -// $ExpectType Semigroup -_.tuple( - String.Semigroup, - Number.SemigroupSum -) +// +// struct +// + +// $ExpectType Semigroup<{ readonly a: string; readonly b: number; }> +_.struct({ + a: String.Semigroup, + b: Number.SemigroupSum +}) diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index a6d5237e3..a0f05b756 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -158,21 +158,11 @@ export const booleanEqv: Monoid = fromSemigroup(semigroup.booleanEqv, t */ export const tuple = >>( ...elements: T -): Monoid<{ [I in keyof T]: [T[I]] extends [Monoid] ? A : never }> => { +): Monoid<{ readonly [I in keyof T]: [T[I]] extends [Monoid] ? A : never }> => { const empty = elements.map((m) => m.empty) as any return fromSemigroup(semigroup.tuple(...elements), empty) } -/** - * Given a type `A`, this function creates and returns a `Monoid` for `Array`. - * The returned `Monoid`'s `empty` value is the empty array. - * - * @category combinators - * @since 1.0.0 - */ -export const mutableArray = (): Monoid> => - fromSemigroup(semigroup.mutableArray(), []) - /** * Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. * The returned `Monoid`'s empty value is the empty array. @@ -180,7 +170,7 @@ export const mutableArray = (): Monoid> => * @category combinators * @since 1.0.0 */ -export const array: () => Monoid> = mutableArray as any +export const array = (): Monoid> => fromSemigroup(semigroup.array(), []) /** * This function creates and returns a new `Monoid` for a struct of values based on the given `Monoid`s for each property in the struct. @@ -195,7 +185,7 @@ export const array: () => Monoid> = mutableArray as any */ export const struct = }>( fields: R -): Monoid<{ [K in keyof R]: [R[K]] extends [Monoid] ? A : never }> => { +): Monoid<{ readonly [K in keyof R]: [R[K]] extends [Monoid] ? A : never }> => { const empty = {} as any for (const k in fields) { if (Object.prototype.hasOwnProperty.call(fields, k)) { diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 6105650ad..3f3e72153 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -282,7 +282,7 @@ export const all = (collection: Iterable>): Semigroup> const semigroups = readonlyArray.fromIterable(collection) return make((x, y) => { const len = Math.min(x.length, y.length, semigroups.length) - const out = [] + const out: Array = [] for (let i = 0; i < len; i++) { out.push(semigroups[i].combine(x[i], y[i])) } @@ -339,17 +339,8 @@ export const Product: product_.Product = { */ export const tuple: >>( ...elements: T -) => Semigroup<{ [I in keyof T]: [T[I]] extends [Semigroup] ? A : never }> = product_ - .tuple(Product) - -/** - * Given a type `A`, this function creates and returns a `Semigroup` for `Array`. - * The returned `Semigroup` combines two arrays by concatenating them. - * - * @category combinators - * @since 1.0.0 - */ -export const mutableArray = (): Semigroup> => make((self, that) => self.concat(that)) +) => Semigroup<{ readonly [I in keyof T]: [T[I]] extends [Semigroup] ? A : never }> = + product_.tuple(Product) /** * Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. @@ -358,7 +349,7 @@ export const mutableArray = (): Semigroup> => make((self, that) => s * @category combinators * @since 1.0.0 */ -export const array: () => Semigroup> = mutableArray as any +export const array = (): Semigroup> => make((self, that) => self.concat(that)) /** * This function creates and returns a new `Semigroup` for a struct of values based on the given `Semigroup`s for each property in the struct. @@ -371,5 +362,5 @@ export const array: () => Semigroup> = mutableArray as any */ export const struct: }>( fields: R -) => Semigroup<{ [K in keyof R]: [R[K]] extends [Semigroup] ? A : never }> = product_ - .struct(Product) +) => Semigroup<{ readonly [K in keyof R]: [R[K]] extends [Semigroup] ? A : never }> = + product_.struct(Product) diff --git a/test/typeclass/Monoid.ts b/test/typeclass/Monoid.ts index 3ac669b4d..16a16393f 100644 --- a/test/typeclass/Monoid.ts +++ b/test/typeclass/Monoid.ts @@ -4,10 +4,6 @@ import * as _ from "@fp-ts/core/typeclass/Monoid" import * as U from "../util" describe("Monoid", () => { - it("exports", () => { - expect(_.mutableArray).exists - }) - it("min", () => { const M = _.min(N.Bounded) U.deepStrictEqual(M.combineAll([]), +Infinity) diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index 73f432725..4c6be7c77 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -8,7 +8,6 @@ import * as U from "../util" describe("Semigroup", () => { it("exports", () => { expect(_.Invariant).exist - expect(_.mutableArray).exists }) it("reverse", () => { From 190d467f4b1ec004cd7edd363d0523c9c0412edb Mon Sep 17 00:00:00 2001 From: Milan Suk Date: Sun, 12 Feb 2023 17:31:26 +0100 Subject: [PATCH 244/255] make `mapComposition` non-curried --- docs/modules/typeclass/Covariant.ts.md | 5 ++--- src/typeclass/Covariant.ts | 7 +++---- test/typeclass/Covariant.ts | 10 +++++----- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/docs/modules/typeclass/Covariant.ts.md b/docs/modules/typeclass/Covariant.ts.md index f0325bc30..32581ead9 100644 --- a/docs/modules/typeclass/Covariant.ts.md +++ b/docs/modules/typeclass/Covariant.ts.md @@ -139,10 +139,9 @@ Returns a default `map` composition. export declare const mapComposition: ( F: Covariant, G: Covariant -) => ( +) => ( + self: Kind>, f: (a: A) => B -) => ( - self: Kind> ) => Kind> ``` diff --git a/src/typeclass/Covariant.ts b/src/typeclass/Covariant.ts index a0e0eed67..bca0b2457 100644 --- a/src/typeclass/Covariant.ts +++ b/src/typeclass/Covariant.ts @@ -24,11 +24,10 @@ export interface Covariant extends Invariant { export const mapComposition = ( F: Covariant, G: Covariant -): (( +): (( + self: Kind>, f: (a: A) => B -) => ( - self: Kind> -) => Kind>) => f => F.map(G.map(f)) +) => Kind>) => (self, f) => F.map(self, G.map(f)) /** * Returns a default `imap` implementation. diff --git a/test/typeclass/Covariant.ts b/test/typeclass/Covariant.ts index c803cfbb0..1ecc7ca6e 100644 --- a/test/typeclass/Covariant.ts +++ b/test/typeclass/Covariant.ts @@ -8,11 +8,11 @@ describe("Covariant", () => { it("mapComposition", () => { const map = _.mapComposition(RA.Covariant, RA.Covariant) const f = (a: string) => a + "!" - U.deepStrictEqual(pipe([], map(f)), []) - U.deepStrictEqual(pipe([[]], map(f)), [[]]) - U.deepStrictEqual(pipe([["a"]], map(f)), [["a!"]]) - U.deepStrictEqual(pipe([["a"], ["b"]], map(f)), [["a!"], ["b!"]]) - U.deepStrictEqual(pipe([["a", "c"], ["b", "d", "e"]], map(f)), [["a!", "c!"], [ + U.deepStrictEqual(map([], f), []) + U.deepStrictEqual(map([[]], f), [[]]) + U.deepStrictEqual(map([["a"]], f), [["a!"]]) + U.deepStrictEqual(map([["a"], ["b"]], f), [["a!"], ["b!"]]) + U.deepStrictEqual(map([["a", "c"], ["b", "d", "e"]], f), [["a!", "c!"], [ "b!", "d!", "e!" From 14c748b62131341b29315798ce7bed61317f3622 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 13 Feb 2023 06:13:53 +0100 Subject: [PATCH 245/255] do not export productAll from Predicate, Equivalence, Order, Semigroup --- docs/modules/Predicate.ts.md | 23 --------------- docs/modules/typeclass/Equivalence.ts.md | 34 ---------------------- docs/modules/typeclass/Monoid.ts.md | 3 +- docs/modules/typeclass/Order.ts.md | 23 --------------- docs/modules/typeclass/Semigroup.ts.md | 20 ------------- src/Predicate.ts | 17 +---------- src/typeclass/Equivalence.ts | 36 ++---------------------- src/typeclass/Monoid.ts | 3 +- src/typeclass/Order.ts | 19 ++----------- src/typeclass/Semigroup.ts | 16 ++--------- test/Predicate.ts | 2 +- test/typeclass/Equivalence.ts | 12 ++------ test/typeclass/Order.ts | 4 +-- test/typeclass/Semigroup.ts | 4 +-- 14 files changed, 21 insertions(+), 195 deletions(-) diff --git a/docs/modules/Predicate.ts.md b/docs/modules/Predicate.ts.md index ddd8296b9..d2be420df 100644 --- a/docs/modules/Predicate.ts.md +++ b/docs/modules/Predicate.ts.md @@ -16,8 +16,6 @@ Added in v1.0.0 - [and](#and) - [not](#not) - [or](#or) -- [combining](#combining) - - [productAll](#productall) - [constructors](#constructors) - [contramap](#contramap) - [do notation](#do-notation) @@ -157,27 +155,6 @@ assert.deepStrictEqual(nonZero(1), true) Added in v1.0.0 -# combining - -## productAll - -Similar to `Promise.all` but operates on `Predicate`s. - -``` -Iterable> -> Predicate -``` - -Given an iterable of `Predicate` returns an `Predicate>` that operates on arrays -by applying each predicate in the iterable in order until a predicate fails. - -**Signature** - -```ts -export declare const productAll: (collection: Iterable>) => Predicate -``` - -Added in v1.0.0 - # constructors ## contramap diff --git a/docs/modules/typeclass/Equivalence.ts.md b/docs/modules/typeclass/Equivalence.ts.md index 06700caa9..af8b11e36 100644 --- a/docs/modules/typeclass/Equivalence.ts.md +++ b/docs/modules/typeclass/Equivalence.ts.md @@ -17,12 +17,9 @@ Added in v1.0.0

Table of contents

- [combinators](#combinators) - - [array](#array) - [contramap](#contramap) - [struct](#struct) - [tuple](#tuple) -- [combining](#combining) - - [all](#all) - [constructors](#constructors) - [make](#make) - [strict](#strict) @@ -47,16 +44,6 @@ Added in v1.0.0 # combinators -## array - -**Signature** - -```ts -export declare const array:
(equivalence: Equivalence) => Equivalence -``` - -Added in v1.0.0 - ## contramap **Signature** @@ -106,27 +93,6 @@ export declare const tuple: []>( Added in v1.0.0 -# combining - -## all - -Similar to `Promise.all` but operates on `Equivalence`s. - -``` -Iterable> -> Equivalence -``` - -Given an iterable of `Equivalence` returns an `Equivalence>` that operates on arrays -by applying each equivalence in the iterable in order until a difference is found. - -**Signature** - -```ts -export declare const all: (collection: Iterable>) => Equivalence -``` - -Added in v1.0.0 - # constructors ## make diff --git a/docs/modules/typeclass/Monoid.ts.md b/docs/modules/typeclass/Monoid.ts.md index b03acba86..8f62f8566 100644 --- a/docs/modules/typeclass/Monoid.ts.md +++ b/docs/modules/typeclass/Monoid.ts.md @@ -41,7 +41,8 @@ Added in v1.0.0 ## array Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. -The returned `Monoid`'s empty value is the empty array. + +The `empty` value is the empty array. **Signature** diff --git a/docs/modules/typeclass/Order.ts.md b/docs/modules/typeclass/Order.ts.md index 5f996a712..0405c06aa 100644 --- a/docs/modules/typeclass/Order.ts.md +++ b/docs/modules/typeclass/Order.ts.md @@ -17,8 +17,6 @@ Added in v1.0.0 - [contramap](#contramap) - [struct](#struct) - [tuple](#tuple) -- [combining](#combining) - - [all](#all) - [constructors](#constructors) - [make](#make) - [instances](#instances) @@ -117,27 +115,6 @@ export declare const tuple: []>( Added in v1.0.0 -# combining - -## all - -Similar to `Promise.all` but operates on `Order`s. - -``` -Iterable> -> Order -``` - -Given an iterable of `Order` returns an `Order>` that operates on arrays -by applying each order in the iterable in order until a difference is found. - -**Signature** - -```ts -export declare const all: (collection: Iterable>) => Order -``` - -Added in v1.0.0 - # constructors ## make diff --git a/docs/modules/typeclass/Semigroup.ts.md b/docs/modules/typeclass/Semigroup.ts.md index 3493a0641..a71d23454 100644 --- a/docs/modules/typeclass/Semigroup.ts.md +++ b/docs/modules/typeclass/Semigroup.ts.md @@ -16,8 +16,6 @@ Added in v1.0.0 - [array](#array) - [struct](#struct) - [tuple](#tuple) -- [combining](#combining) - - [all](#all) - [constructors](#constructors) - [constant](#constant) - [make](#make) @@ -104,24 +102,6 @@ export declare const tuple: []>( Added in v1.0.0 -# combining - -## all - -Similar to `Promise.all` but operates on `Semigroup`s. - -``` -Iterable> -> Semigroup -``` - -**Signature** - -```ts -export declare const all: (collection: Iterable>) => Semigroup -``` - -Added in v1.0.0 - # constructors ## constant diff --git a/src/Predicate.ts b/src/Predicate.ts index 2024450f4..0bc999687 100644 --- a/src/Predicate.ts +++ b/src/Predicate.ts @@ -473,22 +473,7 @@ export const unit: Predicate = of_.unit(Of) const product = (self: Predicate, that: Predicate): Predicate => ([a, b]) => self(a) && that(b) -/** - * Similar to `Promise.all` but operates on `Predicate`s. - * - * ``` - * Iterable> -> Predicate - * ``` - * - * Given an iterable of `Predicate` returns an `Predicate>` that operates on arrays - * by applying each predicate in the iterable in order until a predicate fails. - * - * @param collection - An iterable collection of `Predicate`s to flatten. - * - * @category combining - * @since 1.0.0 - */ -export const productAll = ( +const productAll = ( collection: Iterable> ): Predicate> => { const predicates = readonlyArray.fromIterable(collection) diff --git a/src/typeclass/Equivalence.ts b/src/typeclass/Equivalence.ts index 158c1affd..5ab635aa6 100644 --- a/src/typeclass/Equivalence.ts +++ b/src/typeclass/Equivalence.ts @@ -144,20 +144,7 @@ export const Invariant: invariant.Invariant = { const product = (self: Equivalence, that: Equivalence): Equivalence<[A, B]> => make(([xa, xb], [ya, yb]) => self(xa, ya) && that(xb, yb)) -/** - * Similar to `Promise.all` but operates on `Equivalence`s. - * - * ``` - * Iterable> -> Equivalence - * ``` - * - * Given an iterable of `Equivalence` returns an `Equivalence>` that operates on arrays - * by applying each equivalence in the iterable in order until a difference is found. - * - * @category combining - * @since 1.0.0 - */ -export const all = (collection: Iterable>): Equivalence> => { +const productAll = (collection: Iterable>): Equivalence> => { const equivalences = readonlyArray.fromIterable(collection) return make((x, y) => { const len = Math.min(x.length, y.length, equivalences.length) @@ -174,7 +161,7 @@ const productMany = ( self: Equivalence, collection: Iterable> ): Equivalence<[A, ...Array]> => { - const equivalence = all(collection) + const equivalence = productAll(collection) return make((x, y) => !self(x[0], y[0]) ? false : equivalence(x.slice(1), y.slice(1))) } @@ -199,7 +186,7 @@ export const Product: product_.Product = { imap, product, productMany, - productAll: all + productAll } /** @@ -220,23 +207,6 @@ export const tuple: >>( ) => Equivalence] ? A : never }>> = product_.tuple(Product) -/** - * @category combinators - * @since 1.0.0 - */ -export const array = ( - equivalence: Equivalence -): Equivalence> => - make((x, y) => { - const len = Math.min(x.length, y.length) - for (let i = 0; i < len; i++) { - if (!equivalence(x[i], y[i])) { - return false - } - } - return true - }) - /** * Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct * by applying each `Equivalence` to the corresponding property of the struct. diff --git a/src/typeclass/Monoid.ts b/src/typeclass/Monoid.ts index a0f05b756..68b90b1ca 100644 --- a/src/typeclass/Monoid.ts +++ b/src/typeclass/Monoid.ts @@ -165,7 +165,8 @@ export const tuple = >>( /** * Given a type `A`, this function creates and returns a `Semigroup` for `ReadonlyArray`. - * The returned `Monoid`'s empty value is the empty array. + * + * The `empty` value is the empty array. * * @category combinators * @since 1.0.0 diff --git a/src/typeclass/Order.ts b/src/typeclass/Order.ts index 060e4e939..d61086c8c 100644 --- a/src/typeclass/Order.ts +++ b/src/typeclass/Order.ts @@ -143,20 +143,7 @@ const product = (self: Order, that: Order): Order<[A, B]> => return o !== 0 ? o : that.compare(xb, yb) }) -/** - * Similar to `Promise.all` but operates on `Order`s. - * - * ``` - * Iterable> -> Order - * ``` - * - * Given an iterable of `Order` returns an `Order>` that operates on arrays - * by applying each order in the iterable in order until a difference is found. - * - * @category combining - * @since 1.0.0 - */ -export const all = (collection: Iterable>): Order> => { +const productAll = (collection: Iterable>): Order> => { const orders = readonlyArray.fromIterable(collection) return make((x, y) => { const len = Math.min(x.length, y.length, orders.length) @@ -174,7 +161,7 @@ const productMany = ( self: Order, collection: Iterable> ): Order<[A, ...Array]> => { - const order = all(collection) + const order = productAll(collection) return make((x, y) => { const o = self.compare(x[0], y[0]) return o !== 0 ? o : order.compare(x.slice(1), y.slice(1)) @@ -202,7 +189,7 @@ export const Product: product_.Product = { imap, product, productMany, - productAll: all + productAll } /** diff --git a/src/typeclass/Semigroup.ts b/src/typeclass/Semigroup.ts index 3f3e72153..f9866e1db 100644 --- a/src/typeclass/Semigroup.ts +++ b/src/typeclass/Semigroup.ts @@ -268,17 +268,7 @@ export const Invariant: invariant.Invariant = { const product = (self: Semigroup, that: Semigroup): Semigroup<[A, B]> => make(([xa, xb], [ya, yb]) => [self.combine(xa, ya), that.combine(xb, yb)]) -/** - * Similar to `Promise.all` but operates on `Semigroup`s. - * - * ``` - * Iterable> -> Semigroup - * ``` - * - * @category combining - * @since 1.0.0 - */ -export const all = (collection: Iterable>): Semigroup> => { +const productAll = (collection: Iterable>): Semigroup> => { const semigroups = readonlyArray.fromIterable(collection) return make((x, y) => { const len = Math.min(x.length, y.length, semigroups.length) @@ -294,7 +284,7 @@ const productMany = ( self: Semigroup, collection: Iterable> ): Semigroup<[A, ...Array]> => { - const semigroup = all(collection) + const semigroup = productAll(collection) return make((x, y) => [self.combine(x[0], y[0]), ...semigroup.combine(x.slice(1), y.slice(1))]) } @@ -319,7 +309,7 @@ export const Product: product_.Product = { imap, product, productMany, - productAll: all + productAll } /** diff --git a/test/Predicate.ts b/test/Predicate.ts index ecf1e81da..39806fb32 100644 --- a/test/Predicate.ts +++ b/test/Predicate.ts @@ -78,7 +78,7 @@ describe.concurrent("Predicate", () => { }) it("productAll", () => { - const p = _.productAll([isPositive, isNegative]) + const p = _.Product.productAll([isPositive, isNegative]) deepStrictEqual(p([1]), true) deepStrictEqual(p([1, -1]), true) deepStrictEqual(p([1, 1]), false) diff --git a/test/typeclass/Equivalence.ts b/test/typeclass/Equivalence.ts index dcb6b3086..21b365ab3 100644 --- a/test/typeclass/Equivalence.ts +++ b/test/typeclass/Equivalence.ts @@ -82,16 +82,8 @@ describe("Equivalence", () => { expect(eq(["a", "b"], ["a", "c"])).toEqual(false) }) - it("all", () => { - const eq = _.all([_.string, _.string]) - expect(eq(["a"], ["a"])).toEqual(true) - expect(eq(["a"], ["b"])).toEqual(false) - expect(eq(["a", "b"], ["a", "b"])).toEqual(true) - expect(eq(["a", "b"], ["a", "c"])).toEqual(false) - }) - - it("array", () => { - const eq = _.array(_.string) + it("productAll", () => { + const eq = _.Product.productAll([_.string, _.string]) expect(eq(["a"], ["a"])).toEqual(true) expect(eq(["a"], ["b"])).toEqual(false) expect(eq(["a", "b"], ["a", "b"])).toEqual(true) diff --git a/test/typeclass/Order.ts b/test/typeclass/Order.ts index ae978ac1c..d119c1d6c 100644 --- a/test/typeclass/Order.ts +++ b/test/typeclass/Order.ts @@ -13,8 +13,8 @@ describe("Order", () => { expect(_.bigint).exist }) - it("all", () => { - const O = _.all([_.string, _.string]) + it("productAll", () => { + const O = _.Product.productAll([_.string, _.string]) U.deepStrictEqual(O.compare(["a"], ["b"]), -1) U.deepStrictEqual(O.compare(["a"], ["a"]), 0) U.deepStrictEqual(O.compare(["b"], ["a"]), 1) diff --git a/test/typeclass/Semigroup.ts b/test/typeclass/Semigroup.ts index 4c6be7c77..c5a9b10d8 100644 --- a/test/typeclass/Semigroup.ts +++ b/test/typeclass/Semigroup.ts @@ -112,8 +112,8 @@ describe("Semigroup", () => { U.deepStrictEqual(S.combine(["a", "b", "c"], ["d", "e", "f"]), ["ad", "be", "cf"]) }) - it("all", () => { - const S = _.all([String.Semigroup, String.Semigroup]) + it("productAll", () => { + const S = _.Product.productAll([String.Semigroup, String.Semigroup]) U.deepStrictEqual(S.combine(["a1", "b1"], ["a2", "b2"]), ["a1a2", "b1b2"]) }) }) From 6914a7d02ad0be538207657ad314777fd7d77aeb Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 13 Feb 2023 07:23:36 +0100 Subject: [PATCH 246/255] Tuple: add more APIs --- .changeset/beige-numbers-exist.md | 5 + docs/modules/Either.ts.md | 54 ++++----- docs/modules/Option.ts.md | 72 +++++------ docs/modules/Tuple.ts.md | 194 ++++++++++++++++++++++++++++++ src/Either.ts | 93 +++++--------- src/Option.ts | 64 +++++----- src/Tuple.ts | 150 ++++++++++++++++++++++- test/Tuple.ts | 19 +++ 8 files changed, 487 insertions(+), 164 deletions(-) create mode 100644 .changeset/beige-numbers-exist.md diff --git a/.changeset/beige-numbers-exist.md b/.changeset/beige-numbers-exist.md new file mode 100644 index 000000000..a542b7177 --- /dev/null +++ b/.changeset/beige-numbers-exist.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Tuple: add more APIs diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index 76e011dff..b79bd6f09 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -47,9 +47,11 @@ Added in v1.0.0 - [do notation](#do-notation) - [Do](#do) - [andThenBind](#andthenbind) + - [appendElement](#appendelement) - [bind](#bind) - [bindTo](#bindto) - [let](#let) + - [tupled](#tupled) - [equivalence](#equivalence) - [getEquivalence](#getequivalence) - [error handling](#error-handling) @@ -108,7 +110,6 @@ Added in v1.0.0 - [bimap](#bimap) - [flap](#flap) - [map](#map) - - [tupled](#tupled) - [models](#models) - [Either (type alias)](#either-type-alias) - [Left (interface)](#left-interface) @@ -124,7 +125,6 @@ Added in v1.0.0 - [utils](#utils) - [andThen](#andthen) - [ap](#ap) - - [appendElement](#appendelement) - [composeKleisliArrow](#composekleisliarrow) - [contains](#contains) - [exists](#exists) @@ -635,6 +635,21 @@ assert.deepStrictEqual(result, E.left('e1')) Added in v1.0.0 +## appendElement + +Appends an element to the end of a tuple. + +**Signature** + +```ts +export declare const appendElement: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} +``` + +Added in v1.0.0 + ## bind **Signature** @@ -685,6 +700,16 @@ export declare const let: { Added in v1.0.0 +## tupled + +**Signature** + +```ts +export declare const tupled: (self: Either) => Either +``` + +Added in v1.0.0 + # equivalence ## getEquivalence @@ -1421,16 +1446,6 @@ export declare const map: { Added in v1.0.0 -## tupled - -**Signature** - -```ts -export declare const tupled: (self: Either) => Either -``` - -Added in v1.0.0 - # models ## Either (type alias) @@ -1587,21 +1602,6 @@ export declare const ap: { Added in v1.0.0 -## appendElement - -Appends an element to the end of a tuple. - -**Signature** - -```ts -export declare const appendElement: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} -``` - -Added in v1.0.0 - ## composeKleisliArrow **Signature** diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index 17b8d6495..e52ab8f5e 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -22,7 +22,6 @@ Added in v1.0.0 - [combining](#combining) - [all](#all) - [ap](#ap) - - [appendElement](#appendelement) - [getFailureMonoid](#getfailuremonoid) - [getFailureSemigroup](#getfailuresemigroup) - [getFirstSomeSemigroup](#getfirstsomesemigroup) @@ -55,9 +54,11 @@ Added in v1.0.0 - [do notation](#do-notation) - [Do](#do) - [andThenBind](#andthenbind) + - [appendElement](#appendelement) - [bind](#bind) - [bindTo](#bindto) - [let](#let) + - [tupled](#tupled) - [equivalence](#equivalence) - [getEquivalence](#getequivalence) - [error handling](#error-handling) @@ -103,7 +104,6 @@ Added in v1.0.0 - [flatten](#flatten) - [map](#map) - [tap](#tap) - - [tupled](#tupled) - [type lambdas](#type-lambdas) - [OptionTypeLambda (interface)](#optiontypelambda-interface) - [utils](#utils) @@ -271,30 +271,6 @@ export declare const ap: { Added in v1.0.0 -## appendElement - -Appends an element to the end of a tuple wrapped in an `Option` type. - -**Signature** - -```ts -export declare const appendElement: { - (self: Option, that: Option): Option<[...A, B]> - (that: Option): (self: Option) => Option<[...A, B]> -} -``` - -**Example** - -```ts -import * as O from '@fp-ts/core/Option' - -assert.deepStrictEqual(O.appendElement(O.some([1, 2]), O.some(3)), O.some([1, 2, 3])) -assert.deepStrictEqual(O.appendElement(O.some([1, 2]), O.none()), O.none()) -``` - -Added in v1.0.0 - ## getFailureMonoid Monoid that models the combination of computations that can fail, if at least one element is `None` @@ -881,6 +857,30 @@ export declare const andThenBind: { Added in v1.0.0 +## appendElement + +Appends an element to the end of a tuple wrapped in an `Option` type. + +**Signature** + +```ts +export declare const appendElement: { + (self: Option, that: Option): Option<[...A, B]> + (that: Option): (self: Option) => Option<[...A, B]> +} +``` + +**Example** + +```ts +import * as O from '@fp-ts/core/Option' + +assert.deepStrictEqual(O.appendElement(O.some([1, 2]), O.some(3)), O.some([1, 2, 3])) +assert.deepStrictEqual(O.appendElement(O.some([1, 2]), O.none()), O.none()) +``` + +Added in v1.0.0 + ## bind **Signature** @@ -928,6 +928,16 @@ export declare const let: { Added in v1.0.0 +## tupled + +**Signature** + +```ts +export declare const tupled: (self: Option) => Option<[A]> +``` + +Added in v1.0.0 + # equivalence ## getEquivalence @@ -1686,16 +1696,6 @@ export declare const tap: { Added in v1.0.0 -## tupled - -**Signature** - -```ts -export declare const tupled: (self: Option) => Option<[A]> -``` - -Added in v1.0.0 - # type lambdas ## OptionTypeLambda (interface) diff --git a/docs/modules/Tuple.ts.md b/docs/modules/Tuple.ts.md index 9da196763..9b052a870 100644 --- a/docs/modules/Tuple.ts.md +++ b/docs/modules/Tuple.ts.md @@ -21,8 +21,20 @@ Added in v1.0.0 - [getSemigroup](#getsemigroup) - [constructors](#constructors) - [tuple](#tuple) +- [getters](#getters) + - [getFirst](#getfirst) + - [getSecond](#getsecond) +- [instances](#instances) + - [Bicovariant](#bicovariant) +- [mapping](#mapping) + - [bimap](#bimap) + - [mapFirst](#mapfirst) + - [mapSecond](#mapsecond) +- [type lambdas](#type-lambdas) + - [TupleTypeLambda (interface)](#tupletypelambda-interface) - [utils](#utils) - [appendElement](#appendelement) + - [swap](#swap) --- @@ -102,12 +114,174 @@ Added in v1.0.0 ## tuple +Constructs a new tuple from the provided values. + **Signature** ```ts export declare const tuple: (...elements: A) => A ``` +**Example** + +```ts +import { tuple } from '@fp-ts/core/Tuple' + +assert.deepStrictEqual(tuple(1, 'hello', true), [1, 'hello', true]) +``` + +Added in v1.0.0 + +# getters + +## getFirst + +Return the first element of a tuple. + +**Signature** + +```ts +export declare const getFirst: (self: readonly [L, R]) => L +``` + +**Example** + +```ts +import { getFirst } from '@fp-ts/core/Tuple' + +assert.deepStrictEqual(getFirst(['hello', 42]), 'hello') +``` + +Added in v1.0.0 + +## getSecond + +Return the second element of a tuple. + +**Signature** + +```ts +export declare const getSecond: (self: readonly [L, R]) => R +``` + +**Example** + +```ts +import { getSecond } from '@fp-ts/core/Tuple' + +assert.deepStrictEqual(getSecond(['hello', 42]), 42) +``` + +Added in v1.0.0 + +# instances + +## Bicovariant + +**Signature** + +```ts +export declare const Bicovariant: bicovariant.Bicovariant +``` + +Added in v1.0.0 + +# mapping + +## bimap + +Transforms both elements of a tuple using the given functions. + +**Signature** + +```ts +export declare const bimap: { + (f: (e: L1) => L2, g: (a: R1) => R2): (self: readonly [L1, R1]) => [L2, R2] + (self: readonly [L1, R1], f: (e: L1) => L2, g: (a: R1) => R2): [L2, R2] +} +``` + +**Example** + +```ts +import { bimap } from '@fp-ts/core/Tuple' + +assert.deepStrictEqual( + bimap( + ['hello', 42], + (s) => s.toUpperCase(), + (n) => n.toString() + ), + ['HELLO', '42'] +) +``` + +Added in v1.0.0 + +## mapFirst + +Transforms the first component of a tuple using a given function. + +**Signature** + +```ts +export declare const mapFirst: { + (f: (left: L1) => L2): (self: readonly [L1, R]) => [L2, R] + (self: readonly [L1, R], f: (left: L1) => L2): [L2, R] +} +``` + +**Example** + +```ts +import { mapFirst } from '@fp-ts/core/Tuple' + +assert.deepStrictEqual( + mapFirst(['hello', 42], (s) => s.toUpperCase()), + ['HELLO', 42] +) +``` + +Added in v1.0.0 + +## mapSecond + +Transforms the second component of a tuple using a given function. + +**Signature** + +```ts +export declare const mapSecond: { + (f: (right: R1) => R2): (self: readonly [L, R1]) => [L, R2] + (self: readonly [L, R1], f: (right: R1) => R2): [L, R2] +} +``` + +**Example** + +```ts +import { mapSecond } from '@fp-ts/core/Tuple' + +assert.deepStrictEqual( + mapSecond(['hello', 42], (n) => n.toString()), + ['hello', '42'] +) +``` + +Added in v1.0.0 + +# type lambdas + +## TupleTypeLambda (interface) + +**Signature** + +```ts +export interface TupleTypeLambda extends TypeLambda { + readonly type: [this['Out1'], this['Target']] +} +``` + Added in v1.0.0 # utils @@ -126,3 +300,23 @@ export declare const appendElement: { ``` Added in v1.0.0 + +## swap + +Swaps the two elements of a tuple. + +**Signature** + +```ts +export declare const swap: (self: readonly [L, R]) => [R, L] +``` + +**Example** + +```ts +import { swap } from '@fp-ts/core/Tuple' + +assert.deepStrictEqual(swap(['hello', 42]), [42, 'hello']) +``` + +Added in v1.0.0 diff --git a/src/Either.ts b/src/Either.ts index 5ee32f84a..4179e101f 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -33,9 +33,11 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" -// ------------------------------------------------------------------------------------- -// models -// ------------------------------------------------------------------------------------- +/** + * @category models + * @since 1.0.0 + */ +export type Either = Left | Right /** * @category models @@ -55,12 +57,6 @@ export interface Right { readonly right: A } -/** - * @category models - * @since 1.0.0 - */ -export type Either = Left | Right - /** * @category type lambdas * @since 1.0.0 @@ -69,10 +65,6 @@ export interface EitherTypeLambda extends TypeLambda { readonly type: Either } -// ------------------------------------------------------------------------------------- -// constructors -// ------------------------------------------------------------------------------------- - /** * Constructs a new `Either` holding a `Right` value. This usually represents a successful value due to the right bias * of this structure. @@ -99,10 +91,6 @@ export const left: (e: E) => Either = either.left */ export const of: (a: A) => Either = right -// ------------------------------------------------------------------------------------- -// guards -// ------------------------------------------------------------------------------------- - /** * Tests if a value is a `Either`. * @@ -154,10 +142,6 @@ export const isLeft: (self: Either) => self is Left = either.isLe */ export const isRight: (self: Either) => self is Right = either.isRight -// ------------------------------------------------------------------------------------- -// conversions -// ------------------------------------------------------------------------------------- - /** * Returns a `Refinement` from a `Either` returning function. * This function ensures that a `Refinement` definition is type-safe. @@ -247,10 +231,6 @@ export const fromOption: { (onNone: () => E): (fa: Option) => Either } = either.fromOption -// ------------------------------------------------------------------------------------- -// equivalence -// ------------------------------------------------------------------------------------- - /** * @category equivalence * @since 1.0.0 @@ -338,14 +318,6 @@ export const Invariant: invariant.Invariant = { imap } -/** - * @category mapping - * @since 1.0.0 - */ -export const tupled: (self: Either) => Either = invariant.tupled( - Invariant -) - /** * @category mapping * @since 1.0.0 @@ -510,21 +482,6 @@ export const SemiProduct: semiProduct.SemiProduct = { productMany } -/** - * Appends an element to the end of a tuple. - * - * @since 1.0.0 - */ -export const appendElement: { - , E2, B>( - self: Either, - that: Either - ): Either - ( - that: Either - ): >(self: Either) => Either -} = semiProduct.appendElement(SemiProduct) - /** * Similar to `Promise.all` but operates on `Either`s. * @@ -906,10 +863,6 @@ export const match: { isLeft(self) ? onLeft(self.left) : onRight(self.right) ) -// ------------------------------------------------------------------------------------- -// interop -// ------------------------------------------------------------------------------------- - /** * Takes a lazy default and a nullable value, if the value is not nully, turn it into a `Right`, if the value is nully use * the provided default as a `Left`. @@ -1177,10 +1130,6 @@ export const tap: { (f: (a: A) => Either): (self: Either) => Either } = chainable.tap(Chainable) -// ------------------------------------------------------------------------------------- -// debugging -// ------------------------------------------------------------------------------------- - /** * @category debugging * @since 1.0.0 @@ -1352,10 +1301,6 @@ export const getOptionalSemigroup = (S: Semigroup): Semigroup (isLeft(y) ? x : isLeft(x) ? y : right(S.combine(x.right, y.right)))) -// ------------------------------------------------------------------------------------- -// algebraic operations -// ------------------------------------------------------------------------------------- - /** * @category algebraic operations * @since 1.0.0 @@ -1392,10 +1337,6 @@ export const divide: { (that: Either): (self: Either) => Either } = lift2(N.divide) -// ------------------------------------------------------------------------------------- -// utils -// ------------------------------------------------------------------------------------- - /** * Return all the `Right` elements from an `Interable` of `Either`s. * @@ -1432,6 +1373,30 @@ export const lefts = (self: Iterable>): Array => { // do notation // ------------------------------------------------------------------------------------- +/** + * @category do notation + * @since 1.0.0 + */ +export const tupled: (self: Either) => Either = invariant.tupled( + Invariant +) + +/** + * Appends an element to the end of a tuple. + * + * @category do notation + * @since 1.0.0 + */ +export const appendElement: { + , E2, B>( + self: Either, + that: Either + ): Either + ( + that: Either + ): >(self: Either) => Either +} = semiProduct.appendElement(SemiProduct) + /** * @category do notation * @since 1.0.0 diff --git a/src/Option.ts b/src/Option.ts index 326432293..ec79fe5ef 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -37,6 +37,12 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" import * as semiProduct from "@fp-ts/core/typeclass/SemiProduct" import * as traversable from "@fp-ts/core/typeclass/Traversable" +/** + * @category models + * @since 1.0.0 + */ +export type Option = None | Some + /** * @category models * @since 1.0.0 @@ -54,12 +60,6 @@ export interface Some { readonly value: A } -/** - * @category models - * @since 1.0.0 - */ -export type Option = None | Some - /** * @category type lambdas * @since 1.0.0 @@ -642,12 +642,6 @@ export const Invariant: invariant.Invariant = { imap } -/** - * @category transforming - * @since 1.0.0 - */ -export const tupled: (self: Option) => Option<[A]> = invariant.tupled(Invariant) - /** * @category transforming * @since 1.0.0 @@ -940,26 +934,6 @@ export const SemiProduct: semiProduct.SemiProduct = { productMany } -/** - * Appends an element to the end of a tuple wrapped in an `Option` type. - * - * @param self - The option of a tuple to which an element needs to be added. - * @param that - The element which needs to be added to the tuple. - * - * @example - * import * as O from "@fp-ts/core/Option" - * - * assert.deepStrictEqual(O.appendElement(O.some([1, 2]), O.some(3)), O.some([1, 2, 3])) - * assert.deepStrictEqual(O.appendElement(O.some([1, 2]), O.none()), O.none()) - * - * @category combining - * @since 1.0.0 - */ -export const appendElement: { - , B>(self: Option, that: Option): Option<[...A, B]> - (that: Option): >(self: Option) => Option<[...A, B]> -} = semiProduct.appendElement(SemiProduct) - /** * @since 1.0.0 */ @@ -1642,6 +1616,32 @@ export const multiplyCompact = (self: Iterable>): number => { // do notation // ------------------------------------------------------------------------------------- +/** + * @category do notation + * @since 1.0.0 + */ +export const tupled: (self: Option) => Option<[A]> = invariant.tupled(Invariant) + +/** + * Appends an element to the end of a tuple wrapped in an `Option` type. + * + * @param self - The option of a tuple to which an element needs to be added. + * @param that - The element which needs to be added to the tuple. + * + * @example + * import * as O from "@fp-ts/core/Option" + * + * assert.deepStrictEqual(O.appendElement(O.some([1, 2]), O.some(3)), O.some([1, 2, 3])) + * assert.deepStrictEqual(O.appendElement(O.some([1, 2]), O.none()), O.none()) + * + * @category do notation + * @since 1.0.0 + */ +export const appendElement: { + , B>(self: Option, that: Option): Option<[...A, B]> + (that: Option): >(self: Option) => Option<[...A, B]> +} = semiProduct.appendElement(SemiProduct) + /** * @category do notation * @since 1.0.0 diff --git a/src/Tuple.ts b/src/Tuple.ts index 83e1b8557..429272fcc 100644 --- a/src/Tuple.ts +++ b/src/Tuple.ts @@ -4,17 +4,162 @@ * @since 1.0.0 */ import { dual } from "@fp-ts/core/Function" +import type { TypeLambda } from "@fp-ts/core/HKT" +import * as bicovariant from "@fp-ts/core/typeclass/Bicovariant" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as order from "@fp-ts/core/typeclass/Order" import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** + * @category type lambdas + * @since 1.0.0 + */ +export interface TupleTypeLambda extends TypeLambda { + readonly type: [this["Out1"], this["Target"]] +} + +/** + * Constructs a new tuple from the provided values. + * + * @param elements - The list of elements to create the tuple from. + * + * @example + * import { tuple } from "@fp-ts/core/Tuple" + * + * assert.deepStrictEqual(tuple(1, 'hello', true), [1, 'hello', true]) + * * @category constructors * @since 1.0.0 */ export const tuple = >(...elements: A): A => elements +/** + * Return the first element of a tuple. + * + * @param self - A tuple of length `2`. + * + * @example + * import { getFirst } from "@fp-ts/core/Tuple" + * + * assert.deepStrictEqual(getFirst(["hello", 42]), "hello") + * + * @category getters + * @since 1.0.0 + */ +export const getFirst = (self: readonly [L, R]): L => self[0] + +/** + * Return the second element of a tuple. + * + * @param self - A tuple of length `2`. + * + * @example + * import { getSecond } from "@fp-ts/core/Tuple" + * + * assert.deepStrictEqual(getSecond(["hello", 42]), 42) + * + * @category getters + * @since 1.0.0 + */ +export const getSecond = (self: readonly [L, R]): R => self[1] + +/** + * Transforms both elements of a tuple using the given functions. + * + * @param self - A tuple of length `2`. + * @param f - The function to transform the first element of the tuple. + * @param g - The function to transform the second element of the tuple. + * + * @example + * import { bimap } from "@fp-ts/core/Tuple" + * + * assert.deepStrictEqual( + * bimap(["hello", 42], s => s.toUpperCase(), n => n.toString()), + * ["HELLO", "42"] + * ) + * + * @category mapping + * @since 1.0.0 + */ +export const bimap: { + (f: (e: L1) => L2, g: (a: R1) => R2): (self: readonly [L1, R1]) => [L2, R2] + (self: readonly [L1, R1], f: (e: L1) => L2, g: (a: R1) => R2): [L2, R2] +} = dual( + 3, + ( + self: readonly [L1, R1], + f: (e: L1) => L2, + g: (a: R1) => R2 + ): [L2, R2] => [f(self[0]), g(self[1])] +) + +/** + * @category instances + * @since 1.0.0 + */ +export const Bicovariant: bicovariant.Bicovariant = { + bimap +} + +/** + * Transforms the first component of a tuple using a given function. + * + * @param self - A tuple of length `2`. + * @param f - The function to transform the first element of the tuple. + * + * @example + * import { mapFirst } from "@fp-ts/core/Tuple" + * + * assert.deepStrictEqual( + * mapFirst(["hello", 42], s => s.toUpperCase()), + * ["HELLO", 42] + * ) + * + * @category mapping + * @since 1.0.0 + */ +export const mapFirst: { + (f: (left: L1) => L2): (self: readonly [L1, R]) => [L2, R] + (self: readonly [L1, R], f: (left: L1) => L2): [L2, R] +} = bicovariant.mapLeft(Bicovariant) as any + +/** + * Transforms the second component of a tuple using a given function. + * + * @param self - A tuple of length `2`. + * @param f - The function to transform the second element of the tuple. + * + * @example + * import { mapSecond } from "@fp-ts/core/Tuple" + * + * assert.deepStrictEqual( + * mapSecond(["hello", 42], n => n.toString()), + * ["hello", "42"] + * ) + * + * @category mapping + * @since 1.0.0 + */ +export const mapSecond: { + (f: (right: R1) => R2): (self: readonly [L, R1]) => [L, R2] + (self: readonly [L, R1], f: (right: R1) => R2): [L, R2] +} = bicovariant.map(Bicovariant) as any + +/** + * Swaps the two elements of a tuple. + * + * @param self - A tuple of length `2`. + * + * @example + * import { swap } from "@fp-ts/core/Tuple" + * + * assert.deepStrictEqual(swap(["hello", 42]), [42, "hello"]) + * + * @since 1.0.0 + */ +export const swap = (self: readonly [L, R]): [R, L] => [self[1], self[0]] + /** * Given a tuple of `Equivalence`s returns a new `Equivalence` that compares values of a tuple * by applying each `Equivalence` to the corresponding element of the tuple. @@ -81,11 +226,6 @@ export const appendElement: { TODO: - at - - first - - second - swap - - bimap - - mapLeft - - map */ diff --git a/test/Tuple.ts b/test/Tuple.ts index 63295c648..127ffb84e 100644 --- a/test/Tuple.ts +++ b/test/Tuple.ts @@ -3,6 +3,9 @@ import * as T from "@fp-ts/core/Tuple" describe.concurrent("Tuple", () => { it("exports", () => { + expect(T.Bicovariant).exists + expect(T.mapFirst).exists + expect(T.mapSecond).exists expect(T.appendElement).exists expect(T.getEquivalence).exists expect(T.getOrder).exists @@ -17,4 +20,20 @@ describe.concurrent("Tuple", () => { it("appendElement", () => { expect(pipe(T.tuple("a", 1), T.appendElement(true))).toEqual(["a", 1, true]) }) + + it("getFirst", () => { + expect(T.getFirst(T.tuple("a", 1))).toEqual("a") + }) + + it("getSecond", () => { + expect(T.getSecond(T.tuple("a", 1))).toEqual(1) + }) + + it("bimap", () => { + expect(T.bimap(T.tuple("a", 1), s => s + "!", n => n * 2)).toEqual(["a!", 2]) + }) + + it("swap", () => { + expect(T.swap(T.tuple("a", 1))).toEqual([1, "a"]) + }) }) From cb22f2a7bf1c76471eb09a6b0a6883e4ad4dff90 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 15 Feb 2023 09:35:56 +0100 Subject: [PATCH 247/255] Bigint: feature parity with Number --- .changeset/odd-hornets-wave.md | 5 + docs/modules/Bigint.ts.md | 478 ++++++++++++++++++++++++++++++--- docs/modules/Either.ts.md | 118 ++++---- docs/modules/Number.ts.md | 392 ++++++++++++++++----------- docs/modules/Option.ts.md | 206 +++++++------- docs/modules/These.ts.md | 158 +++++------ src/Bigint.ts | 331 ++++++++++++++++++++++- src/Either.ts | 8 +- src/Number.ts | 181 +++++++++---- src/Option.ts | 14 +- src/These.ts | 10 +- test/Bigint.ts | 21 ++ 12 files changed, 1411 insertions(+), 511 deletions(-) create mode 100644 .changeset/odd-hornets-wave.md diff --git a/.changeset/odd-hornets-wave.md b/.changeset/odd-hornets-wave.md new file mode 100644 index 000000000..5e16eeb48 --- /dev/null +++ b/.changeset/odd-hornets-wave.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Bigint: feature parity with Number diff --git a/docs/modules/Bigint.ts.md b/docs/modules/Bigint.ts.md index cec597bc5..f3059fc52 100644 --- a/docs/modules/Bigint.ts.md +++ b/docs/modules/Bigint.ts.md @@ -16,11 +16,6 @@ Added in v1.0.0

Table of contents

-- [algebraic operations](#algebraic-operations) - - [divide](#divide) - - [multiply](#multiply) - - [subtract](#subtract) - - [sum](#sum) - [guards](#guards) - [isBigint](#isbigint) - [instances](#instances) @@ -28,171 +23,572 @@ Added in v1.0.0 - [MonoidMultiply](#monoidmultiply) - [MonoidSum](#monoidsum) - [Order](#order) + - [SemigroupMax](#semigroupmax) + - [SemigroupMin](#semigroupmin) - [SemigroupMultiply](#semigroupmultiply) - [SemigroupSum](#semigroupsum) -- [utils](#utils) +- [math](#math) - [decrement](#decrement) + - [divide](#divide) - [increment](#increment) + - [multiply](#multiply) + - [multiplyAll](#multiplyall) + - [sign](#sign) + - [subtract](#subtract) + - [sum](#sum) + - [sumAll](#sumall) +- [predicates](#predicates) + - [between](#between) + - [greaterThan](#greaterthan) + - [greaterThanOrEqualTo](#greaterthanorequalto) + - [lessThan](#lessthan) + - [lessThanOrEqualTo](#lessthanorequalto) +- [utils](#utils) + - [clamp](#clamp) + - [max](#max) + - [min](#min) --- -# algebraic operations +# guards + +## isBigint + +Tests if a value is a `bigint`. + +**Signature** + +```ts +export declare const isBigint: (u: unknown) => u is bigint +``` + +**Example** + +```ts +import { isBigint } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(isBigint(1n), true) +assert.deepStrictEqual(isBigint(1), false) +``` + +Added in v1.0.0 + +# instances + +## Equivalence + +**Signature** + +```ts +export declare const Equivalence: equivalence.Equivalence +``` + +Added in v1.0.0 + +## MonoidMultiply + +`bigint` monoid under multiplication. + +The `empty` value is `1n`. + +**Signature** + +```ts +export declare const MonoidMultiply: monoid.Monoid +``` + +**Example** + +```ts +import { MonoidMultiply } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(MonoidMultiply.combine(2n, 3n), 6n) +assert.deepStrictEqual(MonoidMultiply.combine(2n, MonoidMultiply.empty), 2n) +``` + +Added in v1.0.0 + +## MonoidSum + +`bigint` monoid under addition. + +The `empty` value is `0n`. + +**Signature** + +```ts +export declare const MonoidSum: monoid.Monoid +``` + +**Example** + +```ts +import { MonoidSum } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(MonoidSum.combine(2n, 3n), 5n) +assert.deepStrictEqual(MonoidSum.combine(2n, MonoidSum.empty), 2n) +``` + +Added in v1.0.0 + +## Order + +**Signature** + +```ts +export declare const Order: order.Order +``` + +Added in v1.0.0 + +## SemigroupMax + +A `Semigroup` that uses the maximum between two values. + +**Signature** + +```ts +export declare const SemigroupMax: semigroup.Semigroup +``` + +**Example** + +```ts +import { SemigroupMax } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(SemigroupMax.combine(2n, 3n), 3n) +``` + +Added in v1.0.0 + +## SemigroupMin + +A `Semigroup` that uses the minimum between two values. + +**Signature** + +```ts +export declare const SemigroupMin: semigroup.Semigroup +``` + +**Example** + +```ts +import { SemigroupMin } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(SemigroupMin.combine(2n, 3n), 2n) +``` + +Added in v1.0.0 + +## SemigroupMultiply + +`bigint` semigroup under multiplication. + +**Signature** + +```ts +export declare const SemigroupMultiply: semigroup.Semigroup +``` + +Added in v1.0.0 + +## SemigroupSum + +`bigint` semigroup under addition. + +**Signature** + +```ts +export declare const SemigroupSum: semigroup.Semigroup +``` + +**Example** + +```ts +import { SemigroupSum } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(SemigroupSum.combine(2n, 3n), 5n) +``` + +Added in v1.0.0 + +# math + +## decrement + +Decrements a number by `1n`. + +**Signature** + +```ts +export declare const decrement: (n: bigint) => bigint +``` + +**Example** + +```ts +import { decrement } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(decrement(3n), 2n) +``` + +Added in v1.0.0 ## divide +Provides a division operation on `bigint`s. + +If the dividend is not a multiple of the divisor the result will be a `bigint` value +which represents the integer division rounded down to the nearest integer. + **Signature** ```ts export declare const divide: { (that: bigint): (self: bigint) => bigint; (self: bigint, that: bigint): bigint } ``` +**Example** + +```ts +import { divide } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(divide(6n, 3n), 2n) +assert.deepStrictEqual(divide(6n, 4n), 1n) +``` + +Added in v1.0.0 + +## increment + +Returns the result of adding `1n` to a given number. + +**Signature** + +```ts +export declare const increment: (n: bigint) => bigint +``` + +**Example** + +```ts +import { increment } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(increment(2n), 3n) +``` + Added in v1.0.0 ## multiply +Provides a multiplication operation on `bigint`s. + **Signature** ```ts export declare const multiply: { (that: bigint): (self: bigint) => bigint; (self: bigint, that: bigint): bigint } ``` +**Example** + +```ts +import { multiply } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(multiply(2n, 3n), 6n) +``` + +Added in v1.0.0 + +## multiplyAll + +Takes an `Iterable` of `bigint`s and returns their multiplication as a single `number`. + +**Signature** + +```ts +export declare const multiplyAll: (collection: Iterable) => bigint +``` + +**Example** + +```ts +import { multiplyAll } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(multiplyAll([2n, 3n, 4n]), 24n) +``` + +Added in v1.0.0 + +## sign + +Determines the sign of a given `bigint`. + +**Signature** + +```ts +export declare const sign: (n: bigint) => Ordering +``` + +**Example** + +```ts +import { sign } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(sign(-5n), -1) +assert.deepStrictEqual(sign(0n), 0) +assert.deepStrictEqual(sign(5n), 1) +``` + Added in v1.0.0 ## subtract +Provides a subtraction operation on `bigint`s. + **Signature** ```ts export declare const subtract: { (that: bigint): (self: bigint) => bigint; (self: bigint, that: bigint): bigint } ``` +**Example** + +```ts +import { subtract } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(subtract(2n, 3n), -1n) +``` + Added in v1.0.0 ## sum +Provides an addition operation on `bigint`s. + **Signature** ```ts export declare const sum: { (that: bigint): (self: bigint) => bigint; (self: bigint, that: bigint): bigint } ``` -Added in v1.0.0 +**Example** -# guards +```ts +import { sum } from '@fp-ts/core/Bigint' -## isBigint +assert.deepStrictEqual(sum(2n, 3n), 5n) +``` -Tests if a value is a `bigint`. +Added in v1.0.0 + +## sumAll + +Takes an `Iterable` of `bigint`s and returns their sum as a single `bigint **Signature** ```ts -export declare const isBigint: (u: unknown) => u is bigint +export declare const sumAll: (collection: Iterable) => bigint ``` **Example** ```ts -import { isBigint } from '@fp-ts/core/Bigint' +import { sumAll } from '@fp-ts/core/Bigint' -assert.deepStrictEqual(isBigint(1n), true) -assert.deepStrictEqual(isBigint(1), false) +assert.deepStrictEqual(sumAll([2n, 3n, 4n]), 9n) ``` Added in v1.0.0 -# instances +# predicates -## Equivalence +## between + +Checks if a `bigint` is between a `minimum` and `maximum` value (inclusive). **Signature** ```ts -export declare const Equivalence: equivalence.Equivalence +export declare const between: { + (minimum: bigint, maximum: bigint): (self: bigint) => boolean + (self: bigint, minimum: bigint, maximum: bigint): boolean +} ``` -Added in v1.0.0 +**Example** -## MonoidMultiply +```ts +import { between } from '@fp-ts/core/Bigint' -`bigint` monoid under multiplication. +assert.deepStrictEqual(between(0n, 5n)(3n), true) +assert.deepStrictEqual(between(0n, 5n)(-1n), false) +assert.deepStrictEqual(between(0n, 5n)(6n), false) +``` -The `empty` value is `1n`. +Added in v1.0.0 + +## greaterThan + +Returns `true` if the first argument is greater than the second, otherwise `false`. **Signature** ```ts -export declare const MonoidMultiply: monoid.Monoid +export declare const greaterThan: { (that: bigint): (self: bigint) => boolean; (self: bigint, that: bigint): boolean } ``` -Added in v1.0.0 +**Example** -## MonoidSum +```ts +import { greaterThan } from '@fp-ts/core/Bigint' -`bigint` monoid under addition. +assert.deepStrictEqual(greaterThan(2n, 3n), false) +assert.deepStrictEqual(greaterThan(3n, 3n), false) +assert.deepStrictEqual(greaterThan(4n, 3n), true) +``` -The `empty` value is `0n`. +Added in v1.0.0 + +## greaterThanOrEqualTo + +Returns a function that checks if a given `bigint` is greater than or equal to the provided one. **Signature** ```ts -export declare const MonoidSum: monoid.Monoid +export declare const greaterThanOrEqualTo: { + (that: bigint): (self: bigint) => boolean + (self: bigint, that: bigint): boolean +} +``` + +**Example** + +```ts +import { greaterThanOrEqualTo } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(greaterThanOrEqualTo(2n, 3n), false) +assert.deepStrictEqual(greaterThanOrEqualTo(3n, 3n), true) +assert.deepStrictEqual(greaterThanOrEqualTo(4n, 3n), true) ``` Added in v1.0.0 -## Order +## lessThan + +Returns `true` if the first argument is less than the second, otherwise `false`. **Signature** ```ts -export declare const Order: order.Order +export declare const lessThan: { (that: bigint): (self: bigint) => boolean; (self: bigint, that: bigint): boolean } +``` + +**Example** + +```ts +import { lessThan } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(lessThan(2n, 3n), true) +assert.deepStrictEqual(lessThan(3n, 3n), false) +assert.deepStrictEqual(lessThan(4n, 3n), false) ``` Added in v1.0.0 -## SemigroupMultiply +## lessThanOrEqualTo -`bigint` semigroup under multiplication. +Returns a function that checks if a given `bigint` is less than or equal to the provided one. **Signature** ```ts -export declare const SemigroupMultiply: semigroup.Semigroup +export declare const lessThanOrEqualTo: { + (that: bigint): (self: bigint) => boolean + (self: bigint, that: bigint): boolean +} +``` + +**Example** + +```ts +import { lessThanOrEqualTo } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(lessThanOrEqualTo(2n, 3n), true) +assert.deepStrictEqual(lessThanOrEqualTo(3n, 3n), true) +assert.deepStrictEqual(lessThanOrEqualTo(4n, 3n), false) ``` Added in v1.0.0 -## SemigroupSum +# utils -`bigint` semigroup under addition. +## clamp + +Restricts the given `bigint` to be within the range specified by the `minimum` and `maximum` values. + +- If the `bigint` is less than the `minimum` value, the function returns the `minimum` value. +- If the `bigint` is greater than the `maximum` value, the function returns the `maximum` value. +- Otherwise, it returns the original `bigint`. **Signature** ```ts -export declare const SemigroupSum: semigroup.Semigroup +export declare const clamp: { + (minimum: bigint, maximum: bigint): (self: bigint) => bigint + (self: bigint, minimum: bigint, maximum: bigint): bigint +} +``` + +**Example** + +```ts +import { clamp } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(clamp(0n, 5n)(3n), 3n) +assert.deepStrictEqual(clamp(0n, 5n)(-1n), 0n) +assert.deepStrictEqual(clamp(0n, 5n)(6n), 5n) ``` Added in v1.0.0 -# utils +## max -## decrement +Returns the maximum between two `bigint`s. **Signature** ```ts -export declare const decrement: (n: bigint) => bigint +export declare const max: { (that: bigint): (self: bigint) => bigint; (self: bigint, that: bigint): bigint } +``` + +**Example** + +```ts +import { max } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(max(2n, 3n), 3n) ``` Added in v1.0.0 -## increment +## min + +Returns the minimum between two `bigint`s. **Signature** ```ts -export declare const increment: (n: bigint) => bigint +export declare const min: { (that: bigint): (self: bigint) => bigint; (self: bigint, that: bigint): bigint } +``` + +**Example** + +```ts +import { min } from '@fp-ts/core/Bigint' + +assert.deepStrictEqual(min(2n, 3n), 2n) ``` Added in v1.0.0 diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md index b79bd6f09..971d0b12c 100644 --- a/docs/modules/Either.ts.md +++ b/docs/modules/Either.ts.md @@ -12,11 +12,6 @@ Added in v1.0.0

Table of contents

-- [algebraic operations](#algebraic-operations) - - [divide](#divide) - - [multiply](#multiply) - - [subtract](#subtract) - - [sum](#sum) - [combinators](#combinators) - [tap](#tap) - [combining](#combining) @@ -110,6 +105,11 @@ Added in v1.0.0 - [bimap](#bimap) - [flap](#flap) - [map](#map) +- [math](#math) + - [divide](#divide) + - [multiply](#multiply) + - [subtract](#subtract) + - [sum](#sum) - [models](#models) - [Either (type alias)](#either-type-alias) - [Left (interface)](#left-interface) @@ -136,60 +136,6 @@ Added in v1.0.0 --- -# algebraic operations - -## divide - -**Signature** - -```ts -export declare const divide: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} -``` - -Added in v1.0.0 - -## multiply - -**Signature** - -```ts -export declare const multiply: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} -``` - -Added in v1.0.0 - -## subtract - -**Signature** - -```ts -export declare const subtract: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} -``` - -Added in v1.0.0 - -## sum - -**Signature** - -```ts -export declare const sum: { - (self: Either, that: Either): Either - (that: Either): (self: Either) => Either -} -``` - -Added in v1.0.0 - # combinators ## tap @@ -1446,6 +1392,60 @@ export declare const map: { Added in v1.0.0 +# math + +## divide + +**Signature** + +```ts +export declare const divide: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} +``` + +Added in v1.0.0 + +## multiply + +**Signature** + +```ts +export declare const multiply: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} +``` + +Added in v1.0.0 + +## subtract + +**Signature** + +```ts +export declare const subtract: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} +``` + +Added in v1.0.0 + +## sum + +**Signature** + +```ts +export declare const sum: { + (self: Either, that: Either): Either + (that: Either): (self: Either) => Either +} +``` + +Added in v1.0.0 + # models ## Either (type alias) diff --git a/docs/modules/Number.ts.md b/docs/modules/Number.ts.md index 29a037fe3..626de54c3 100644 --- a/docs/modules/Number.ts.md +++ b/docs/modules/Number.ts.md @@ -16,14 +16,6 @@ Added in v1.0.0

Table of contents

-- [algebraic operations](#algebraic-operations) - - [divide](#divide) - - [multiply](#multiply) - - [multiplyAll](#multiplyall) - - [remainder](#remainder) - - [subtract](#subtract) - - [sum](#sum) - - [sumAll](#sumall) - [guards](#guards) - [isNumber](#isnumber) - [instances](#instances) @@ -38,6 +30,17 @@ Added in v1.0.0 - [SemigroupMin](#semigroupmin) - [SemigroupMultiply](#semigroupmultiply) - [SemigroupSum](#semigroupsum) +- [math](#math) + - [decrement](#decrement) + - [divide](#divide) + - [increment](#increment) + - [multiply](#multiply) + - [multiplyAll](#multiplyall) + - [remainder](#remainder) + - [sign](#sign) + - [subtract](#subtract) + - [sum](#sum) + - [sumAll](#sumall) - [predicates](#predicates) - [between](#between) - [greaterThan](#greaterthan) @@ -46,303 +49,442 @@ Added in v1.0.0 - [lessThanOrEqualTo](#lessthanorequalto) - [utils](#utils) - [clamp](#clamp) - - [decrement](#decrement) - - [increment](#increment) - [max](#max) - [min](#min) - - [sign](#sign) --- -# algebraic operations +# guards -## divide +## isNumber -Provides a division operation on numbers. -It can be used as a binary function or a curried function. +Tests if a value is a `number`. **Signature** ```ts -export declare const divide: { (that: number): (self: number) => number; (self: number, that: number): number } +export declare const isNumber: (input: unknown) => input is number ``` **Example** ```ts -import { divide } from '@fp-ts/core/Number' +import { isNumber } from '@fp-ts/core/Number' -assert.deepStrictEqual(divide(6, 3), 2) +assert.deepStrictEqual(isNumber(2), true) +assert.deepStrictEqual(isNumber('2'), false) ``` Added in v1.0.0 -## multiply +# instances -Provides a multiplication operation on numbers. -It can be used as a binary function or a curried function. +## Bounded **Signature** ```ts -export declare const multiply: { (that: number): (self: number) => number; (self: number, that: number): number } +export declare const Bounded: bounded.Bounded ``` -**Example** +Added in v1.0.0 -```ts -import { multiply } from '@fp-ts/core/Number' +## Equivalence -assert.deepStrictEqual(multiply(2, 3), 6) +**Signature** + +```ts +export declare const Equivalence: equivalence.Equivalence ``` Added in v1.0.0 -## multiplyAll +## MonoidMax + +A `Monoid` that uses the maximum between two values. + +The `empty` value is `Infinity`. **Signature** ```ts -export declare const multiplyAll: (collection: Iterable) => number +export declare const MonoidMax: monoid.Monoid +``` + +**Example** + +```ts +import { MonoidMax } from '@fp-ts/core/Number' + +assert.deepStrictEqual(MonoidMax.combine(2, 3), 3) +assert.deepStrictEqual(MonoidMax.combine(2, MonoidMax.empty), 2) ``` Added in v1.0.0 -## remainder +## MonoidMin -Returns the remainder left over when one operand is divided by a second operand. +A `Monoid` that uses the minimum between two values. -It always takes the sign of the dividend. +The `empty` value is `-Infinity`. **Signature** ```ts -export declare const remainder: { (divisor: number): (self: number) => number; (self: number, divisor: number): number } +export declare const MonoidMin: monoid.Monoid ``` **Example** ```ts -import { remainder } from '@fp-ts/core/Number' +import { MonoidMin } from '@fp-ts/core/Number' -assert.deepStrictEqual(remainder(2, 2), 0) -assert.deepStrictEqual(remainder(3, 2), 1) -assert.deepStrictEqual(remainder(-4, 2), -0) +assert.deepStrictEqual(MonoidMin.combine(2, 3), 2) +assert.deepStrictEqual(MonoidMin.combine(2, MonoidMin.empty), 2) ``` Added in v1.0.0 -## subtract +## MonoidMultiply + +`number` monoid under multiplication. -Provides a subtraction operation on numbers. -It can be used as a binary function or a curried function. +The `empty` value is `1`. **Signature** ```ts -export declare const subtract: { (that: number): (self: number) => number; (self: number, that: number): number } +export declare const MonoidMultiply: monoid.Monoid ``` **Example** ```ts -import { subtract } from '@fp-ts/core/Number' +import { MonoidMultiply } from '@fp-ts/core/Number' -assert.deepStrictEqual(subtract(2, 3), -1) +assert.deepStrictEqual(MonoidMultiply.combine(2, 3), 6) +assert.deepStrictEqual(MonoidMultiply.combine(2, MonoidMultiply.empty), 2) ``` Added in v1.0.0 -## sum +## MonoidSum -Provides an addition operation on numbers. -It can be used as a binary function or a curried function. +`number` monoid under addition. + +The `empty` value is `0`. **Signature** ```ts -export declare const sum: { (that: number): (self: number) => number; (self: number, that: number): number } +export declare const MonoidSum: monoid.Monoid ``` **Example** ```ts -import { sum } from '@fp-ts/core/Number' +import { MonoidSum } from '@fp-ts/core/Number' -assert.deepStrictEqual(sum(2, 3), 5) +assert.deepStrictEqual(MonoidSum.combine(2, 3), 5) +assert.deepStrictEqual(MonoidSum.combine(2, MonoidSum.empty), 2) ``` Added in v1.0.0 -## sumAll +## Order **Signature** ```ts -export declare const sumAll: (collection: Iterable) => number +export declare const Order: order.Order ``` Added in v1.0.0 -# guards - -## isNumber +## SemigroupMax -Tests if a value is a `number`. +A `Semigroup` that uses the maximum between two values. **Signature** ```ts -export declare const isNumber: (input: unknown) => input is number +export declare const SemigroupMax: semigroup.Semigroup ``` **Example** ```ts -import { isNumber } from '@fp-ts/core/Number' +import { SemigroupMax } from '@fp-ts/core/Number' -assert.deepStrictEqual(isNumber(2), true) -assert.deepStrictEqual(isNumber('2'), false) +assert.deepStrictEqual(SemigroupMax.combine(2, 3), 3) ``` Added in v1.0.0 -# instances +## SemigroupMin -## Bounded +A `Semigroup` that uses the minimum between two values. **Signature** ```ts -export declare const Bounded: bounded.Bounded +export declare const SemigroupMin: semigroup.Semigroup +``` + +**Example** + +```ts +import { SemigroupMin } from '@fp-ts/core/Number' + +assert.deepStrictEqual(SemigroupMin.combine(2, 3), 2) ``` Added in v1.0.0 -## Equivalence +## SemigroupMultiply + +`number` semigroup under multiplication. **Signature** ```ts -export declare const Equivalence: equivalence.Equivalence +export declare const SemigroupMultiply: semigroup.Semigroup +``` + +**Example** + +```ts +import { SemigroupMultiply } from '@fp-ts/core/Number' + +assert.deepStrictEqual(SemigroupMultiply.combine(2, 3), 6) ``` Added in v1.0.0 -## MonoidMax +## SemigroupSum + +`number` semigroup under addition. **Signature** ```ts -export declare const MonoidMax: monoid.Monoid +export declare const SemigroupSum: semigroup.Semigroup +``` + +**Example** + +```ts +import { SemigroupSum } from '@fp-ts/core/Number' + +assert.deepStrictEqual(SemigroupSum.combine(2, 3), 5) ``` Added in v1.0.0 -## MonoidMin +# math + +## decrement + +Decrements a number by `1`. **Signature** ```ts -export declare const MonoidMin: monoid.Monoid +export declare const decrement: (n: number) => number +``` + +**Example** + +```ts +import { decrement } from '@fp-ts/core/Number' + +assert.deepStrictEqual(decrement(3), 2) ``` Added in v1.0.0 -## MonoidMultiply +## divide -`number` monoid under multiplication. +Provides a division operation on `number`s. -The `empty` value is `1`. +**Signature** + +```ts +export declare const divide: { (that: number): (self: number) => number; (self: number, that: number): number } +``` + +**Example** + +```ts +import { divide } from '@fp-ts/core/Number' + +assert.deepStrictEqual(divide(6, 3), 2) +``` + +Added in v1.0.0 + +## increment + +Returns the result of adding `1` to a given number. **Signature** ```ts -export declare const MonoidMultiply: monoid.Monoid +export declare const increment: (n: number) => number +``` + +**Example** + +```ts +import { increment } from '@fp-ts/core/Number' + +assert.deepStrictEqual(increment(2), 3) ``` Added in v1.0.0 -## MonoidSum +## multiply -`number` monoid under addition. +Provides a multiplication operation on `number`s. -The `empty` value is `0`. +**Signature** + +```ts +export declare const multiply: { (that: number): (self: number) => number; (self: number, that: number): number } +``` + +**Example** + +```ts +import { multiply } from '@fp-ts/core/Number' + +assert.deepStrictEqual(multiply(2, 3), 6) +``` + +Added in v1.0.0 + +## multiplyAll + +Takes an `Iterable` of `number`s and returns their multiplication as a single `number`. **Signature** ```ts -export declare const MonoidSum: monoid.Monoid +export declare const multiplyAll: (collection: Iterable) => number +``` + +**Example** + +```ts +import { multiplyAll } from '@fp-ts/core/Number' + +assert.deepStrictEqual(multiplyAll([2, 3, 4]), 24) ``` Added in v1.0.0 -## Order +## remainder + +Returns the remainder left over when one operand is divided by a second operand. + +It always takes the sign of the dividend. **Signature** ```ts -export declare const Order: order.Order +export declare const remainder: { (divisor: number): (self: number) => number; (self: number, divisor: number): number } +``` + +**Example** + +```ts +import { remainder } from '@fp-ts/core/Number' + +assert.deepStrictEqual(remainder(2, 2), 0) +assert.deepStrictEqual(remainder(3, 2), 1) +assert.deepStrictEqual(remainder(-4, 2), -0) ``` Added in v1.0.0 -## SemigroupMax +## sign + +Determines the sign of a given `number`. **Signature** ```ts -export declare const SemigroupMax: semigroup.Semigroup +export declare const sign: (n: number) => Ordering +``` + +**Example** + +```ts +import { sign } from '@fp-ts/core/Number' + +assert.deepStrictEqual(sign(-5), -1) +assert.deepStrictEqual(sign(0), 0) +assert.deepStrictEqual(sign(5), 1) ``` Added in v1.0.0 -## SemigroupMin +## subtract + +Provides a subtraction operation on `number`s. **Signature** ```ts -export declare const SemigroupMin: semigroup.Semigroup +export declare const subtract: { (that: number): (self: number) => number; (self: number, that: number): number } +``` + +**Example** + +```ts +import { subtract } from '@fp-ts/core/Number' + +assert.deepStrictEqual(subtract(2, 3), -1) ``` Added in v1.0.0 -## SemigroupMultiply +## sum -`number` semigroup under multiplication. +Provides an addition operation on `number`s. **Signature** ```ts -export declare const SemigroupMultiply: semigroup.Semigroup +export declare const sum: { (that: number): (self: number) => number; (self: number, that: number): number } ``` **Example** ```ts -import { SemigroupMultiply } from '@fp-ts/core/Number' +import { sum } from '@fp-ts/core/Number' -assert.deepStrictEqual(SemigroupMultiply.combine(2, 3), 6) +assert.deepStrictEqual(sum(2, 3), 5) ``` Added in v1.0.0 -## SemigroupSum +## sumAll -`number` semigroup under addition. +Takes an `Iterable` of `number`s and returns their sum as a single `number`. **Signature** ```ts -export declare const SemigroupSum: semigroup.Semigroup +export declare const sumAll: (collection: Iterable) => number ``` **Example** ```ts -import { SemigroupSum } from '@fp-ts/core/Number' +import { sumAll } from '@fp-ts/core/Number' -assert.deepStrictEqual(SemigroupSum.combine(2, 3), 5) +assert.deepStrictEqual(sumAll([2, 3, 4]), 9) ``` Added in v1.0.0 @@ -351,7 +493,7 @@ Added in v1.0.0 ## between -Checks if a number is between a minimum and maximum value (inclusive). +Checks if a `number` is between a `minimum` and `maximum` value (inclusive). **Signature** @@ -398,7 +540,7 @@ Added in v1.0.0 ## greaterThanOrEqualTo -Returns a function that checks if a given number is greater than or equal to the provided one. +Returns a function that checks if a given `number` is greater than or equal to the provided one. **Signature** @@ -445,7 +587,7 @@ Added in v1.0.0 ## lessThanOrEqualTo -Returns a function that checks if a given number is less than or equal to the provided one. +Returns a function that checks if a given `number` is less than or equal to the provided one. **Signature** @@ -472,11 +614,11 @@ Added in v1.0.0 ## clamp -Restricts the given number to be within the range specified by the minimum and maximum values. +Restricts the given `number` to be within the range specified by the `minimum` and `maximum` values. -- If the number is less than the minimum value, the function returns the minimum value. -- If the number is greater than the maximum value, the function returns the maximum value. -- Otherwise, it returns the original number. +- If the `number` is less than the `minimum` value, the function returns the `minimum` value. +- If the `number` is greater than the `maximum` value, the function returns the `maximum` value. +- Otherwise, it returns the original `number`. **Signature** @@ -499,49 +641,9 @@ assert.deepStrictEqual(clamp(0, 5)(6), 5) Added in v1.0.0 -## decrement - -Decrements a number by `1`. - -**Signature** - -```ts -export declare const decrement: (n: number) => number -``` - -**Example** - -```ts -import { decrement } from '@fp-ts/core/Number' - -assert.deepStrictEqual(decrement(3), 2) -``` - -Added in v1.0.0 - -## increment - -Returns the result of adding `1` to a given number. - -**Signature** - -```ts -export declare const increment: (n: number) => number -``` - -**Example** - -```ts -import { increment } from '@fp-ts/core/Number' - -assert.deepStrictEqual(increment(2), 3) -``` - -Added in v1.0.0 - ## max -Returns the maximum between two numbers. +Returns the maximum between two `number`s. **Signature** @@ -561,7 +663,7 @@ Added in v1.0.0 ## min -Returns the minimum between two numbers. +Returns the minimum between two `number`s. **Signature** @@ -578,13 +680,3 @@ assert.deepStrictEqual(min(2, 3), 2) ``` Added in v1.0.0 - -## sign - -**Signature** - -```ts -export declare const sign: (n: number) => Ordering -``` - -Added in v1.0.0 diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md index e52ab8f5e..e8528904a 100644 --- a/docs/modules/Option.ts.md +++ b/docs/modules/Option.ts.md @@ -12,13 +12,6 @@ Added in v1.0.0

Table of contents

-- [algebraic operations](#algebraic-operations) - - [divide](#divide) - - [multiply](#multiply) - - [multiplyCompact](#multiplycompact) - - [subtract](#subtract) - - [sum](#sum) - - [sumCompact](#sumcompact) - [combining](#combining) - [all](#all) - [ap](#ap) @@ -83,6 +76,13 @@ Added in v1.0.0 - [lift2](#lift2) - [liftEither](#lifteither) - [liftPredicate](#liftpredicate) +- [math](#math) + - [divide](#divide) + - [multiply](#multiply) + - [multiplyCompact](#multiplycompact) + - [subtract](#subtract) + - [sum](#sum) + - [sumCompact](#sumcompact) - [models](#models) - [None (interface)](#none-interface) - [Option (type alias)](#option-type-alias) @@ -132,102 +132,6 @@ Added in v1.0.0 --- -# algebraic operations - -## divide - -**Signature** - -```ts -export declare const divide: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} -``` - -Added in v1.0.0 - -## multiply - -**Signature** - -```ts -export declare const multiply: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} -``` - -Added in v1.0.0 - -## multiplyCompact - -Multiply all numbers in an iterable of `Option` ignoring the `None` values. - -**Signature** - -```ts -export declare const multiplyCompact: (self: Iterable>) => number -``` - -**Example** - -```ts -import { multiplyCompact, some, none } from '@fp-ts/core/Option' - -const iterable = [some(2), none(), some(3), none()] -assert.deepStrictEqual(multiplyCompact(iterable), 6) -``` - -Added in v1.0.0 - -## subtract - -**Signature** - -```ts -export declare const subtract: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} -``` - -Added in v1.0.0 - -## sum - -**Signature** - -```ts -export declare const sum: { - (self: Option, that: Option): Option - (that: Option): (self: Option) => Option -} -``` - -Added in v1.0.0 - -## sumCompact - -Sum all numbers in an iterable of `Option` ignoring the `None` values. - -**Signature** - -```ts -export declare const sumCompact: (self: Iterable>) => number -``` - -**Example** - -```ts -import { sumCompact, some, none } from '@fp-ts/core/Option' - -const iterable = [some(2), none(), some(3), none()] -assert.deepStrictEqual(sumCompact(iterable), 5) -``` - -Added in v1.0.0 - # combining ## all @@ -1357,6 +1261,102 @@ assert.deepStrictEqual(getOption(1), O.some(1)) Added in v1.0.0 +# math + +## divide + +**Signature** + +```ts +export declare const divide: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} +``` + +Added in v1.0.0 + +## multiply + +**Signature** + +```ts +export declare const multiply: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} +``` + +Added in v1.0.0 + +## multiplyCompact + +Multiply all numbers in an iterable of `Option` ignoring the `None` values. + +**Signature** + +```ts +export declare const multiplyCompact: (self: Iterable>) => number +``` + +**Example** + +```ts +import { multiplyCompact, some, none } from '@fp-ts/core/Option' + +const iterable = [some(2), none(), some(3), none()] +assert.deepStrictEqual(multiplyCompact(iterable), 6) +``` + +Added in v1.0.0 + +## subtract + +**Signature** + +```ts +export declare const subtract: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} +``` + +Added in v1.0.0 + +## sum + +**Signature** + +```ts +export declare const sum: { + (self: Option, that: Option): Option + (that: Option): (self: Option) => Option +} +``` + +Added in v1.0.0 + +## sumCompact + +Sum all numbers in an iterable of `Option` ignoring the `None` values. + +**Signature** + +```ts +export declare const sumCompact: (self: Iterable>) => number +``` + +**Example** + +```ts +import { sumCompact, some, none } from '@fp-ts/core/Option' + +const iterable = [some(2), none(), some(3), none()] +assert.deepStrictEqual(sumCompact(iterable), 5) +``` + +Added in v1.0.0 + # models ## None (interface) diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md index cdc6de92c..5f22da4be 100644 --- a/docs/modules/These.ts.md +++ b/docs/modules/These.ts.md @@ -12,11 +12,6 @@ Added in v1.0.0

Table of contents

-- [algebraic operations](#algebraic-operations) - - [divide](#divide) - - [multiply](#multiply) - - [subtract](#subtract) - - [sum](#sum) - [combinators](#combinators) - [tap](#tap) - [combining](#combining) @@ -128,6 +123,11 @@ Added in v1.0.0 - [flap](#flap) - [map](#map) - [tupled](#tupled) +- [math](#math) + - [divide](#divide) + - [multiply](#multiply) + - [subtract](#subtract) + - [sum](#sum) - [model](#model) - [Both (interface)](#both-interface) - [These (type alias)](#these-type-alias) @@ -157,80 +157,6 @@ Added in v1.0.0 --- -# algebraic operations - -## divide - -**Signature** - -```ts -export declare const divide: { - (self: These, that: These): These< - readonly [E1 | E2, ...(E1 | E2)[]], - number - > - (that: These): ( - self: These - ) => These -} -``` - -Added in v1.0.0 - -## multiply - -**Signature** - -```ts -export declare const multiply: { - (self: These, that: These): These< - readonly [E1 | E2, ...(E1 | E2)[]], - number - > - (that: These): ( - self: These - ) => These -} -``` - -Added in v1.0.0 - -## subtract - -**Signature** - -```ts -export declare const subtract: { - (self: These, that: These): These< - readonly [E1 | E2, ...(E1 | E2)[]], - number - > - (that: These): ( - self: These - ) => These -} -``` - -Added in v1.0.0 - -## sum - -**Signature** - -```ts -export declare const sum: { - (self: These, that: These): These< - readonly [E1 | E2, ...(E1 | E2)[]], - number - > - (that: These): ( - self: These - ) => These -} -``` - -Added in v1.0.0 - # combinators ## tap @@ -1612,6 +1538,80 @@ export declare const tupled: (self: These) => These Added in v1.0.0 +# math + +## divide + +**Signature** + +```ts +export declare const divide: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + number + > + (that: These): ( + self: These + ) => These +} +``` + +Added in v1.0.0 + +## multiply + +**Signature** + +```ts +export declare const multiply: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + number + > + (that: These): ( + self: These + ) => These +} +``` + +Added in v1.0.0 + +## subtract + +**Signature** + +```ts +export declare const subtract: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + number + > + (that: These): ( + self: These + ) => These +} +``` + +Added in v1.0.0 + +## sum + +**Signature** + +```ts +export declare const sum: { + (self: These, that: These): These< + readonly [E1 | E2, ...(E1 | E2)[]], + number + > + (that: These): ( + self: These + ) => These +} +``` + +Added in v1.0.0 + # model ## Both (interface) diff --git a/src/Bigint.ts b/src/Bigint.ts index eaab9a780..8cc82b156 100644 --- a/src/Bigint.ts +++ b/src/Bigint.ts @@ -7,6 +7,7 @@ */ import { dual } from "@fp-ts/core/Function" +import type { Ordering } from "@fp-ts/core/Ordering" import * as predicate from "@fp-ts/core/Predicate" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" @@ -30,7 +31,17 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" export const isBigint: (u: unknown) => u is bigint = predicate.isBigint /** - * @category algebraic operations + * Provides an addition operation on `bigint`s. + * + * @param self - The first operand. + * @param that - The second operand. + * + * @example + * import { sum } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(sum(2n, 3n), 5n) + * + * @category math * @since 1.0.0 */ export const sum: { @@ -39,7 +50,17 @@ export const sum: { } = dual(2, semigroup.bigintSum.combine) /** - * @category algebraic operations + * Provides a multiplication operation on `bigint`s. + * + * @param self - The first operand. + * @param that - The second operand. + * + * @example + * import { multiply } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(multiply(2n, 3n), 6n) + * + * @category math * @since 1.0.0 */ export const multiply: { @@ -48,7 +69,17 @@ export const multiply: { } = dual(2, semigroup.bigintMultiply.combine) /** - * @category algebraic operations + * Provides a subtraction operation on `bigint`s. + * + * @param self - The first operand. + * @param that - The second operand. + * + * @example + * import { subtract } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(subtract(2n, 3n), -1n) + * + * @category math * @since 1.0.0 */ export const subtract: { @@ -57,7 +88,22 @@ export const subtract: { } = dual(2, (self: bigint, that: bigint): bigint => self - that) /** - * @category algebraic operations + * Provides a division operation on `bigint`s. + * + * If the dividend is not a multiple of the divisor the result will be a `bigint` value + * which represents the integer division rounded down to the nearest integer. + * + * @param self - The dividend operand. + * @param that - The divisor operand. + * + * @example + * import { divide } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(divide(6n, 3n), 2n) + * assert.deepStrictEqual(divide(6n, 4n), 1n) + * + * @category math + * @since 1.0.0 * @since 1.0.0 */ export const divide: { @@ -66,11 +112,31 @@ export const divide: { } = dual(2, (self: bigint, that: bigint): bigint => self / that) /** + * Returns the result of adding `1n` to a given number. + * + * @param n - A `bigint` to be incremented. + * + * @example + * import { increment } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(increment(2n), 3n) + * + * @category math * @since 1.0.0 */ export const increment = (n: bigint): bigint => n + 1n /** + * Decrements a number by `1n`. + * + * @param n - A `bigint` to be decremented. + * + * @example + * import { decrement } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(decrement(3n), 2n) + * + * @category math * @since 1.0.0 */ export const decrement = (n: bigint): bigint => n - 1n @@ -87,9 +153,181 @@ export const Equivalence: equivalence.Equivalence = equivalence.bigint */ export const Order: order.Order = order.bigint +/** + * Returns `true` if the first argument is less than the second, otherwise `false`. + * + * @param self - The first argument. + * @param that - The second argument. + * + * @example + * import { lessThan } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(lessThan(2n, 3n), true) + * assert.deepStrictEqual(lessThan(3n, 3n), false) + * assert.deepStrictEqual(lessThan(4n, 3n), false) + * + * @category predicates + * @since 1.0.0 + */ +export const lessThan: { + (that: bigint): (self: bigint) => boolean + (self: bigint, that: bigint): boolean +} = order.lessThan(Order) + +/** + * Returns a function that checks if a given `bigint` is less than or equal to the provided one. + * + * @param self - The first `bigint` to compare with. + * @param that - The second `bigint` to compare with. + * + * @example + * import { lessThanOrEqualTo } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(lessThanOrEqualTo(2n, 3n), true) + * assert.deepStrictEqual(lessThanOrEqualTo(3n, 3n), true) + * assert.deepStrictEqual(lessThanOrEqualTo(4n, 3n), false) + * + * @category predicates + * @since 1.0.0 + */ +export const lessThanOrEqualTo: { + (that: bigint): (self: bigint) => boolean + (self: bigint, that: bigint): boolean +} = order.lessThanOrEqualTo(Order) + +/** + * Returns `true` if the first argument is greater than the second, otherwise `false`. + * + * @param self - The first argument. + * @param that - The second argument. + * + * @example + * import { greaterThan } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(greaterThan(2n, 3n), false) + * assert.deepStrictEqual(greaterThan(3n, 3n), false) + * assert.deepStrictEqual(greaterThan(4n, 3n), true) + * + * @category predicates + * @since 1.0.0 + */ +export const greaterThan: { + (that: bigint): (self: bigint) => boolean + (self: bigint, that: bigint): boolean +} = order.greaterThan(Order) + +/** + * Returns a function that checks if a given `bigint` is greater than or equal to the provided one. + * + * @param self - The first `bigint` to compare with. + * @param that - The second `bigint` to compare with. + * + * @example + * import { greaterThanOrEqualTo } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(greaterThanOrEqualTo(2n, 3n), false) + * assert.deepStrictEqual(greaterThanOrEqualTo(3n, 3n), true) + * assert.deepStrictEqual(greaterThanOrEqualTo(4n, 3n), true) + * + * @category predicates + * @since 1.0.0 + */ +export const greaterThanOrEqualTo: { + (that: bigint): (self: bigint) => boolean + (self: bigint, that: bigint): boolean +} = order.greaterThanOrEqualTo(Order) + +/** + * Checks if a `bigint` is between a `minimum` and `maximum` value (inclusive). + * + * @param self - The `number` to check. + * @param minimum - The `minimum` value to check. + * @param maximum - The `maximum` value to check. + * + * @example + * import { between } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(between(0n, 5n)(3n), true) + * assert.deepStrictEqual(between(0n, 5n)(-1n), false) + * assert.deepStrictEqual(between(0n, 5n)(6n), false) + * + * @category predicates + * @since 1.0.0 + */ +export const between: { + (minimum: bigint, maximum: bigint): (self: bigint) => boolean + (self: bigint, minimum: bigint, maximum: bigint): boolean +} = order.between(Order) + +/** + * Restricts the given `bigint` to be within the range specified by the `minimum` and `maximum` values. + * + * - If the `bigint` is less than the `minimum` value, the function returns the `minimum` value. + * - If the `bigint` is greater than the `maximum` value, the function returns the `maximum` value. + * - Otherwise, it returns the original `bigint`. + * + * @param self - The `bigint` to be clamped. + * @param minimum - The lower end of the range. + * @param maximum - The upper end of the range. + * + * @example + * import { clamp } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(clamp(0n, 5n)(3n), 3n) + * assert.deepStrictEqual(clamp(0n, 5n)(-1n), 0n) + * assert.deepStrictEqual(clamp(0n, 5n)(6n), 5n) + * + * @since 1.0.0 + */ +export const clamp: { + (minimum: bigint, maximum: bigint): (self: bigint) => bigint + (self: bigint, minimum: bigint, maximum: bigint): bigint +} = order.clamp(Order) + +/** + * Returns the minimum between two `bigint`s. + * + * @param self - The first `bigint`. + * @param that - The second `bigint`. + * + * @example + * import { min } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(min(2n, 3n), 2n) + * + * @since 1.0.0 + */ +export const min: { + (that: bigint): (self: bigint) => bigint + (self: bigint, that: bigint): bigint +} = order.min(Order) + +/** + * Returns the maximum between two `bigint`s. + * + * @param self - The first `bigint`. + * @param that - The second `bigint`. + * + * @example + * import { max } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(max(2n, 3n), 3n) + * + * @since 1.0.0 + */ +export const max: { + (that: bigint): (self: bigint) => bigint + (self: bigint, that: bigint): bigint +} = order.max(Order) + /** * `bigint` semigroup under addition. * + * @example + * import { SemigroupSum } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(SemigroupSum.combine(2n, 3n), 5n) + * * @category instances * @since 1.0.0 */ @@ -103,11 +341,43 @@ export const SemigroupSum: semigroup.Semigroup = semigroup.bigintSum */ export const SemigroupMultiply: semigroup.Semigroup = semigroup.bigintMultiply +/** + * A `Semigroup` that uses the minimum between two values. + * + * @example + * import { SemigroupMin } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(SemigroupMin.combine(2n, 3n), 2n) + * + * @category instances + * @since 1.0.0 + */ +export const SemigroupMin: semigroup.Semigroup = semigroup.min(Order) + +/** + * A `Semigroup` that uses the maximum between two values. + * + * @example + * import { SemigroupMax } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(SemigroupMax.combine(2n, 3n), 3n) + * + * @category instances + * @since 1.0.0 + */ +export const SemigroupMax: semigroup.Semigroup = semigroup.max(Order) + /** * `bigint` monoid under addition. * * The `empty` value is `0n`. * + * @example + * import { MonoidSum } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(MonoidSum.combine(2n, 3n), 5n) + * assert.deepStrictEqual(MonoidSum.combine(2n, MonoidSum.empty), 2n) + * * @category instances * @since 1.0.0 */ @@ -118,7 +388,60 @@ export const MonoidSum: monoid.Monoid = monoid.bigintSum * * The `empty` value is `1n`. * + * @example + * import { MonoidMultiply } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(MonoidMultiply.combine(2n, 3n), 6n) + * assert.deepStrictEqual(MonoidMultiply.combine(2n, MonoidMultiply.empty), 2n) + * * @category instances * @since 1.0.0 */ export const MonoidMultiply: monoid.Monoid = monoid.bigintMultiply + +/** + * Determines the sign of a given `bigint`. + * + * @param n - The `bigint` to determine the sign of. + * + * @example + * import { sign } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(sign(-5n), -1) + * assert.deepStrictEqual(sign(0n), 0) + * assert.deepStrictEqual(sign(5n), 1) + * + * @category math + * @since 1.0.0 + */ +export const sign = (n: bigint): Ordering => Order.compare(n, 0n) + +/** + * Takes an `Iterable` of `bigint`s and returns their sum as a single `bigint + * + * @param collection - The collection of `bigint`s to sum. + * + * @example + * import { sumAll } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(sumAll([2n, 3n, 4n]), 9n) + * + * @category math + * @since 1.0.0 + */ +export const sumAll: (collection: Iterable) => bigint = MonoidSum.combineAll + +/** + * Takes an `Iterable` of `bigint`s and returns their multiplication as a single `number`. + * + * @param collection - The collection of `bigint`s to multiply. + * + * @example + * import { multiplyAll } from '@fp-ts/core/Bigint' + * + * assert.deepStrictEqual(multiplyAll([2n, 3n, 4n]), 24n) + * + * @category math + * @since 1.0.0 + */ +export const multiplyAll: (collection: Iterable) => bigint = MonoidMultiply.combineAll diff --git a/src/Either.ts b/src/Either.ts index 4179e101f..a64a487ea 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -1302,7 +1302,7 @@ export const getOptionalSemigroup = (S: Semigroup
): Semigroup (isLeft(y) ? x : isLeft(x) ? y : right(S.combine(x.right, y.right)))) /** - * @category algebraic operations + * @category math * @since 1.0.0 */ export const sum: { @@ -1311,7 +1311,7 @@ export const sum: { } = lift2(N.sum) /** - * @category algebraic operations + * @category math * @since 1.0.0 */ export const multiply: { @@ -1320,7 +1320,7 @@ export const multiply: { } = lift2(N.multiply) /** - * @category algebraic operations + * @category math * @since 1.0.0 */ export const subtract: { @@ -1329,7 +1329,7 @@ export const subtract: { } = lift2(N.subtract) /** - * @category algebraic operations + * @category math * @since 1.0.0 */ export const divide: { diff --git a/src/Number.ts b/src/Number.ts index f12f81198..dbc36825e 100644 --- a/src/Number.ts +++ b/src/Number.ts @@ -31,8 +31,7 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" export const isNumber: (input: unknown) => input is number = predicate.isNumber /** - * Provides an addition operation on numbers. - * It can be used as a binary function or a curried function. + * Provides an addition operation on `number`s. * * @param self - The first operand. * @param that - The second operand. @@ -42,7 +41,7 @@ export const isNumber: (input: unknown) => input is number = predicate.isNumber * * assert.deepStrictEqual(sum(2, 3), 5) * - * @category algebraic operations + * @category math * @since 1.0.0 */ export const sum: { @@ -51,8 +50,7 @@ export const sum: { } = dual(2, semigroup.numberSum.combine) /** - * Provides a multiplication operation on numbers. - * It can be used as a binary function or a curried function. + * Provides a multiplication operation on `number`s. * * @param self - The first operand. * @param that - The second operand. @@ -62,7 +60,7 @@ export const sum: { * * assert.deepStrictEqual(multiply(2, 3), 6) * - * @category algebraic operations + * @category math * @since 1.0.0 */ export const multiply: { @@ -71,8 +69,7 @@ export const multiply: { } = dual(2, semigroup.numberMultiply.combine) /** - * Provides a subtraction operation on numbers. - * It can be used as a binary function or a curried function. + * Provides a subtraction operation on `number`s. * * @param self - The first operand. * @param that - The second operand. @@ -82,7 +79,7 @@ export const multiply: { * * assert.deepStrictEqual(subtract(2, 3), -1) * - * @category algebraic operations + * @category math * @since 1.0.0 */ export const subtract: { @@ -91,18 +88,17 @@ export const subtract: { } = dual(2, (self: number, that: number): number => self - that) /** - * Provides a division operation on numbers. - * It can be used as a binary function or a curried function. + * Provides a division operation on `number`s. * - * @param self - The first operand. - * @param that - The second operand. + * @param self - The dividend operand. + * @param that - The divisor operand. * * @example * import { divide } from '@fp-ts/core/Number' * * assert.deepStrictEqual(divide(6, 3), 2) * - * @category algebraic operations + * @category math * @since 1.0.0 */ export const divide: { @@ -113,13 +109,14 @@ export const divide: { /** * Returns the result of adding `1` to a given number. * - * @param n - A number to be incremented. + * @param n - A `number` to be incremented. * * @example * import { increment } from '@fp-ts/core/Number' * * assert.deepStrictEqual(increment(2), 3) * + * @category math * @since 1.0.0 */ export const increment = (n: number): number => n + 1 @@ -127,13 +124,14 @@ export const increment = (n: number): number => n + 1 /** * Decrements a number by `1`. * - * @param n - A number to be decremented. + * @param n - A `number` to be decremented. * * @example * import { decrement } from '@fp-ts/core/Number' * * assert.deepStrictEqual(decrement(3), 2) * + * @category math * @since 1.0.0 */ export const decrement = (n: number): number => n - 1 @@ -172,10 +170,10 @@ export const lessThan: { } = order.lessThan(Order) /** - * Returns a function that checks if a given number is less than or equal to the provided one. + * Returns a function that checks if a given `number` is less than or equal to the provided one. * - * @param self - The first number to compare with. - * @param that - The second number to compare with. + * @param self - The first `number` to compare with. + * @param that - The second `number` to compare with. * * @example * import { lessThanOrEqualTo } from '@fp-ts/core/Number' @@ -214,10 +212,10 @@ export const greaterThan: { } = order.greaterThan(Order) /** - * Returns a function that checks if a given number is greater than or equal to the provided one. + * Returns a function that checks if a given `number` is greater than or equal to the provided one. * - * @param self - The first number to compare with. - * @param that - The second number to compare with. + * @param self - The first `number` to compare with. + * @param that - The second `number` to compare with. * * @example * import { greaterThanOrEqualTo } from '@fp-ts/core/Number' @@ -235,11 +233,11 @@ export const greaterThanOrEqualTo: { } = order.greaterThanOrEqualTo(Order) /** - * Checks if a number is between a minimum and maximum value (inclusive). + * Checks if a `number` is between a `minimum` and `maximum` value (inclusive). * - * @param self - The number to check. - * @param minimum - The minimum value to check. - * @param maximum - The maximum value to check. + * @param self - The `number` to check. + * @param minimum - The `minimum` value to check. + * @param maximum - The `maximum` value to check. * * @example * import { between } from '@fp-ts/core/Number' @@ -257,13 +255,13 @@ export const between: { } = order.between(Order) /** - * Restricts the given number to be within the range specified by the minimum and maximum values. + * Restricts the given `number` to be within the range specified by the `minimum` and `maximum` values. * - * - If the number is less than the minimum value, the function returns the minimum value. - * - If the number is greater than the maximum value, the function returns the maximum value. - * - Otherwise, it returns the original number. + * - If the `number` is less than the `minimum` value, the function returns the `minimum` value. + * - If the `number` is greater than the `maximum` value, the function returns the `maximum` value. + * - Otherwise, it returns the original `number`. * - * @param self - The number to be clamped. + * @param self - The `number` to be clamped. * @param minimum - The lower end of the range. * @param maximum - The upper end of the range. * @@ -282,10 +280,10 @@ export const clamp: { } = order.clamp(Order) /** - * Returns the minimum between two numbers. + * Returns the minimum between two `number`s. * - * @param self - The first number. - * @param that - The second number. + * @param self - The first `number`. + * @param that - The second `number`. * * @example * import { min } from '@fp-ts/core/Number' @@ -300,10 +298,10 @@ export const min: { } = order.min(Order) /** - * Returns the maximum between two numbers. + * Returns the maximum between two `number`s. * - * @param self - The first number. - * @param that - The second number. + * @param self - The first `number`. + * @param that - The second `number`. * * @example * import { max } from '@fp-ts/core/Number' @@ -337,35 +335,55 @@ export const Bounded: bounded.Bounded = bounded.number export const SemigroupSum: semigroup.Semigroup = semigroup.numberSum /** + * `number` semigroup under multiplication. + * + * @example + * import { SemigroupMultiply } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(SemigroupMultiply.combine(2, 3), 6) + * * @category instances * @since 1.0.0 */ -export const SemigroupMax: semigroup.Semigroup = semigroup.max(Order) +export const SemigroupMultiply: semigroup.Semigroup = semigroup.numberMultiply /** + * A `Semigroup` that uses the minimum between two values. + * + * @example + * import { SemigroupMin } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(SemigroupMin.combine(2, 3), 2) + * * @category instances * @since 1.0.0 */ export const SemigroupMin: semigroup.Semigroup = semigroup.min(Order) /** - * `number` semigroup under multiplication. + * A `Semigroup` that uses the maximum between two values. * * @example - * import { SemigroupMultiply } from '@fp-ts/core/Number' + * import { SemigroupMax } from '@fp-ts/core/Number' * - * assert.deepStrictEqual(SemigroupMultiply.combine(2, 3), 6) + * assert.deepStrictEqual(SemigroupMax.combine(2, 3), 3) * * @category instances * @since 1.0.0 */ -export const SemigroupMultiply: semigroup.Semigroup = semigroup.numberMultiply +export const SemigroupMax: semigroup.Semigroup = semigroup.max(Order) /** * `number` monoid under addition. * * The `empty` value is `0`. * + * @example + * import { MonoidSum } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(MonoidSum.combine(2, 3), 5) + * assert.deepStrictEqual(MonoidSum.combine(2, MonoidSum.empty), 2) + * * @category instances * @since 1.0.0 */ @@ -376,36 +394,92 @@ export const MonoidSum: monoid.Monoid = monoid.numberSum * * The `empty` value is `1`. * + * @example + * import { MonoidMultiply } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(MonoidMultiply.combine(2, 3), 6) + * assert.deepStrictEqual(MonoidMultiply.combine(2, MonoidMultiply.empty), 2) + * * @category instances * @since 1.0.0 */ export const MonoidMultiply: monoid.Monoid = monoid.numberMultiply /** + * A `Monoid` that uses the minimum between two values. + * + * The `empty` value is `-Infinity`. + * + * @example + * import { MonoidMin } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(MonoidMin.combine(2, 3), 2) + * assert.deepStrictEqual(MonoidMin.combine(2, MonoidMin.empty), 2) + * * @category instances * @since 1.0.0 */ -export const MonoidMax: monoid.Monoid = bounded.max(Bounded) +export const MonoidMin: monoid.Monoid = bounded.min(Bounded) /** + * A `Monoid` that uses the maximum between two values. + * + * The `empty` value is `Infinity`. + * + * @example + * import { MonoidMax } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(MonoidMax.combine(2, 3), 3) + * assert.deepStrictEqual(MonoidMax.combine(2, MonoidMax.empty), 2) + * * @category instances * @since 1.0.0 */ -export const MonoidMin: monoid.Monoid = bounded.min(Bounded) +export const MonoidMax: monoid.Monoid = bounded.max(Bounded) /** + * Determines the sign of a given `number`. + * + * @param n - The `number` to determine the sign of. + * + * @example + * import { sign } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(sign(-5), -1) + * assert.deepStrictEqual(sign(0), 0) + * assert.deepStrictEqual(sign(5), 1) + * + * @category math * @since 1.0.0 */ -export const sign = (n: number): Ordering => n < 0 ? -1 : n > 0 ? 1 : 0 +export const sign = (n: number): Ordering => Order.compare(n, 0) /** - * @category algebraic operations + * Takes an `Iterable` of `number`s and returns their sum as a single `number`. + * + * @param collection - The collection of `number`s to sum. + * + * @example + * import { sumAll } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(sumAll([2, 3, 4]), 9) + * + * @category math * @since 1.0.0 */ export const sumAll: (collection: Iterable) => number = MonoidSum.combineAll /** - * @category algebraic operations + * Takes an `Iterable` of `number`s and returns their multiplication as a single `number`. + * + * @param collection - The collection of `number`s to multiply. + * + * @example + * import { multiplyAll } from '@fp-ts/core/Number' + * + * assert.deepStrictEqual(multiplyAll([2, 3, 4]), 24) + * + * @category math * @since 1.0.0 */ export const multiplyAll: (collection: Iterable) => number = MonoidMultiply.combineAll @@ -425,7 +499,7 @@ export const multiplyAll: (collection: Iterable) => number = MonoidMulti * assert.deepStrictEqual(remainder(3, 2), 1) * assert.deepStrictEqual(remainder(-4, 2), -0) * - * @category algebraic operations + * @category math * @since 1.0.0 */ export const remainder: { @@ -440,14 +514,3 @@ export const remainder: { const divisorInt = parseInt(divisor.toFixed(decCount).replace(".", "")) return (selfInt % divisorInt) / Math.pow(10, decCount) }) - -/* - - Missing: - - - toFixed - - toPrecision - - toExponential - - toLocaleString - -*/ diff --git a/src/Option.ts b/src/Option.ts index ec79fe5ef..fee13ef07 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -1521,11 +1521,11 @@ export const exists: { ) // ------------------------------------------------------------------------------------- -// algebraic operations +// math // ------------------------------------------------------------------------------------- /** - * @category algebraic operations + * @category math * @since 1.0.0 */ export const sum: { @@ -1534,7 +1534,7 @@ export const sum: { } = lift2(N.sum) /** - * @category algebraic operations + * @category math * @since 1.0.0 */ export const multiply: { @@ -1543,7 +1543,7 @@ export const multiply: { } = lift2(N.multiply) /** - * @category algebraic operations + * @category math * @since 1.0.0 */ export const subtract: { @@ -1552,7 +1552,7 @@ export const subtract: { } = lift2(N.subtract) /** - * @category algebraic operations + * @category math * @since 1.0.0 */ export const divide: { @@ -1571,7 +1571,7 @@ export const divide: { * const iterable = [some(2), none(), some(3), none()] * assert.deepStrictEqual(sumCompact(iterable), 5) * - * @category algebraic operations + * @category math * @since 1.0.0 */ export const sumCompact = (self: Iterable>): number => { @@ -1595,7 +1595,7 @@ export const sumCompact = (self: Iterable>): number => { * const iterable = [some(2), none(), some(3), none()] * assert.deepStrictEqual(multiplyCompact(iterable), 6) * - * @category algebraic operations + * @category math * @since 1.0.0 */ export const multiplyCompact = (self: Iterable>): number => { diff --git a/src/These.ts b/src/These.ts index ae419bed4..e669dbaad 100644 --- a/src/These.ts +++ b/src/These.ts @@ -1491,11 +1491,11 @@ export const Monad: monad.Monad = { } // ------------------------------------------------------------------------------------- -// algebraic operations +// math // ------------------------------------------------------------------------------------- /** - * @category algebraic operations + * @category math * @since 1.0.0 */ export const sum: { @@ -1504,7 +1504,7 @@ export const sum: { } = lift2(N.sum) /** - * @category algebraic operations + * @category math * @since 1.0.0 */ export const multiply: { @@ -1513,7 +1513,7 @@ export const multiply: { } = lift2(N.multiply) /** - * @category algebraic operations + * @category math * @since 1.0.0 */ export const subtract: { @@ -1522,7 +1522,7 @@ export const subtract: { } = lift2(N.subtract) /** - * @category algebraic operations + * @category math * @since 1.0.0 */ export const divide: { diff --git a/test/Bigint.ts b/test/Bigint.ts index 4f0661ffd..a6ffc7fee 100644 --- a/test/Bigint.ts +++ b/test/Bigint.ts @@ -3,6 +3,27 @@ import { pipe } from "@fp-ts/core/Function" import { deepStrictEqual } from "@fp-ts/core/test/util" describe.concurrent("Bigint", () => { + it("exports", () => { + expect(Bigint.SemigroupMax).exists + expect(Bigint.SemigroupMin).exists + expect(Bigint.sumAll).exists + expect(Bigint.multiplyAll).exists + expect(Bigint.lessThan).exists + expect(Bigint.lessThanOrEqualTo).exists + expect(Bigint.greaterThan).exists + expect(Bigint.greaterThanOrEqualTo).exists + expect(Bigint.between).exists + expect(Bigint.clamp).exists + expect(Bigint.min).exists + expect(Bigint.max).exists + }) + + it("sign", () => { + assert.deepStrictEqual(Bigint.sign(-5n), -1) + assert.deepStrictEqual(Bigint.sign(0n), 0) + assert.deepStrictEqual(Bigint.sign(5n), 1) + }) + it("isBigint", () => { expect(Bigint.isBigint(1n)).toEqual(true) expect(Bigint.isBigint(1)).toEqual(false) From f6e0f6d42cc8ab77641c1882fac60c53255a839c Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 15 Feb 2023 15:43:30 +0100 Subject: [PATCH 248/255] Function: swap apply arguments --- .changeset/hungry-comics-kneel.md | 5 +++++ docs/modules/Function.ts.md | 22 ++++++++++++++++++---- src/Function.ts | 27 ++++++++++++++++++++++----- test/Function.ts | 2 +- 4 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 .changeset/hungry-comics-kneel.md diff --git a/.changeset/hungry-comics-kneel.md b/.changeset/hungry-comics-kneel.md new file mode 100644 index 000000000..30cccff23 --- /dev/null +++ b/.changeset/hungry-comics-kneel.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +Function: swap apply arguments diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 2f9a4cdd9..5c5203a9b 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -160,16 +160,16 @@ Apply a function to a given value. **Signature** ```ts -export declare const apply: (self: (a: A) => B) => (a: A) => B +export declare const apply: (a: A) => (self: (a: A) => B) => B ``` **Example** ```ts import { pipe, apply } from '@fp-ts/core/Function' -import { increment } from '@fp-ts/core/Number' +import { length } from '@fp-ts/core/String' -assert.deepStrictEqual(pipe(2, apply(increment)), 3) +assert.deepStrictEqual(pipe(length, apply('hello')), 5) ``` Added in v1.0.0 @@ -278,7 +278,7 @@ Added in v1.0.0 ## dual -Creates a function that is both data-last and data-first. +Creates a function that can be used in a data-last (aka `pipe`able) or data-first style. **Signature** @@ -292,6 +292,20 @@ export declare const dual: < ) => DataLast & DataFirst ``` +**Example** + +```ts +import { dual, pipe } from '@fp-ts/core/Function' + +export const sum: { + (that: number): (self: number) => number + (self: number, that: number): number +} = dual(2, (self: number, that: number): number => self + that) + +assert.deepStrictEqual(sum(2, 3), 5) +assert.deepStrictEqual(pipe(2, sum(3)), 5) +``` + Added in v1.0.0 ## flip diff --git a/src/Function.ts b/src/Function.ts index 1cbd357d3..22a3551a7 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -32,7 +32,21 @@ export interface FunctionTypeLambda extends TypeLambda { export const isFunction = (input: unknown): input is Function => typeof input === "function" /** - * Creates a function that is both data-last and data-first. + * Creates a function that can be used in a data-last (aka `pipe`able) or data-first style. + * + * @param dataFirstArity - The arity of the uncurried function. + * @param body - The definition of the uncurried function. + * + * @example + * import { dual, pipe } from "@fp-ts/core/Function" + * + * export const sum: { + * (that: number): (self: number) => number + * (self: number, that: number): number + * } = dual(2, (self: number, that: number): number => self + that) + * + * assert.deepStrictEqual(sum(2, 3), 5) + * assert.deepStrictEqual(pipe(2, sum(3)), 5) * * @since 1.0.0 */ @@ -56,15 +70,18 @@ export const dual = < /** * Apply a function to a given value. * + * @param a - The value that the function will be applied to. + * @param self - The function to be applied to a value. + * * @example * import { pipe, apply } from '@fp-ts/core/Function' - * import { increment } from '@fp-ts/core/Number' + * import { length } from '@fp-ts/core/String' * - * assert.deepStrictEqual(pipe(2, apply(increment)), 3) + * assert.deepStrictEqual(pipe(length, apply("hello")), 5) * * @since 1.0.0 */ -export const apply = (self: (a: A) => B) => (a: A): B => self(a) +export const apply = (a: A) => (self: (a: A) => B): B => self(a) /** * A lazy argument @@ -147,7 +164,7 @@ export const constVoid: LazyArg = constUndefined /** * Reverses the order of arguments for a curried function. * - * @param f -A curried function that takes multiple arguments. + * @param f - A curried function that takes multiple arguments. * * @example * import { flip } from '@fp-ts/core/Function' diff --git a/test/Function.ts b/test/Function.ts index b7bba3d8b..1fc57f71c 100644 --- a/test/Function.ts +++ b/test/Function.ts @@ -8,7 +8,7 @@ const g = double describe.concurrent("Function", () => { it("apply", () => { - deepStrictEqual(_.pipe("a", _.apply(String.length)), 1) + deepStrictEqual(_.pipe(String.length, _.apply("a")), 1) }) it("compose", () => { From 5ac1e785eedef22a85cf2dfd1614e0da33805153 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 15 Feb 2023 17:08:19 +0100 Subject: [PATCH 249/255] Function: add docs --- docs/modules/Function.ts.md | 117 ++++++++++++++++++++++++++++++---- src/Function.ts | 121 +++++++++++++++++++++++++++--------- 2 files changed, 199 insertions(+), 39 deletions(-) diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 5c5203a9b..1be9dc39c 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -102,7 +102,7 @@ Added in v1.0.0 ## LazyArg (interface) -A lazy argument +A lazy argument. **Signature** @@ -112,6 +112,14 @@ export interface LazyArg { } ``` +**Example** + +```ts +import { LazyArg, constant } from '@fp-ts/core/Function' + +export const constNull: LazyArg = constant(null) +``` + Added in v1.0.0 ## SK @@ -142,8 +150,7 @@ Added in v1.0.0 The `absurd` function is a stub for cases where a value of type `never` is encountered in your code, meaning that it should be impossible for this code to be executed. -This function is particularly useful in functional programming, where it's often necessary to specify that certain cases are impossible. -By calling `absurd`, you can ensure that the type system correctly reflects that a certain value should never occur. +This function is particularly when it's necessary to specify that certain cases are impossible. **Signature** @@ -193,10 +200,10 @@ export declare const compose: { ```ts import { compose } from '@fp-ts/core/Function' -const inc = (n: number) => n + 1 +const increment = (n: number) => n + 1 const square = (n: number) => n * n -assert.strictEqual(compose(inc, square)(2), 9) +assert.strictEqual(compose(increment, square)(2), 9) ``` Added in v1.0.0 @@ -211,6 +218,14 @@ A thunk that returns always `false`. export declare const constFalse: LazyArg ``` +**Example** + +```ts +import { constFalse } from '@fp-ts/core/Function' + +assert.deepStrictEqual(constFalse(), false) +``` + Added in v1.0.0 ## constNull @@ -223,6 +238,14 @@ A thunk that returns always `null`. export declare const constNull: LazyArg ``` +**Example** + +```ts +import { constNull } from '@fp-ts/core/Function' + +assert.deepStrictEqual(constNull(), null) +``` + Added in v1.0.0 ## constTrue @@ -235,6 +258,14 @@ A thunk that returns always `true`. export declare const constTrue: LazyArg ``` +**Example** + +```ts +import { constTrue } from '@fp-ts/core/Function' + +assert.deepStrictEqual(constTrue(), true) +``` + Added in v1.0.0 ## constUndefined @@ -247,6 +278,14 @@ A thunk that returns always `undefined`. export declare const constUndefined: LazyArg ``` +**Example** + +```ts +import { constUndefined } from '@fp-ts/core/Function' + +assert.deepStrictEqual(constUndefined(), undefined) +``` + Added in v1.0.0 ## constVoid @@ -259,6 +298,14 @@ A thunk that returns always `void`. export declare const constVoid: LazyArg ``` +**Example** + +```ts +import { constVoid } from '@fp-ts/core/Function' + +assert.deepStrictEqual(constVoid(), undefined) +``` + Added in v1.0.0 ## constant @@ -274,6 +321,17 @@ and want that inner function to always use the same value, no matter how many ti export declare const constant: (value: A) => LazyArg ``` +**Example** + +```ts +import { constant } from '@fp-ts/core/Function' + +const constNull = constant(null) + +assert.deepStrictEqual(constNull(), null) +assert.deepStrictEqual(constNull(), null) +``` + Added in v1.0.0 ## dual @@ -287,7 +345,7 @@ export declare const dual: < DataLast extends (...args: Array) => any, DataFirst extends (...args: Array) => any >( - dataFirstArity: Parameters['length'], + arity: Parameters['length'], body: DataFirst ) => DataLast & DataFirst ``` @@ -419,7 +477,7 @@ Added in v1.0.0 ## hole -Type hole simulation +Type hole simulation. **Signature** @@ -431,18 +489,34 @@ Added in v1.0.0 ## identity +The identity function, i.e. A function that returns its input argument. + **Signature** ```ts export declare const identity: (a: A) => A ``` +**Example** + +```ts +import { identity } from '@fp-ts/core/Function' + +assert.deepStrictEqual(identity(5), 5) +``` + Added in v1.0.0 ## pipe Pipes the value of an expression into a pipeline of functions. +This is useful in combination with data-last functions as a simulation of methods: + +``` +as.map(f).filter(g) -> pipe(as, map(f), filter(g)) +``` + **Signature** ```ts @@ -683,10 +757,11 @@ export declare function pipe s.length +const length = (s: string): number => s.length const double = (n: number): number => n * 2 +const decrement = (n: number): number => n - 1 -assert.deepStrictEqual(pipe('aaa', len, double), 6) +assert.deepStrictEqual(pipe(length('hello'), double, decrement), 9) ``` Added in v1.0.0 @@ -706,21 +781,31 @@ export declare const tupled: (f: (...a: A) => B ```ts import { tupled } from '@fp-ts/core/Function' -const add = tupled((x: number, y: number): number => x + y) +const sumTupled = tupled((x: number, y: number): number => x + y) -assert.deepStrictEqual(add([1, 2]), 3) +assert.deepStrictEqual(sumTupled([1, 2]), 3) ``` Added in v1.0.0 ## unsafeCoerce +Casts the result to the specified type. + **Signature** ```ts export declare const unsafeCoerce: (a: A) => B ``` +**Example** + +```ts +import { unsafeCoerce, identity } from '@fp-ts/core/function' + +assert.deepStrictEqual(unsafeCoerce, identity) +``` + Added in v1.0.0 ## untupled @@ -733,4 +818,14 @@ Inverse function of `tupled` export declare const untupled: (f: (a: A) => B) => (...a: A) => B ``` +**Example** + +```ts +import { untupled } from '@fp-ts/core/Function' + +const getFirst = untupled((tuple: [A, B]): A => tuple[0]) + +assert.deepStrictEqual(getFirst(1, 2), 1) +``` + Added in v1.0.0 diff --git a/src/Function.ts b/src/Function.ts index 22a3551a7..9ddaaea0e 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -3,10 +3,6 @@ */ import type { TypeLambda } from "@fp-ts/core/HKT" -// ------------------------------------------------------------------------------------- -// type lambdas -// ------------------------------------------------------------------------------------- - /** * @category type lambdas * @since 1.0.0 @@ -34,7 +30,7 @@ export const isFunction = (input: unknown): input is Function => typeof input == /** * Creates a function that can be used in a data-last (aka `pipe`able) or data-first style. * - * @param dataFirstArity - The arity of the uncurried function. + * @param arity - The arity of the uncurried function. * @param body - The definition of the uncurried function. * * @example @@ -54,12 +50,12 @@ export const dual = < DataLast extends (...args: Array) => any, DataFirst extends (...args: Array) => any >( - dataFirstArity: Parameters["length"], + arity: Parameters["length"], body: DataFirst ): DataLast & DataFirst => { // @ts-expect-error return function() { - if (arguments.length >= dataFirstArity) { + if (arguments.length >= arity) { // @ts-expect-error return body.apply(this, arguments) } @@ -74,7 +70,7 @@ export const dual = < * @param self - The function to be applied to a value. * * @example - * import { pipe, apply } from '@fp-ts/core/Function' + * import { pipe, apply } from "@fp-ts/core/Function" * import { length } from '@fp-ts/core/String' * * assert.deepStrictEqual(pipe(length, apply("hello")), 5) @@ -84,7 +80,12 @@ export const dual = < export const apply = (a: A) => (self: (a: A) => B): B => self(a) /** - * A lazy argument + * A lazy argument. + * + * @example + * import { LazyArg, constant } from "@fp-ts/core/Function" + * + * export const constNull: LazyArg = constant(null) * * @since 1.0.0 */ @@ -94,7 +95,7 @@ export interface LazyArg { /** * @example - * import { FunctionN } from '@fp-ts/core/Function' + * import { FunctionN } from "@fp-ts/core/Function" * * export const sum: FunctionN<[number, number], number> = (a, b) => a + b * @@ -105,11 +106,29 @@ export interface FunctionN, B> { } /** + * The identity function, i.e. A function that returns its input argument. + * + * @param a - The input argument. + * + * @example + * import { identity } from "@fp-ts/core/Function" + * + * assert.deepStrictEqual(identity(5), 5) + * * @since 1.0.0 */ export const identity = (a: A): A => a /** + * Casts the result to the specified type. + * + * @param a - The value to be casted to the target type. + * + * @example + * import { unsafeCoerce, identity } from "@fp-ts/core/function" + * + * assert.deepStrictEqual(unsafeCoerce, identity) + * * @since 1.0.0 */ export const unsafeCoerce: (a: A) => B = identity as any @@ -120,7 +139,15 @@ export const unsafeCoerce: (a: A) => B = identity as any * This is useful when you want to pass a value to a higher-order function (a function that takes another function as its argument) * and want that inner function to always use the same value, no matter how many times it is called. * - * @param value - The constant value to be returned + * @param value - The constant value to be returned. + * + * @example + * import { constant } from "@fp-ts/core/Function" + * + * const constNull = constant(null) + * + * assert.deepStrictEqual(constNull(), null) + * assert.deepStrictEqual(constNull(), null) * * @since 1.0.0 */ @@ -129,6 +156,11 @@ export const constant = (value: A): LazyArg => () => value /** * A thunk that returns always `true`. * + * @example + * import { constTrue } from "@fp-ts/core/Function" + * + * assert.deepStrictEqual(constTrue(), true) + * * @since 1.0.0 */ export const constTrue: LazyArg = constant(true) @@ -136,6 +168,11 @@ export const constTrue: LazyArg = constant(true) /** * A thunk that returns always `false`. * + * @example + * import { constFalse } from "@fp-ts/core/Function" + * + * assert.deepStrictEqual(constFalse(), false) + * * @since 1.0.0 */ export const constFalse: LazyArg = constant(false) @@ -143,6 +180,11 @@ export const constFalse: LazyArg = constant(false) /** * A thunk that returns always `null`. * + * @example + * import { constNull } from "@fp-ts/core/Function" + * + * assert.deepStrictEqual(constNull(), null) + * * @since 1.0.0 */ export const constNull: LazyArg = constant(null) @@ -150,6 +192,11 @@ export const constNull: LazyArg = constant(null) /** * A thunk that returns always `undefined`. * + * @example + * import { constUndefined } from "@fp-ts/core/Function" + * + * assert.deepStrictEqual(constUndefined(), undefined) + * * @since 1.0.0 */ export const constUndefined: LazyArg = constant(undefined) @@ -157,6 +204,11 @@ export const constUndefined: LazyArg = constant(undefined) /** * A thunk that returns always `void`. * + * @example + * import { constVoid } from "@fp-ts/core/Function" + * + * assert.deepStrictEqual(constVoid(), undefined) + * * @since 1.0.0 */ export const constVoid: LazyArg = constUndefined @@ -167,7 +219,7 @@ export const constVoid: LazyArg = constUndefined * @param f - A curried function that takes multiple arguments. * * @example - * import { flip } from '@fp-ts/core/Function' + * import { flip } from "@fp-ts/core/Function" * * const f = (a: number) => (b: string) => a - b.length * @@ -183,7 +235,7 @@ export const flip = , B extends Array, C>( * Performs left-to-right function composition. The first argument may have any arity, the remaining arguments must be unary. * * @example - * import { flow } from '@fp-ts/core/Function' + * import { flow } from "@fp-ts/core/Function" * * const len = (s: string): number => s.length * const double = (n: number): number => n * 2 @@ -314,12 +366,12 @@ export function flow( * @param bc - A function that maps from `B` to `C`. * * @example - * import { compose } from '@fp-ts/core/Function' + * import { compose } from "@fp-ts/core/Function" * - * const inc = (n: number) => n + 1; + * const increment = (n: number) => n + 1; * const square = (n: number) => n * n; * - * assert.strictEqual(compose(inc, square)(2), 9); + * assert.strictEqual(compose(increment, square)(2), 9); * * @since 1.0.0 */ @@ -332,8 +384,7 @@ export const compose: { * The `absurd` function is a stub for cases where a value of type `never` is encountered in your code, * meaning that it should be impossible for this code to be executed. * - * This function is particularly useful in functional programming, where it's often necessary to specify that certain cases are impossible. - * By calling `absurd`, you can ensure that the type system correctly reflects that a certain value should never occur. + * This function is particularly when it's necessary to specify that certain cases are impossible. * * @since 1.0.0 */ @@ -345,11 +396,11 @@ export const absurd = (_: never): A => { * Creates a tupled version of this function: instead of `n` arguments, it accepts a single tuple argument. * * @example - * import { tupled } from '@fp-ts/core/Function' + * import { tupled } from "@fp-ts/core/Function" * - * const add = tupled((x: number, y: number): number => x + y) + * const sumTupled = tupled((x: number, y: number): number => x + y) * - * assert.deepStrictEqual(add([1, 2]), 3) + * assert.deepStrictEqual(sumTupled([1, 2]), 3) * * @since 1.0.0 */ @@ -359,6 +410,13 @@ export const tupled = , B>(f: (...a: A) => B): /** * Inverse function of `tupled` * + * @example + * import { untupled } from "@fp-ts/core/Function" + * + * const getFirst = untupled((tuple: [A, B]): A => tuple[0]) + * + * assert.deepStrictEqual(getFirst(1, 2), 1) + * * @since 1.0.0 */ export const untupled = , B>(f: (a: A) => B): ((...a: A) => B) => @@ -367,13 +425,20 @@ export const untupled = , B>(f: (a: A) => B): ( /** * Pipes the value of an expression into a pipeline of functions. * + * This is useful in combination with data-last functions as a simulation of methods: + * + * ``` + * as.map(f).filter(g) -> pipe(as, map(f), filter(g)) + * ``` + * * @example - * import { pipe } from '@fp-ts/core/Function' + * import { pipe } from "@fp-ts/core/Function" * - * const len = (s: string): number => s.length + * const length = (s: string): number => s.length * const double = (n: number): number => n * 2 + * const decrement = (n: number): number => n - 1 * - * assert.deepStrictEqual(pipe('aaa', len, double), 6) + * assert.deepStrictEqual(pipe(length("hello"), double, decrement), 9) * * @see {@link flow} * @since 1.0.0 @@ -660,11 +725,11 @@ export function pipe( } /** - * Type hole simulation + * Type hole simulation. * * @since 1.0.0 */ -export const hole: () => T = absurd as any +export const hole: () => T = unsafeCoerce(absurd) /** * The SK combinator, also known as the "S-K combinator" or "S-combinator", is a fundamental combinator in the @@ -676,9 +741,9 @@ export const hole: () => T = absurd as any * @param b - The second argument to be returned. * * @example - * import { SK } from '@fp-ts/core/Function'; + * import { SK } from "@fp-ts/core/Function"; * - * assert.deepStrictEqual(SK(0, 'hello'), 'hello') + * assert.deepStrictEqual(SK(0, "hello"), "hello") * * @since 1.0.0 */ From 7ca3c22e6298241ccd540dfa3cce540f629b0043 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 15 Feb 2023 17:19:28 +0100 Subject: [PATCH 250/255] Ordering: add docs --- docs/modules/Ordering.ts.md | 55 ++++++++++++++++++++++++++++++++++- src/Ordering.ts | 58 +++++++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 4 deletions(-) diff --git a/docs/modules/Ordering.ts.md b/docs/modules/Ordering.ts.md index 6690675d6..4ce18e1d3 100644 --- a/docs/modules/Ordering.ts.md +++ b/docs/modules/Ordering.ts.md @@ -28,22 +28,48 @@ Added in v1.0.0 ## Monoid +`Monoid` instance for `Ordering`, returns the left-most non-zero `Ordering`. + +The `empty` value is `0`. + **Signature** ```ts export declare const Monoid: monoid.Monoid<0 | 1 | -1> ``` +**Example** + +```ts +import { Monoid } from '@fp-ts/core/Ordering' + +assert.deepStrictEqual(Monoid.combine(Monoid.empty, -1), -1) +assert.deepStrictEqual(Monoid.combine(Monoid.empty, 1), 1) +assert.deepStrictEqual(Monoid.combine(1, -1), 1) +``` + Added in v1.0.0 ## Semigroup +`Semigroup` instance for `Ordering`, returns the left-most non-zero `Ordering`. + **Signature** ```ts export declare const Semigroup: semigroup.Semigroup<0 | 1 | -1> ``` +**Example** + +```ts +import { Semigroup } from '@fp-ts/core/Ordering' + +assert.deepStrictEqual(Semigroup.combine(0, -1), -1) +assert.deepStrictEqual(Semigroup.combine(0, 1), 1) +assert.deepStrictEqual(Semigroup.combine(1, -1), 1) +``` + Added in v1.0.0 # model @@ -62,25 +88,52 @@ Added in v1.0.0 ## match +Depending on the `Ordering` parameter given to it, returns a value produced by one of the 3 functions provided as parameters. + **Signature** ```ts export declare const match: { - (onLessThan: LazyArg, onEqual: LazyArg, onGreaterThan: LazyArg): (o: Ordering) => A | B | C + (onLessThan: LazyArg, onEqual: LazyArg, onGreaterThan: LazyArg): (self: Ordering) => A | B | C (o: Ordering, onLessThan: LazyArg, onEqual: LazyArg, onGreaterThan: LazyArg): A | B | C } ``` +**Example** + +```ts +import { match } from '@fp-ts/core/Ordering' +import { constant } from '@fp-ts/core/Function' + +const toMessage = match(constant('less than'), constant('equal'), constant('greater than')) + +assert.deepStrictEqual(toMessage(-1), 'less than') +assert.deepStrictEqual(toMessage(0), 'equal') +assert.deepStrictEqual(toMessage(1), 'greater than') +``` + Added in v1.0.0 # utils ## reverse +Inverts the ordering of the input `Ordering`. + **Signature** ```ts export declare const reverse: (o: Ordering) => Ordering ``` +**Example** + +```ts +import { reverse } from '@fp-ts/core/Ordering' + +assert.deepStrictEqual(reverse(1), -1) +assert.deepStrictEqual(reverse(-1), 1) +assert.deepStrictEqual(reverse(0), 0) +``` + Added in v1.0.0 diff --git a/src/Ordering.ts b/src/Ordering.ts index 60164d78e..60d443af5 100644 --- a/src/Ordering.ts +++ b/src/Ordering.ts @@ -13,11 +13,43 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" export type Ordering = -1 | 0 | 1 /** + * Inverts the ordering of the input `Ordering`. + * + * @param o - The input `Ordering`. + * + * @example + * import { reverse } from "@fp-ts/core/Ordering" + * + * assert.deepStrictEqual(reverse(1), -1) + * assert.deepStrictEqual(reverse(-1), 1) + * assert.deepStrictEqual(reverse(0), 0) + * * @since 1.0.0 */ export const reverse = (o: Ordering): Ordering => (o === -1 ? 1 : o === 1 ? -1 : 0) /** + * Depending on the `Ordering` parameter given to it, returns a value produced by one of the 3 functions provided as parameters. + * + * @param self - The `Ordering` parameter to match against. + * @param onLessThan - A function that will be called if the `Ordering` parameter is `-1`. + * @param onEqual - A function that will be called if the `Ordering` parameter is `0`. + * @param onGreaterThan - A function that will be called if the `Ordering` parameter is `1`. + * + * @example + * import { match } from "@fp-ts/core/Ordering" + * import { constant } from "@fp-ts/core/Function" + * + * const toMessage = match( + * constant('less than'), + * constant('equal'), + * constant('greater than') + * ) + * + * assert.deepStrictEqual(toMessage(-1), "less than") + * assert.deepStrictEqual(toMessage(0), "equal") + * assert.deepStrictEqual(toMessage(1), "greater than") + * * @category pattern matching * @since 1.0.0 */ @@ -26,7 +58,7 @@ export const match: { onLessThan: LazyArg, onEqual: LazyArg, onGreaterThan: LazyArg - ): (o: Ordering) => A | B | C + ): (self: Ordering) => A | B | C ( o: Ordering, onLessThan: LazyArg, @@ -34,13 +66,22 @@ export const match: { onGreaterThan: LazyArg ): A | B | C } = dual(4, ( - o: Ordering, + self: Ordering, onLessThan: LazyArg, onEqual: LazyArg, onGreaterThan: LazyArg -): A | B | C => o === -1 ? onLessThan() : o === 0 ? onEqual() : onGreaterThan()) +): A | B | C => self === -1 ? onLessThan() : self === 0 ? onEqual() : onGreaterThan()) /** + * `Semigroup` instance for `Ordering`, returns the left-most non-zero `Ordering`. + * + * @example + * import { Semigroup } from "@fp-ts/core/Ordering" + * + * assert.deepStrictEqual(Semigroup.combine(0, -1), -1) + * assert.deepStrictEqual(Semigroup.combine(0, 1), 1) + * assert.deepStrictEqual(Semigroup.combine(1, -1), 1) + * * @category instances * @since 1.0.0 */ @@ -61,6 +102,17 @@ export const Semigroup: semigroup.Semigroup = semigroup.make( ) /** + * `Monoid` instance for `Ordering`, returns the left-most non-zero `Ordering`. + * + * The `empty` value is `0`. + * + * @example + * import { Monoid } from "@fp-ts/core/Ordering" + * + * assert.deepStrictEqual(Monoid.combine(Monoid.empty, -1), -1) + * assert.deepStrictEqual(Monoid.combine(Monoid.empty, 1), 1) + * assert.deepStrictEqual(Monoid.combine(1, -1), 1) + * * @category instances * @since 1.0.0 */ From cf45fbf09aaf397fba5cb8afed73127b3fdd15e2 Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 15 Feb 2023 18:08:11 +0100 Subject: [PATCH 251/255] Struct: add docs --- docs/modules/Function.ts.md | 4 +++ docs/modules/String.ts.md | 2 ++ docs/modules/Struct.ts.md | 64 +++++++++++++++++++++++++++++++++++ src/Function.ts | 6 ++-- src/String.ts | 2 ++ src/Struct.ts | 66 ++++++++++++++++++++++++++++++++----- 6 files changed, 134 insertions(+), 10 deletions(-) diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 1be9dc39c..559e9da9d 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -394,6 +394,8 @@ Added in v1.0.0 Performs left-to-right function composition. The first argument may have any arity, the remaining arguments must be unary. +See also {@link pipe}. + **Signature** ```ts @@ -517,6 +519,8 @@ This is useful in combination with data-last functions as a simulation of method as.map(f).filter(g) -> pipe(as, map(f), filter(g)) ``` +See also {@link flow}. + **Signature** ```ts diff --git a/docs/modules/String.ts.md b/docs/modules/String.ts.md index 46c8fae6f..a5f125b43 100644 --- a/docs/modules/String.ts.md +++ b/docs/modules/String.ts.md @@ -133,6 +133,8 @@ Added in v1.0.0 ## empty +The empty string `""`. + **Signature** ```ts diff --git a/docs/modules/Struct.ts.md b/docs/modules/Struct.ts.md index 4887a2642..f517f901a 100644 --- a/docs/modules/Struct.ts.md +++ b/docs/modules/Struct.ts.md @@ -32,6 +32,8 @@ Added in v1.0.0 Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct by applying each `Equivalence` to the corresponding property of the struct. +Alias of {@link equivalence.struct}. + **Signature** ```ts @@ -40,6 +42,22 @@ export declare const getEquivalence: equivalence.Equivalence<{ readonly [K in keyof R]: [R[K]] extends [equivalence.Equivalence] ? A : never }> ``` +**Example** + +```ts +import { getEquivalence } from '@fp-ts/core/Struct' +import * as S from '@fp-ts/core/String' +import * as N from '@fp-ts/core/Number' + +const PersonEquivalence = getEquivalence({ + name: S.Equivalence, + age: N.Equivalence, +}) + +assert.deepStrictEqual(PersonEquivalence({ name: 'John', age: 25 }, { name: 'John', age: 25 }), true) +assert.deepStrictEqual(PersonEquivalence({ name: 'John', age: 25 }, { name: 'John', age: 40 }), false) +``` + Added in v1.0.0 ## getMonoid @@ -51,6 +69,8 @@ The `empty` value of the returned `Monoid` is a struct where each property is th It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. +See also {@link getSemigroup}. + **Signature** ```ts @@ -66,6 +86,8 @@ Added in v1.0.0 This function creates and returns a new `Order` for a struct of values based on the given `Order`s for each property in the struct. +Alias of {@link order.struct}. + **Signature** ```ts @@ -83,6 +105,8 @@ The returned `Semigroup` combines two structs of the same type by applying the c It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. +See also {@link getMonoid}. + **Signature** ```ts @@ -91,6 +115,28 @@ export declare const getSemigroup: semigroup.Semigroup<{ [K in keyof R]: [R[K]] extends [semigroup.Semigroup] ? A : never }> ``` +**Example** + +```ts +import { getSemigroup } from '@fp-ts/core/Struct' +import * as Semigroup from '@fp-ts/core/typeclass/Semigroup' +import * as O from '@fp-ts/core/Option' + +const PersonSemigroup = getSemigroup({ + name: Semigroup.last(), + age: O.getOptionalMonoid(Semigroup.last()), +}) + +assert.deepStrictEqual(PersonSemigroup.combine({ name: 'John', age: O.none() }, { name: 'John', age: O.some(25) }), { + name: 'John', + age: O.some(25), +}) +assert.deepStrictEqual(PersonSemigroup.combine({ name: 'John', age: O.some(25) }, { name: 'John', age: O.none() }), { + name: 'John', + age: O.some(25), +}) +``` + Added in v1.0.0 # utils @@ -107,6 +153,15 @@ export declare const omit: ( ) => (s: S) => { [K in Exclude]: S[K] } ``` +**Example** + +```ts +import { omit } from '@fp-ts/core/Struct' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe({ a: 'a', b: 1, c: true }, omit('c')), { a: 'a', b: 1 }) +``` + Added in v1.0.0 ## pick @@ -121,4 +176,13 @@ export declare const pick: ( ) => (s: S) => { [K in Keys[number]]: S[K] } ``` +**Example** + +```ts +import { pick } from '@fp-ts/core/Struct' +import { pipe } from '@fp-ts/core/Function' + +assert.deepStrictEqual(pipe({ a: 'a', b: 1, c: true }, pick('a', 'b')), { a: 'a', b: 1 }) +``` + Added in v1.0.0 diff --git a/src/Function.ts b/src/Function.ts index 9ddaaea0e..619ba3a2a 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -234,6 +234,8 @@ export const flip = , B extends Array, C>( /** * Performs left-to-right function composition. The first argument may have any arity, the remaining arguments must be unary. * + * See also {@link pipe}. + * * @example * import { flow } from "@fp-ts/core/Function" * @@ -244,7 +246,6 @@ export const flip = , B extends Array, C>( * * assert.deepStrictEqual(f('aaa'), 6) * - * @see {@link pipe} * @since 1.0.0 */ export function flow, B>(ab: (...a: A) => B): (...a: A) => B @@ -431,6 +432,8 @@ export const untupled = , B>(f: (a: A) => B): ( * as.map(f).filter(g) -> pipe(as, map(f), filter(g)) * ``` * + * See also {@link flow}. + * * @example * import { pipe } from "@fp-ts/core/Function" * @@ -440,7 +443,6 @@ export const untupled = , B>(f: (a: A) => B): ( * * assert.deepStrictEqual(pipe(length("hello"), double, decrement), 9) * - * @see {@link flow} * @since 1.0.0 */ export function pipe(a: A): A diff --git a/src/String.ts b/src/String.ts index d283a6d38..e8f9528c1 100644 --- a/src/String.ts +++ b/src/String.ts @@ -63,6 +63,8 @@ export const Semigroup: semigroup.Semigroup = semigroup.string export const Monoid: monoid.Monoid = monoid.string /** + * The empty string `""`. + * * @since 1.0.0 */ export const empty: "" = "" as const diff --git a/src/Struct.ts b/src/Struct.ts index c98dcf80f..79255cfa6 100644 --- a/src/Struct.ts +++ b/src/Struct.ts @@ -12,6 +12,12 @@ import * as semigroup from "@fp-ts/core/typeclass/Semigroup" /** * Create a new object by picking properties of an existing object. * + * @example + * import { pick } from "@fp-ts/core/Struct" + * import { pipe } from "@fp-ts/core/Function" + * + * assert.deepStrictEqual(pipe({ a: "a", b: 1, c: true }, pick("a", "b")), { a: "a", b: 1 }) + * * @since 1.0.0 */ export const pick = ]>( @@ -28,6 +34,12 @@ export const pick = ]>( /** * Create a new object by omitting properties of an existing object. * + * @example + * import { omit } from "@fp-ts/core/Struct" + * import { pipe } from "@fp-ts/core/Function" + * + * assert.deepStrictEqual(pipe({ a: "a", b: 1, c: true }, omit("c")), { a: "a", b: 1 }) + * * @since 1.0.0 */ export const omit = ]>( @@ -45,6 +57,27 @@ export const omit = ]>( * Given a struct of `Equivalence`s returns a new `Equivalence` that compares values of a struct * by applying each `Equivalence` to the corresponding property of the struct. * + * Alias of {@link equivalence.struct}. + * + * @example + * import { getEquivalence } from "@fp-ts/core/Struct" + * import * as S from "@fp-ts/core/String" + * import * as N from "@fp-ts/core/Number" + * + * const PersonEquivalence = getEquivalence({ + * name: S.Equivalence, + * age: N.Equivalence + * }) + * + * assert.deepStrictEqual( + * PersonEquivalence({ name: "John", age: 25 }, { name: "John", age: 25 }), + * true + * ) + * assert.deepStrictEqual( + * PersonEquivalence({ name: "John", age: 25 }, { name: "John", age: 40 }), + * false + * ) + * * @category combinators * @since 1.0.0 */ @@ -58,6 +91,8 @@ export const getEquivalence: }>( * * It is useful when you need to combine two structs of the same type and you have a specific way of combining each property of the struct. * + * See also {@link getMonoid}. + * + * @example + * import { getSemigroup } from "@fp-ts/core/Struct" + * import * as Semigroup from "@fp-ts/core/typeclass/Semigroup" + * import * as O from "@fp-ts/core/Option" + * + * const PersonSemigroup = getSemigroup({ + * name: Semigroup.last(), + * age: O.getOptionalMonoid(Semigroup.last()) + * }) + * + * assert.deepStrictEqual( + * PersonSemigroup.combine({ name: "John", age: O.none() }, { name: "John", age: O.some(25) }), + * { name: "John", age: O.some(25) } + * ) + * assert.deepStrictEqual( + * PersonSemigroup.combine({ name: "John", age: O.some(25) }, { name: "John", age: O.none() }), + * { name: "John", age: O.some(25) } + * ) + * * @category combinators * @since 1.0.0 */ @@ -89,6 +145,8 @@ export const getSemigroup: }> fields: R ) => monoid.Monoid<{ [K in keyof R]: [R[K]] extends [monoid.Monoid] ? A : never }> = monoid.struct - -/* - - TODO: - - - at - -*/ From fade89cc3000f2948fcc94d25e16ec74c37121ae Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 15 Feb 2023 18:14:50 +0100 Subject: [PATCH 252/255] fix unsafeCoerce example --- docs/modules/Function.ts.md | 2 +- src/Function.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/Function.ts.md b/docs/modules/Function.ts.md index 559e9da9d..07b7ffc5b 100644 --- a/docs/modules/Function.ts.md +++ b/docs/modules/Function.ts.md @@ -805,7 +805,7 @@ export declare const unsafeCoerce: (a: A) => B **Example** ```ts -import { unsafeCoerce, identity } from '@fp-ts/core/function' +import { unsafeCoerce, identity } from '@fp-ts/core/Function' assert.deepStrictEqual(unsafeCoerce, identity) ``` diff --git a/src/Function.ts b/src/Function.ts index 619ba3a2a..a64e6e02d 100644 --- a/src/Function.ts +++ b/src/Function.ts @@ -125,7 +125,7 @@ export const identity = (a: A): A => a * @param a - The value to be casted to the target type. * * @example - * import { unsafeCoerce, identity } from "@fp-ts/core/function" + * import { unsafeCoerce, identity } from "@fp-ts/core/Function" * * assert.deepStrictEqual(unsafeCoerce, identity) * From f031207e5f0f1b494d5ac8f370f8392b49e199bd Mon Sep 17 00:00:00 2001 From: gcanti Date: Wed, 15 Feb 2023 18:45:48 +0100 Subject: [PATCH 253/255] ReadonlyRecord: map: add support for structs --- .changeset/tough-planets-lick.md | 5 ++++ docs/modules/ReadonlyRecord.ts.md | 4 +-- dtslint/ts4.8/ReadonlyRecord.ts | 50 +++++++++++++++++++++++++++---- src/ReadonlyRecord.ts | 4 +-- 4 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 .changeset/tough-planets-lick.md diff --git a/.changeset/tough-planets-lick.md b/.changeset/tough-planets-lick.md new file mode 100644 index 000000000..d7ce05bfe --- /dev/null +++ b/.changeset/tough-planets-lick.md @@ -0,0 +1,5 @@ +--- +"@fp-ts/core": patch +--- + +ReadonlyRecord: map: add support for structs diff --git a/docs/modules/ReadonlyRecord.ts.md b/docs/modules/ReadonlyRecord.ts.md index 2fecf4825..f929ba54d 100644 --- a/docs/modules/ReadonlyRecord.ts.md +++ b/docs/modules/ReadonlyRecord.ts.md @@ -697,8 +697,8 @@ Maps a `ReadonlyRecord` into another `Record` by applying a transformation funct ```ts export declare const map: { - (f: (a: A, key: string) => B): (self: ReadonlyRecord) => Record - (self: ReadonlyRecord, f: (a: A, key: string) => B): Record + (f: (a: A, key: K) => B): (self: Readonly>) => Record + (self: Readonly>, f: (a: A, key: K) => B): Record } ``` diff --git a/dtslint/ts4.8/ReadonlyRecord.ts b/dtslint/ts4.8/ReadonlyRecord.ts index 2dd5d3362..a9d0e1314 100644 --- a/dtslint/ts4.8/ReadonlyRecord.ts +++ b/dtslint/ts4.8/ReadonlyRecord.ts @@ -1,31 +1,69 @@ import { pipe } from '@fp-ts/core/Function' -import * as _ from '@fp-ts/core/ReadonlyRecord' +import * as RR from '@fp-ts/core/ReadonlyRecord' declare const r: Record +declare const struct: Record<'a' | 'b', number> + +// +// map +// + +// $ExpectType Record +RR.map(r, ( + value, // $ExpectType number + _key, // $ExpectType string +) => value > 0) + +// $ExpectType Record +pipe(r, RR.map(( + value, // $ExpectType number + _key, // $ExpectType string +) => value > 0)) + +// $ExpectType Record<"a" | "b", boolean> +RR.map(struct, ( + value, // $ExpectType number + _key, // $ExpectType "a" | "b" +) => value > 0) + +// $ExpectType Record<"a" | "b", boolean> +pipe(struct, RR.map(( + value, // $ExpectType number + _key, // $ExpectType "a" | "b" +) => value > 0)) + +const constStruct = { a: 1, b: 2 } as const; + +function mapToBoolean(): { [K in keyof typeof constStruct]: boolean } { + return RR.map(constStruct, () => true); +} + +// $ExpectType { readonly a: boolean; readonly b: boolean; } +mapToBoolean() // // get // // $ExpectType Option -pipe(r, _.get('a')) +pipe(r, RR.get('a')) // // replaceOption // // $ExpectType Option> -pipe(r, _.replaceOption('a', 2)) +pipe(r, RR.replaceOption('a', 2)) // $ExpectType Option> -pipe(r, _.replaceOption('a', true)) +pipe(r, RR.replaceOption('a', true)) // // modifyOption // // $ExpectType Option> -pipe(r, _.modifyOption('a', () => 2)) +pipe(r, RR.modifyOption('a', () => 2)) // $ExpectType Option> -pipe(r, _.modifyOption('a', () => true)) +pipe(r, RR.modifyOption('a', () => true)) diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index 636abf4db..2ff8e96ea 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -364,8 +364,8 @@ export const pop: { * @since 1.0.0 */ export const map: { - (f: (a: A, key: string) => B): (self: ReadonlyRecord) => Record - (self: ReadonlyRecord, f: (a: A, key: string) => B): Record + (f: (a: A, key: K) => B): (self: Readonly>) => Record + (self: Readonly>, f: (a: A, key: K) => B): Record } = dual( 2, (self: ReadonlyRecord, f: (a: A, key: string) => B): Record => { From e27c9fc8941d201f45aac2ed6b8012d86457fa0a Mon Sep 17 00:00:00 2001 From: gcanti Date: Fri, 17 Feb 2023 10:09:54 +0100 Subject: [PATCH 254/255] ReadonlyArray: revert isEmpty, isNonEmpty change --- docs/modules/ReadonlyArray.ts.md | 58 +++++++++++++++++++++++++++----- docs/modules/String.ts.md | 4 +-- dtslint/ts4.8/ReadonlyArray.ts | 25 ++++++++++++-- src/ReadonlyArray.ts | 55 +++++++++++++++++++++++------- src/String.ts | 10 +++--- src/internal/ReadonlyArray.ts | 9 ++--- test/ReadonlyArray.ts | 16 ++++++--- 7 files changed, 138 insertions(+), 39 deletions(-) diff --git a/docs/modules/ReadonlyArray.ts.md b/docs/modules/ReadonlyArray.ts.md index 2d0e2b014..62f628ba9 100644 --- a/docs/modules/ReadonlyArray.ts.md +++ b/docs/modules/ReadonlyArray.ts.md @@ -92,7 +92,9 @@ Added in v1.0.0 - [groupBy](#groupby) - [guards](#guards) - [isEmpty](#isempty) + - [isEmptyArray](#isemptyarray) - [isNonEmpty](#isnonempty) + - [isNonEmptyArray](#isnonemptyarray) - [instances](#instances) - [Applicative](#applicative) - [Chainable](#chainable) @@ -1169,13 +1171,12 @@ Added in v1.0.0 ## isEmpty -Determine if a `ReadonlyArray` is empty narrowing down the type to `[]`. +Determine if a `ReadonlyArray` is empty narrowing down the type to `readonly []`. **Signature** ```ts -export declare function isEmpty(self: Array): self is [] -export declare function isEmpty(self: ReadonlyArray): self is readonly [] +export declare const isEmpty: (self: readonly A[]) => self is readonly [] ``` **Example** @@ -1189,19 +1190,37 @@ assert.deepStrictEqual(isEmpty([1, 2, 3]), false) Added in v1.0.0 +## isEmptyArray + +Determine if an `Array` is empty narrowing down the type to `[]`. + +**Signature** + +```ts +export declare const isEmptyArray: (self: A[]) => self is [] +``` + +**Example** + +```ts +import { isEmptyArray } from '@fp-ts/core/ReadonlyArray' + +assert.deepStrictEqual(isEmptyArray([]), true) +assert.deepStrictEqual(isEmptyArray([1, 2, 3]), false) +``` + +Added in v1.0.0 + ## isNonEmpty -Determine if a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyArray`. +Determine if a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyReadonlyArray`. A `ReadonlyArray` is considered to be a `NonEmptyReadonlyArray` if it contains at least one element. **Signature** ```ts -export declare const isNonEmpty: { - (self: A[]): self is [A, ...A[]] - (self: readonly A[]): self is readonly [A, ...A[]] -} +export declare const isNonEmpty: (self: readonly A[]) => self is readonly [A, ...A[]] ``` **Example** @@ -1215,6 +1234,29 @@ assert.deepStrictEqual(isNonEmpty([1, 2, 3]), true) Added in v1.0.0 +## isNonEmptyArray + +Determine if an `Array` is non empty narrowing down the type to `NonEmptyArray`. + +An `Array` is considered to be a `NonEmptyArray` if it contains at least one element. + +**Signature** + +```ts +export declare const isNonEmptyArray: (self: A[]) => self is [A, ...A[]] +``` + +**Example** + +```ts +import { isNonEmptyArray } from '@fp-ts/core/ReadonlyArray' + +assert.deepStrictEqual(isNonEmptyArray([]), false) +assert.deepStrictEqual(isNonEmptyArray([1, 2, 3]), true) +``` + +Added in v1.0.0 + # instances ## Applicative diff --git a/docs/modules/String.ts.md b/docs/modules/String.ts.md index a5f125b43..50d1d6c92 100644 --- a/docs/modules/String.ts.md +++ b/docs/modules/String.ts.md @@ -340,8 +340,8 @@ Added in v1.0.0 ```ts export declare const split: { - (separator: string | RegExp): (self: string) => readonly [string, ...string[]] - (self: string, separator: string | RegExp): readonly [string, ...string[]] + (separator: string | RegExp): (self: string) => [string, ...string[]] + (self: string, separator: string | RegExp): [string, ...string[]] } ``` diff --git a/dtslint/ts4.8/ReadonlyArray.ts b/dtslint/ts4.8/ReadonlyArray.ts index 5f59ead93..fe48330a2 100644 --- a/dtslint/ts4.8/ReadonlyArray.ts +++ b/dtslint/ts4.8/ReadonlyArray.ts @@ -1,5 +1,6 @@ import { pipe } from '@fp-ts/core/Function' import * as RA from '@fp-ts/core/ReadonlyArray' +import * as O from '@fp-ts/core/Option' declare const neras: RA.NonEmptyReadonlyArray declare const neas: RA.NonEmptyArray @@ -15,11 +16,21 @@ if (RA.isEmpty(ras)) { ras } -if (RA.isEmpty(as)) { +// $ExpectType (c: readonly A[]) => Option +O.liftPredicate(RA.isEmpty) + +// ------------------------------------------------------------------------------------- +// isEmptyArray +// ------------------------------------------------------------------------------------- + +if (RA.isEmptyArray(as)) { // $ExpectType [] as } +// $ExpectType (c: A[]) => Option<[]> +O.liftPredicate(RA.isEmptyArray) + // ------------------------------------------------------------------------------------- // isNonEmpty // ------------------------------------------------------------------------------------- @@ -29,11 +40,21 @@ if (RA.isNonEmpty(ras)) { ras } -if (RA.isNonEmpty(as)) { +// $ExpectType (c: readonly A[]) => Option +O.liftPredicate(RA.isNonEmpty) + +// ------------------------------------------------------------------------------------- +// isNonEmptyArray +// ------------------------------------------------------------------------------------- + +if (RA.isNonEmptyArray(as)) { // $ExpectType [number, ...number[]] as } +// $ExpectType (c: A[]) => Option<[A, ...A[]]> +O.liftPredicate(RA.isNonEmptyArray) + // ------------------------------------------------------------------------------------- // map // ------------------------------------------------------------------------------------- diff --git a/src/ReadonlyArray.ts b/src/ReadonlyArray.ts index 1e76360d4..2bd5f6aed 100644 --- a/src/ReadonlyArray.ts +++ b/src/ReadonlyArray.ts @@ -311,7 +311,23 @@ export const scanRight: { }) /** - * Determine if a `ReadonlyArray` is empty narrowing down the type to `[]`. + * Determine if an `Array` is empty narrowing down the type to `[]`. + * + * @param self - The `Array` to check. + * + * @example + * import { isEmptyArray } from "@fp-ts/core/ReadonlyArray" + * + * assert.deepStrictEqual(isEmptyArray([]), true); + * assert.deepStrictEqual(isEmptyArray([1, 2, 3]), false); + * + * @category guards + * @since 1.0.0 + */ +export const isEmptyArray = (self: Array): self is [] => self.length === 0 + +/** + * Determine if a `ReadonlyArray` is empty narrowing down the type to `readonly []`. * * @param self - The `ReadonlyArray` to check. * @@ -324,14 +340,30 @@ export const scanRight: { * @category guards * @since 1.0.0 */ -export function isEmpty(self: Array): self is [] -export function isEmpty(self: ReadonlyArray): self is readonly [] -export function isEmpty(self: ReadonlyArray): self is readonly [] { - return self.length === 0 -} +// TODO: rename to isEmptyReadonlyArray +export const isEmpty: (self: ReadonlyArray) => self is readonly [] = isEmptyArray as any + +/** + * Determine if an `Array` is non empty narrowing down the type to `NonEmptyArray`. + * + * An `Array` is considered to be a `NonEmptyArray` if it contains at least one element. + * + * @param self - The `Array` to check. + * + * @example + * import { isNonEmptyArray } from "@fp-ts/core/ReadonlyArray" + * + * assert.deepStrictEqual(isNonEmptyArray([]), false); + * assert.deepStrictEqual(isNonEmptyArray([1, 2, 3]), true); + * + * @category guards + * @since 1.0.0 + */ +export const isNonEmptyArray: (self: Array) => self is NonEmptyArray = + readonlyArray.isNonEmptyArray /** - * Determine if a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyArray`. + * Determine if a `ReadonlyArray` is non empty narrowing down the type to `NonEmptyReadonlyArray`. * * A `ReadonlyArray` is considered to be a `NonEmptyReadonlyArray` if it contains at least one element. * @@ -346,10 +378,9 @@ export function isEmpty(self: ReadonlyArray): self is readonly [] { * @category guards * @since 1.0.0 */ -export const isNonEmpty: { - (self: Array): self is NonEmptyArray - (self: ReadonlyArray): self is NonEmptyReadonlyArray -} = readonlyArray.isNonEmpty +// TODO: rename to isNonEmptyReadonlyArray +export const isNonEmpty: (self: ReadonlyArray) => self is NonEmptyReadonlyArray = + readonlyArray.isNonEmptyArray /** * Return the number of elements in a `ReadonlyArray`. @@ -1181,7 +1212,7 @@ export const chopNonEmpty: { const [b, rest] = f(self) const out: NonEmptyArray = [b] let next: ReadonlyArray = rest - while (readonlyArray.isNonEmpty(next)) { + while (readonlyArray.isNonEmptyArray(next)) { const [b, rest] = f(next) out.push(b) next = rest diff --git a/src/String.ts b/src/String.ts index e8f9528c1..d89a7b7de 100644 --- a/src/String.ts +++ b/src/String.ts @@ -10,7 +10,7 @@ import { dual } from "@fp-ts/core/Function" import * as readonlyArray from "@fp-ts/core/internal/ReadonlyArray" import type { Refinement } from "@fp-ts/core/Predicate" import * as predicate from "@fp-ts/core/Predicate" -import type { NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" +import type { NonEmptyArray } from "@fp-ts/core/ReadonlyArray" import * as equivalence from "@fp-ts/core/typeclass/Equivalence" import * as monoid from "@fp-ts/core/typeclass/Monoid" import * as order from "@fp-ts/core/typeclass/Order" @@ -204,11 +204,11 @@ export const length = (self: string): number => self.length * @since 1.0.0 */ export const split: { - (separator: string | RegExp): (self: string) => NonEmptyReadonlyArray - (self: string, separator: string | RegExp): NonEmptyReadonlyArray -} = dual(2, (self: string, separator: string | RegExp): NonEmptyReadonlyArray => { + (separator: string | RegExp): (self: string) => NonEmptyArray + (self: string, separator: string | RegExp): NonEmptyArray +} = dual(2, (self: string, separator: string | RegExp): NonEmptyArray => { const out = self.split(separator) - return readonlyArray.isNonEmpty(out) ? out : [self] + return readonlyArray.isNonEmptyArray(out) ? out : [self] }) /** diff --git a/src/internal/ReadonlyArray.ts b/src/internal/ReadonlyArray.ts index de2139f91..40acb91f4 100644 --- a/src/internal/ReadonlyArray.ts +++ b/src/internal/ReadonlyArray.ts @@ -2,14 +2,11 @@ * @since 1.0.0 */ -import type { NonEmptyArray, NonEmptyReadonlyArray } from "@fp-ts/core/ReadonlyArray" +import type { NonEmptyArray } from "@fp-ts/core/ReadonlyArray" /** @internal */ -export function isNonEmpty(self: Array): self is NonEmptyArray -export function isNonEmpty(self: ReadonlyArray): self is NonEmptyReadonlyArray -export function isNonEmpty(self: ReadonlyArray): self is readonly [] { - return self.length > 0 -} +export const isNonEmptyArray = (self: ReadonlyArray): self is NonEmptyArray => + self.length > 0 /** @internal */ export const fromIterable = (collection: Iterable): Array => diff --git a/test/ReadonlyArray.ts b/test/ReadonlyArray.ts index 971c64b82..e74063adf 100644 --- a/test/ReadonlyArray.ts +++ b/test/ReadonlyArray.ts @@ -1020,17 +1020,25 @@ describe.concurrent("ReadonlyArray", () => { }) it("isEmpty", () => { - const as: ReadonlyArray = [1, 2, 3] - deepStrictEqual(RA.isEmpty(as), false) + deepStrictEqual(RA.isEmpty([1, 2, 3]), false) deepStrictEqual(RA.isEmpty([]), true) }) + it("isEmptyArray", () => { + deepStrictEqual(RA.isEmptyArray([1, 2, 3]), false) + deepStrictEqual(RA.isEmptyArray([]), true) + }) + it("isNotEmpty", () => { - const as: ReadonlyArray = [1, 2, 3] - deepStrictEqual(RA.isNonEmpty(as), true) + deepStrictEqual(RA.isNonEmpty([1, 2, 3]), true) deepStrictEqual(RA.isNonEmpty([]), false) }) + it("isNonEmptyArray", () => { + deepStrictEqual(RA.isNonEmptyArray([1, 2, 3]), true) + deepStrictEqual(RA.isNonEmptyArray([]), false) + }) + it("head", () => { const as: ReadonlyArray = [1, 2, 3] deepStrictEqual(RA.head(as), O.some(1)) From 7a190bacb4760dc0af44b89235057ca39903960a Mon Sep 17 00:00:00 2001 From: gcanti Date: Sun, 19 Feb 2023 19:17:47 +0100 Subject: [PATCH 255/255] Announcement --- README.md | 86 +------------------------------------------------------ 1 file changed, 1 insertion(+), 85 deletions(-) diff --git a/README.md b/README.md index 00dc1dd2d..04c40161c 100644 --- a/README.md +++ b/README.md @@ -1,85 +1 @@ -

- - - -

- -

-Functional programming in TypeScript -

- -

- - npm downloads - -

- -# Credits and sponsorship - -This library was inspired by the following projects: - -- [fp-ts](https://github.com/gcanti/fp-ts) - -A huge thanks to my sponsors who made the development of `@fp-ts/core` possible. - -If you also want to **become a sponsor** to ensure this library continues to improve and receive maintenance, check out my [GitHub Sponsors profile](https://github.com/sponsors/gcanti?o=sd&sc=t) - -## Requirements - -- TypeScript 4.8 or newer -- The `strict` flag enabled in your `tsconfig.json` file - -``` -{ - // ... - "compilerOptions": { - // ... - "strict": true, - } -} -``` - -# Typed functional programming in TypeScript - -This project represents the next major iteration of [`fp-ts`](https://github.com/gcanti/fp-ts) and it's objective is a reconciliation with [`@effect`](https://github.com/Effect-TS) in order to unify the ecosystems. - -The [`@effect`](https://github.com/Effect-TS) project will reduce it's scope to simply being an effect system and will delegate to `fp-ts org` all the lower level abstractions such as typeclasses and common data structures. - -The objective of the `fp-ts org` in github and in npm (`@fp-ts`) is to simplify structure and management of the project, have smaller and better scoped packages. - -Our "current" idea (that is well open for changes) is for `fp-ts org` to have: - -- The [`@fp-ts/core`](https://github.com/fp-ts/core) library features a new implementation of the Higher Kinded Type (HKT) pattern, including common typeclasses such as `Monad` and widely-used data types like `Option`, `Either`, and `ReadonlyArray` -- [`@fp-ts/schema`](https://github.com/fp-ts/schema) offers schema validation with static type inference, including decoders for data structures in `@fp-ts/core` and `@effect/data` -- [`@fp-ts/optic`](https://github.com/fp-ts/optic) provides optics for structures in both `@fp-ts/core` and `@effect/data` - -For those using [`fp-ts`](https://github.com/gcanti/fp-ts) v2 and its ecosystem, roughly these are the equivalents: - -- [`fp-ts`](https://github.com/gcanti/fp-ts) -> [`@fp-ts/core`](https://github.com/fp-ts/core) + [`@effect/*` packages](https://github.com/Effect-TS) -- [`io-ts`](https://github.com/gcanti/io-ts) -> [`@fp-ts/schema`](https://github.com/fp-ts/schema) -- [`monocle-ts`](https://github.com/gcanti/monocle-ts) -> [`@fp-ts/optic`](https://github.com/fp-ts/optic) - -Note that `@fp-ts/core` will not contain any effect system (e.g. `Task`, `TaskEither`, `ReaderTaskEither`) since the handling of effects is entirely delegated to the packages contained in [`@effect/*`](https://github.com/Effect-TS). - -# Installation - -To install the **alpha** version: - -``` -npm install @fp-ts/core -``` - -**Warning**. This package is primarily published to receive early feedback and for contributors, during this development phase we cannot guarantee the stability of the APIs, consider each release to contain breaking changes. - -# Documentation - -- Guides (WIP) - - [Typeclass overview](./guides/typeclass.md) - - [Standard TypeScript types](./guides/ts-types.md) - - Data types - - [`Option`](./guides/Option.md) -- [API Reference](https://fp-ts.github.io/core/) - -# License - -The MIT License (MIT) +**Announcement**: following the [official decision](https://dev.to/effect-ts/a-bright-future-for-effect-455m) to merge the `fp-ts` project with the Effect-TS ecosystem, active development has been transferred to the repository https://github.com/Effect-TS/data.