1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-12-07 23:03:15 +02:00

Compare commits

..

309 Commits

Author SHA1 Message Date
Dr. Carsten Leue
0c742b81e6 fix: better performance for either
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-08 10:01:14 +01:00
Dr. Carsten Leue
a1d6c94b15 fix: run benchmarks
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-08 09:31:48 +01:00
Dr. Carsten Leue
e4e28a6556 fix: more Kleisli simplified types
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-07 17:53:47 +01:00
Dr. Carsten Leue
7e7cc06f11 fix: add more Kleisli definitions
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-07 17:42:54 +01:00
Dr. Carsten Leue
54d5dbd04a fix: more tests for iso and prism
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-07 17:31:27 +01:00
Dr. Carsten Leue
51adce0c95 fix: better package import
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-07 16:15:16 +01:00
Dr. Carsten Leue
aa5e908810 fix: introduce Kleisli type
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-07 14:35:46 +01:00
Dr. Carsten Leue
b3bd5e9ad3 fix: bind docs
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 16:18:15 +01:00
Dr. Carsten Leue
178df09ff7 fix: document ApS
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 16:08:35 +01:00
Dr. Carsten Leue
92eb9715bd fix: implement some useful prisms
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 13:53:02 +01:00
Dr. Carsten Leue
41ebb04ae0 fix: upload coverage to coverall
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 11:45:01 +01:00
Dr. Carsten Leue
b2705e3adf fix: disable to version updates
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 11:39:17 +01:00
renovate[bot]
b232183e47 chore(config): migrate config renovate.json (#143)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-06 11:26:23 +01:00
Dr. Carsten Leue
0f9f89f16d doc: improve documentation
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 11:20:50 +01:00
Dr. Carsten Leue
0d3a8634b1 fix: add inline annotations
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 10:54:24 +01:00
Dr. Carsten Leue
56c8f1b034 fix: fix build
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 09:57:58 +01:00
Dr. Carsten Leue
bad86cd769 fix: try to fix build
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 09:50:03 +01:00
Dr. Carsten Leue
d0c5f32111 fix: add go 1.25 to build matrix
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 09:43:27 +01:00
renovate[bot]
77745c1348 fix(deps): update go dependencies (#142)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-06 09:39:27 +01:00
李鑫
2c96cef500 feat: add array.MonadReduce() function (#132)
Signed-off-by: lixin <lixin@dustess.com>
Co-authored-by: lixin <lixin@dustess.com>
2025-11-06 09:28:20 +01:00
Carsten Leue
3385c705dc Implement v2 using type aliases (#141)
* fix: initial checkin of v2

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: slowly migrate IO

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: migrate MonadTraverseArray and TraverseArray

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: migrate traversal

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: complete migration of IO

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: migrate ioeither

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: refactorY

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: next step in migration

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: adjust IO generation code

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: get rid of more IO methods

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: get rid of more IO

* fix: convert iooption

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: convert reader

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: convert a bit of reader

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: new build script

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: cleanup

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: reformat

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: simplify

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: some cleanup

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: adjust Pair to Haskell semantic

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: documentation and testcases

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: some performance optimizations

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: remove coverage

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: better doc

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

---------

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-06 09:27:00 +01:00
ibm-mend-app[bot]
7874859c4b Add .whitesource configuration file (#140)
Co-authored-by: ibm-mend-app[bot] <142626574+ibm-mend-app[bot]@users.noreply.github.com>
2025-11-06 09:22:43 +01:00
renovate[bot]
25e3d1d85c fix(deps): update module github.com/stretchr/testify to v1.11.1 (#139)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-27 22:40:53 +00:00
renovate[bot]
d7ff994fb7 fix(deps): update module github.com/stretchr/testify to v1.11.0 (#138)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-25 01:44:33 +00:00
renovate[bot]
1cdca552b2 chore(deps): update actions/checkout action to v4.3.0 (#137)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 18:38:27 +00:00
renovate[bot]
73480ca030 fix(deps): update module github.com/urfave/cli/v2 to v2.27.7 (#136)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-14 10:26:20 +00:00
renovate[bot]
734e2b0055 chore(deps): update actions/setup-node action to v4.4.0 (#134)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-14 10:54:36 +00:00
renovate[bot]
4c28859e89 chore(deps): update actions/setup-node action to v4.3.0 (#131)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-17 06:44:51 +00:00
renovate[bot]
a516849c07 fix(deps): update module github.com/urfave/cli/v2 to v2.27.6 (#130)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 22:50:57 +00:00
sarabande
29200d34dc docs(iterator): update Cycle function documentation (#128) 2025-03-02 00:21:41 +01:00
renovate[bot]
7a3989989b chore(deps): update actions/setup-node action to v4.2.0 (#127)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-27 22:04:25 +00:00
renovate[bot]
6a6d53f025 fix(deps): update module github.com/stretchr/testify to v1.10.0 (#126)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-23 15:33:28 +00:00
renovate[bot]
078da752cd chore(deps): update actions/setup-node action to v4.1.0 2024-10-24 20:12:43 +00:00
renovate[bot]
1a489fde27 chore(deps): update actions/checkout action to v4.2.2 2024-10-23 19:31:36 +00:00
renovate[bot]
a135b2acae fix(deps): update module github.com/urfave/cli/v2 to v2.27.5 2024-10-13 20:09:16 +00:00
renovate[bot]
9e9dfa1f5f chore(deps): update actions/checkout action to v4.2.1 2024-10-07 22:39:01 +00:00
renovate[bot]
dd87ea12b3 chore(deps): update actions/checkout action to v4.2.0 2024-09-25 21:29:08 +00:00
renovate[bot]
5fc0d18c97 chore(deps): update actions/setup-node action to v4.0.4 2024-09-19 20:14:45 +00:00
CRaLFa
76c1297576 fix typos in README and comment (#119)
Signed-off-by: CRaLFa <minami.smd@gmail.com>
2024-09-12 09:40:19 +02:00
Dr. Carsten Leue
68aeb4c725 fix: script
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-08-27 16:57:59 +02:00
Dr. Carsten Leue
53f3fa1828 fix: semantic release
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-08-27 16:43:21 +02:00
Dr. Carsten Leue
97e1e4d92d fix: add test for go 1.23
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-08-27 16:39:52 +02:00
Dr. Carsten Leue
ec57d5cd4a fix: go mod tidy
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-08-27 16:37:22 +02:00
renovate[bot]
0ae5b43724 fix(deps): update module github.com/urfave/cli/v2 to v2.27.4 2024-08-11 19:12:08 +00:00
renovate[bot]
e73e14c0ae fix(deps): update module github.com/urfave/cli/v2 to v2.27.3 2024-07-25 03:34:59 +00:00
renovate[bot]
325bc376f9 chore(deps): update actions/setup-node action to v4.0.3 2024-07-09 20:06:20 +00:00
Dr. Carsten Leue
f646ace9fe chore: git mod tidy
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-06-24 09:24:15 +02:00
Laglangyue
9f8161fbc1 chore: ignore fp-go file for unix machine (#115)
Signed-off-by: tangjiafu <tangjiafu@apache.org>
Co-authored-by: tangjiafu <tangjiafu@apache.org>
2024-06-24 09:22:40 +02:00
renovate[bot]
1c4f2c0403 chore(deps): update actions/checkout action to v4.1.7 2024-06-13 02:39:23 +00:00
Dr. Carsten Leue
3b3b80aed0 fix: some more tests
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-05-27 11:54:04 +02:00
Dr. Carsten Leue
fdff4e4735 fix: more tests
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-05-26 16:23:40 +02:00
Dr. Carsten Leue
391754e5a6 fix: more testing
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-05-25 15:41:32 +02:00
Dr. Carsten Leue
598a7b261b fix: add more tests
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-05-24 23:19:24 +02:00
Dr. Carsten Leue
f0f1a48965 fix: do not use v8
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-05-24 21:43:36 +02:00
Dr. Carsten Leue
e39e5e0920 fix: add missing Fold to ReaderIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-05-24 12:55:20 +02:00
李鑫
9c7a5bb24b fix: string format of pair.pairString() (#113)
Signed-off-by: lixin <lixin@dustess.com>
Co-authored-by: lixin <lixin@dustess.com>
2024-05-20 21:48:24 +02:00
renovate[bot]
89bda4f500 chore(deps): update actions/checkout action to v4.1.6 2024-05-17 05:37:34 +00:00
renovate[bot]
15dffb3256 chore(deps): update actions/checkout action to v4.1.5 2024-05-09 02:10:28 +00:00
t-hg
95fbd93696 Fix typo (#106)
Opertator -> Operator
2024-04-29 08:47:26 +02:00
renovate[bot]
6e0d5704bc fix(deps): update module github.com/urfave/cli/v2 to v2.27.2 2024-04-27 19:09:18 +00:00
renovate[bot]
0aa95e656b chore(deps): update actions/checkout action to v4.1.4 2024-04-25 18:08:51 +00:00
renovate[bot]
b3544a32fc chore(deps): update actions/checkout action to v4.1.3 2024-04-22 16:18:16 +00:00
Dr. Carsten Leue
9ad9b4a9bf fix: update dependencies
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-03-20 21:43:03 +01:00
Francis Zhou
74763bdadc correct the generic type for FromIO (#104)
Signed-off-by: francis <francis.tm@me.com>
2024-03-11 16:18:30 +01:00
renovate[bot]
9aa2ae041f fix(deps): update module github.com/stretchr/testify to v1.9.0 2024-03-02 18:23:13 +00:00
Dr. Carsten Leue
d356fa3c89 fix: more auto generated templates fo DI
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-29 16:27:23 +01:00
Dr. Carsten Leue
f61507254d fix: small changes to readall
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-22 13:58:39 +01:00
Dr. Carsten Leue
85f8071c75 fix: add ToWriter
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-20 16:10:58 +01:00
Dr. Carsten Leue
76ae6f2bec fix: more functions for StateReaderIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-19 14:34:35 +01:00
Dr. Carsten Leue
f4f4fb306c fix: add conversions for StateReaderIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-18 21:45:15 +01:00
Dr. Carsten Leue
747f477a96 fix: next small step towards StateReaderIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-18 21:01:39 +01:00
Dr. Carsten Leue
045f4e8849 fix: add basic implementation of StateReaderIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-17 23:06:52 +01:00
Dr. Carsten Leue
65e09e0e90 fix: expose Monad and Pointed for IOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-16 15:54:40 +01:00
Dr. Carsten Leue
6ab6ff094b fix: correct sequence order of TraverseArraySeq for IO
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-16 15:46:12 +01:00
Dr. Carsten Leue
e6e35d643c fix: update doc
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-13 14:25:56 +01:00
Dr. Carsten Leue
01d490b710 fix: add State monad
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-13 14:23:33 +01:00
Dr. Carsten Leue
01786a054b fix: refactor Writer monad
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-13 10:44:57 +01:00
Dr. Carsten Leue
d0e4984b60 fix: switch internal implementation of iterator from Tuple2 to Pair
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-12 10:33:42 +01:00
Dr. Carsten Leue
51ed1693a5 fix: refactory tests a bit
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-09 15:06:06 +01:00
Dr. Carsten Leue
0afedbd7fe fix: generic order on ContramapCache
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-08 13:19:01 +01:00
Dr. Carsten Leue
3f1bde219a fix: add go 1.22 to test
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-08 10:08:25 +01:00
Dr. Carsten Leue
6f91e91eb9 fix: add hash to http builder
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-08 09:42:29 +01:00
Dr. Carsten Leue
9f6b6d4968 fix: optimize use of tuples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-08 08:41:51 +01:00
Dr. Carsten Leue
79652d8474 fix: disable inlining of debug functions
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-07 13:41:47 +01:00
Dr. Carsten Leue
a774d63e66 fix: try a more efficient implementation of standard interfaces
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-07 13:26:17 +01:00
Dr. Carsten Leue
d86cf55a3d fix: add correct _test suffix to examples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-07 11:32:14 +01:00
Carsten Leue
8150ae2a68 fix: refactor either type (#102)
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-07 11:03:20 +01:00
Dr. Carsten Leue
7daf65effc Merge branch 'main' of github.com:IBM/fp-go 2024-02-07 10:10:50 +01:00
Dr. Carsten Leue
909f7c3bce fix: linter bugs
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-07 10:07:37 +01:00
renovate[bot]
5f0c644c6d chore(deps): update actions/setup-node action to v4.0.2 2024-02-07 09:04:33 +00:00
Dr. Carsten Leue
9b3d9c6930 fix: shrink size of DI a bit
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-06 22:13:34 +01:00
Dr. Carsten Leue
59381c1e50 fix: some internal refactorings
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-06 21:35:33 +01:00
Dr. Carsten Leue
358573cc20 fix: optimize strings package
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-06 14:43:23 +01:00
Dr. Carsten Leue
e166806d1b fix: adjust to some linter findings
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-05 13:46:12 +01:00
Dr. Carsten Leue
02ec50c91d fix: attempt to expose Monad as an interface
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-05 12:29:45 +01:00
Dr. Carsten Leue
9e04974d0e fix: add ReaderIOEither sample
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-04 22:25:51 +01:00
Dr. Carsten Leue
2f99ca471a fix: add example for dependency injection using a Reader
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-04 21:52:50 +01:00
Dr. Carsten Leue
3e09a19d68 fix: Writer monad
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-01 22:11:29 +01:00
Dr. Carsten Leue
839ef47054 fix: refactor writer
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-01 18:26:09 +01:00
Dr. Carsten Leue
144b27233b fix: some internal refactorings
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-01 17:26:51 +01:00
Dr. Carsten Leue
668eb85aea fix: some smaller optimizations
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-02-01 09:08:31 +01:00
Dr. Carsten Leue
b077fed094 fix: optimize PipeXXX calls
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-31 21:50:33 +01:00
Carsten Leue
7d3759619c Add Do notation support and Bind to Monads (#100)
* fix: implement bind, let, apS for serveral monads

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: implement bind for maps

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: implement do notation for more monads

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: add bind to more monads

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: add Do and Bind support to Monads

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

---------

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-31 21:34:46 +01:00
Dr. Carsten Leue
c73467caf5 fix: add WithTime and WithDuration
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-26 10:09:39 +01:00
Dr. Carsten Leue
ca606767f3 fix: icorrect order of generics for IO.Flap
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-26 09:15:56 +01:00
Dr. Carsten Leue
fb82af9a69 fix: signature of IO.Flap
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-26 09:11:27 +01:00
Dr. Carsten Leue
57ad8c6466 fix: expose MkDirAll
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-20 16:52:58 +01:00
Dr. Carsten Leue
5a9f405362 fix: better handling of HTTP errors
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-20 09:57:23 +01:00
Dr. Carsten Leue
89c34254a9 fix: add Join
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-17 11:57:26 +01:00
Dr. Carsten Leue
a14feff1d6 fix: add missing MapLeft
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-15 12:04:55 +01:00
Dr. Carsten Leue
f3642bad60 fix: remove 1.22
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-15 10:52:16 +01:00
Dr. Carsten Leue
997627b318 fix: node version
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-15 10:51:17 +01:00
Dr. Carsten Leue
1e1411c003 fix: add LogJson
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-15 10:46:50 +01:00
Dr. Carsten Leue
9ed9f8a171 fix: implement foldMap for records
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-12 17:19:38 +01:00
Dr. Carsten Leue
e7428549e4 fix: add consistent Delay and After functions to IO
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-12 13:20:50 +01:00
Dr. Carsten Leue
aef0048119 fix: add Wrap and Unwrap to endomorphism
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-11 17:18:35 +01:00
Dr. Carsten Leue
709d74b135 fix: refactor builder
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-11 14:12:53 +01:00
Dr. Carsten Leue
38c6541254 fix: handling of headers in builder
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-09 23:30:55 +01:00
Dr. Carsten Leue
813b83b423 fix: add WithQueryArg to request builder
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-08 21:35:39 +01:00
Dr. Carsten Leue
9139dedbbe fix: add lazy support for iterators
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2024-01-08 14:22:08 +01:00
Elliot Chen
5e15119653 run go mod tidy (#97)
Co-authored-by: zichang.chen <zichange.chen@grabtaxi.com>
2024-01-08 08:08:59 +01:00
Elliot Chen
986aa21055 add idea filter in gitignore (#94)
Co-authored-by: zichang.chen <zichange.chen@grabtaxi.com>
2024-01-02 21:56:40 +01:00
renovate[bot]
3a4c46ec1e fix(deps): update module github.com/urfave/cli/v2 to v2.27.1 2023-12-30 18:29:29 +00:00
renovate[bot]
96c3ee20ff fix(deps): update module github.com/urfave/cli/v2 to v2.27.0 2023-12-27 02:11:30 +00:00
Dr. Carsten Leue
7af9acfd99 fix: Chain for Endomorphism
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-22 16:43:19 +01:00
Dr. Carsten Leue
36eefbcd27 fix: name the endomorphism for the Y combinator
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-22 14:41:55 +01:00
Dr. Carsten Leue
973138c822 fix: add prepend method
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-21 16:46:47 +01:00
Dr. Carsten Leue
12ef79184b fix: typing for Y combinator
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-21 16:25:35 +01:00
Dr. Carsten Leue
5ac47440a1 fix: add a single element cache
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-21 14:10:46 +01:00
Dr. Carsten Leue
3aa55c74d4 fix: add WithBearer
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-19 14:33:52 +01:00
Dr. Carsten Leue
a6f55a199c fix: experiment with doc links
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-19 12:18:07 +01:00
Dr. Carsten Leue
2b500d15da Merge branch 'main' of github.com:IBM/fp-go 2023-12-18 21:40:39 +01:00
Dr. Carsten Leue
599b8256b6 fix: generate DI variations
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-18 21:40:30 +01:00
renovate[bot]
cf70b47984 chore(deps): update actions/setup-node action to v4.0.1 2023-12-18 15:59:48 +00:00
Dr. Carsten Leue
7bceb856f8 fix: move DI to separate package
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-18 10:06:47 +01:00
Dr. Carsten Leue
49e89de783 fix: make Curry operations a bit more generic
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-18 09:46:46 +01:00
Dr. Carsten Leue
a87de2f644 fix: use endomorphism in optics
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-18 09:28:36 +01:00
Dr. Carsten Leue
6d043d2752 fix: common functions for endomorphism
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-17 22:59:25 +01:00
Dr. Carsten Leue
1d02f21ff5 fix: rename FormEndomorphism and FormBuilder
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-17 22:38:55 +01:00
Dr. Carsten Leue
e82575fe08 fix: consistent endomorphism
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-17 13:24:05 +01:00
Dr. Carsten Leue
5fcd0b1595 fix: use endomorphism
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-17 12:34:15 +01:00
Dr. Carsten Leue
5caabf478c fix: add Lens for FormData
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-16 23:38:03 +01:00
Dr. Carsten Leue
b7ec18c83e fix: Content-Length header in Requester
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-16 22:06:40 +01:00
Dr. Carsten Leue
96686425fb fix: add WithFormData and WithJson
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-16 19:29:20 +01:00
Dr. Carsten Leue
1f675e08fa fix: add support for request builder
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-16 16:49:57 +01:00
Dr. Carsten Leue
4d2f410c98 fix: add MakeBodyRequest
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-15 16:00:58 +01:00
Dr. Carsten Leue
8f49c1328c fix: add provider factories with more dependencies
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-15 15:31:01 +01:00
Dr. Carsten Leue
2a1d5821db fix: expose http client as injection token
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-15 15:21:07 +01:00
renovate[bot]
6abbdc5ee1 chore(deps): update actions/setup-go action to v5 2023-12-06 19:24:14 +00:00
renovate[bot]
5fea9858a9 fix(deps): update module github.com/urfave/cli/v2 to v2.26.0 2023-12-03 00:19:17 +00:00
Carsten Leue
e6426c90c0 fix: add WithResource to IO and IOOption (#90)
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-12-01 09:38:30 +01:00
Carsten Leue
54ce59105e fix: add ChainFirstIOK (#89)
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-11-30 14:50:29 +01:00
Carsten Leue
8bb006c741 fix: add a uniq method to arrays (#88)
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-11-30 09:03:16 +01:00
Carsten Leue
b6efa35b03 fix: bug in compact array (#87)
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-11-29 22:13:46 +01:00
Carsten Leue
35848900c0 fix: generic parameter order for ChainTo (#86)
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-11-28 09:26:19 +01:00
Dr. Carsten Leue
3d54f99739 fix: add missing TraverseArraySeq
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-11-27 20:52:02 +01:00
Carsten Leue
ffd9418cac fix: support Alt for IOOption (#84)
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-11-27 17:00:59 +01:00
Carsten Leue
acfcea59f4 fix: break cyclic dependencies between IOOption and IOEither (#83)
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-11-27 14:55:10 +01:00
Carsten Leue
b4bf511f03 fix: http interface of IOEither (#82)
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-11-27 12:12:44 +01:00
Carsten Leue
211340952b Dependency injection (#81)
* fix: checkin

Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>

* fix: add initial DI implementation

Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>

* fix: add multi provider

Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>

* fix: simplify DI implementation

Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>

* fix: simplify provider

Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>

* fix: add Switch to function package

Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>

* fix: add DI

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

---------

Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-11-25 16:56:39 +01:00
Carsten Leue
56860425c4 fix: add Flip function (#80)
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
2023-11-12 13:34:27 +01:00
Carsten Leue
c0b16c675b fix: add reduce and filter (#79)
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
2023-11-11 16:50:18 +01:00
Carsten Leue
4b68e66528 fix: add samples for Any and Next to iterator package (#78)
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
2023-11-10 13:46:10 +01:00
renovate[bot]
5b7e5b153b chore(deps): update actions/checkout action to v4.1.1 2023-11-08 10:44:39 +00:00
Carsten Leue
d43fbeb375 Add presentation to sample section (#76)
* doc: add presentation

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: add some more examples

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* doc: update presentation

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: update presentation

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: add presentation and samples

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: benchmarks

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* fix: upload presentation

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>

* doc: add presentation

Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>

* doc: add link to video

Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>

---------

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
2023-11-08 09:58:23 +01:00
Carsten Leue
57d507c1ba Merge pull request #75 from pinguo-lixin/fix-magma-reverse
fix: magma.Reverse
2023-11-05 20:13:42 +01:00
lixin
aa19857127 fix: magma.Reverse 2023-11-04 14:49:30 +08:00
Dr. Carsten Leue
7766787cc1 fix: update
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-27 13:24:40 +02:00
Carsten Leue
6a9f38f990 Merge pull request #74 from IBM/cleue-add-asserts
fix: add assertions
2023-10-24 12:27:36 +02:00
Dr. Carsten Leue
e9584bc247 fix: add assertions
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-24 12:27:10 +02:00
renovate[bot]
55252c5680 chore(deps): update actions/setup-node action to v4 2023-10-23 19:08:50 +00:00
Carsten Leue
88bf35c4af Merge pull request #72 from IBM/cleue-improve-with-lock
Cleanup Either, context.Reader and context.ReaderIO
2023-10-23 09:06:22 +02:00
Dr. Carsten Leue
da3c9683eb fix: remove Reader and ReaderEither for context since they do not make sense
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-23 09:05:10 +02:00
Dr. Carsten Leue
08d9fed9af fix: remove unnecesary indirection in E.TryCatch
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-23 08:36:32 +02:00
Carsten Leue
83a0c6cdef Merge pull request #71 from IBM/cleue-add-mutex-to-io
fix: add WithLock to limit concurrency
2023-10-22 21:08:06 +02:00
Dr. Carsten Leue
9da484b79e fix: add WithLock to limit concurrency
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-22 21:07:40 +02:00
Carsten Leue
e46cfd89d4 Merge pull request #70 from IBM/cleue-add-bool-package
fix: add monoid for bool
2023-10-12 21:39:03 +02:00
Dr. Carsten Leue
6a4cdfa891 fix: add monoid for bool
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-12 21:38:11 +02:00
Carsten Leue
93a7e9964b Merge pull request #69 from IBM/cleue-add-missing-FromIO
fix: add missing FromIO to ReaderIO
2023-10-12 11:18:07 +02:00
Dr. Carsten Leue
9ef98e1ec4 fix: add missing FromIO to ReaderIO
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-12 11:17:31 +02:00
Carsten Leue
f1a730998d Merge pull request #68 from IBM/cleue-add-flap-to-readerio
fix: add Flap to more monads
2023-10-12 09:49:18 +02:00
Dr. Carsten Leue
f129297045 fix: add Flap to more monads
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-12 09:48:42 +02:00
Carsten Leue
b434f1fbf4 Merge pull request #67 from IBM/cleue-add-flap-to-reader
fix: add flap to Reader
2023-10-11 22:24:00 +02:00
Dr. Carsten Leue
756e1336dc fix: add flap to Reader
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-11 22:23:19 +02:00
Carsten Leue
c629d18bb3 Merge pull request #66 from IBM/cleue-add-try-catch-for-single-value-return
fix: remove File.GetName and add Join for convenience
2023-10-11 21:25:17 +02:00
Dr. Carsten Leue
1eefc28ba6 fix: remove File.GetName and add Join for convenience
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-11 17:36:11 +02:00
Carsten Leue
af2915d98a Merge pull request #65 from IBM/cleue-fix-flap-order
fix: change order of generics for flap
2023-10-10 22:41:43 +02:00
Dr. Carsten Leue
e9f9c2777f fix: change order of generics for flap
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-10 22:40:59 +02:00
Carsten Leue
895862a67e Merge pull request #64 from IBM/cleue-add-FromReaderIO
fix: add missing RightReaderIO and FromReaderIO to context
2023-10-10 15:05:34 +02:00
Dr. Carsten Leue
caf0574742 fix: add missing RightReaderIO and FromReaderIO to context
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-10 15:04:59 +02:00
Carsten Leue
bace6f01eb Merge pull request #62 from IBM/cleue-add-missing-chain-readeriok
fix: add missing ChainReaderIOK
2023-10-06 23:03:16 +02:00
Dr. Carsten Leue
254c63a16f fix: add missing ChainReaderIOK
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-06 23:02:45 +02:00
Carsten Leue
655c8a9b1d Merge pull request #61 from IBM/cleue-add-chain-first-to-readerio
fix: add missing ChainXXIOK to Reader
2023-10-06 22:36:38 +02:00
Dr. Carsten Leue
c6d6be66e0 fix: add missing ChainXXIOK to Reader
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-06 22:36:04 +02:00
Carsten Leue
e313f95865 Merge pull request #60 from IBM/cleue-alternative-monoid-for-option
fix: provide AltMonoid
2023-10-06 21:50:57 +02:00
Dr. Carsten Leue
5f25317f97 fix: provide AltMonoid
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-06 21:50:22 +02:00
Carsten Leue
f5aa2d6c15 Merge pull request #58 from IBM/renovate/major-go-dependencies
chore(deps): update actions/checkout action to v4
2023-10-05 15:20:29 +02:00
renovate[bot]
7262820624 chore(deps): update actions/checkout action to v4 2023-10-05 12:37:09 +00:00
Carsten Leue
c8fc10358b Merge pull request #56 from IBM/cleue-add-flap
fix: add flap and non empty array
2023-09-26 22:33:30 +02:00
Dr. Carsten Leue
1cd167541d fix: add flap and non empty array
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-26 22:32:53 +02:00
Carsten Leue
ebe94d71dc Merge pull request #55 from IBM/sample-match
fix: add match example
2023-09-24 22:17:05 +02:00
Dr. Carsten Leue
7ef6eb524b fix: add match example
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-24 22:15:01 +02:00
Carsten Leue
7b82e87bf3 Merge pull request #53 from IBM/cleue-add-missing-flatten-to-reader
fix: add missing Flatten to Reader
2023-09-20 17:54:07 +02:00
Dr. Carsten Leue
e8fdbe9f87 fix: add missing Flatten to Reader
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-20 17:53:45 +02:00
Carsten Leue
226c7039de Merge pull request #52 from IBM/cleue-add-memoize-to-reader
fix: add missing Memoize to readers
2023-09-20 16:04:51 +02:00
Dr. Carsten Leue
943ae8e009 fix: add missing Memoize to readers
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-20 15:56:02 +02:00
Carsten Leue
44c8441b07 Merge pull request #51 from IBM/cleue-rioe-tests
fix: add RIOE testcases
2023-09-19 22:33:56 +02:00
Dr. Carsten Leue
600aeae770 fix: add RIOE testcases
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-19 22:31:55 +02:00
Carsten Leue
f74a407294 Merge pull request #50 from IBM/cleue-add-some-tweaks
fix: add WithTempFile to ReaderIOEither
2023-09-19 18:07:06 +02:00
Dr. Carsten Leue
b15ab38861 fix: add WithTempFile to ReaderIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-19 18:06:32 +02:00
Carsten Leue
6532a83e82 Merge pull request #49 from IBM/cleue-add-ioeither-sample-with-return-tuple
fix: add missing IOO.FromIOEither
2023-09-19 12:29:23 +02:00
Dr. Carsten Leue
7c12b72db1 fix: add missing IOO.FromIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-19 12:24:05 +02:00
Carsten Leue
dc894ad643 Merge pull request #48 from IBM/cleue-some-benchmarking
fix: add some benchmarks
2023-09-19 10:22:04 +02:00
Dr. Carsten Leue
c902058320 fix: add some benchmarks
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-19 10:21:16 +02:00
Carsten Leue
bf33f4fb66 Merge pull request #46 from a-lipson/main
Modified doc for generateTupled functions (& changed occurences)
2023-09-19 10:12:57 +02:00
Dre
b4d2a5c6be fixed typo in ioeither ChainFirstIOK doc line 2023-09-18 15:48:00 -07:00
a-lipson
705b71d95c Modified doc for generateTupled functions (& changed occurences) 2023-09-15 17:01:11 -07:00
Carsten Leue
34844bcfc2 Merge pull request #45 from IBM/cleue-prefer-second-over-SK
doc: ad doc to SK function
2023-09-13 15:04:50 +02:00
Dr. Carsten Leue
9a9d13b066 doc: ad doc to SK function
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-13 15:04:19 +02:00
Carsten Leue
da1449e680 Merge pull request #44 from IBM/cleue-add-apply-monoid
fix: add missing alt methods and semigroup
2023-09-12 22:16:20 +02:00
Dr. Carsten Leue
865d9fe064 fix: add missing alt methods and semigroup
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-12 22:10:33 +02:00
Carsten Leue
c5b1bae65a Merge pull request #43 from IBM/cleue-add-custom-type-sample
Cleue add custom type sample
2023-09-12 13:47:12 +02:00
Dr. Carsten Leue
0a395f63ff fix: merge
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-12 13:45:07 +02:00
Dr. Carsten Leue
26a7066de0 fix: add UnslicedN
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-12 13:28:23 +02:00
Dr. Carsten Leue
52823e2c8e fix: add UnslicedN
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-12 10:52:39 +02:00
Carsten Leue
503021c65e Merge pull request #42 from IBM/cleue-add-traverse-with-index
fix: add missing withIndex methods
2023-09-11 13:50:30 +02:00
Dr. Carsten Leue
a2a6a41993 fix: add missing withIndex methods
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-11 13:48:51 +02:00
Carsten Leue
7da9de6f41 Merge pull request #41 from IBM/cleue-add-missing-functions
fix: order of parameters in optics
2023-09-10 21:56:23 +02:00
Dr. Carsten Leue
ff1b6faf84 fix: order of parameters in optics
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-10 21:49:44 +02:00
Carsten Leue
38120764e7 Merge pull request #40 from IBM/cleue-add-missing-lenses
fix: change Cache to Memoize and fix order of parameters to ToType
2023-09-10 21:37:38 +02:00
Dr. Carsten Leue
a83c2aec49 fix: change Cache to Memoize and fix order of parameters to ToType
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-10 21:29:01 +02:00
Carsten Leue
03debd37c8 Merge pull request #39 from IBM/cleue-implement-compact
fix: add compact methods
2023-09-08 22:57:18 +02:00
Dr. Carsten Leue
4f04344cda fix: add compact methods
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-08 22:54:58 +02:00
Carsten Leue
cf1c886f48 Merge pull request #37 from IBM/cleue-fix-order-of-generics-for-ChainOptionK
fix: order of generic parameters
2023-09-08 18:18:36 +02:00
Dr. Carsten Leue
3e0eb99b88 fix: order of generic parameters
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-08 18:16:06 +02:00
Carsten Leue
cb15a3d9fc Merge pull request #36 from IBM/cleue-mostly-adequate-more-samples
Cleue mostly adequate more samples
2023-09-08 15:31:01 +02:00
Dr. Carsten Leue
16535605f5 fix: add better sequence and traverse for option and either
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-08 15:26:56 +02:00
Dr. Carsten Leue
53f4e5ebd7 fix: add more mostly-adequate examples and solutions
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-08 15:25:44 +02:00
Dr. Carsten Leue
fb91fd5dc8 fix: add more mostly-adequate examples and solutions
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-07 17:21:39 +02:00
Carsten Leue
3ccafb5302 Merge pull request #35 from IBM/cleue-mostly-adequate-capter10
Add more examples for mostly-adequate
2023-09-06 15:15:00 +02:00
Dr. Carsten Leue
52b71ef4f3 fix: add more examples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-05 22:51:46 +02:00
Dr. Carsten Leue
5d77d5bb3d fix: add sample app for rendering cat images
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-04 22:55:14 +02:00
Dr. Carsten Leue
8ba8f852fa Merge branch 'main' into cleue-mostly-adequate-capter10 2023-09-04 22:35:13 +02:00
Carsten Leue
29d9882d2a Merge pull request #34 from IBM/cleue-request-builder-example
doc: document how to use a request builder for http
2023-09-04 11:15:28 +02:00
Dr. Carsten Leue
f80ca31e14 doc: document how to use a request builder for http
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-04 11:13:58 +02:00
Dr. Carsten Leue
8692078972 doc: add examples and solutions from mostly adequate
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-03 22:21:23 +02:00
Dr. Carsten Leue
12a4f6801c fix: add ap sample
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-02 14:30:01 +02:00
Carsten Leue
8650a8a600 Merge pull request #33 from IBM/cleue-mostly-adequate-fp-go
fix: add examples for [Frisby's Mostly Adequate Guide]
2023-09-01 17:50:59 +02:00
Dr. Carsten Leue
fb3b1f115c fix: add examples for [Frisby's Mostly Adequate Guide] 2023-09-01 17:31:47 +02:00
Carsten Leue
ce66cf2295 Merge pull request #31 from IBM/cleue-add-cache
fix: implement simple cache for pure functions
2023-08-31 11:07:46 +02:00
Dr. Carsten Leue
80e579dd0b fix: implement simple cache for pure functions
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-31 10:27:32 +02:00
Carsten Leue
ddafd1ee57 Merge pull request #30 from IBM/cleue-sample-ioeither
Add samples for IOEither
2023-08-29 09:16:17 +02:00
Dr. Carsten Leue
b5f077da71 fix: remove types from this branch
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-29 09:11:03 +02:00
Dr. Carsten Leue
1a0c40b419 fix: add helpers for reflect types
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-25 22:53:09 +02:00
Carsten Leue
d5d89b1853 fix: add runtime type validation
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
2023-08-24 22:49:03 +02:00
Carsten Leue
0f061a5099 fix: initial implementation of types
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
2023-08-22 22:34:05 +02:00
Carsten Leue
45e05f25ff Merge pull request #27 from jdbaldry/main-1
Fix a couple of spelling errors
2023-08-21 14:49:54 +02:00
Carsten Leue
a390d53451 add: bind to IOEither
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
2023-08-18 22:15:26 +02:00
Jack Baldry
1346b9378a Fix a couple spelling errors 2023-08-18 09:45:27 +01:00
Carsten Leue
befd4f471e fix: add basic bind as do notation
Signed-off-by: Carsten Leue <carsten.leue@de.ibm.com>
2023-08-17 23:03:03 +02:00
Carsten Leue
db8d3da87a Merge pull request #26 from IBM/cleue-more-samples
fix: add array examples
2023-08-11 22:32:26 +02:00
Dr. Carsten Leue
ee4e936183 fix: add array examples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-11 22:31:36 +02:00
Carsten Leue
0064ac1c75 Merge pull request #25 from IBM/cleue-fix-build-break-1
fix: build break
2023-08-11 17:32:07 +02:00
Dr. Carsten Leue
8944a66c18 fix: build break
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-11 17:31:31 +02:00
Carsten Leue
bd0c42db01 Merge pull request #24 from IBM/cleue-add-disclaimer
fix: add more examples
2023-08-11 16:26:58 +02:00
Dr. Carsten Leue
e9f03e2d26 fix: add more examples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-11 16:26:15 +02:00
Carsten Leue
bb630810fc Merge pull request #23 from IBM/cleue-better-docs
fix: experiment with docs and examples
2023-08-11 12:08:51 +02:00
Dr. Carsten Leue
9ba9eaacbe fix: experiment with docs and examples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-11 11:56:11 +02:00
Carsten Leue
a9f6839acd Merge pull request #22 from IBM/cleue-add-FoldMap
fix: implement FoldMap
2023-08-10 18:08:48 +02:00
Dr. Carsten Leue
1b1dccc551 fix: implement FoldMap
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-10 18:08:11 +02:00
Carsten Leue
39c6108bf5 Merge pull request #21 from IBM/cleue-fix-buildbreak
fix: build break
2023-08-10 13:24:28 +02:00
Dr. Carsten Leue
83e1ff30c1 chore: test on multiple versions of go
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-10 13:22:31 +02:00
Dr. Carsten Leue
d9dda4cfa5 fix: build break
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-10 13:14:48 +02:00
Carsten Leue
d9b2804a7e Merge pull request #20 from IBM/cleue-add-FilterChain-operations
fix: implement FilterChain
2023-08-10 11:47:07 +02:00
Dr. Carsten Leue
c0028918ae fix: implement FilterChain
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-10 11:46:30 +02:00
Carsten Leue
cd53cb7036 Merge pull request #19 from IBM/cleue-implement-first-and-last
fix: add first and last
2023-08-07 22:36:12 +02:00
Dr. Carsten Leue
469c60f05d fix: add first and last
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-07 22:35:06 +02:00
Carsten Leue
74fd0c96e7 Merge pull request #18 from IBM/cleue-add-some-more-itertools
fix: more iterator functions
2023-08-04 17:12:50 +02:00
Dr. Carsten Leue
e53e2c53e8 fix: more iterator functions
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-04 17:12:24 +02:00
Carsten Leue
2cd35870cb Merge pull request #17 from IBM/cleue-add-take
fix: add Take to Iterables
2023-08-03 15:33:05 +02:00
Dr. Carsten Leue
411caa6dff fix: add Take to Iterables
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-03 15:32:27 +02:00
Carsten Leue
d69a13ecf4 Merge pull request #16 from IBM/cleue-add-zip
Cleue add zip
2023-08-03 14:34:09 +02:00
Dr. Carsten Leue
4ed0046971 fix: add uniq
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-03 14:32:46 +02:00
Dr. Carsten Leue
e4fd34a6b5 fix: add Zip and ZipWith to iterators
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-08-03 13:27:41 +02:00
Carsten Leue
89265eed7c Merge pull request #15 from IBM/cleue-implement-with-temp-file
fix: add WithTempFile
2023-07-30 16:05:00 +02:00
Dr. Carsten Leue
fbc6757f82 fix: add WithTempFile
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-30 16:04:37 +02:00
Carsten Leue
a12936a86c Merge pull request #14 from IBM/cleue-add-missing-methods
fix: add missing array traversal to either
2023-07-28 22:51:34 +02:00
Dr. Carsten Leue
94bcfde0d3 fix: add missing array traversal to either
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-28 22:50:52 +02:00
Carsten Leue
4e1cb825e7 Merge pull request #13 from IBM/cleue-add-more-generated-code
fix: add support for JSON serialization on tuples
2023-07-28 15:50:30 +02:00
Dr. Carsten Leue
9988ae27ef fix: add support for JSON serialization on tuples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-28 15:50:03 +02:00
Carsten Leue
903669c1bc Merge pull request #12 from IBM/cleue-more-iterator
Add more iterators and auto generate sequence operations
2023-07-27 23:06:33 +02:00
Dr. Carsten Leue
dc836fd0be fix: add some typical usecases to readme
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-27 23:05:12 +02:00
Dr. Carsten Leue
47a6d3c177 fix: auto generate more sequence operations
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-27 22:39:38 +02:00
Dr. Carsten Leue
d2346b016e fix: add Ap for iterators
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-25 17:34:32 +02:00
Carsten Leue
41b792b23a Merge pull request #11 from IBM/cleue-better-doc
fix: introduce stateless iterator
2023-07-24 16:44:12 +02:00
Dr. Carsten Leue
1713de0c3e fix: introduce stateless iterator
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-24 16:43:07 +02:00
Carsten Leue
8c58e8d760 Merge pull request #10 from IBM/cleue-add-writer
Add optics and consistent copyright
2023-07-23 22:07:20 +02:00
Dr. Carsten Leue
7476b70a23 fix: add optics and consistent copyright
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-23 22:05:54 +02:00
Dr. Carsten Leue
9e14cd1c00 fix: add writer
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-23 21:45:32 +02:00
Carsten Leue
205b728bda Merge pull request #9 from IBM/cleue-add-renovate
chore: add renovate file
2023-07-21 11:58:45 +02:00
Dr. Carsten Leue
7817f3c676 chore: add renovate file
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-21 11:58:17 +02:00
Carsten Leue
811f966553 Merge pull request #8 from IBM/cleue-auto-generate-traversal-for-readeroieither
fix: auto generate SequenceT for ReaderIOEither
2023-07-21 10:55:57 +02:00
Dr. Carsten Leue
91d7961363 fix: auto generate TraverseTuple for ReaderIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-21 10:55:03 +02:00
Dr. Carsten Leue
ff7d750d97 fix: auto generate SequenceTuple for ReaderIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-20 23:22:02 +02:00
Dr. Carsten Leue
9e32acf551 fix: auto generate SequenceT for ReaderIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-20 16:17:23 +02:00
Carsten Leue
680c103239 Merge pull request #7 from IBM/cleue-http-example
doc: add sample for http
2023-07-20 11:48:25 +02:00
Dr. Carsten Leue
cb2875bf1e doc: add sample for http
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-20 11:48:01 +02:00
Carsten Leue
78a84374dd Merge pull request #6 from IBM/cleue-fix-ap
fix: implementation of traversal for ReaderIOEither
2023-07-19 17:06:20 +02:00
Dr. Carsten Leue
b87cfcf941 fix: implementation of traversal for ReaderIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-07-19 17:05:50 +02:00
1544 changed files with 170896 additions and 6199 deletions

View File

@@ -4,9 +4,7 @@ on:
push:
branches:
- main
pull_request:
workflow_dispatch:
inputs:
dryRun:
@@ -15,32 +13,109 @@ on:
required: false
env:
# Currently no way to detect automatically
DEFAULT_BRANCH: main
GO_VERSION: 1.20.5 # renovate: datasource=golang-version depName=golang
NODE_VERSION: 18
LATEST_GO_VERSION: 1.25.2 # renovate: datasource=golang-version depName=golang
NODE_VERSION: 24
DRY_RUN: true
jobs:
build:
build-v1:
name: Build v1 (Go ${{ matrix.go-version }})
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.20.x', '1.21.x', '1.22.x', '1.23.x', '1.24.x', '1.25.x']
fail-fast: false # Continue with other versions if one fails
steps:
# full checkout for semantic-release
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
- name: Set up go ${{env.GO_VERSION}}
uses: actions/setup-go@v4
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{env.GO_VERSION}}
-
name: Tests
go-version: ${{ matrix.go-version }}
cache: true # Enable Go module caching
- name: Run tests
run: |
go mod tidy
go test -v ./...
go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Upload coverage to Coveralls
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
file: ./coverage.txt
flag-name: v1-go-${{ matrix.go-version }}
parallel: true
# - name: Upload coverage to Codecov
# uses: codecov/codecov-action@v5
# with:
# file: ./coverage.txt
# flags: v1,go-${{ matrix.go-version }}
# name: v1-go-${{ matrix.go-version }}
# fail_ci_if_error: false
# env:
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
build-v2:
name: Build v2 (Go ${{ matrix.go-version }})
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.24.x', '1.25.x']
steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
- name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache: true # Enable Go module caching
- name: Run tests
run: |
cd v2
go mod tidy
go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
- name: Upload coverage to Coveralls
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
file: ./v2/coverage.txt
flag-name: v2-go-${{ matrix.go-version }}
parallel: true
# - name: Upload coverage to Codecov
# uses: codecov/codecov-action@v5
# with:
# file: ./v2/coverage.txt
# flags: v2,go-${{ matrix.go-version }}
# name: v2-go-${{ matrix.go-version }}
# fail_ci_if_error: false
# env:
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
coveralls-finish:
name: Finish Coveralls
needs:
- build-v1
- build-v2
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
parallel-finished: true
release:
needs: [build]
name: Release
needs:
- build-v1
- build-v2
if: github.repository == 'IBM/fp-go' && github.event_name != 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 15
@@ -48,38 +123,37 @@ jobs:
contents: write
issues: write
pull-requests: write
steps:
# full checkout for semantic-release
- name: Full checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
fetch-depth: 0
- name: Set up Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Set up go ${{env.GO_VERSION}}
uses: actions/setup-go@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{env.GO_VERSION}}
go-version: ${{ env.LATEST_GO_VERSION }}
cache: true # Enable Go module caching
# The dry-run evaluation is only made for non PR events. Manual trigger w/dryRun true, main branch and any tagged branches will set DRY run to false
- name: Check dry run
- name: Determine release mode
id: release-mode
run: |
if [[ "${{github.event_name}}" == "workflow_dispatch" && "${{ github.event.inputs.dryRun }}" != "true" ]]; then
echo "DRY_RUN=false" >> $GITHUB_ENV
elif [[ "${{github.ref}}" == "refs/heads/${{env.DEFAULT_BRANCH}}" ]]; then
if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ github.event.inputs.dryRun }}" != "true" ]]; then
echo "DRY_RUN=false" >> $GITHUB_ENV
elif [[ "${{github.ref}}" =~ ^refs/heads/v[0-9]+(\.[0-9]+)?$ ]]; then
elif [[ "${{ github.ref }}" == "refs/heads/${{ env.DEFAULT_BRANCH }}" ]]; then
echo "DRY_RUN=false" >> $GITHUB_ENV
elif [[ "${{ github.ref }}" =~ ^refs/heads/v[0-9]+(\.[0-9]+)?$ ]]; then
echo "DRY_RUN=false" >> $GITHUB_ENV
fi
- name: Semantic Release
- name: Run semantic release
run: |
npx -p conventional-changelog-conventionalcommits -p semantic-release semantic-release --dry-run ${{env.DRY_RUN}}
npx -p conventional-changelog-conventionalcommits -p semantic-release semantic-release --dry-run ${{ env.DRY_RUN }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

5
.gitignore vendored
View File

@@ -1,3 +1,6 @@
fp-go.exe
fp-go
main.exe
build/
build/
.idea
*.exe

3
.whitesource Normal file
View File

@@ -0,0 +1,3 @@
{
"settingsInheritedFrom": "ibm-mend-config/mend-config@main"
}

332
README.md
View File

@@ -1,160 +1,312 @@
# Functional programming library for golang
# fp-go: Functional Programming Library for Go
**🚧 Work in progress! 🚧** Despite major version 1 because of https://github.com/semantic-release/semantic-release/issues/1507. Trying to not make breaking changes, but devil is in the details.
[![Go Reference](https://pkg.go.dev/badge/github.com/IBM/fp-go.svg)](https://pkg.go.dev/github.com/IBM/fp-go)
[![Coverage Status](https://coveralls.io/repos/github/IBM/fp-go/badge.svg?branch=main)](https://coveralls.io/github/IBM/fp-go?branch=main)
**🚧 Work in progress! 🚧** Despite major version 1 (due to [semantic-release limitations](https://github.com/semantic-release/semantic-release/issues/1507)), we're working to minimize breaking changes.
![logo](resources/images/logo.png)
This library is strongly influenced by the awesome [fp-ts](https://github.com/gcanti/fp-ts).
A comprehensive functional programming library for Go, strongly influenced by the excellent [fp-ts](https://github.com/gcanti/fp-ts) library for TypeScript.
## Getting started
## 📚 Table of Contents
- [Getting Started](#-getting-started)
- [Design Goals](#-design-goals)
- [Core Concepts](#-core-concepts)
- [Comparison to Idiomatic Go](#comparison-to-idiomatic-go)
- [Implementation Notes](#implementation-notes)
- [Common Operations](#common-operations)
- [Resources](#-resources)
## 🚀 Getting Started
### Installation
```bash
go get github.com/IBM/fp-go
```
Refer to the [samples](./samples/).
### Quick Example
## Design Goal
```go
import (
"errors"
"github.com/IBM/fp-go/either"
"github.com/IBM/fp-go/function"
)
This library aims to provide a set of data types and functions that make it easy and fun to write maintainable and testable code in golang. It encourages the following patterns:
// Pure function that can fail
func divide(a, b int) either.Either[error, int] {
if b == 0 {
return either.Left[int](errors.New("division by zero"))
}
return either.Right[error](a / b)
}
- write many small, testable and pure functions, i.e. functions that produce output only depending on their input and that do not execute side effects
- offer helpers to isolate side effects into lazily executed functions (IO)
- expose a consistent set of composition to create new functions from existing ones
- for each data type there exists a small set of composition functions
- these functions are called the same across all data types, so you only have to learn a small number of function names
- the semantic of functions of the same name is consistent across all data types
// Compose operations safely
result := function.Pipe2(
divide(10, 2),
either.Map(func(x int) int { return x * 2 }),
either.GetOrElse(func() int { return 0 }),
)
// result = 10
```
### How does this play with the [🧘🏽 Zen Of Go](https://the-zen-of-go.netlify.app/)?
### Resources
#### 🧘🏽 Each package fulfils a single purpose
- 📖 [API Documentation](https://pkg.go.dev/github.com/IBM/fp-go)
- 💡 [Code Samples](./samples/)
- 🆕 [V2 Documentation](./v2/README.md) (requires Go 1.24+)
✔️ Each of the top level packages (e.g. Option, Either, ReaderIOEither, ...) fulfils the purpose of defining the respective data type and implementing the set of common operations for this data type.
## 🎯 Design Goals
#### 🧘🏽 Handle errors explicitly
This library aims to provide a set of data types and functions that make it easy and fun to write maintainable and testable code in Go. It encourages the following patterns:
✔️ The library makes a clear distinction between that operations that cannot fail by design and operations that can fail. Failure is represented via the `Either` type and errors are handled explicitly by using `Either`'s monadic set of operations.
### Core Principles
#### 🧘🏽 Return early rather than nesting deeply
- **Pure Functions**: Write many small, testable, and pure functions that produce output only depending on their input and execute no side effects
- **Side Effect Isolation**: Isolate side effects into lazily executed functions using the `IO` monad
- **Consistent Composition**: Expose a consistent set of composition functions across all data types
- Each data type has a small set of composition functions
- Functions are named consistently across all data types
- Semantics of same-named functions are consistent across data types
✔️ We recommend to implement simple, small functions that implement one feature and that would typically not invoke other functions. Interaction with other functions is done by function composition and the composition makes sure to run one function after the other. In the error case the `Either` monad makes sure to skip the error path.
### 🧘🏽 Alignment with the Zen of Go
#### 🧘🏽 Leave concurrency to the caller
This library respects and aligns with [The Zen of Go](https://the-zen-of-go.netlify.app/):
✔️ All pure are synchronous by default. The I/O operations are asynchronous per default.
| Principle | Alignment | Explanation |
|-----------|-----------|-------------|
| 🧘🏽 Each package fulfills a single purpose | ✔️ | Each top-level package (Option, Either, ReaderIOEither, etc.) defines one data type and its operations |
| 🧘🏽 Handle errors explicitly | ✔️ | Clear distinction between operations that can/cannot fail; failures represented via `Either` type |
| 🧘🏽 Return early rather than nesting deeply | ✔️ | Small, focused functions composed together; `Either` monad handles error paths automatically |
| 🧘🏽 Leave concurrency to the caller | ✔️ | Pure functions are synchronous; I/O operations are asynchronous by default |
| 🧘🏽 Before you launch a goroutine, know when it will stop | 🤷🏽 | Library doesn't start goroutines; Task monad supports cancellation via context |
| 🧘🏽 Avoid package level state | ✔️ | No package-level state anywhere |
| 🧘🏽 Simplicity matters | ✔️ | Small, consistent interface across data types; focus on business logic |
| 🧘🏽 Write tests to lock in behaviour | 🟡 | Programming pattern encourages testing; library has growing test coverage |
| 🧘🏽 If you think it's slow, first prove it with a benchmark | ✔️ | Performance claims should be backed by benchmarks |
| 🧘🏽 Moderation is a virtue | ✔️ | No custom goroutines or expensive synchronization; atomic counters for coordination |
| 🧘🏽 Maintainability counts | ✔️ | Small, concise operations; pure functions with clear type signatures |
#### 🧘🏽 Before you launch a goroutine, know when it will stop
## 💡 Core Concepts
🤷🏽 This is left to the user of the library since the library itself will not start goroutines on its own. The Task monad offers support for cancellation via the golang context, though.
### Data Types
#### 🧘🏽 Avoid package level state
The library provides several key functional data types:
✔️ No package level state anywhere, this would be a significant anti-pattern
- **`Option[A]`**: Represents an optional value (Some or None)
- **`Either[E, A]`**: Represents a value that can be one of two types (Left for errors, Right for success)
- **`IO[A]`**: Represents a lazy computation that produces a value
- **`IOEither[E, A]`**: Represents a lazy computation that can fail
- **`Reader[R, A]`**: Represents a computation that depends on an environment
- **`ReaderIOEither[R, E, A]`**: Combines Reader, IO, and Either for effectful computations with dependencies
- **`Task[A]`**: Represents an asynchronous computation
- **`State[S, A]`**: Represents a stateful computation
#### 🧘🏽 Simplicity matters
### Monadic Operations
✔️ The library is simple in the sense that it offers a small, consistent interface to a variety of data types. Users can concentrate on implementing business logic rather than dealing with low level data structures.
All data types support common monadic operations:
#### 🧘🏽 Write tests to lock in the behaviour of your package’s API
- **`Map`**: Transform the value inside a context
- **`Chain`** (FlatMap): Transform and flatten nested contexts
- **`Ap`**: Apply a function in a context to a value in a context
- **`Of`**: Wrap a value in a context
- **`Fold`**: Extract a value from a context
🟡 The programming pattern suggested by this library encourages writing test cases. The library itself also has a growing number of tests, but not enough, yet. TBD
## Comparison to Idiomatic Go
#### 🧘🏽 If you think it’s slow, first prove it with a benchmark
This section explains how functional APIs differ from idiomatic Go and how to convert between them.
✔️ Absolutely. If you think the function composition offered by this library is too slow, please provide a benchmark.
### Pure Functions
#### 🧘🏽 Moderation is a virtue
Pure functions take input parameters and compute output without changing global state or mutating inputs. They always return the same output for the same input.
✔️ The library does not implement its own goroutines and also does not require any expensive synchronization primitives. Coordination of IO operations is implemented via atomic counters without additional primitives.
#### Without Errors
#### 🧘🏽 Maintainability counts
If your pure function doesn't return an error, the idiomatic signature works as-is:
✔️ Code that consumes this library is easy to maintain because of the small and concise set of operations exposed. Also the suggested programming paradigm to decompose an application into small functions increases maintainability, because these functions are easy to understand and if they are pure, it's often sufficient to look at the type signature to understand the purpose.
```go
func add(a, b int) int {
return a + b
}
```
The library itself also comprises many small functions, but it's admittedly harder to maintain than code that uses it. However this asymmetry is intended because it offloads complexity from users into a central component.
#### With Errors
**Idiomatic Go:**
```go
func divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
```
**Functional Style:**
```go
func divide(a, b int) either.Either[error, int] {
if b == 0 {
return either.Left[int](errors.New("division by zero"))
}
return either.Right[error](a / b)
}
```
**Conversion:**
- Use `either.EitherizeXXX` to convert from idiomatic to functional style
- Use `either.UneitherizeXXX` to convert from functional to idiomatic style
### Effectful Functions
An effectful function changes data outside its scope or doesn't always produce the same output for the same input.
#### Without Errors
**Functional signature:** `IO[T]`
```go
func getCurrentTime() io.IO[time.Time] {
return func() time.Time {
return time.Now()
}
}
```
#### With Errors
**Functional signature:** `IOEither[error, T]`
```go
func readFile(path string) ioeither.IOEither[error, []byte] {
return func() either.Either[error, []byte] {
data, err := os.ReadFile(path)
if err != nil {
return either.Left[[]byte](err)
}
return either.Right[error](data)
}
}
```
**Conversion:**
- Use `ioeither.EitherizeXXX` to convert idiomatic Go functions to functional style
### Go Context
Functions that take a `context.Context` are effectful because they depend on mutable context.
**Idiomatic Go:**
```go
func fetchData(ctx context.Context, url string) ([]byte, error) {
// implementation
}
```
**Functional Style:**
```go
func fetchData(url string) readerioeither.ReaderIOEither[context.Context, error, []byte] {
return func(ctx context.Context) ioeither.IOEither[error, []byte] {
return func() either.Either[error, []byte] {
// implementation
}
}
}
```
**Conversion:**
- Use `readerioeither.EitherizeXXX` to convert idiomatic Go functions with context to functional style
## Implementation Notes
### Generics
All monadic operations are implemented via generics, i.e. they offer a type safe way to compose operations. This allows for convenient IDE support and also gives confidence about the correctness of the composition at compile time.
All monadic operations use Go generics for type safety:
Downside is that this will result in different versions of each operation per type, these versions are generated by the golang compiler at build time (unlike type erasure in languages such as Java of TypeScript). This might lead to large binaries for codebases with many different types. If this is a concern, you can always implement type erasure on top, i.e. use the monadic operations with the `any` type as if generics were not supported. You loose type safety, but this might result in smaller binaries.
-**Pros**: Type-safe composition, IDE support, compile-time correctness
- ⚠️ **Cons**: May result in larger binaries (different versions per type)
- 💡 **Tip**: For binary size concerns, use type erasure with `any` type
### Ordering of Generic Type Parameters
In go we need to specify all type parameters of a function on the global function definition, even if the function returns a higher order function and some of the type parameters are only applicable to the higher order function. So the following is not possible:
Go requires all type parameters on the global function definition. Parameters that cannot be auto-detected come first:
```go
func Map[A, B any](f func(A) B) [R, E any]func(fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
// Map: B cannot be auto-detected, so it comes first
func Map[R, E, A, B any](f func(A) B) func(ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
// Ap: B cannot be auto-detected from the argument
func Ap[B, R, E, A any](fa ReaderIOEither[R, E, A]) func(ReaderIOEither[R, E, func(A) B]) ReaderIOEither[R, E, B]
```
Note that the parameters `R` and `E` are not needed by the first level of `Map` but only by the resulting higher order function. Instead we need to specify the following:
This ordering maximizes type inference where possible.
```go
func Map[R, E, A, B any](f func(A) B) func(fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
```
### Use of the ~ Operator
which overspecifies `Map` on the global scope. As a result the go compiler will not be able to auto-detect these parameters, it can only auto detect `A` and `B` since they appear in the argument of `Map`. We need to explicitly pass values for these type parameters when `Map` is being used.
Because of this limitation the order of parameters on a function matters. We want to make sure that we define those parameters that cannot be auto-detected, first, and the parameters that can be auto-detected, last. This can lead to inconsistencies in parameter ordering, but we believe that the gain in convenience is worth it. The parameter order of `Ap` is e.g. different from that of `Map`:
```go
func Ap[B, R, E, A any](fa ReaderIOEither[R, E, A]) func(fab ReaderIOEither[R, E, func(A) B]) ReaderIOEither[R, E, B]
```
because `R`, `E` and `A` can be determined from the argument to `Ap` but `B` cannot.
### Use of the [~ Operator](https://go.googlesource.com/proposal/+/master/design/47781-parameterized-go-ast.md)
The FP library attempts to be easy to consume and one aspect of this is the definition of higher level type definitions instead of having to use their low level equivalent. It is e.g. more convenient and readable to use
```go
ReaderIOEither[R, E, A]
```
than
```go
func(R) func() Either.Either[E, A]
```
although both are logically equivalent. At the time of this writing the go type system does not support generic type aliases, only generic type definition, i.e. it is not possible to write:
```go
type ReaderIOEither[R, E, A any] = RD.Reader[R, IOE.IOEither[E, A]]
```
only
Go doesn't support generic type aliases (until Go 1.24), only type definitions. The `~` operator allows generic implementations to work with compatible types:
```go
type ReaderIOEither[R, E, A any] RD.Reader[R, IOE.IOEither[E, A]]
```
This makes a big difference, because in the second case the type `ReaderIOEither[R, E, A any]` is considered a completely new type, not compatible to its right hand side, so it's not just a shortcut but a fully new type.
**Generic Subpackages:**
- Each higher-level type has a `generic` subpackage with fully generic implementations
- These are for library extensions, not end-users
- Main packages specialize generic implementations for convenience
From the implementation perspective however there is no reason to restrict the implementation to the new type, it can be generic for all compatible types. The way to express this in go is the [~](https://go.googlesource.com/proposal/+/master/design/47781-parameterized-go-ast.md) operator. This comes with some quite complicated type declarations in some cases, which undermines the goal of the library to be easy to use.
### Higher Kinded Types (HKT)
For that reason there exist sub-packages called `Generic` for all higher level types. These packages contain the fully generic implementation of the operations, preferring abstraction over usability. These packages are not meant to be used by end-users but are meant to be used by library extensions. The implementation for the convenient higher level types specializes the generic implementation for the particular higher level type, i.e. this layer does not contain any business logic but only *type magic*.
Go doesn't support HKT natively. This library addresses this by:
### Higher Kinded Types
- Introducing HKTs as individual types (e.g., `HKTA` for `HKT[A]`)
- Implementing generic algorithms in the `internal` package
- Keeping complexity hidden from end-users
Go does not support higher kinded types (HKT). Such types occur if a generic type itself is parametrized by another generic type. Example:
## Common Operations
The `Map` operation for `ReaderIOEither` is defined as:
### Map/Chain/Ap/Flap
| Operator | Parameter | Monad | Result | Use Case |
| -------- | ---------------- | --------------- | -------- | -------- |
| Map | `func(A) B` | `HKT[A]` | `HKT[B]` | Transform value in context |
| Chain | `func(A) HKT[B]` | `HKT[A]` | `HKT[B]` | Transform and flatten |
| Ap | `HKT[A]` | `HKT[func(A)B]` | `HKT[B]` | Apply function in context |
| Flap | `A` | `HKT[func(A)B]` | `HKT[B]` | Apply value to function in context |
### Example: Chaining Operations
```go
func Map[R, E, A, B any](f func(A) B) func(fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
import (
"github.com/IBM/fp-go/either"
"github.com/IBM/fp-go/function"
)
result := function.Pipe3(
either.Right[error](10),
either.Map(func(x int) int { return x * 2 }),
either.Chain(func(x int) either.Either[error, int] {
if x > 15 {
return either.Right[error](x)
}
return either.Left[int](errors.New("too small"))
}),
either.GetOrElse(func() int { return 0 }),
)
```
and in fact the equivalent operations for all other mondas follow the same pattern, we could try to introduce a new type for `ReaderIOEither` (without a parameter) as a HKT, e.g. like so (made-up syntax, does not work in go):
## 📚 Resources
```go
func Map[HKT, R, E, A, B any](f func(A) B) func(HKT[R, E, A]) HKT[R, E, B]
```
- [API Documentation](https://pkg.go.dev/github.com/IBM/fp-go)
- [Code Samples](./samples/)
- [V2 Documentation](./v2/README.md) - New features in Go 1.24+
- [fp-ts](https://github.com/gcanti/fp-ts) - Original TypeScript inspiration
this would be the completely generic method signature for all possible monads. In particular in many cases it is possible to compose functions independent of the concrete knowledge of the actual `HKT`. From the perspective of a library this is the ideal situation because then a particular algorithm only has to be implemented and tested once.
## 🤝 Contributing
This FP library addresses this by introducing the HKTs as individual types, e.g. `HKT[A]` would be represented as a new generic type `HKTA`. This loses the correlation to the type `A` but allows to implement generic algorithms, at the price of readability.
Contributions are welcome! Please feel free to submit issues or pull requests.
For that reason these implementations are kept in the `internal` package. These are meant to be used by the library itself or by extensions, not by end users.
## 📄 License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

30
array/any.go Normal file
View File

@@ -0,0 +1,30 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
G "github.com/IBM/fp-go/array/generic"
)
// AnyWithIndex tests if any of the elements in the array matches the predicate
func AnyWithIndex[A any](pred func(int, A) bool) func([]A) bool {
return G.AnyWithIndex[[]A](pred)
}
// Any tests if any of the elements in the array matches the predicate
func Any[A any](pred func(A) bool) func([]A) bool {
return G.Any[[]A](pred)
}

30
array/any_test.go Normal file
View File

@@ -0,0 +1,30 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
"testing"
F "github.com/IBM/fp-go/function"
"github.com/stretchr/testify/assert"
)
func TestAny(t *testing.T) {
anyBool := Any(F.Identity[bool])
assert.True(t, anyBool(From(false, true, false)))
assert.False(t, anyBool(From(false, false, false)))
}

View File

@@ -1,7 +1,23 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
G "github.com/IBM/fp-go/array/generic"
EM "github.com/IBM/fp-go/endomorphism"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/array"
M "github.com/IBM/fp-go/monoid"
@@ -15,22 +31,13 @@ func From[A any](data ...A) []A {
}
// MakeBy returns a `Array` of length `n` with element `i` initialized with `f(i)`.
func MakeBy[A any](n int, f func(int) A) []A {
// sanity check
if n <= 0 {
return Empty[A]()
}
// run the generator function across the input
as := make([]A, n)
for i := n - 1; i >= 0; i-- {
as[i] = f(i)
}
return as
func MakeBy[F ~func(int) A, A any](n int, f F) []A {
return G.MakeBy[[]A](n, f)
}
// Replicate creates a `Array` containing a value repeated the specified number of times.
func Replicate[A any](n int, a A) []A {
return MakeBy(n, F.Constant1[int](a))
return G.Replicate[[]A](n, a)
}
func MonadMap[A, B any](as []A, f func(a A) B) []B {
@@ -46,26 +53,18 @@ func MonadMapRef[A, B any](as []A, f func(a *A) B) []B {
return bs
}
func MapWithIndex[A, B any](f func(int, A) B) func([]A) []B {
return G.MapWithIndex[[]A, []B](f)
}
func Map[A, B any](f func(a A) B) func([]A) []B {
return F.Bind2nd(MonadMap[A, B], f)
return G.Map[[]A, []B, A, B](f)
}
func MapRef[A, B any](f func(a *A) B) func([]A) []B {
return F.Bind2nd(MonadMapRef[A, B], f)
}
func filter[A any](fa []A, pred func(A) bool) []A {
var result []A
count := len(fa)
for i := 0; i < count; i++ {
a := fa[i]
if pred(a) {
result = append(result, a)
}
}
return result
}
func filterRef[A any](fa []A, pred func(a *A) bool) []A {
var result []A
count := len(fa)
@@ -90,22 +89,43 @@ func filterMapRef[A, B any](fa []A, pred func(a *A) bool, f func(a *A) B) []B {
return result
}
func Filter[A any](pred func(A) bool) func([]A) []A {
return F.Bind2nd(filter[A], pred)
// Filter returns a new array with all elements from the original array that match a predicate
func Filter[A any](pred func(A) bool) EM.Endomorphism[[]A] {
return G.Filter[[]A](pred)
}
func FilterRef[A any](pred func(*A) bool) func([]A) []A {
// FilterWithIndex returns a new array with all elements from the original array that match a predicate
func FilterWithIndex[A any](pred func(int, A) bool) EM.Endomorphism[[]A] {
return G.FilterWithIndex[[]A](pred)
}
func FilterRef[A any](pred func(*A) bool) EM.Endomorphism[[]A] {
return F.Bind2nd(filterRef[A], pred)
}
func MonadFilterMap[A, B any](fa []A, f func(a A) O.Option[B]) []B {
func MonadFilterMap[A, B any](fa []A, f func(A) O.Option[B]) []B {
return G.MonadFilterMap[[]A, []B](fa, f)
}
func FilterMap[A, B any](f func(a A) O.Option[B]) func([]A) []B {
func MonadFilterMapWithIndex[A, B any](fa []A, f func(int, A) O.Option[B]) []B {
return G.MonadFilterMapWithIndex[[]A, []B](fa, f)
}
// FilterMap maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
func FilterMap[A, B any](f func(A) O.Option[B]) func([]A) []B {
return G.FilterMap[[]A, []B](f)
}
// FilterMapWithIndex maps an array with an iterating function that returns an [O.Option] and it keeps only the Some values discarding the Nones.
func FilterMapWithIndex[A, B any](f func(int, A) O.Option[B]) func([]A) []B {
return G.FilterMapWithIndex[[]A, []B](f)
}
// FilterChain maps an array with an iterating function that returns an [O.Option] of an array. It keeps only the Some values discarding the Nones and then flattens the result.
func FilterChain[A, B any](f func(A) O.Option[[]B]) func([]A) []B {
return G.FilterChain[[]A](f)
}
func FilterMapRef[A, B any](pred func(a *A) bool, f func(a *A) B) func([]A) []B {
return func(fa []A) []B {
return filterMapRef(fa, pred, f)
@@ -121,10 +141,24 @@ func reduceRef[A, B any](fa []A, f func(B, *A) B, initial B) B {
return current
}
func MonadReduce[A, B any](fa []A, f func(B, A) B, initial B) B {
return G.MonadReduce(fa, f, initial)
}
func Reduce[A, B any](f func(B, A) B, initial B) func([]A) B {
return func(as []A) B {
return array.Reduce(as, f, initial)
}
return G.Reduce[[]A](f, initial)
}
func ReduceWithIndex[A, B any](f func(int, B, A) B, initial B) func([]A) B {
return G.ReduceWithIndex[[]A](f, initial)
}
func ReduceRight[A, B any](f func(A, B) B, initial B) func([]A) B {
return G.ReduceRight[[]A](f, initial)
}
func ReduceRightWithIndex[A, B any](f func(int, A, B) B, initial B) func([]A) B {
return G.ReduceRightWithIndex[[]A](f, initial)
}
func ReduceRef[A, B any](f func(B, *A) B, initial B) func([]A) B {
@@ -138,7 +172,7 @@ func Append[A any](as []A, a A) []A {
}
func IsEmpty[A any](as []A) bool {
return array.IsEmpty(as)
return G.IsEmpty(as)
}
func IsNonEmpty[A any](as []A) bool {
@@ -159,30 +193,27 @@ func Of[A any](a A) []A {
}
func MonadChain[A, B any](fa []A, f func(a A) []B) []B {
return array.Reduce(fa, func(bs []B, a A) []B {
return append(bs, f(a)...)
}, Zero[B]())
return G.MonadChain[[]A, []B](fa, f)
}
func Chain[A, B any](f func(a A) []B) func([]A) []B {
return F.Bind2nd(MonadChain[A, B], f)
func Chain[A, B any](f func(A) []B) func([]A) []B {
return G.Chain[[]A, []B](f)
}
func MonadAp[B, A any](fab []func(A) B, fa []A) []B {
return MonadChain(fab, F.Bind1st(MonadMap[A, B], fa))
return G.MonadAp[[]B](fab, fa)
}
func Ap[B, A any](fa []A) func([]func(A) B) []B {
return F.Bind2nd(MonadAp[B, A], fa)
return G.Ap[[]B, []func(A) B](fa)
}
func Match[A, B any](onEmpty func() B, onNonEmpty func([]A) B) func([]A) B {
return func(as []A) B {
if IsEmpty(as) {
return onEmpty()
}
return onNonEmpty(as)
}
return G.Match[[]A](onEmpty, onNonEmpty)
}
func MatchLeft[A, B any](onEmpty func() B, onNonEmpty func(A, []A) B) func([]A) B {
return G.MatchLeft[[]A](onEmpty, onNonEmpty)
}
func Tail[A any](as []A) O.Option[[]A] {
@@ -201,7 +232,7 @@ func Last[A any](as []A) O.Option[A] {
return G.Last(as)
}
func PrependAll[A any](middle A) func([]A) []A {
func PrependAll[A any](middle A) EM.Endomorphism[[]A] {
return func(as []A) []A {
count := len(as)
dst := count * 2
@@ -216,7 +247,7 @@ func PrependAll[A any](middle A) func([]A) []A {
}
}
func Intersperse[A any](middle A) func([]A) []A {
func Intersperse[A any](middle A) EM.Endomorphism[[]A] {
prepend := PrependAll(middle)
return func(as []A) []A {
if IsEmpty(as) {
@@ -227,14 +258,14 @@ func Intersperse[A any](middle A) func([]A) []A {
}
func Intercalate[A any](m M.Monoid[A]) func(A) func([]A) A {
concatAll := ConcatAll[A](m)(m.Empty())
concatAll := ConcatAll[A](m)
return func(middle A) func([]A) A {
return Match(m.Empty, F.Flow2(Intersperse(middle), concatAll))
}
}
func Flatten[A any](mma [][]A) []A {
return MonadChain(mma, F.Identity[[]A])
return G.Flatten(mma)
}
func Slice[A any](low, high int) func(as []A) []A {
@@ -245,7 +276,7 @@ func Lookup[A any](idx int) func([]A) O.Option[A] {
return G.Lookup[[]A](idx)
}
func UpsertAt[A any](a A) func([]A) []A {
func UpsertAt[A any](a A) EM.Endomorphism[[]A] {
return G.UpsertAt[[]A](a)
}
@@ -277,3 +308,48 @@ func IsNonNil[A any](as []A) bool {
func ConstNil[A any]() []A {
return array.ConstNil[[]A]()
}
func SliceRight[A any](start int) EM.Endomorphism[[]A] {
return G.SliceRight[[]A](start)
}
// Copy creates a shallow copy of the array
func Copy[A any](b []A) []A {
return G.Copy(b)
}
// Clone creates a deep copy of the array using the provided endomorphism to clone the values
func Clone[A any](f func(A) A) func(as []A) []A {
return G.Clone[[]A](f)
}
// FoldMap maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.
func FoldMap[A, B any](m M.Monoid[B]) func(func(A) B) func([]A) B {
return G.FoldMap[[]A](m)
}
// FoldMapWithIndex maps and folds an array. Map the Array passing each value to the iterating function. Then fold the results using the provided Monoid.
func FoldMapWithIndex[A, B any](m M.Monoid[B]) func(func(int, A) B) func([]A) B {
return G.FoldMapWithIndex[[]A](m)
}
// Fold folds the array using the provided Monoid.
func Fold[A any](m M.Monoid[A]) func([]A) A {
return G.Fold[[]A](m)
}
func Push[A any](a A) EM.Endomorphism[[]A] {
return G.Push[EM.Endomorphism[[]A]](a)
}
func MonadFlap[B, A any](fab []func(A) B, a A) []B {
return G.MonadFlap[func(A) B, []func(A) B, []B, A, B](fab, a)
}
func Flap[B, A any](a A) func([]func(A) B) []B {
return G.Flap[func(A) B, []func(A) B, []B, A, B](a)
}
func Prepend[A any](head A) EM.Endomorphism[[]A] {
return G.Prepend[EM.Endomorphism[[]A]](head)
}

View File

@@ -1,6 +1,22 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
"fmt"
"strings"
"testing"
@@ -43,6 +59,17 @@ func TestMap(t *testing.T) {
assert.Equal(t, dst, []string{"A", "B", "C"})
}
func TestReduceRight(t *testing.T) {
values := From("a", "b", "c")
f := func(a, acc string) string {
return fmt.Sprintf("%s%s", acc, a)
}
b := ""
assert.Equal(t, "cba", ReduceRight(f, b)(values))
assert.Equal(t, "", ReduceRight(f, b)(Empty[string]()))
}
func TestReduce(t *testing.T) {
values := MakeBy(101, F.Identity[int])
@@ -127,3 +154,52 @@ func TestPartition(t *testing.T) {
assert.Equal(t, T.MakeTuple2(Empty[int](), Empty[int]()), Partition(pred)(Empty[int]()))
assert.Equal(t, T.MakeTuple2(From(1), From(3)), Partition(pred)(From(1, 3)))
}
func TestFilterChain(t *testing.T) {
src := From(1, 2, 3)
f := func(i int) O.Option[[]string] {
if i%2 != 0 {
return O.Of(From(fmt.Sprintf("a%d", i), fmt.Sprintf("b%d", i)))
}
return O.None[[]string]()
}
res := FilterChain(f)(src)
assert.Equal(t, From("a1", "b1", "a3", "b3"), res)
}
func TestFilterMap(t *testing.T) {
src := From(1, 2, 3)
f := func(i int) O.Option[string] {
if i%2 != 0 {
return O.Of(fmt.Sprintf("a%d", i))
}
return O.None[string]()
}
res := FilterMap(f)(src)
assert.Equal(t, From("a1", "a3"), res)
}
func TestFoldMap(t *testing.T) {
src := From("a", "b", "c")
fold := FoldMap[string](S.Monoid)(strings.ToUpper)
assert.Equal(t, "ABC", fold(src))
}
func ExampleFoldMap() {
src := From("a", "b", "c")
fold := FoldMap[string](S.Monoid)(strings.ToUpper)
fmt.Println(fold(src))
// Output: ABC
}

66
array/bind.go Normal file
View File

@@ -0,0 +1,66 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
G "github.com/IBM/fp-go/array/generic"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[S any](
empty S,
) []S {
return G.Do[[]S, S](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) []T,
) func([]S1) []S2 {
return G.Bind[[]S1, []S2, []T, S1, S2, T](setter, f)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) T,
) func([]S1) []S2 {
return G.Let[[]S1, []S2, S1, S2, T](setter, f)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[S1, S2, T any](
setter func(T) func(S1) S2,
b T,
) func([]S1) []S2 {
return G.LetTo[[]S1, []S2, S1, S2, T](setter, b)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[S1, T any](
setter func(T) S1,
) func([]T) []S1 {
return G.BindTo[[]S1, []T, S1, T](setter)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[S1, S2, T any](
setter func(T) func(S1) S2,
fa []T,
) func([]S1) []S2 {
return G.ApS[[]S1, []S2, []T, S1, S2, T](setter, fa)
}

56
array/bind_test.go Normal file
View File

@@ -0,0 +1,56 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
"testing"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/utils"
"github.com/stretchr/testify/assert"
)
func getLastName(s utils.Initial) []string {
return Of("Doe")
}
func getGivenName(s utils.WithLastName) []string {
return Of("John")
}
func TestBind(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
Bind(utils.SetLastName, getLastName),
Bind(utils.SetGivenName, getGivenName),
Map(utils.GetFullName),
)
assert.Equal(t, res, Of("John Doe"))
}
func TestApS(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
ApS(utils.SetLastName, Of("Doe")),
ApS(utils.SetGivenName, Of("John")),
Map(utils.GetFullName),
)
assert.Equal(t, res, Of("John Doe"))
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (

77
array/example_any_test.go Normal file
View File

@@ -0,0 +1,77 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
"fmt"
F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option"
)
func Example_any() {
pred := func(val int) bool {
return val&2 == 0
}
data1 := From(1, 2, 3)
fmt.Println(Any(pred)(data1))
// Output:
// true
}
func Example_any_filter() {
pred := func(val int) bool {
return val&2 == 0
}
data1 := From(1, 2, 3)
// Any tests if any of the entries in the array matches the condition
Any := F.Flow2(
Filter(pred),
IsNonEmpty[int],
)
fmt.Println(Any(data1))
// Output:
// true
}
func Example_any_find() {
pred := func(val int) bool {
return val&2 == 0
}
data1 := From(1, 2, 3)
// Any tests if any of the entries in the array matches the condition
Any := F.Flow2(
FindFirst(pred),
O.IsSome[int],
)
fmt.Println(Any(data1))
// Output:
// true
}

View File

@@ -0,0 +1,55 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
"fmt"
F "github.com/IBM/fp-go/function"
)
func Example_find() {
pred := func(val int) bool {
return val&2 == 0
}
data1 := From(1, 2, 3)
fmt.Println(FindFirst(pred)(data1))
// Output:
// Some[int](1)
}
func Example_find_filter() {
pred := func(val int) bool {
return val&2 == 0
}
data1 := From(1, 2, 3)
Find := F.Flow2(
Filter(pred),
Head[int],
)
fmt.Println(Find(data1))
// Output:
// Some[int](1)
}

View File

@@ -0,0 +1,59 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
"fmt"
F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option"
)
// Example_basic adapts examples from [https://github.com/inato/fp-ts-cheatsheet#basic-manipulation]
func Example_basic() {
someArray := From(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) // []int
isEven := func(num int) bool {
return num%2 == 0
}
square := func(num int) int {
return num * num
}
// filter and map
result := F.Pipe2(
someArray,
Filter(isEven),
Map(square),
) // [0 4 16 36 64]
// or in one go with filterMap
resultFilterMap := F.Pipe1(
someArray,
FilterMap(
F.Flow2(O.FromPredicate(isEven), O.Map(square)),
),
)
fmt.Println(result)
fmt.Println(resultFilterMap)
// Output:
// [0 4 16 36 64]
// [0 4 16 36 64]
}

View File

@@ -0,0 +1,92 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
"fmt"
F "github.com/IBM/fp-go/function"
I "github.com/IBM/fp-go/number/integer"
O "github.com/IBM/fp-go/option"
"github.com/IBM/fp-go/ord"
S "github.com/IBM/fp-go/string"
)
type user struct {
name string
age O.Option[int]
}
func (user user) GetName() string {
return user.name
}
func (user user) GetAge() O.Option[int] {
return user.age
}
// Example_sort adapts examples from [https://github.com/inato/fp-ts-cheatsheet#sort-elements-with-ord]
func Example_sort() {
strings := From("zyx", "abc", "klm")
sortedStrings := F.Pipe1(
strings,
Sort(S.Ord),
) // => ['abc', 'klm', 'zyx']
// reverse sort
reverseSortedStrings := F.Pipe1(
strings,
Sort(ord.Reverse(S.Ord)),
) // => ['zyx', 'klm', 'abc']
// sort Option
optionalNumbers := From(O.Some(1337), O.None[int](), O.Some(42))
sortedNums := F.Pipe1(
optionalNumbers,
Sort(O.Ord(I.Ord)),
)
// complex object with different rules
byName := F.Pipe1(
S.Ord,
ord.Contramap(user.GetName),
) // ord.Ord[user]
byAge := F.Pipe1(
O.Ord(I.Ord),
ord.Contramap(user.GetAge),
) // ord.Ord[user]
sortedUsers := F.Pipe1(
From(user{name: "a", age: O.Of(30)}, user{name: "d", age: O.Of(10)}, user{name: "c"}, user{name: "b", age: O.Of(10)}),
SortBy(From(byAge, byName)),
)
fmt.Println(sortedStrings)
fmt.Println(reverseSortedStrings)
fmt.Println(sortedNums)
fmt.Println(sortedUsers)
// Output:
// [abc klm zyx]
// [zyx klm abc]
// [None[int] Some[int](42) Some[int](1337)]
// [{c {false 0}} {b {true 10}} {d {true 10}} {a {true 30}}]
}

61
array/find.go Normal file
View File

@@ -0,0 +1,61 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
G "github.com/IBM/fp-go/array/generic"
O "github.com/IBM/fp-go/option"
)
// FindFirst finds the first element which satisfies a predicate (or a refinement) function
func FindFirst[A any](pred func(A) bool) func([]A) O.Option[A] {
return G.FindFirst[[]A](pred)
}
// FindFirstWithIndex finds the first element which satisfies a predicate (or a refinement) function
func FindFirstWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
return G.FindFirstWithIndex[[]A](pred)
}
// FindFirstMap finds the first element returned by an [O.Option] based selector function
func FindFirstMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
return G.FindFirstMap[[]A](sel)
}
// FindFirstMapWithIndex finds the first element returned by an [O.Option] based selector function
func FindFirstMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.Option[B] {
return G.FindFirstMapWithIndex[[]A](sel)
}
// FindLast finds the Last element which satisfies a predicate (or a refinement) function
func FindLast[A any](pred func(A) bool) func([]A) O.Option[A] {
return G.FindLast[[]A](pred)
}
// FindLastWithIndex finds the Last element which satisfies a predicate (or a refinement) function
func FindLastWithIndex[A any](pred func(int, A) bool) func([]A) O.Option[A] {
return G.FindLastWithIndex[[]A](pred)
}
// FindLastMap finds the Last element returned by an [O.Option] based selector function
func FindLastMap[A, B any](sel func(A) O.Option[B]) func([]A) O.Option[B] {
return G.FindLastMap[[]A](sel)
}
// FindLastMapWithIndex finds the Last element returned by an [O.Option] based selector function
func FindLastMapWithIndex[A, B any](sel func(int, A) O.Option[B]) func([]A) O.Option[B] {
return G.FindLastMapWithIndex[[]A](sel)
}

34
array/generic/any.go Normal file
View File

@@ -0,0 +1,34 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option"
)
// AnyWithIndex tests if any of the elements in the array matches the predicate
func AnyWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) bool {
return F.Flow2(
FindFirstWithIndex[AS](pred),
O.IsSome[A],
)
}
// Any tests if any of the elements in the array matches the predicate
func Any[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) bool {
return AnyWithIndex[AS](F.Ignore1of2[int](pred))
}

View File

@@ -1,8 +1,25 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/array"
FC "github.com/IBM/fp-go/internal/functor"
M "github.com/IBM/fp-go/monoid"
O "github.com/IBM/fp-go/option"
"github.com/IBM/fp-go/tuple"
)
@@ -12,11 +29,69 @@ func Of[GA ~[]A, A any](value A) GA {
return GA{value}
}
func Reduce[GA ~[]A, A, B any](f func(B, A) B, initial B) func(GA) B {
return func(as GA) B {
return MonadReduce[GA](as, f, initial)
}
}
func ReduceWithIndex[GA ~[]A, A, B any](f func(int, B, A) B, initial B) func(GA) B {
return func(as GA) B {
return MonadReduceWithIndex[GA](as, f, initial)
}
}
func ReduceRight[GA ~[]A, A, B any](f func(A, B) B, initial B) func(GA) B {
return func(as GA) B {
return MonadReduceRight[GA](as, f, initial)
}
}
func ReduceRightWithIndex[GA ~[]A, A, B any](f func(int, A, B) B, initial B) func(GA) B {
return func(as GA) B {
return MonadReduceRightWithIndex[GA](as, f, initial)
}
}
func MonadReduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B {
return array.Reduce(fa, f, initial)
}
func MonadReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
return array.ReduceWithIndex(fa, f, initial)
}
func MonadReduceRight[GA ~[]A, A, B any](fa GA, f func(A, B) B, initial B) B {
return array.ReduceRight(fa, f, initial)
}
func MonadReduceRightWithIndex[GA ~[]A, A, B any](fa GA, f func(int, A, B) B, initial B) B {
return array.ReduceRightWithIndex(fa, f, initial)
}
// From constructs an array from a set of variadic arguments
func From[GA ~[]A, A any](data ...A) GA {
return data
}
// MakeBy returns a `Array` of length `n` with element `i` initialized with `f(i)`.
func MakeBy[AS ~[]A, F ~func(int) A, A any](n int, f F) AS {
// sanity check
if n <= 0 {
return Empty[AS]()
}
// run the generator function across the input
as := make(AS, n)
for i := n - 1; i >= 0; i-- {
as[i] = f(i)
}
return as
}
func Replicate[AS ~[]A, A any](n int, a A) AS {
return MakeBy[AS](n, F.Constant1[int](a))
}
func Lookup[GA ~[]A, A any](idx int) func(GA) O.Option[A] {
none := O.None[A]()
if idx < 0 {
@@ -71,24 +146,79 @@ func MonadMap[GA ~[]A, GB ~[]B, A, B any](as GA, f func(a A) B) GB {
return array.MonadMap[GA, GB](as, f)
}
func Map[GA ~[]A, GB ~[]B, A, B any](f func(a A) B) func(GA) GB {
return array.Map[GA, GB](f)
}
func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(int, A) B) GB {
return array.MonadMapWithIndex[GA, GB](as, f)
}
func MapWithIndex[GA ~[]A, GB ~[]B, A, B any](f func(int, A) B) func(GA) GB {
return F.Bind2nd(MonadMapWithIndex[GA, GB, A, B], f)
}
func Size[GA ~[]A, A any](as GA) int {
return len(as)
}
func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(a A) O.Option[B]) GB {
func filterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
return array.Reduce(fa, func(bs GB, a A) GB {
return O.MonadFold(f(a), F.Constant(bs), F.Bind1st(Append[GB, B], bs))
}, Empty[GB]())
}
func MonadFilterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(a A) O.Option[B]) GB {
func filterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB {
return array.ReduceWithIndex(fa, func(idx int, bs GB, a A) GB {
return O.MonadFold(f(idx, a), F.Constant(bs), F.Bind1st(Append[GB, B], bs))
}, Empty[GB]())
}
func MonadFilterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(A) O.Option[B]) GB {
return filterMap[GA, GB](fa, f)
}
func FilterMap[GA ~[]A, GB ~[]B, A, B any](f func(a A) O.Option[B]) func(GA) GB {
func MonadFilterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(int, A) O.Option[B]) GB {
return filterMapWithIndex[GA, GB](fa, f)
}
func filterWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](fa AS, pred PRED) AS {
result := make(AS, 0, len(fa))
for i, a := range fa {
if pred(i, a) {
result = append(result, a)
}
}
return result
}
func FilterWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) AS {
return F.Bind2nd(filterWithIndex[AS, PRED, A], pred)
}
func Filter[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) AS {
return FilterWithIndex[AS](F.Ignore1of2[int](pred))
}
func FilterChain[GA ~[]A, GB ~[]B, A, B any](f func(a A) O.Option[GB]) func(GA) GB {
return F.Flow2(
FilterMap[GA, []GB](f),
Flatten[[]GB],
)
}
func Flatten[GAA ~[]GA, GA ~[]A, A any](mma GAA) GA {
return MonadChain(mma, F.Identity[GA])
}
func FilterMap[GA ~[]A, GB ~[]B, A, B any](f func(A) O.Option[B]) func(GA) GB {
return F.Bind2nd(MonadFilterMap[GA, GB, A, B], f)
}
func FilterMapWithIndex[GA ~[]A, GB ~[]B, A, B any](f func(int, A) O.Option[B]) func(GA) GB {
return F.Bind2nd(MonadFilterMapWithIndex[GA, GB, A, B], f)
}
func MonadPartition[GA ~[]A, A any](as GA, pred func(A) bool) tuple.Tuple2[GA, GA] {
left := Empty[GA]()
right := Empty[GA]()
@@ -107,3 +237,116 @@ func MonadPartition[GA ~[]A, A any](as GA, pred func(A) bool) tuple.Tuple2[GA, G
func Partition[GA ~[]A, A any](pred func(A) bool) func(GA) tuple.Tuple2[GA, GA] {
return F.Bind2nd(MonadPartition[GA, A], pred)
}
func MonadChain[AS ~[]A, BS ~[]B, A, B any](fa AS, f func(a A) BS) BS {
return array.Reduce(fa, func(bs BS, a A) BS {
return append(bs, f(a)...)
}, Empty[BS]())
}
func Chain[AS ~[]A, BS ~[]B, A, B any](f func(A) BS) func(AS) BS {
return F.Bind2nd(MonadChain[AS, BS, A, B], f)
}
func MonadAp[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fab ABS, fa AS) BS {
return MonadChain(fab, F.Bind1st(MonadMap[AS, BS, A, B], fa))
}
func Ap[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fa AS) func(ABS) BS {
return F.Bind2nd(MonadAp[BS, ABS, AS], fa)
}
func IsEmpty[AS ~[]A, A any](as AS) bool {
return array.IsEmpty(as)
}
func IsNil[GA ~[]A, A any](as GA) bool {
return array.IsNil(as)
}
func IsNonNil[GA ~[]A, A any](as GA) bool {
return array.IsNonNil(as)
}
func Match[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(AS) B) func(AS) B {
return func(as AS) B {
if IsEmpty(as) {
return onEmpty()
}
return onNonEmpty(as)
}
}
func MatchLeft[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(A, AS) B) func(AS) B {
return func(as AS) B {
if IsEmpty(as) {
return onEmpty()
}
return onNonEmpty(as[0], as[1:])
}
}
func Slice[AS ~[]A, A any](start int, end int) func(AS) AS {
return func(a AS) AS {
return a[start:end]
}
}
func SliceRight[AS ~[]A, A any](start int) func(AS) AS {
return func(a AS) AS {
return a[start:]
}
}
func Copy[AS ~[]A, A any](b AS) AS {
buf := make(AS, len(b))
copy(buf, b)
return buf
}
func Clone[AS ~[]A, A any](f func(A) A) func(as AS) AS {
// implementation assumes that map does not optimize for the empty array
return Map[AS, AS](f)
}
func FoldMap[AS ~[]A, A, B any](m M.Monoid[B]) func(func(A) B) func(AS) B {
return func(f func(A) B) func(AS) B {
return func(as AS) B {
return array.Reduce(as, func(cur B, a A) B {
return m.Concat(cur, f(a))
}, m.Empty())
}
}
}
func FoldMapWithIndex[AS ~[]A, A, B any](m M.Monoid[B]) func(func(int, A) B) func(AS) B {
return func(f func(int, A) B) func(AS) B {
return func(as AS) B {
return array.ReduceWithIndex(as, func(idx int, cur B, a A) B {
return m.Concat(cur, f(idx, a))
}, m.Empty())
}
}
}
func Fold[AS ~[]A, A any](m M.Monoid[A]) func(AS) A {
return func(as AS) A {
return array.Reduce(as, m.Concat, m.Empty())
}
}
func Push[ENDO ~func(GA) GA, GA ~[]A, A any](a A) ENDO {
return F.Bind2nd(array.Push[GA, A], a)
}
func MonadFlap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](fab GFAB, a A) GB {
return FC.MonadFlap(MonadMap[GFAB, GB], fab, a)
}
func Flap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](a A) func(GFAB) GB {
return FC.Flap(Map[GFAB, GB], a)
}
func Prepend[ENDO ~func(AS) AS, AS []A, A any](head A) ENDO {
return array.Prepend[ENDO](head)
}

89
array/generic/bind.go Normal file
View File

@@ -0,0 +1,89 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
A "github.com/IBM/fp-go/internal/apply"
C "github.com/IBM/fp-go/internal/chain"
F "github.com/IBM/fp-go/internal/functor"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[GS ~[]S, S any](
empty S,
) GS {
return Of[GS](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[GS1 ~[]S1, GS2 ~[]S2, GT ~[]T, S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) GT,
) func(GS1) GS2 {
return C.Bind(
Chain[GS1, GS2, S1, S2],
Map[GT, GS2, T, S2],
setter,
f,
)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[GS1 ~[]S1, GS2 ~[]S2, S1, S2, T any](
key func(T) func(S1) S2,
f func(S1) T,
) func(GS1) GS2 {
return F.Let(
Map[GS1, GS2, S1, S2],
key,
f,
)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[GS1 ~[]S1, GS2 ~[]S2, S1, S2, B any](
key func(B) func(S1) S2,
b B,
) func(GS1) GS2 {
return F.LetTo(
Map[GS1, GS2, S1, S2],
key,
b,
)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[GS1 ~[]S1, GT ~[]T, S1, T any](
setter func(T) S1,
) func(GT) GS1 {
return C.BindTo(
Map[GT, GS1, T, S1],
setter,
)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[GS1 ~[]S1, GS2 ~[]S2, GT ~[]T, S1, S2, T any](
setter func(T) func(S1) S2,
fa GT,
) func(GS1) GS2 {
return A.ApS(
Ap[GS2, []func(T) S2, GT, S2, T],
Map[GS1, []func(T) S2, S1, func(T) S2],
setter,
fa,
)
}

97
array/generic/find.go Normal file
View File

@@ -0,0 +1,97 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/option"
)
// FindFirstWithIndex finds the first element which satisfies a predicate (or a refinement) function
func FindFirstWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) O.Option[A] {
none := O.None[A]()
return func(as AS) O.Option[A] {
for i, a := range as {
if pred(i, a) {
return O.Some(a)
}
}
return none
}
}
// FindFirst finds the first element which satisfies a predicate (or a refinement) function
func FindFirst[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) O.Option[A] {
return FindFirstWithIndex[AS](F.Ignore1of2[int](pred))
}
// FindFirstMapWithIndex finds the first element returned by an [O.Option] based selector function
func FindFirstMapWithIndex[AS ~[]A, PRED ~func(int, A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
none := O.None[B]()
return func(as AS) O.Option[B] {
count := len(as)
for i := 0; i < count; i++ {
out := pred(i, as[i])
if O.IsSome(out) {
return out
}
}
return none
}
}
// FindFirstMap finds the first element returned by an [O.Option] based selector function
func FindFirstMap[AS ~[]A, PRED ~func(A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
return FindFirstMapWithIndex[AS](F.Ignore1of2[int](pred))
}
// FindLastWithIndex finds the first element which satisfies a predicate (or a refinement) function
func FindLastWithIndex[AS ~[]A, PRED ~func(int, A) bool, A any](pred PRED) func(AS) O.Option[A] {
none := O.None[A]()
return func(as AS) O.Option[A] {
for i := len(as) - 1; i >= 0; i-- {
a := as[i]
if pred(i, a) {
return O.Some(a)
}
}
return none
}
}
// FindLast finds the first element which satisfies a predicate (or a refinement) function
func FindLast[AS ~[]A, PRED ~func(A) bool, A any](pred PRED) func(AS) O.Option[A] {
return FindLastWithIndex[AS](F.Ignore1of2[int](pred))
}
// FindLastMapWithIndex finds the first element returned by an [O.Option] based selector function
func FindLastMapWithIndex[AS ~[]A, PRED ~func(int, A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
none := O.None[B]()
return func(as AS) O.Option[B] {
for i := len(as) - 1; i >= 0; i-- {
out := pred(i, as[i])
if O.IsSome(out) {
return out
}
}
return none
}
}
// FindLastMap finds the first element returned by an [O.Option] based selector function
func FindLastMap[AS ~[]A, PRED ~func(A) O.Option[B], A, B any](pred PRED) func(AS) O.Option[B] {
return FindLastMapWithIndex[AS](F.Ignore1of2[int](pred))
}

43
array/generic/monad.go Normal file
View File

@@ -0,0 +1,43 @@
// Copyright (c) 2024 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
"github.com/IBM/fp-go/internal/monad"
)
type arrayMonad[A, B any, GA ~[]A, GB ~[]B, GAB ~[]func(A) B] struct{}
func (o *arrayMonad[A, B, GA, GB, GAB]) Of(a A) GA {
return Of[GA, A](a)
}
func (o *arrayMonad[A, B, GA, GB, GAB]) Map(f func(A) B) func(GA) GB {
return Map[GA, GB, A, B](f)
}
func (o *arrayMonad[A, B, GA, GB, GAB]) Chain(f func(A) GB) func(GA) GB {
return Chain[GA, GB, A, B](f)
}
func (o *arrayMonad[A, B, GA, GB, GAB]) Ap(fa GA) func(GAB) GB {
return Ap[GB, GAB, GA, B, A](fa)
}
// Monad implements the monadic operations for an array
func Monad[A, B any, GA ~[]A, GB ~[]B, GAB ~[]func(A) B]() monad.Monad[A, B, GA, GB, GAB] {
return &arrayMonad[A, B, GA, GB, GAB]{}
}

View File

@@ -1,13 +1,34 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
"sort"
F "github.com/IBM/fp-go/function"
O "github.com/IBM/fp-go/ord"
)
// Sort implements a stable sort on the array given the provided ordering
func Sort[GA ~[]T, T any](ord O.Ord[T]) func(ma GA) GA {
return SortByKey[GA](ord, F.Identity[T])
}
// SortByKey implements a stable sort on the array given the provided ordering on an extracted key
func SortByKey[GA ~[]T, K, T any](ord O.Ord[K], f func(T) K) func(ma GA) GA {
return func(ma GA) GA {
// nothing to sort
@@ -19,8 +40,17 @@ func Sort[GA ~[]T, T any](ord O.Ord[T]) func(ma GA) GA {
cpy := make(GA, l)
copy(cpy, ma)
sort.Slice(cpy, func(i, j int) bool {
return ord.Compare(cpy[i], cpy[j]) < 0
return ord.Compare(f(cpy[i]), f(cpy[j])) < 0
})
return cpy
}
}
// SortBy implements a stable sort on the array given the provided ordering
func SortBy[GA ~[]T, GO ~[]O.Ord[T], T any](ord GO) func(ma GA) GA {
return F.Pipe2(
ord,
Fold[GO](O.Monoid[T]()),
Sort[GA, T],
)
}

32
array/generic/uniq.go Normal file
View File

@@ -0,0 +1,32 @@
package generic
import F "github.com/IBM/fp-go/function"
// StrictUniq converts an array of arbitrary items into an array or unique items
// where uniqueness is determined by the built-in uniqueness constraint
func StrictUniq[AS ~[]A, A comparable](as AS) AS {
return Uniq[AS](F.Identity[A])(as)
}
// uniquePredUnsafe returns a predicate on a map for uniqueness
func uniquePredUnsafe[PRED ~func(A) K, A any, K comparable](f PRED) func(int, A) bool {
lookup := make(map[K]bool)
return func(_ int, a A) bool {
k := f(a)
_, has := lookup[k]
if has {
return false
}
lookup[k] = true
return true
}
}
// Uniq converts an array of arbitrary items into an array or unique items
// where uniqueness is determined based on a key extractor function
func Uniq[AS ~[]A, PRED ~func(A) K, A any, K comparable](f PRED) func(as AS) AS {
return func(as AS) AS {
// we need to create a new predicate for each iteration
return filterWithIndex(as, uniquePredUnsafe(f))
}
}

52
array/generic/zip.go Normal file
View File

@@ -0,0 +1,52 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
F "github.com/IBM/fp-go/function"
N "github.com/IBM/fp-go/number"
T "github.com/IBM/fp-go/tuple"
)
// ZipWith applies a function to pairs of elements at the same index in two arrays, collecting the results in a new array. If one
// input array is short, excess elements of the longer array are discarded.
func ZipWith[AS ~[]A, BS ~[]B, CS ~[]C, FCT ~func(A, B) C, A, B, C any](fa AS, fb BS, f FCT) CS {
l := N.Min(len(fa), len(fb))
res := make(CS, l)
for i := l - 1; i >= 0; i-- {
res[i] = f(fa[i], fb[i])
}
return res
}
// Zip takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
// longer array are discarded
func Zip[AS ~[]A, BS ~[]B, CS ~[]T.Tuple2[A, B], A, B any](fb BS) func(AS) CS {
return F.Bind23of3(ZipWith[AS, BS, CS, func(A, B) T.Tuple2[A, B]])(fb, T.MakeTuple2[A, B])
}
// Unzip is the function is reverse of [Zip]. Takes an array of pairs and return two corresponding arrays
func Unzip[AS ~[]A, BS ~[]B, CS ~[]T.Tuple2[A, B], A, B any](cs CS) T.Tuple2[AS, BS] {
l := len(cs)
as := make(AS, l)
bs := make(BS, l)
for i := l - 1; i >= 0; i-- {
t := cs[i]
as[i] = t.F1
bs[i] = t.F2
}
return T.MakeTuple2(as, bs)
}

View File

@@ -1,10 +1,24 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
F "github.com/IBM/fp-go/function"
M "github.com/IBM/fp-go/magma"
M "github.com/IBM/fp-go/monoid"
)
func ConcatAll[A any](m M.Magma[A]) func(A) func([]A) A {
return F.Bind1st(Reduce[A, A], m.Concat)
func ConcatAll[A any](m M.Monoid[A]) func([]A) A {
return Reduce(m.Concat, m.Empty())
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
@@ -5,16 +20,16 @@ import (
"github.com/stretchr/testify/assert"
M "github.com/IBM/fp-go/magma"
M "github.com/IBM/fp-go/monoid"
)
var subInt = M.MakeMagma(func(first int, second int) int {
var subInt = M.MakeMonoid(func(first int, second int) int {
return first - second
})
}, 0)
func TestConcatAll(t *testing.T) {
var subAll = ConcatAll(subInt)(0)
var subAll = ConcatAll(subInt)
assert.Equal(t, subAll([]int{1, 2, 3}), -6)

26
array/monad.go Normal file
View File

@@ -0,0 +1,26 @@
// Copyright (c) 2024 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
G "github.com/IBM/fp-go/array/generic"
"github.com/IBM/fp-go/internal/monad"
)
// Monad returns the monadic operations for an array
func Monad[A, B any]() monad.Monad[A, B, []A, []B, []func(A) B] {
return G.Monad[A, B, []A, []B, []func(A) B]()
}

View File

@@ -1,17 +1,33 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
"github.com/IBM/fp-go/internal/array"
M "github.com/IBM/fp-go/monoid"
S "github.com/IBM/fp-go/semigroup"
)
func concat[T any](left, right []T) []T {
// some performance checks
ll := len(left)
lr := len(right)
if ll == 0 {
return right
}
lr := len(right)
if lr == 0 {
return left
}
@@ -25,6 +41,10 @@ func Monoid[T any]() M.Monoid[[]T] {
return M.MakeMonoid(concat[T], Empty[T]())
}
func Semigroup[T any]() S.Semigroup[[]T] {
return S.MakeSemigroup(concat[T])
}
func addLen[A any](count int, data []A) int {
return count + len(data)
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (

136
array/nonempty/array.go Normal file
View File

@@ -0,0 +1,136 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nonempty
import (
G "github.com/IBM/fp-go/array/generic"
EM "github.com/IBM/fp-go/endomorphism"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/array"
S "github.com/IBM/fp-go/semigroup"
)
// NonEmptyArray represents an array with at least one element
type NonEmptyArray[A any] []A
// Of constructs a single element array
func Of[A any](first A) NonEmptyArray[A] {
return G.Of[NonEmptyArray[A]](first)
}
// From constructs a [NonEmptyArray] from a set of variadic arguments
func From[A any](first A, data ...A) NonEmptyArray[A] {
count := len(data)
if count == 0 {
return Of(first)
}
// allocate the requested buffer
buffer := make(NonEmptyArray[A], count+1)
buffer[0] = first
copy(buffer[1:], data)
return buffer
}
func IsEmpty[A any](_ NonEmptyArray[A]) bool {
return false
}
func IsNonEmpty[A any](_ NonEmptyArray[A]) bool {
return true
}
func MonadMap[A, B any](as NonEmptyArray[A], f func(a A) B) NonEmptyArray[B] {
return G.MonadMap[NonEmptyArray[A], NonEmptyArray[B]](as, f)
}
func Map[A, B any](f func(a A) B) func(NonEmptyArray[A]) NonEmptyArray[B] {
return F.Bind2nd(MonadMap[A, B], f)
}
func Reduce[A, B any](f func(B, A) B, initial B) func(NonEmptyArray[A]) B {
return func(as NonEmptyArray[A]) B {
return array.Reduce(as, f, initial)
}
}
func ReduceRight[A, B any](f func(A, B) B, initial B) func(NonEmptyArray[A]) B {
return func(as NonEmptyArray[A]) B {
return array.ReduceRight(as, f, initial)
}
}
func Tail[A any](as NonEmptyArray[A]) []A {
return as[1:]
}
func Head[A any](as NonEmptyArray[A]) A {
return as[0]
}
func First[A any](as NonEmptyArray[A]) A {
return as[0]
}
func Last[A any](as NonEmptyArray[A]) A {
return as[len(as)-1]
}
func Size[A any](as NonEmptyArray[A]) int {
return G.Size(as)
}
func Flatten[A any](mma NonEmptyArray[NonEmptyArray[A]]) NonEmptyArray[A] {
return G.Flatten(mma)
}
func MonadChain[A, B any](fa NonEmptyArray[A], f func(a A) NonEmptyArray[B]) NonEmptyArray[B] {
return G.MonadChain[NonEmptyArray[A], NonEmptyArray[B]](fa, f)
}
func Chain[A, B any](f func(A) NonEmptyArray[B]) func(NonEmptyArray[A]) NonEmptyArray[B] {
return G.Chain[NonEmptyArray[A], NonEmptyArray[B]](f)
}
func MonadAp[B, A any](fab NonEmptyArray[func(A) B], fa NonEmptyArray[A]) NonEmptyArray[B] {
return G.MonadAp[NonEmptyArray[B]](fab, fa)
}
func Ap[B, A any](fa NonEmptyArray[A]) func(NonEmptyArray[func(A) B]) NonEmptyArray[B] {
return G.Ap[NonEmptyArray[B], NonEmptyArray[func(A) B]](fa)
}
// FoldMap maps and folds a [NonEmptyArray]. Map the [NonEmptyArray] passing each value to the iterating function. Then fold the results using the provided [Semigroup].
func FoldMap[A, B any](s S.Semigroup[B]) func(func(A) B) func(NonEmptyArray[A]) B {
return func(f func(A) B) func(NonEmptyArray[A]) B {
return func(as NonEmptyArray[A]) B {
return array.Reduce(Tail(as), func(cur B, a A) B {
return s.Concat(cur, f(a))
}, f(Head(as)))
}
}
}
// Fold folds the [NonEmptyArray] using the provided [Semigroup].
func Fold[A any](s S.Semigroup[A]) func(NonEmptyArray[A]) A {
return func(as NonEmptyArray[A]) A {
return array.Reduce(Tail(as), s.Concat, Head(as))
}
}
// Prepend prepends a single value to an array
func Prepend[A any](head A) EM.Endomorphism[NonEmptyArray[A]] {
return array.Prepend[EM.Endomorphism[NonEmptyArray[A]]](head)
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
@@ -9,3 +24,13 @@ import (
func Sort[T any](ord O.Ord[T]) func(ma []T) []T {
return G.Sort[[]T](ord)
}
// SortByKey implements a stable sort on the array given the provided ordering on an extracted key
func SortByKey[K, T any](ord O.Ord[K], f func(T) K) func(ma []T) []T {
return G.SortByKey[[]T](ord, f)
}
// SortBy implements a stable sort on the array given the provided ordering
func SortBy[T any](ord []O.Ord[T]) func(ma []T) []T {
return G.SortBy[[]T, []O.Ord[T]](ord)
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (

74
array/testing/laws.go Normal file
View File

@@ -0,0 +1,74 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package testing
import (
"testing"
RA "github.com/IBM/fp-go/array"
EQ "github.com/IBM/fp-go/eq"
L "github.com/IBM/fp-go/internal/monad/testing"
)
// AssertLaws asserts the apply monad laws for the array monad
func AssertLaws[A, B, C any](t *testing.T,
eqa EQ.Eq[A],
eqb EQ.Eq[B],
eqc EQ.Eq[C],
ab func(A) B,
bc func(B) C,
) func(a A) bool {
return L.AssertLaws(t,
RA.Eq(eqa),
RA.Eq(eqb),
RA.Eq(eqc),
RA.Of[A],
RA.Of[B],
RA.Of[C],
RA.Of[func(A) A],
RA.Of[func(A) B],
RA.Of[func(B) C],
RA.Of[func(func(A) B) B],
RA.MonadMap[A, A],
RA.MonadMap[A, B],
RA.MonadMap[A, C],
RA.MonadMap[B, C],
RA.MonadMap[func(B) C, func(func(A) B) func(A) C],
RA.MonadChain[A, A],
RA.MonadChain[A, B],
RA.MonadChain[A, C],
RA.MonadChain[B, C],
RA.MonadAp[A, A],
RA.MonadAp[B, A],
RA.MonadAp[C, B],
RA.MonadAp[C, A],
RA.MonadAp[B, func(A) B],
RA.MonadAp[func(A) C, func(A) B],
ab,
bc,
)
}

View File

@@ -0,0 +1,47 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package testing
import (
"fmt"
"testing"
EQ "github.com/IBM/fp-go/eq"
"github.com/stretchr/testify/assert"
)
func TestMonadLaws(t *testing.T) {
// some comparison
eqa := EQ.FromStrictEquals[bool]()
eqb := EQ.FromStrictEquals[int]()
eqc := EQ.FromStrictEquals[string]()
ab := func(a bool) int {
if a {
return 1
}
return 0
}
bc := func(b int) string {
return fmt.Sprintf("value %d", b)
}
laws := AssertLaws(t, eqa, eqb, eqc, ab, bc)
assert.True(t, laws(true))
assert.True(t, laws(false))
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import "github.com/IBM/fp-go/internal/array"

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (

17
array/uniq.go Normal file
View File

@@ -0,0 +1,17 @@
package array
import (
G "github.com/IBM/fp-go/array/generic"
)
// StrictUniq converts an array of arbitrary items into an array or unique items
// where uniqueness is determined by the built-in uniqueness constraint
func StrictUniq[A comparable](as []A) []A {
return G.StrictUniq[[]A](as)
}
// Uniq converts an array of arbitrary items into an array or unique items
// where uniqueness is determined based on a key extractor function
func Uniq[A any, K comparable](f func(A) K) func(as []A) []A {
return G.Uniq[[]A](f)
}

14
array/uniq_test.go Normal file
View File

@@ -0,0 +1,14 @@
package array
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestUniq(t *testing.T) {
data := From(1, 2, 3, 2, 4, 1)
uniq := StrictUniq(data)
assert.Equal(t, From(1, 2, 3, 4), uniq)
}

38
array/zip.go Normal file
View File

@@ -0,0 +1,38 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
G "github.com/IBM/fp-go/array/generic"
T "github.com/IBM/fp-go/tuple"
)
// ZipWith applies a function to pairs of elements at the same index in two arrays, collecting the results in a new array. If one
// input array is short, excess elements of the longer array are discarded.
func ZipWith[FCT ~func(A, B) C, A, B, C any](fa []A, fb []B, f FCT) []C {
return G.ZipWith[[]A, []B, []C, FCT](fa, fb, f)
}
// Zip takes two arrays and returns an array of corresponding pairs. If one input array is short, excess elements of the
// longer array are discarded
func Zip[A, B any](fb []B) func([]A) []T.Tuple2[A, B] {
return G.Zip[[]A, []B, []T.Tuple2[A, B]](fb)
}
// Unzip is the function is reverse of [Zip]. Takes an array of pairs and return two corresponding arrays
func Unzip[A, B any](cs []T.Tuple2[A, B]) T.Tuple2[[]A, []B] {
return G.Unzip[[]A, []B, []T.Tuple2[A, B]](cs)
}

56
array/zip_test.go Normal file
View File

@@ -0,0 +1,56 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package array
import (
"fmt"
"testing"
T "github.com/IBM/fp-go/tuple"
"github.com/stretchr/testify/assert"
)
func TestZipWith(t *testing.T) {
left := From(1, 2, 3)
right := From("a", "b", "c", "d")
res := ZipWith(left, right, func(l int, r string) string {
return fmt.Sprintf("%s%d", r, l)
})
assert.Equal(t, From("a1", "b2", "c3"), res)
}
func TestZip(t *testing.T) {
left := From(1, 2, 3)
right := From("a", "b", "c", "d")
res := Zip[string](left)(right)
assert.Equal(t, From(T.MakeTuple2("a", 1), T.MakeTuple2("b", 2), T.MakeTuple2("c", 3)), res)
}
func TestUnzip(t *testing.T) {
left := From(1, 2, 3)
right := From("a", "b", "c")
zipped := Zip[string](left)(right)
unzipped := Unzip(zipped)
assert.Equal(t, right, unzipped.F1)
assert.Equal(t, left, unzipped.F2)
}

109
assert/assert_test.go Normal file
View File

@@ -0,0 +1,109 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package assert
import (
"fmt"
"testing"
E "github.com/IBM/fp-go/either"
EQ "github.com/IBM/fp-go/eq"
"github.com/stretchr/testify/assert"
)
var (
errTest = fmt.Errorf("test failure")
// Eq is the equal predicate checking if objects are equal
Eq = EQ.FromEquals(assert.ObjectsAreEqual)
)
func wrap1[T any](wrapped func(t assert.TestingT, expected, actual any, msgAndArgs ...any) bool, t *testing.T, expected T) func(actual T) E.Either[error, T] {
return func(actual T) E.Either[error, T] {
ok := wrapped(t, expected, actual)
if ok {
return E.Of[error](actual)
}
return E.Left[T](errTest)
}
}
// NotEqual tests if the expected and the actual values are not equal
func NotEqual[T any](t *testing.T, expected T) func(actual T) E.Either[error, T] {
return wrap1(assert.NotEqual, t, expected)
}
// Equal tests if the expected and the actual values are equal
func Equal[T any](t *testing.T, expected T) func(actual T) E.Either[error, T] {
return wrap1(assert.Equal, t, expected)
}
// Length tests if an array has the expected length
func Length[T any](t *testing.T, expected int) func(actual []T) E.Either[error, []T] {
return func(actual []T) E.Either[error, []T] {
ok := assert.Len(t, actual, expected)
if ok {
return E.Of[error](actual)
}
return E.Left[[]T](errTest)
}
}
// NoError validates that there is no error
func NoError[T any](t *testing.T) func(actual E.Either[error, T]) E.Either[error, T] {
return func(actual E.Either[error, T]) E.Either[error, T] {
return E.MonadFold(actual, func(e error) E.Either[error, T] {
assert.NoError(t, e)
return E.Left[T](e)
}, func(value T) E.Either[error, T] {
assert.NoError(t, nil)
return E.Right[error](value)
})
}
}
// ArrayContains tests if a value is contained in an array
func ArrayContains[T any](t *testing.T, expected T) func(actual []T) E.Either[error, []T] {
return func(actual []T) E.Either[error, []T] {
ok := assert.Contains(t, actual, expected)
if ok {
return E.Of[error](actual)
}
return E.Left[[]T](errTest)
}
}
// ContainsKey tests if a key is contained in a map
func ContainsKey[T any, K comparable](t *testing.T, expected K) func(actual map[K]T) E.Either[error, map[K]T] {
return func(actual map[K]T) E.Either[error, map[K]T] {
ok := assert.Contains(t, actual, expected)
if ok {
return E.Of[error](actual)
}
return E.Left[map[K]T](errTest)
}
}
// NotContainsKey tests if a key is not contained in a map
func NotContainsKey[T any, K comparable](t *testing.T, expected K) func(actual map[K]T) E.Either[error, map[K]T] {
return func(actual map[K]T) E.Either[error, map[K]T] {
ok := assert.NotContains(t, actual, expected)
if ok {
return E.Of[error](actual)
}
return E.Left[map[K]T](errTest)
}
}

59
boolean/boolean.go Normal file
View File

@@ -0,0 +1,59 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package boolean
import (
EQ "github.com/IBM/fp-go/eq"
M "github.com/IBM/fp-go/monoid"
O "github.com/IBM/fp-go/ord"
)
var (
// MonoidAny is the boolean [M.Monoid] under disjunction
MonoidAny = M.MakeMonoid(
func(l, r bool) bool {
return l || r
},
false,
)
// MonoidAll is the boolean [M.Monoid] under conjuction
MonoidAll = M.MakeMonoid(
func(l, r bool) bool {
return l && r
},
true,
)
// Eq is the equals predicate for boolean
Eq = EQ.FromStrictEquals[bool]()
// Ord is the strict ordering for boolean
Ord = O.MakeOrd(func(l, r bool) int {
if l {
if r {
return 0
}
return +1
}
if r {
return -1
}
return 0
}, func(l, r bool) bool {
return l == r
})
)

64
bounded/bounded.go Normal file
View File

@@ -0,0 +1,64 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bounded
import (
O "github.com/IBM/fp-go/ord"
)
type Bounded[T any] interface {
O.Ord[T]
Top() T
Bottom() T
}
type bounded[T any] struct {
c func(x, y T) int
e func(x, y T) bool
t T
b T
}
func (b bounded[T]) Equals(x, y T) bool {
return b.e(x, y)
}
func (b bounded[T]) Compare(x, y T) int {
return b.c(x, y)
}
func (b bounded[T]) Top() T {
return b.t
}
func (b bounded[T]) Bottom() T {
return b.b
}
// MakeBounded creates an instance of a bounded type
func MakeBounded[T any](o O.Ord[T], t, b T) Bounded[T] {
return bounded[T]{c: o.Compare, e: o.Equals, t: t, b: b}
}
// Clamp returns a function that clamps against the bounds defined in the bounded type
func Clamp[T any](b Bounded[T]) func(T) T {
return O.Clamp[T](b)(b.Bottom(), b.Top())
}
// Reverse reverses the ordering and swaps the bounds
func Reverse[T any](b Bounded[T]) Bounded[T] {
return MakeBounded(O.Reverse[T](b), b.Bottom(), b.Top())
}

View File

@@ -1,5 +1,28 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bytes
func Empty() []byte {
return Monoid.Empty()
}
func ToString(a []byte) string {
return string(a)
}
func Size(as []byte) int {
return len(as)
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bytes
import (

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bytes
import (

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -373,7 +388,7 @@ func generateApplyHelpers(filename string, count int) error {
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n", time.Now())
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -251,7 +266,7 @@ func generateBindHelpers(filename string, count int) error {
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n", time.Now())
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n", pkg)

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -16,5 +31,9 @@ func Commands() []*C.Command {
ContextReaderIOEitherCommand(),
ReaderIOEitherCommand(),
ReaderCommand(),
IOEitherCommand(),
IOCommand(),
IOOptionCommand(),
DICommand(),
}
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -5,10 +20,307 @@ import (
"log"
"os"
"path/filepath"
"strings"
C "github.com/urfave/cli/v2"
)
func generateNestedCallbacks(i, total int) string {
var buf strings.Builder
for j := i; j < total; j++ {
if j > i {
buf.WriteString(" ")
}
buf.WriteString(fmt.Sprintf("func(T%d)", j+1))
}
if i > 0 {
buf.WriteString(" ")
}
buf.WriteString(tupleType("T")(total))
return buf.String()
}
func generateContextReaderIOEitherTraverseTuple(suffix string) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tupleT type
tupleT := tupleType("T")(i)
tupleA := tupleType("A")(i)
// non-generic version
// generic version
fmt.Fprintf(f, "\n// Traverse%sTuple%d converts a [T.Tuple%d] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple%d].\n", suffix, i, i, i)
fmt.Fprintf(f, "func Traverse%sTuple%d[", suffix, i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "F%d ~func(A%d) ReaderIOEither[T%d]", j+1, j+1, j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", A%d, T%d", j+1, j+1)
}
fmt.Fprintf(f, " any](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d F%d", j+1, j+1)
}
fmt.Fprintf(f, ") func(%s) ReaderIOEither[%s] {\n", tupleA, tupleT)
fmt.Fprintf(f, " return G.Traverse%sTuple%d[ReaderIOEither[%s]](", suffix, i, tupleT)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d", j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// Traverse%sTuple%d converts a [T.Tuple%d] of readers into a reader of a [T.Tuple%d].\n", suffix, i, i, i)
fmt.Fprintf(fg, "func Traverse%sTuple%d[\n", suffix, i)
fmt.Fprintf(fg, " GR_TUPLE%d ~func(context.Context) GIO_TUPLE%d,\n", i, i)
// the transformation functions
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " F%d ~func(A%d) GR_T%d,\n", j+1, j+1, j+1)
}
// the readers
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " GR_T%d ~func(context.Context) GIO_T%d,\n", j+1, j+1)
}
// the tuples
fmt.Fprintf(fg, " GIO_TUPLE%d ~func() E.Either[error, %s],\n", i, tupleT)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " GIO_T%d ~func() E.Either[error, T%d],\n", j+1, j+1)
}
// input and result parameters
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " A%d,\n", j+1)
fmt.Fprintf(fg, " T%d", j+1)
if j < i-1 {
fmt.Fprintf(fg, ",\n")
}
}
fmt.Fprintf(fg, " any](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "f%d F%d", j+1, j+1)
}
fmt.Fprintf(fg, ") func(%s) GR_TUPLE%d {\n", tupleA, i)
fmt.Fprintf(fg, " return func(t %s) GR_TUPLE%d {\n", tupleA, i)
fmt.Fprintf(fg, " return A.TraverseTuple%d(\n", i)
// map call
var cr string
if i > 1 {
cb := generateNestedCallbacks(1, i)
cio := fmt.Sprintf("func() E.Either[error, %s]", cb)
cr = fmt.Sprintf("func(context.Context) %s", cio)
} else {
cr = fmt.Sprintf("GR_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[GR_T%d, %s, GIO_T%d],\n", 1, cr, 1)
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio := fmt.Sprintf("func() E.Either[error, %s]", cb)
cr = fmt.Sprintf("func(context.Context) %s", cio)
} else {
cr = fmt.Sprintf("GR_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap%s[%s, func(context.Context) func() E.Either[error, %s], GR_T%d],\n", suffix, cr, generateNestedCallbacks(j, i), j+1)
}
// function parameters
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " f%d,\n", j+1)
}
// raw parameters
fmt.Fprintf(fg, " t,\n")
fmt.Fprintf(fg, " )\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
}
func generateContextReaderIOEitherSequenceTuple(suffix string) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple type
tuple := tupleType("T")(i)
// non-generic version
// generic version
fmt.Fprintf(f, "\n// Sequence%sTuple%d converts a [T.Tuple%d] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple%d].\n", suffix, i, i, i)
fmt.Fprintf(f, "func Sequence%sTuple%d[", suffix, i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any](t T.Tuple%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "ReaderIOEither[T%d]", j+1)
}
fmt.Fprintf(f, "]) ReaderIOEither[%s] {\n", tuple)
fmt.Fprintf(f, " return G.Sequence%sTuple%d[ReaderIOEither[%s]](t)\n", suffix, i, tuple)
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// Sequence%sTuple%d converts a [T.Tuple%d] of readers into a reader of a [T.Tuple%d].\n", suffix, i, i, i)
fmt.Fprintf(fg, "func Sequence%sTuple%d[\n", suffix, i)
fmt.Fprintf(fg, " GR_TUPLE%d ~func(context.Context) GIO_TUPLE%d,\n", i, i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " GR_T%d ~func(context.Context) GIO_T%d,\n", j+1, j+1)
}
fmt.Fprintf(fg, " GIO_TUPLE%d ~func() E.Either[error, %s],\n", i, tuple)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " GIO_T%d ~func() E.Either[error, T%d],\n", j+1, j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " T%d", j+1)
if j < i-1 {
fmt.Fprintf(fg, ",\n")
}
}
fmt.Fprintf(fg, " any](t T.Tuple%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "GR_T%d", j+1)
}
fmt.Fprintf(fg, "]) GR_TUPLE%d {\n", i)
fmt.Fprintf(fg, " return A.SequenceTuple%d(\n", i)
// map call
var cr string
if i > 1 {
cb := generateNestedCallbacks(1, i)
cio := fmt.Sprintf("func() E.Either[error, %s]", cb)
cr = fmt.Sprintf("func(context.Context) %s", cio)
} else {
cr = fmt.Sprintf("GR_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[GR_T%d, %s, GIO_T%d],\n", 1, cr, 1)
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio := fmt.Sprintf("func() E.Either[error, %s]", cb)
cr = fmt.Sprintf("func(context.Context) %s", cio)
} else {
cr = fmt.Sprintf("GR_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap%s[%s, func(context.Context) func() E.Either[error, %s], GR_T%d],\n", suffix, cr, generateNestedCallbacks(j, i), j+1)
}
// raw parameters
fmt.Fprintf(fg, " t,\n")
fmt.Fprintf(fg, " )\n")
fmt.Fprintf(fg, "}\n")
}
}
func generateContextReaderIOEitherSequenceT(suffix string) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple type
tuple := tupleType("T")(i)
// non-generic version
// generic version
fmt.Fprintf(f, "\n// Sequence%sT%d converts %d [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple%d].\n", suffix, i, i, i)
fmt.Fprintf(f, "func Sequence%sT%d[", suffix, i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d ReaderIOEither[T%d]", j+1, j+1)
}
fmt.Fprintf(f, ") ReaderIOEither[%s] {\n", tuple)
fmt.Fprintf(f, " return G.Sequence%sT%d[ReaderIOEither[%s]](", suffix, i, tuple)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// Sequence%sT%d converts %d readers into a reader of a [T.Tuple%d].\n", suffix, i, i, i)
fmt.Fprintf(fg, "func Sequence%sT%d[\n", suffix, i)
fmt.Fprintf(fg, " GR_TUPLE%d ~func(context.Context) GIO_TUPLE%d,\n", i, i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " GR_T%d ~func(context.Context) GIO_T%d,\n", j+1, j+1)
}
fmt.Fprintf(fg, " GIO_TUPLE%d ~func() E.Either[error, %s],\n", i, tuple)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " GIO_T%d ~func() E.Either[error, T%d],\n", j+1, j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " T%d", j+1)
if j < i-1 {
fmt.Fprintf(fg, ",\n")
}
}
fmt.Fprintf(fg, " any](\n")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " t%d GR_T%d,\n", j+1, j+1)
}
fmt.Fprintf(fg, ") GR_TUPLE%d {\n", i)
fmt.Fprintf(fg, " return A.SequenceT%d(\n", i)
// map call
var cr string
if i > 1 {
cb := generateNestedCallbacks(1, i)
cio := fmt.Sprintf("func() E.Either[error, %s]", cb)
cr = fmt.Sprintf("func(context.Context) %s", cio)
} else {
cr = fmt.Sprintf("GR_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[GR_T%d, %s, GIO_T%d],\n", 1, cr, 1)
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio := fmt.Sprintf("func() E.Either[error, %s]", cb)
cr = fmt.Sprintf("func(context.Context) %s", cio)
} else {
cr = fmt.Sprintf("GR_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap%s[%s, func(context.Context) func() E.Either[error, %s], GR_T%d],\n", suffix, cr, generateNestedCallbacks(j, i), j+1)
}
// raw parameters
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " t%d,\n", j+1)
}
fmt.Fprintf(fg, " )\n")
fmt.Fprintf(fg, "}\n")
}
}
func generateContextReaderIOEitherEitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [ReaderIOEither[R]]\n// The inverse function is [Uneitherize%d]\n", i, i, i, i)
@@ -53,6 +365,70 @@ func generateContextReaderIOEitherEitherize(f, fg *os.File, i int) {
fmt.Fprintln(fg, "}")
}
func generateContextReaderIOEitherUneitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Uneitherize%d converts a function with %d parameters returning a [ReaderIOEither[R]] into a function with %d parameters returning a tuple.\n// The first parameter is considered to be the [context.Context].\n", i, i+1, i)
fmt.Fprintf(f, "func Uneitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") ReaderIOEither[R]")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", R any](f F) func(context.Context")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") (R, error) {\n")
fmt.Fprintf(f, " return G.Uneitherize%d[ReaderIOEither[R]", i)
fmt.Fprintf(f, ", func(context.Context")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ")(R, error)](f)\n")
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Uneitherize%d converts a function with %d parameters returning a [GRA] into a function with %d parameters returning a tuple.\n// The first parameter is considered to be the [context.Context].\n", i, i, i)
fmt.Fprintf(fg, "func Uneitherize%d[GRA ~func(context.Context) GIOA, F ~func(context.Context", i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ") (R, error), GIOA ~func() E.Either[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ", R any](f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j)
}
fmt.Fprintf(fg, ") GRA) F {\n")
fmt.Fprintf(fg, " return func(c context.Context")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", t%d T%d", j, j)
}
fmt.Fprintf(fg, ") (R, error) {\n")
fmt.Fprintf(fg, " return E.UnwrapError(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d", j)
}
fmt.Fprintf(fg, ")(c)())\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
func generateContextReaderIOEitherHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
@@ -90,6 +466,7 @@ import (
"context"
G "github.com/IBM/fp-go/context/%s/generic"
T "github.com/IBM/fp-go/tuple"
)
`, pkg)
@@ -101,14 +478,30 @@ import (
E "github.com/IBM/fp-go/either"
RE "github.com/IBM/fp-go/readerioeither/generic"
A "github.com/IBM/fp-go/internal/apply"
T "github.com/IBM/fp-go/tuple"
)
`)
generateContextReaderIOEitherEitherize(f, fg, 0)
generateContextReaderIOEitherUneitherize(f, fg, 0)
for i := 1; i <= count; i++ {
// eitherize
generateContextReaderIOEitherEitherize(f, fg, i)
generateContextReaderIOEitherUneitherize(f, fg, i)
// sequenceT
generateContextReaderIOEitherSequenceT("")(f, fg, i)
generateContextReaderIOEitherSequenceT("Seq")(f, fg, i)
generateContextReaderIOEitherSequenceT("Par")(f, fg, i)
// sequenceTuple
generateContextReaderIOEitherSequenceTuple("")(f, fg, i)
generateContextReaderIOEitherSequenceTuple("Seq")(f, fg, i)
generateContextReaderIOEitherSequenceTuple("Par")(f, fg, i)
// traverseTuple
generateContextReaderIOEitherTraverseTuple("")(f, fg, i)
generateContextReaderIOEitherTraverseTuple("Seq")(f, fg, i)
generateContextReaderIOEitherTraverseTuple("Par")(f, fg, i)
}
return nil

231
cli/di.go Normal file
View File

@@ -0,0 +1,231 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
C "github.com/urfave/cli/v2"
)
func generateMakeProvider(f *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// MakeProvider%d creates a [DIE.Provider] for an [InjectionToken] from a function with %d dependencies\n", i, i)
fmt.Fprintf(f, "func MakeProvider%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any, R any](\n")
fmt.Fprintf(f, " token InjectionToken[R],\n")
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
}
fmt.Fprintf(f, " f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
fmt.Fprintf(f, ") DIE.Provider {\n")
fmt.Fprint(f, " return DIE.MakeProvider(\n")
fmt.Fprint(f, " token,\n")
fmt.Fprintf(f, " MakeProviderFactory%d(\n", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d,\n", j+1)
}
fmt.Fprint(f, " f,\n")
fmt.Fprint(f, " ))\n")
fmt.Fprintf(f, "}\n")
}
func generateMakeTokenWithDefault(f *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// MakeTokenWithDefault%d creates an [InjectionToken] with a default implementation with %d dependencies\n", i, i)
fmt.Fprintf(f, "func MakeTokenWithDefault%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any, R any](\n")
fmt.Fprintf(f, " name string,\n")
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
}
fmt.Fprintf(f, " f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
fmt.Fprintf(f, ") InjectionToken[R] {\n")
fmt.Fprintf(f, " return MakeTokenWithDefault[R](name, MakeProviderFactory%d(\n", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d,\n", j+1)
}
fmt.Fprint(f, " f,\n")
fmt.Fprint(f, " ))\n")
fmt.Fprintf(f, "}\n")
}
func generateMakeProviderFactory(f *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// MakeProviderFactory%d creates a [DIE.ProviderFactory] from a function with %d arguments and %d dependencies\n", i, i, i)
fmt.Fprintf(f, "func MakeProviderFactory%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any, R any](\n")
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
}
fmt.Fprintf(f, " f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOE.IOEither[error, R],\n")
fmt.Fprintf(f, ") DIE.ProviderFactory {\n")
fmt.Fprint(f, " return DIE.MakeProviderFactory(\n")
fmt.Fprint(f, " A.From[DIE.Dependency](\n")
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d,\n", j+1)
}
fmt.Fprint(f, " ),\n")
fmt.Fprintf(f, " eraseProviderFactory%d(\n", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d,\n", j+1)
}
fmt.Fprint(f, " f,\n")
fmt.Fprint(f, " ),\n")
fmt.Fprint(f, " )\n")
fmt.Fprintf(f, "}\n")
}
func generateEraseProviderFactory(f *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// eraseProviderFactory%d creates a function that takes a variadic number of untyped arguments and from a function of %d strongly typed arguments and %d dependencies\n", i, i, i)
fmt.Fprintf(f, "func eraseProviderFactory%d[", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any, R any](\n")
for j := 0; j < i; j++ {
fmt.Fprintf(f, " d%d Dependency[T%d],\n", j+1, j+1)
}
fmt.Fprintf(f, " f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {\n")
fmt.Fprintf(f, " ft := eraseTuple(T.Tupled%d(f))\n", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, " t%d := lookupAt[T%d](%d, d%d)\n", j+1, j+1, j, j+1)
}
fmt.Fprint(f, " return func(params ...any) IOE.IOEither[error, any] {\n")
fmt.Fprintf(f, " return ft(E.SequenceT%d(\n", i)
for j := 0; j < i; j++ {
fmt.Fprintf(f, " t%d(params),\n", j+1)
}
fmt.Fprint(f, " ))\n")
fmt.Fprint(f, " }\n")
fmt.Fprintf(f, "}\n")
}
func generateDIHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprint(f, `
import (
E "github.com/IBM/fp-go/either"
IOE "github.com/IBM/fp-go/ioeither"
T "github.com/IBM/fp-go/tuple"
A "github.com/IBM/fp-go/array"
DIE "github.com/IBM/fp-go/di/erasure"
)
`)
for i := 1; i <= count; i++ {
generateEraseProviderFactory(f, i)
generateMakeProviderFactory(f, i)
generateMakeTokenWithDefault(f, i)
generateMakeProvider(f, i)
}
return nil
}
func DICommand() *C.Command {
return &C.Command{
Name: "di",
Usage: "generate code for the dependency injection package",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateDIHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -100,16 +115,14 @@ func generateEitherize(f *os.File, i int) {
fmt.Fprintf(f, "t%d T%d", j, j)
}
fmt.Fprintf(f, ") Either[error, R] {\n")
fmt.Fprintf(f, " return TryCatchError(func() (R, error) {\n")
fmt.Fprintf(f, " return f(")
fmt.Fprintf(f, " return TryCatchError(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j)
}
fmt.Fprintln(f, ")")
fmt.Fprintln(f, " })")
fmt.Fprintln(f, "))")
fmt.Fprintln(f, " }")
fmt.Fprintln(f, "}")
}
@@ -135,7 +148,7 @@ func generateEitherHelpers(filename string, count int) error {
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n", time.Now())
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -12,5 +27,5 @@ func writePackage(f *os.File, pkg string) {
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n", time.Now())
fmt.Fprintf(f, "// %s\n\n", time.Now())
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -47,7 +62,7 @@ func generateIdentityHelpers(filename string, count int) error {
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n", time.Now())
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)

136
cli/io.go Normal file
View File

@@ -0,0 +1,136 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
A "github.com/IBM/fp-go/array"
C "github.com/urfave/cli/v2"
)
func nonGenericIO(param string) string {
return fmt.Sprintf("IO[%s]", param)
}
func genericIO(param string) string {
return fmt.Sprintf("func() %s", param)
}
var extrasIO = A.Empty[string]()
func generateIOSequenceT(f, fg *os.File, i int) {
generateGenericSequenceT(nonGenericIO, genericIO, extrasIO)(f, fg, i)
}
func generateIOSequenceTuple(f, fg *os.File, i int) {
generateGenericSequenceTuple(nonGenericIO, genericIO, extrasIO)(f, fg, i)
}
func generateIOTraverseTuple(f, fg *os.File, i int) {
generateGenericTraverseTuple(nonGenericIO, genericIO, extrasIO)(f, fg, i)
}
func generateIOHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// construct subdirectory
genFilename := filepath.Join("generic", filename)
err = os.MkdirAll("generic", os.ModePerm)
if err != nil {
return err
}
fg, err := os.Create(filepath.Clean(genFilename))
if err != nil {
return err
}
defer fg.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
G "github.com/IBM/fp-go/%s/generic"
T "github.com/IBM/fp-go/tuple"
)
`, pkg)
// some header
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(fg, "// This file was generated by robots at")
fmt.Fprintf(fg, "// %s\n", time.Now())
fmt.Fprintf(fg, "package generic\n\n")
fmt.Fprintf(fg, `
import (
T "github.com/IBM/fp-go/tuple"
A "github.com/IBM/fp-go/internal/apply"
)
`)
for i := 1; i <= count; i++ {
// sequenceT
generateIOSequenceT(f, fg, i)
// sequenceTuple
generateIOSequenceTuple(f, fg, i)
// traverseTuple
generateIOTraverseTuple(f, fg, i)
}
return nil
}
func IOCommand() *C.Command {
return &C.Command{
Name: "io",
Usage: "generate code for IO",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateIOHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

282
cli/ioeither.go Normal file
View File

@@ -0,0 +1,282 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
A "github.com/IBM/fp-go/array"
C "github.com/urfave/cli/v2"
)
// [GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GTAB ~func() ET.Either[E, T.Tuple2[A, B]], E, A, B any](a GA, b GB) GTAB {
func nonGenericIOEither(param string) string {
return fmt.Sprintf("IOEither[E, %s]", param)
}
func genericIOEither(param string) string {
return fmt.Sprintf("func() ET.Either[E, %s]", param)
}
var extrasIOEither = A.From("E")
func generateIOEitherSequenceT(f, fg *os.File, i int) {
generateGenericSequenceT(nonGenericIOEither, genericIOEither, extrasIOEither)(f, fg, i)
}
func generateIOEitherSequenceTuple(f, fg *os.File, i int) {
generateGenericSequenceTuple(nonGenericIOEither, genericIOEither, extrasIOEither)(f, fg, i)
}
func generateIOEitherTraverseTuple(f, fg *os.File, i int) {
generateGenericTraverseTuple(nonGenericIOEither, genericIOEither, extrasIOEither)(f, fg, i)
}
func generateIOEitherUneitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Uneitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [IOEither[error, R]]\n", i, i+1, i)
fmt.Fprintf(f, "func Uneitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOEither[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j+1)
}
fmt.Fprintf(f, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") (R, error) {\n")
fmt.Fprintf(f, " return G.Uneitherize%d[IOEither[error, R]](f)\n", i)
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Uneitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GIOA]\n", i, i, i)
fmt.Fprintf(fg, "func Uneitherize%d[GIOA ~func() ET.Either[error, R], GTA ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j+1)
}
fmt.Fprintf(fg, ") GIOA")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j+1)
}
fmt.Fprintf(fg, ", R any](f GTA) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j+1)
}
fmt.Fprintf(fg, ") (R, error) {\n")
fmt.Fprintf(fg, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d T%d", j+1, j+1)
}
fmt.Fprintf(fg, ") (R, error) {\n")
fmt.Fprintf(fg, " return ET.Unwrap(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d", j+1)
}
fmt.Fprintf(fg, ")())\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
func generateIOEitherEitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [IOEither[error, R]]\n", i, i+1, i)
fmt.Fprintf(f, "func Eitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") (R, error)")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j+1)
}
fmt.Fprintf(f, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, ") IOEither[error, R] {\n")
fmt.Fprintf(f, " return G.Eitherize%d[IOEither[error, R]](f)\n", i)
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning a [GIOA]\n", i, i, i)
fmt.Fprintf(fg, "func Eitherize%d[GIOA ~func() ET.Either[error, R], F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j+1)
}
fmt.Fprintf(fg, ") (R, error)")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j+1)
}
fmt.Fprintf(fg, ", R any](f F) func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j+1)
}
fmt.Fprintf(fg, ") GIOA {\n")
fmt.Fprintf(fg, " e := ET.Eitherize%d(f)\n", i)
fmt.Fprintf(fg, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d T%d", j+1, j+1)
}
fmt.Fprintf(fg, ") GIOA {\n")
fmt.Fprintf(fg, " return func() ET.Either[error, R] {\n")
fmt.Fprintf(fg, " return e(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d", j+1)
}
fmt.Fprintf(fg, ")\n")
fmt.Fprintf(fg, " }}\n")
fmt.Fprintf(fg, "}\n")
}
func generateIOEitherHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// construct subdirectory
genFilename := filepath.Join("generic", filename)
err = os.MkdirAll("generic", os.ModePerm)
if err != nil {
return err
}
fg, err := os.Create(filepath.Clean(genFilename))
if err != nil {
return err
}
defer fg.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
G "github.com/IBM/fp-go/%s/generic"
T "github.com/IBM/fp-go/tuple"
)
`, pkg)
// some header
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(fg, "// This file was generated by robots at")
fmt.Fprintf(fg, "// %s\n", time.Now())
fmt.Fprintf(fg, "package generic\n\n")
fmt.Fprintf(fg, `
import (
ET "github.com/IBM/fp-go/either"
T "github.com/IBM/fp-go/tuple"
A "github.com/IBM/fp-go/internal/apply"
)
`)
// eitherize
generateIOEitherEitherize(f, fg, 0)
// uneitherize
generateIOEitherUneitherize(f, fg, 0)
for i := 1; i <= count; i++ {
// eitherize
generateIOEitherEitherize(f, fg, i)
// uneitherize
generateIOEitherUneitherize(f, fg, i)
// sequenceT
generateIOEitherSequenceT(f, fg, i)
// sequenceTuple
generateIOEitherSequenceTuple(f, fg, i)
// traverseTuple
generateIOEitherTraverseTuple(f, fg, i)
}
return nil
}
func IOEitherCommand() *C.Command {
return &C.Command{
Name: "ioeither",
Usage: "generate code for IOEither",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateIOEitherHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

137
cli/iooption.go Normal file
View File

@@ -0,0 +1,137 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
A "github.com/IBM/fp-go/array"
C "github.com/urfave/cli/v2"
)
func nonGenericIOOption(param string) string {
return fmt.Sprintf("IOOption[%s]", param)
}
func genericIOOption(param string) string {
return fmt.Sprintf("func() O.Option[%s]", param)
}
var extrasIOOption = A.Empty[string]()
func generateIOOptionSequenceT(f, fg *os.File, i int) {
generateGenericSequenceT(nonGenericIOOption, genericIOOption, extrasIOOption)(f, fg, i)
}
func generateIOOptionSequenceTuple(f, fg *os.File, i int) {
generateGenericSequenceTuple(nonGenericIOOption, genericIOOption, extrasIOOption)(f, fg, i)
}
func generateIOOptionTraverseTuple(f, fg *os.File, i int) {
generateGenericTraverseTuple(nonGenericIOOption, genericIOOption, extrasIOOption)(f, fg, i)
}
func generateIOOptionHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
return err
}
absDir, err := filepath.Abs(dir)
if err != nil {
return err
}
pkg := filepath.Base(absDir)
f, err := os.Create(filepath.Clean(filename))
if err != nil {
return err
}
defer f.Close()
// construct subdirectory
genFilename := filepath.Join("generic", filename)
err = os.MkdirAll("generic", os.ModePerm)
if err != nil {
return err
}
fg, err := os.Create(filepath.Clean(genFilename))
if err != nil {
return err
}
defer fg.Close()
// log
log.Printf("Generating code in [%s] for package [%s] with [%d] repetitions ...", filename, pkg, count)
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
G "github.com/IBM/fp-go/%s/generic"
T "github.com/IBM/fp-go/tuple"
)
`, pkg)
// some header
fmt.Fprintln(fg, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(fg, "// This file was generated by robots at")
fmt.Fprintf(fg, "// %s\n", time.Now())
fmt.Fprintf(fg, "package generic\n\n")
fmt.Fprintf(fg, `
import (
T "github.com/IBM/fp-go/tuple"
O "github.com/IBM/fp-go/option"
A "github.com/IBM/fp-go/internal/apply"
)
`)
for i := 1; i <= count; i++ {
// sequenceT
generateIOOptionSequenceT(f, fg, i)
// sequenceTuple
generateIOOptionSequenceTuple(f, fg, i)
// traverseTuple
generateIOOptionTraverseTuple(f, fg, i)
}
return nil
}
func IOOptionCommand() *C.Command {
return &C.Command{
Name: "iooption",
Usage: "generate code for IOOption",
Flags: []C.Flag{
flagCount,
flagFilename,
},
Action: func(ctx *C.Context) error {
return generateIOOptionHelpers(
ctx.String(keyFilename),
ctx.Int(keyCount),
)
},
}
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -6,18 +21,20 @@ import (
"strings"
)
func tupleType(i int) string {
var buf strings.Builder
buf.WriteString(fmt.Sprintf("T.Tuple%d[", i))
for j := 0; j < i; j++ {
if j > 0 {
buf.WriteString(", ")
func tupleType(name string) func(i int) string {
return func(i int) string {
var buf strings.Builder
buf.WriteString(fmt.Sprintf("T.Tuple%d[", i))
for j := 0; j < i; j++ {
if j > 0 {
buf.WriteString(", ")
}
buf.WriteString(fmt.Sprintf("%s%d", name, j+1))
}
buf.WriteString(fmt.Sprintf("T%d", j+1))
}
buf.WriteString("]")
buf.WriteString("]")
return buf.String()
return buf.String()
}
}
func monadGenerateSequenceTNonGeneric(
@@ -27,7 +44,7 @@ func monadGenerateSequenceTNonGeneric(
) func(f *os.File, i int) {
return func(f *os.File, i int) {
tuple := tupleType(i)
tuple := tupleType("T")(i)
fmt.Fprintf(f, "SequenceT%d[", i)
for j := 0; j < i; j++ {
@@ -80,7 +97,7 @@ func monadGenerateSequenceTGeneric(
) func(f *os.File, i int) {
return func(f *os.File, i int) {
tuple := tupleType(i)
tuple := tupleType("T")(i)
fmt.Fprintf(f, "SequenceT%d[", i)
for j := 0; j < i; j++ {
@@ -131,7 +148,7 @@ func generateTraverseTuple1(
infix string) func(f *os.File, i int) {
return func(f *os.File, i int) {
tuple := tupleType(i)
tuple := tupleType("T")(i)
fmt.Fprintf(f, "\n// TraverseTuple%d converts a [Tuple%d] of [A] via transformation functions transforming [A] to [%s] into a [%s].\n", i, i, hkt("A"), hkt(fmt.Sprintf("Tuple%d", i)))
fmt.Fprintf(f, "func TraverseTuple%d[", i)
@@ -218,7 +235,7 @@ func generateSequenceTuple1(
return func(f *os.File, i int) {
tuple := tupleType(i)
tuple := tupleType("T")(i)
fmt.Fprintf(f, "\n// SequenceTuple%d converts a [Tuple%d] of [%s] into an [%s].\n", i, i, hkt("T"), hkt(fmt.Sprintf("Tuple%d", i)))
fmt.Fprintf(f, "func SequenceTuple%d[", i)
@@ -281,7 +298,7 @@ func generateSequenceT1(
return func(f *os.File, i int) {
tuple := tupleType(i)
tuple := tupleType("T")(i)
fmt.Fprintf(f, "\n// SequenceT%d converts %d parameters of [%s] into a [%s].\n", i, i, hkt("T"), hkt(fmt.Sprintf("Tuple%d", i)))
fmt.Fprintf(f, "func SequenceT%d[", i)

284
cli/monad2.go Normal file
View File

@@ -0,0 +1,284 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"fmt"
"os"
A "github.com/IBM/fp-go/array"
F "github.com/IBM/fp-go/function"
N "github.com/IBM/fp-go/number"
S "github.com/IBM/fp-go/string"
)
var (
concStrgs = A.Monoid[string]().Concat
intercalStrgs = A.Intercalate(S.Monoid)
concAllStrgs = A.ConcatAll(A.Monoid[string]())
)
func joinAll(middle string) func(all ...[]string) string {
ic := intercalStrgs(middle)
return func(all ...[]string) string {
return ic(concAllStrgs(all))
}
}
func generateGenericSequenceT(
nonGenericType func(string) string,
genericType func(string) string,
extra []string,
) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple
tuple := tupleType("T")(i)
// all types T
typesT := A.MakeBy(i, F.Flow2(
N.Inc[int],
S.Format[int]("T%d"),
))
// non generic version
fmt.Fprintf(f, "\n// SequenceT%d converts %d [%s] into a [%s]\n", i, i, nonGenericType("T"), nonGenericType(tuple))
fmt.Fprintf(f, "func SequenceT%d[%s any](\n", i, joinAll(", ")(extra, typesT))
for j := 0; j < i; j++ {
fmt.Fprintf(f, " t%d %s,\n", j+1, nonGenericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, ") %s {\n", nonGenericType(tuple))
fmt.Fprintf(f, " return G.SequenceT%d[\n", i)
fmt.Fprintf(f, " %s,\n", nonGenericType(tuple))
for j := 0; j < i; j++ {
fmt.Fprintf(f, " %s,\n", nonGenericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, " ](")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// SequenceT%d converts %d [%s] into a [%s]\n", i, i, genericType("T"), genericType(tuple))
fmt.Fprintf(fg, "func SequenceT%d[\n", i)
fmt.Fprintf(fg, " G_TUPLE%d ~%s,\n", i, genericType(tuple))
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " G_T%d ~%s, \n", j+1, genericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(fg, " %s any](\n", joinAll(", ")(extra, typesT))
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " t%d G_T%d,\n", j+1, j+1)
}
fmt.Fprintf(fg, ") G_TUPLE%d {\n", i)
fmt.Fprintf(fg, " return A.SequenceT%d(\n", i)
// map call
var cio string
cb := generateNestedCallbacks(1, i)
if i > 1 {
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[%s],\n", joinAll(", ")(A.From("G_T1", cio), extra, A.From("T1", cb)))
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap[%s, %s, G_T%d],\n", cio, genericType(generateNestedCallbacks(j, i)), j+1)
}
// function parameters
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " t%d,\n", j+1)
}
fmt.Fprintf(fg, " )\n")
fmt.Fprintf(fg, "}\n")
}
}
func generateGenericSequenceTuple(
nonGenericType func(string) string,
genericType func(string) string,
extra []string,
) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple
tuple := tupleType("T")(i)
// all types T
typesT := A.MakeBy(i, F.Flow2(
N.Inc[int],
S.Format[int]("T%d"),
))
// non generic version
fmt.Fprintf(f, "\n// SequenceTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, nonGenericType("T"), nonGenericType(tuple))
fmt.Fprintf(f, "func SequenceTuple%d[%s any](t T.Tuple%d[", i, joinAll(", ")(extra, typesT), i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "%s", nonGenericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, "]) %s {\n", nonGenericType(tuple))
fmt.Fprintf(f, " return G.SequenceTuple%d[\n", i)
fmt.Fprintf(f, " %s,\n", nonGenericType(tuple))
for j := 0; j < i; j++ {
fmt.Fprintf(f, " %s,\n", nonGenericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(f, " ](t)\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// SequenceTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, genericType("T"), genericType(tuple))
fmt.Fprintf(fg, "func SequenceTuple%d[\n", i)
fmt.Fprintf(fg, " G_TUPLE%d ~%s,\n", i, genericType(tuple))
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " G_T%d ~%s, \n", j+1, genericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(fg, " %s any](t T.Tuple%d[", joinAll(", ")(extra, typesT), i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "G_T%d", j+1)
}
fmt.Fprintf(fg, "]) G_TUPLE%d {\n", i)
fmt.Fprintf(fg, " return A.SequenceTuple%d(\n", i)
// map call
var cio string
cb := generateNestedCallbacks(1, i)
if i > 1 {
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[%s],\n", joinAll(", ")(A.From("G_T1", cio), extra, A.From("T1", cb)))
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap[%s, %s, G_T%d],\n", cio, genericType(generateNestedCallbacks(j, i)), j+1)
}
// function parameters
fmt.Fprintf(fg, " t)\n")
fmt.Fprintf(fg, "}\n")
}
}
func generateGenericTraverseTuple(
nonGenericType func(string) string,
genericType func(string) string,
extra []string,
) func(f, fg *os.File, i int) {
return func(f, fg *os.File, i int) {
// tuple
tupleT := tupleType("T")(i)
tupleA := tupleType("A")(i)
// all types T
typesT := A.MakeBy(i, F.Flow2(
N.Inc[int],
S.Format[int]("T%d"),
))
// all types A
typesA := A.MakeBy(i, F.Flow2(
N.Inc[int],
S.Format[int]("A%d"),
))
// all function types
typesF := A.MakeBy(i, F.Flow2(
N.Inc[int],
func(j int) string {
return fmt.Sprintf("F%d ~func(A%d) %s", j, j, nonGenericType(fmt.Sprintf("T%d", j)))
},
))
// non generic version
fmt.Fprintf(f, "\n// TraverseTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, nonGenericType("T"), nonGenericType(tupleT))
fmt.Fprintf(f, "func TraverseTuple%d[%s any](", i, joinAll(", ")(typesF, extra, typesA, typesT))
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d F%d", j+1, j+1)
}
fmt.Fprintf(f, ") func(%s) %s {\n", tupleA, nonGenericType(tupleT))
fmt.Fprintf(f, " return G.TraverseTuple%d[%s](", i, nonGenericType(tupleT))
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d", j+1)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
// generic version
fmt.Fprintf(fg, "\n// TraverseTuple%d converts a [T.Tuple%d[%s]] into a [%s]\n", i, i, genericType("T"), genericType(tupleT))
fmt.Fprintf(fg, "func TraverseTuple%d[\n", i)
fmt.Fprintf(fg, " G_TUPLE%d ~%s,\n", i, genericType(tupleT))
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " F%d ~func(A%d) G_T%d,\n", j+1, j+1, j+1)
}
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " G_T%d ~%s, \n", j+1, genericType(fmt.Sprintf("T%d", j+1)))
}
fmt.Fprintf(fg, " %s any](", joinAll(", ")(extra, typesA, typesT))
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "f%d F%d", j+1, j+1)
}
fmt.Fprintf(fg, ") func(%s) G_TUPLE%d {\n", tupleA, i)
fmt.Fprintf(fg, " return func(t %s) G_TUPLE%d {\n", tupleA, i)
fmt.Fprintf(fg, " return A.TraverseTuple%d(\n", i)
// map call
var cio string
cb := generateNestedCallbacks(1, i)
if i > 1 {
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Map[%s],\n", joinAll(", ")(A.From("G_T1", cio), extra, A.From("T1", cb)))
// the apply calls
for j := 1; j < i; j++ {
if j < i-1 {
cb := generateNestedCallbacks(j+1, i)
cio = genericType(cb)
} else {
cio = fmt.Sprintf("G_TUPLE%d", i)
}
fmt.Fprintf(fg, " Ap[%s, %s, G_T%d],\n", cio, genericType(generateNestedCallbacks(j, i)), j+1)
}
// function parameters
for j := 0; j < i; j++ {
fmt.Fprintf(fg, " f%d,\n", j+1)
}
// tuple parameter
fmt.Fprintf(fg, " t)\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -133,7 +148,7 @@ func generateOptionHelpers(filename string, count int) error {
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n", time.Now())
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -10,6 +25,40 @@ import (
C "github.com/urfave/cli/v2"
)
func generateUnsliced(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Unsliced%d converts a function taking a slice parameter into a function with %d parameters\n", i, i)
fmt.Fprintf(f, "func Unsliced%d[F ~func([]T) R, T, R any](f F) func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T")
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j+1)
}
if i > 0 {
fmt.Fprintf(f, " T")
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return f([]T{")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j+1)
}
fmt.Fprintln(f, "})")
fmt.Fprintln(f, " }")
fmt.Fprintln(f, "}")
}
func generateVariadic(f *os.File, i int) {
// Create the nullary version
fmt.Fprintf(f, "\n// Variadic%d converts a function taking %d parameters and a final slice into a function with %d parameters but a final variadic argument\n", i, i, i)
@@ -68,7 +117,7 @@ func generateVariadic(f *os.File, i int) {
fmt.Fprintf(f, "v)\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}")
fmt.Fprintf(f, "}\n")
}
func generateUnvariadic(f *os.File, i int) {
@@ -129,7 +178,7 @@ func generateUnvariadic(f *os.File, i int) {
fmt.Fprintf(f, "v...)\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}")
fmt.Fprintf(f, "}\n")
}
func generateNullary(f *os.File, i int) {
@@ -216,10 +265,15 @@ func generatePipe(f *os.File, i int) {
fmt.Fprintf(f, ", f%d F%d", j, j)
}
fmt.Fprintf(f, ") T%d {\n", i)
for j := 1; j <= i; j++ {
fmt.Fprintf(f, " t%d := f%d(t%d)\n", j, j, j-1)
fmt.Fprintf(f, " return ")
for j := i; j >= 1; j-- {
fmt.Fprintf(f, "f%d(", j)
}
fmt.Fprintf(f, " return t%d\n", i)
fmt.Fprintf(f, "t0")
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ")")
}
fmt.Fprintf(f, "\n")
fmt.Fprintln(f, "}")
}
@@ -246,15 +300,16 @@ func recurseCurry(f *os.File, indent string, total, count int) {
func generateCurry(f *os.File, i int) {
// Create the curry version
fmt.Fprintf(f, "\n// Curry%d takes a function with %d parameters and returns a cascade of functions each taking only one parameter.\n// The inverse function is [Uncurry%d]\n", i, i, i)
fmt.Fprintf(f, "func Curry%d[T0", i)
for j := 1; j <= i; j++ {
fmt.Fprintf(f, "func Curry%d[FCT ~func(T0", i)
for j := 1; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, " any](f func(T0")
for j := 2; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j-1)
fmt.Fprintf(f, ") T%d", i)
// type arguments
for j := 0; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") T%d) func(T0)", i)
fmt.Fprintf(f, " any](f FCT) func(T0)")
for j := 2; j <= i; j++ {
fmt.Fprintf(f, " func(T%d)", j-1)
}
@@ -266,15 +321,16 @@ func generateCurry(f *os.File, i int) {
func generateUncurry(f *os.File, i int) {
// Create the uncurry version
fmt.Fprintf(f, "\n// Uncurry%d takes a cascade of %d functions each taking only one parameter and returns a function with %d parameters .\n// The inverse function is [Curry%d]\n", i, i, i, i)
fmt.Fprintf(f, "func Uncurry%d[T0", i)
for j := 1; j <= i; j++ {
fmt.Fprintf(f, "func Uncurry%d[FCT ~func(T0)", i)
for j := 1; j < i; j++ {
fmt.Fprintf(f, " func(T%d)", j)
}
fmt.Fprintf(f, " T%d", i)
// the type parameters
for j := 0; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, " any](f")
for j := 1; j <= i; j++ {
fmt.Fprintf(f, " func(T%d)", j-1)
}
fmt.Fprintf(f, " T%d) func(", i)
fmt.Fprintf(f, " any](f FCT) func(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
@@ -322,7 +378,7 @@ func generatePipeHelpers(filename string, count int) error {
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n", time.Now())
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n", pkg)
@@ -332,6 +388,8 @@ func generatePipeHelpers(filename string, count int) error {
generateVariadic(f, 0)
// unvariadic
generateUnvariadic(f, 0)
// unsliced
generateUnsliced(f, 0)
for i := 1; i <= count; i++ {
@@ -349,6 +407,8 @@ func generatePipeHelpers(filename string, count int) error {
generateVariadic(f, i)
// unvariadic
generateUnvariadic(f, i)
// unsliced
generateUnsliced(f, i)
}
return nil

View File

@@ -12,6 +12,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -117,7 +118,7 @@ func generateReaderHelpers(filename string, count int) error {
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n", time.Now())
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -121,6 +136,70 @@ func generateReaderIOEitherEitherize(f, fg *os.File, i int) {
fmt.Fprintf(fg, "}\n")
}
func generateReaderIOEitherUneitherize(f, fg *os.File, i int) {
// non generic version
fmt.Fprintf(f, "\n// Uneitherize%d converts a function with %d parameters returning a [ReaderIOEither[C, error, R]] into a function with %d parameters returning a tuple.\n// The first parameter is considered to be the context [C].\n", i, i+1, i)
fmt.Fprintf(f, "func Uneitherize%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j)
}
fmt.Fprintf(f, ") ReaderIOEither[C, error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", C, R any](f F) func(C")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ") (R, error) {\n")
fmt.Fprintf(f, " return G.Uneitherize%d[ReaderIOEither[C, error, R]", i)
fmt.Fprintf(f, ", func(C")
for j := 0; j < i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ")(R, error)](f)\n")
fmt.Fprintln(f, "}")
// generic version
fmt.Fprintf(fg, "\n// Uneitherize%d converts a function with %d parameters returning a [GRA] into a function with %d parameters returning a tuple.\n// The first parameter is considered to be the context [C].\n", i, i, i)
fmt.Fprintf(fg, "func Uneitherize%d[GRA ~func(C) GIOA, F ~func(C", i)
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ") (R, error), GIOA ~func() E.Either[error, R]")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", T%d", j)
}
fmt.Fprintf(fg, ", C, R any](f func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "T%d", j)
}
fmt.Fprintf(fg, ") GRA) F {\n")
fmt.Fprintf(fg, " return func(c C")
for j := 0; j < i; j++ {
fmt.Fprintf(fg, ", t%d T%d", j, j)
}
fmt.Fprintf(fg, ") (R, error) {\n")
fmt.Fprintf(fg, " return E.UnwrapError(f(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(fg, ", ")
}
fmt.Fprintf(fg, "t%d", j)
}
fmt.Fprintf(fg, ")(c)())\n")
fmt.Fprintf(fg, " }\n")
fmt.Fprintf(fg, "}\n")
}
func generateReaderIOEitherHelpers(filename string, count int) error {
dir, err := os.Getwd()
if err != nil {
@@ -154,7 +233,7 @@ func generateReaderIOEitherHelpers(filename string, count int) error {
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n", time.Now())
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
@@ -182,12 +261,16 @@ import (
generateReaderIOEitherFrom(f, fg, 0)
// eitherize
generateReaderIOEitherEitherize(f, fg, 0)
// uneitherize
generateReaderIOEitherUneitherize(f, fg, 0)
for i := 1; i <= count; i++ {
// from
generateReaderIOEitherFrom(f, fg, i)
// eitherize
generateReaderIOEitherEitherize(f, fg, i)
// uneitherize
generateReaderIOEitherUneitherize(f, fg, i)
}
return nil

View File

@@ -0,0 +1,15 @@
package templates
import (
"text/template"
E "github.com/IBM/fp-go/either"
)
var (
templateFunctions = template.FuncMap{}
)
func Parse(name, tmpl string) E.Either[error, *template.Template] {
return E.TryCatchError(template.New(name).Funcs(templateFunctions).Parse(tmpl))
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
@@ -5,6 +20,7 @@ import (
"log"
"os"
"path/filepath"
"strings"
"time"
C "github.com/urfave/cli/v2"
@@ -21,8 +37,51 @@ func writeTupleType(f *os.File, symbol string, i int) {
fmt.Fprintf(f, "]")
}
func makeTupleType(name string) func(i int) string {
return func(i int) string {
var buf strings.Builder
buf.WriteString(fmt.Sprintf("Tuple%d[", i))
for j := 0; j < i; j++ {
if j > 0 {
buf.WriteString(", ")
}
buf.WriteString(fmt.Sprintf("%s%d", name, j+1))
}
buf.WriteString("]")
return buf.String()
}
}
func generatePush(f *os.File, i int) {
tuple1 := makeTupleType("T")(i)
tuple2 := makeTupleType("T")(i + 1)
// Create the replicate version
fmt.Fprintf(f, "\n// Push%d creates a [Tuple%d] from a [Tuple%d] by appending a constant value\n", i, i+1, i)
fmt.Fprintf(f, "func Push%d[", i)
// function prototypes
for j := 0; j <= i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T%d", j+1)
}
fmt.Fprintf(f, " any](value T%d) func(%s) %s {\n", i+1, tuple1, tuple2)
fmt.Fprintf(f, " return func(t %s) %s {\n", tuple1, tuple2)
fmt.Fprintf(f, " return MakeTuple%d(", i+1)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t.F%d", j+1)
}
fmt.Fprintf(f, ", value)\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
}
func generateReplicate(f *os.File, i int) {
// Create the optionize version
// Create the replicate version
fmt.Fprintf(f, "\n// Replicate%d creates a [Tuple%d] with all fields set to the input value `t`\n", i, i)
fmt.Fprintf(f, "func Replicate%d[T any](t T) Tuple%d[", i, i)
for j := 1; j <= i; j++ {
@@ -279,7 +338,7 @@ func generateUntupled(f *os.File, i int) {
func generateTupled(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Tupled%d converts a function with %d parameters returning into a function taking a Tuple%d\n// The inverse function is [Untupled%d]\n", i, i, i, i)
fmt.Fprintf(f, "\n// Tupled%d converts a function with %d parameters into a function taking a Tuple%d\n// The inverse function is [Untupled%d]\n", i, i, i, i)
fmt.Fprintf(f, "func Tupled%d[F ~func(", i)
for j := 0; j < i; j++ {
if j > 0 {
@@ -340,14 +399,14 @@ func generateTupleHelpers(filename string, count int) error {
// some header
fmt.Fprintln(f, "// Code generated by go generate; DO NOT EDIT.")
fmt.Fprintln(f, "// This file was generated by robots at")
fmt.Fprintf(f, "// %s\n", time.Now())
fmt.Fprintf(f, "// %s\n\n", time.Now())
fmt.Fprintf(f, "package %s\n\n", pkg)
fmt.Fprintf(f, `
import (
M "github.com/IBM/fp-go/monoid"
O "github.com/IBM/fp-go/ord"
O "github.com/IBM/fp-go/ord"
)
`)
@@ -371,11 +430,183 @@ import (
generateMap(f, i)
// generate replicate
generateReplicate(f, i)
// generate tuple functions such as string and fmt
generateTupleString(f, i)
// generate json support
generateTupleMarshal(f, i)
// generate json support
generateTupleUnmarshal(f, i)
// generate toArray
generateToArray(f, i)
// generate fromArray
generateFromArray(f, i)
// generate push
if i < count {
generatePush(f, i)
}
}
return nil
}
func generateTupleMarshal(f *os.File, i int) {
// Create the stringify version
fmt.Fprintf(f, "\n// MarshalJSON marshals the [Tuple%d] into a JSON array\n", i)
fmt.Fprintf(f, "func (t ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") MarshalJSON() ([]byte, error) {\n")
fmt.Fprintf(f, " return tupleMarshalJSON(")
// function prototypes
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t.F%d", j)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
}
func generateTupleUnmarshal(f *os.File, i int) {
// Create the stringify version
fmt.Fprintf(f, "\n// UnmarshalJSON unmarshals a JSON array into a [Tuple%d]\n", i)
fmt.Fprintf(f, "func (t *")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") UnmarshalJSON(data []byte) error {\n")
fmt.Fprintf(f, " return tupleUnmarshalJSON(data")
// function prototypes
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", &t.F%d", j)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
}
func generateToArray(f *os.File, i int) {
// Create the stringify version
fmt.Fprintf(f, "\n// ToArray converts the [Tuple%d] into an array of type [R] using %d transformation functions from [T] to [R]\n// The inverse function is [FromArray%d]\n", i, i, i)
fmt.Fprintf(f, "func ToArray%d[", i)
// function prototypes
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "F%d ~func(T%d) R", j, j)
}
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", R any](")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d F%d", j, j)
}
fmt.Fprintf(f, ") func(t ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") []R {\n")
fmt.Fprintf(f, " return func(t ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") []R {\n")
fmt.Fprintf(f, " return []R{\n")
for j := 1; j <= i; j++ {
fmt.Fprintf(f, " f%d(t.F%d),\n", j, j)
}
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
}
func generateFromArray(f *os.File, i int) {
// Create the stringify version
fmt.Fprintf(f, "\n// FromArray converts an array of [R] into a [Tuple%d] using %d functions from [R] to [T]\n// The inverse function is [ToArray%d]\n", i, i, i)
fmt.Fprintf(f, "func FromArray%d[", i)
// function prototypes
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "F%d ~func(R) T%d", j, j)
}
for j := 1; j <= i; j++ {
fmt.Fprintf(f, ", T%d", j)
}
fmt.Fprintf(f, ", R any](")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "f%d F%d", j, j)
}
fmt.Fprintf(f, ") func(r []R) ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, " {\n")
fmt.Fprintf(f, " return func(r []R) ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, " {\n")
fmt.Fprintf(f, " return MakeTuple%d(\n", i)
for j := 1; j <= i; j++ {
fmt.Fprintf(f, " f%d(r[%d]),\n", j, j-1)
}
fmt.Fprintf(f, " )\n")
fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}\n")
}
func generateTupleString(f *os.File, i int) {
// Create the stringify version
fmt.Fprintf(f, "\n// String prints some debug info for the [Tuple%d]\n", i)
fmt.Fprintf(f, "func (t ")
writeTupleType(f, "T", i)
fmt.Fprintf(f, ") String() string {\n")
// convert to string
fmt.Fprint(f, " return tupleString(")
for j := 1; j <= i; j++ {
if j > 1 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t.F%d", j)
}
fmt.Fprintf(f, ")\n")
fmt.Fprintf(f, "}\n")
}
// func generateTupleJson(f *os.File, i int) {
// // Create the stringify version
// fmt.Fprintf(f, "\n// MarshalJSON converts the [Tuple%d] into a JSON byte stream\n", i)
// fmt.Fprintf(f, "func (t ")
// writeTupleType(f, "T", i)
// fmt.Fprintf(f, ") MarshalJSON() ([]byte, error) {\n")
// // convert to string
// fmt.Fprintf(f, " return fmt.Sprintf(\"Tuple%d[", i)
// for j := 1; j <= i; j++ {
// if j > 1 {
// fmt.Fprintf(f, ", ")
// }
// fmt.Fprintf(f, "%s", "%T")
// }
// fmt.Fprintf(f, "](")
// for j := 1; j <= i; j++ {
// if j > 1 {
// fmt.Fprintf(f, ", ")
// }
// fmt.Fprintf(f, "%s", "%v")
// }
// fmt.Fprintf(f, ")\", ")
// for j := 1; j <= i; j++ {
// if j > 1 {
// fmt.Fprintf(f, ", ")
// }
// fmt.Fprintf(f, "t.F%d", j)
// }
// for j := 1; j <= i; j++ {
// fmt.Fprintf(f, ", t.F%d", j)
// }
// fmt.Fprintf(f, ")\n")
// fmt.Fprintf(f, "}\n")
// }
func TupleCommand() *C.Command {
return &C.Command{
Name: "tuple",

59
constant/const.go Normal file
View File

@@ -0,0 +1,59 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package constant
import (
F "github.com/IBM/fp-go/function"
M "github.com/IBM/fp-go/monoid"
S "github.com/IBM/fp-go/semigroup"
)
type Const[E, A any] struct {
value E
}
func Make[E, A any](e E) Const[E, A] {
return Const[E, A]{value: e}
}
func Unwrap[E, A any](c Const[E, A]) E {
return c.value
}
func Of[E, A any](m M.Monoid[E]) func(A) Const[E, A] {
return F.Constant1[A](Make[E, A](m.Empty()))
}
func MonadMap[E, A, B any](fa Const[E, A], _ func(A) B) Const[E, B] {
return Make[E, B](fa.value)
}
func MonadAp[E, A, B any](s S.Semigroup[E]) func(fab Const[E, func(A) B], fa Const[E, A]) Const[E, B] {
return func(fab Const[E, func(A) B], fa Const[E, A]) Const[E, B] {
return Make[E, B](s.Concat(fab.value, fa.value))
}
}
func Map[E, A, B any](f func(A) B) func(fa Const[E, A]) Const[E, B] {
return F.Bind2nd(MonadMap[E, A, B], f)
}
func Ap[E, A, B any](s S.Semigroup[E]) func(fa Const[E, A]) func(fab Const[E, func(A) B]) Const[E, B] {
monadap := MonadAp[E, A, B](s)
return func(fa Const[E, A]) func(fab Const[E, func(A) B]) Const[E, B] {
return F.Bind2nd(monadap, fa)
}
}

40
constant/const_test.go Normal file
View File

@@ -0,0 +1,40 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package constant
import (
"testing"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/utils"
S "github.com/IBM/fp-go/string"
"github.com/stretchr/testify/assert"
)
func TestMap(t *testing.T) {
fa := Make[string, int]("foo")
assert.Equal(t, fa, F.Pipe1(fa, Map[string, int](utils.Double)))
}
func TestOf(t *testing.T) {
assert.Equal(t, Make[string, int](""), Of[string, int](S.Monoid)(1))
}
func TestAp(t *testing.T) {
fab := Make[string, int]("bar")
assert.Equal(t, Make[string, int]("foobar"), Ap[string, int, int](S.Monoid)(fab)(Make[string, func(int) int]("foo")))
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package constraints
type Ordered interface {
@@ -19,3 +34,7 @@ type Integer interface {
type Float interface {
~float32 | ~float64
}
type Complex interface {
~complex64 | ~complex128
}

View File

@@ -13,5 +13,5 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package context contains versions of monads that work with a golang [context.Context]
// Package context contains versions of reader IO monads that work with a golang [context.Context]
package context

View File

@@ -1,18 +1,32 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
"context"
E "github.com/IBM/fp-go/either"
ET "github.com/IBM/fp-go/either"
IOE "github.com/IBM/fp-go/ioeither/generic"
)
// withContext wraps an existing IOEither and performs a context check for cancellation before delegating
// WithContext wraps an existing IOEither and performs a context check for cancellation before delegating
func WithContext[GIO ~func() E.Either[error, A], A any](ctx context.Context, ma GIO) GIO {
return IOE.MakeIO[GIO](func() E.Either[error, A] {
if err := context.Cause(ctx); err != nil {
return ET.Left[A](err)
return E.Left[A](err)
}
return ma()
})

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ioeither
import (

View File

@@ -1,53 +0,0 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package reader
import (
"context"
R "github.com/IBM/fp-go/reader/generic"
)
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
func Curry0[A any](f func(context.Context) A) Reader[A] {
return R.Curry0[Reader[A]](f)
}
func Curry1[T1, A any](f func(context.Context, T1) A) func(T1) Reader[A] {
return R.Curry1[Reader[A]](f)
}
func Curry2[T1, T2, A any](f func(context.Context, T1, T2) A) func(T1) func(T2) Reader[A] {
return R.Curry2[Reader[A]](f)
}
func Curry3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) A) func(T1) func(T2) func(T3) Reader[A] {
return R.Curry3[Reader[A]](f)
}
func Uncurry1[T1, A any](f func(T1) Reader[A]) func(context.Context, T1) A {
return R.Uncurry1(f)
}
func Uncurry2[T1, T2, A any](f func(T1) func(T2) Reader[A]) func(context.Context, T1, T2) A {
return R.Uncurry2(f)
}
func Uncurry3[T1, T2, T3, A any](f func(T1) func(T2) func(T3) Reader[A]) func(context.Context, T1, T2, T3) A {
return R.Uncurry3(f)
}

View File

@@ -1,26 +0,0 @@
package reader
import (
"context"
R "github.com/IBM/fp-go/reader/generic"
)
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
func From0[A any](f func(context.Context) A) func() Reader[A] {
return R.From0[Reader[A]](f)
}
func From1[T1, A any](f func(context.Context, T1) A) func(T1) Reader[A] {
return R.From1[Reader[A]](f)
}
func From2[T1, T2, A any](f func(context.Context, T1, T2) A) func(T1, T2) Reader[A] {
return R.From2[Reader[A]](f)
}
func From3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) A) func(T1, T2, T3) Reader[A] {
return R.From3[Reader[A]](f)
}

View File

@@ -1,43 +0,0 @@
package reader
import (
"context"
R "github.com/IBM/fp-go/reader/generic"
)
func MonadMap[A, B any](fa Reader[A], f func(A) B) Reader[B] {
return R.MonadMap[Reader[A], Reader[B]](fa, f)
}
func Map[A, B any](f func(A) B) func(Reader[A]) Reader[B] {
return R.Map[Reader[A], Reader[B]](f)
}
func MonadChain[A, B any](ma Reader[A], f func(A) Reader[B]) Reader[B] {
return R.MonadChain(ma, f)
}
func Chain[A, B any](f func(A) Reader[B]) func(Reader[A]) Reader[B] {
return R.Chain[Reader[A]](f)
}
func Of[A any](a A) Reader[A] {
return R.Of[Reader[A]](a)
}
func MonadAp[A, B any](fab Reader[func(A) B], fa Reader[A]) Reader[B] {
return R.MonadAp[Reader[A], Reader[B]](fab, fa)
}
func Ap[A, B any](fa Reader[A]) func(Reader[func(A) B]) Reader[B] {
return R.Ap[Reader[A], Reader[B], Reader[func(A) B]](fa)
}
func Ask() Reader[context.Context] {
return R.Ask[Reader[context.Context]]()
}
func Asks[A any](r Reader[A]) Reader[A] {
return R.Asks(r)
}

View File

@@ -1,60 +0,0 @@
package reader
import (
"context"
"fmt"
"strings"
"testing"
F "github.com/IBM/fp-go/function"
T "github.com/IBM/fp-go/tuple"
"github.com/stretchr/testify/assert"
)
func GoFunction(ctx context.Context, data string) string {
return strings.ToUpper(data)
}
func GoIntFunction(ctx context.Context, data string, number int) string {
return fmt.Sprintf("%s: %d", data, number)
}
func TestReaderFrom(t *testing.T) {
ctx := context.Background()
f := From1(GoFunction)
result := f("input")(ctx)
assert.Equal(t, result, "INPUT")
}
func MyFinalResult(left, right string) string {
return fmt.Sprintf("%s-%s", left, right)
}
func TestReadersFrom(t *testing.T) {
ctx := context.Background()
f1 := From1(GoFunction)
f2 := From2(GoIntFunction)
result1 := f1("input")(ctx)
result2 := f2("input", 10)(ctx)
result3 := MyFinalResult(result1, result2)
h := F.Pipe1(
SequenceT2(f1("input"), f2("input", 10)),
Map(T.Tupled2(MyFinalResult)),
)
composedResult := h(ctx)
assert.Equal(t, result1, "INPUT")
assert.Equal(t, result2, "input: 10")
assert.Equal(t, result3, "INPUT-input: 10")
assert.Equal(t, composedResult, "INPUT-input: 10")
}

View File

@@ -1,42 +0,0 @@
package reader
import (
R "github.com/IBM/fp-go/reader/generic"
T "github.com/IBM/fp-go/tuple"
)
// SequenceT converts n inputs of higher kinded types into a higher kinded types of n strongly typed values, represented as a tuple
func SequenceT1[A any](a Reader[A]) Reader[T.Tuple1[A]] {
return R.SequenceT1[
Reader[A],
Reader[T.Tuple1[A]],
](a)
}
func SequenceT2[A, B any](a Reader[A], b Reader[B]) Reader[T.Tuple2[A, B]] {
return R.SequenceT2[
Reader[A],
Reader[B],
Reader[T.Tuple2[A, B]],
](a, b)
}
func SequenceT3[A, B, C any](a Reader[A], b Reader[B], c Reader[C]) Reader[T.Tuple3[A, B, C]] {
return R.SequenceT3[
Reader[A],
Reader[B],
Reader[C],
Reader[T.Tuple3[A, B, C]],
](a, b, c)
}
func SequenceT4[A, B, C, D any](a Reader[A], b Reader[B], c Reader[C], d Reader[D]) Reader[T.Tuple4[A, B, C, D]] {
return R.SequenceT4[
Reader[A],
Reader[B],
Reader[C],
Reader[D],
Reader[T.Tuple4[A, B, C, D]],
](a, b, c, d)
}

View File

@@ -1,11 +0,0 @@
// Package reader implements a specialization of the Reader monad assuming a golang context as the context of the monad
package reader
import (
"context"
R "github.com/IBM/fp-go/reader"
)
// Reader is a specialization of the Reader monad assuming a golang context as the context of the monad
type Reader[A any] R.Reader[context.Context, A]

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readereither
import (
@@ -9,6 +24,11 @@ func TraverseArray[A, B any](f func(A) ReaderEither[B]) func([]A) ReaderEither[[
return RE.TraverseArray[ReaderEither[B], ReaderEither[[]B], []A](f)
}
// TraverseArrayWithIndex transforms an array
func TraverseArrayWithIndex[A, B any](f func(int, A) ReaderEither[B]) func([]A) ReaderEither[[]B] {
return RE.TraverseArrayWithIndex[ReaderEither[B], ReaderEither[[]B], []A](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[A any](ma []ReaderEither[A]) ReaderEither[[]A] {
return RE.SequenceArray[ReaderEither[A], ReaderEither[[]A]](ma)

View File

@@ -0,0 +1,68 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readereither
import (
"context"
G "github.com/IBM/fp-go/readereither/generic"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[S any](
empty S,
) ReaderEither[S] {
return G.Do[ReaderEither[S], context.Context, error, S](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) ReaderEither[T],
) func(ReaderEither[S1]) ReaderEither[S2] {
return G.Bind[ReaderEither[S1], ReaderEither[S2], ReaderEither[T], context.Context, error, S1, S2, T](setter, f)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) T,
) func(ReaderEither[S1]) ReaderEither[S2] {
return G.Let[ReaderEither[S1], ReaderEither[S2], context.Context, error, S1, S2, T](setter, f)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[S1, S2, T any](
setter func(T) func(S1) S2,
b T,
) func(ReaderEither[S1]) ReaderEither[S2] {
return G.LetTo[ReaderEither[S1], ReaderEither[S2], context.Context, error, S1, S2, T](setter, b)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[S1, T any](
setter func(T) S1,
) func(ReaderEither[T]) ReaderEither[S1] {
return G.BindTo[ReaderEither[S1], ReaderEither[T], context.Context, error, S1, T](setter)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[S1, S2, T any](
setter func(T) func(S1) S2,
fa ReaderEither[T],
) func(ReaderEither[S1]) ReaderEither[S2] {
return G.ApS[ReaderEither[S1], ReaderEither[S2], ReaderEither[T], context.Context, error, S1, S2, T](setter, fa)
}

View File

@@ -0,0 +1,58 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readereither
import (
"context"
"testing"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/utils"
"github.com/stretchr/testify/assert"
)
func getLastName(s utils.Initial) ReaderEither[string] {
return Of("Doe")
}
func getGivenName(s utils.WithLastName) ReaderEither[string] {
return Of("John")
}
func TestBind(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
Bind(utils.SetLastName, getLastName),
Bind(utils.SetGivenName, getGivenName),
Map(utils.GetFullName),
)
assert.Equal(t, res(context.Background()), E.Of[error]("John Doe"))
}
func TestApS(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
ApS(utils.SetLastName, Of("Doe")),
ApS(utils.SetGivenName, Of("John")),
Map(utils.GetFullName),
)
assert.Equal(t, res(context.Background()), E.Of[error]("John Doe"))
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readereither
import (

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readereither
import (

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package exec
import (
@@ -19,8 +34,6 @@ var (
func command(name string, args []string, in []byte) RE.ReaderEither[exec.CommandOutput] {
return func(ctx context.Context) E.Either[error, exec.CommandOutput] {
return E.TryCatchError(func() (exec.CommandOutput, error) {
return GE.Exec(ctx, name, args, in)
})
return E.TryCatchError(GE.Exec(ctx, name, args, in))
}
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readereither
import (

View File

@@ -1,9 +1,23 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readereither
import (
"context"
R "github.com/IBM/fp-go/context/reader"
ET "github.com/IBM/fp-go/either"
O "github.com/IBM/fp-go/option"
RE "github.com/IBM/fp-go/readereither/generic"
@@ -17,14 +31,6 @@ func FromEither[A any](e ET.Either[error, A]) ReaderEither[A] {
return RE.FromEither[ReaderEither[A]](e)
}
func RightReader[A any](r R.Reader[A]) ReaderEither[A] {
return RE.RightReader[R.Reader[A], ReaderEither[A]](r)
}
func LeftReader[A any](l R.Reader[error]) ReaderEither[A] {
return RE.LeftReader[R.Reader[error], ReaderEither[A]](l)
}
func Left[A any](l error) ReaderEither[A] {
return RE.Left[ReaderEither[A]](l)
}
@@ -33,10 +39,6 @@ func Right[A any](r A) ReaderEither[A] {
return RE.Right[ReaderEither[A]](r)
}
func FromReader[A any](r R.Reader[A]) ReaderEither[A] {
return RE.FromReader[R.Reader[A], ReaderEither[A]](r)
}
func MonadMap[A, B any](fa ReaderEither[A], f func(A) B) ReaderEither[B] {
return RE.MonadMap[ReaderEither[A], ReaderEither[B]](fa, f)
}
@@ -69,30 +71,14 @@ func FromPredicate[A any](pred func(A) bool, onFalse func(A) error) func(A) Read
return RE.FromPredicate[ReaderEither[A]](pred, onFalse)
}
func Fold[A, B any](onLeft func(error) R.Reader[B], onRight func(A) R.Reader[B]) func(ReaderEither[A]) R.Reader[B] {
return RE.Fold[ReaderEither[A]](onLeft, onRight)
}
func GetOrElse[A any](onLeft func(error) R.Reader[A]) func(ReaderEither[A]) R.Reader[A] {
return RE.GetOrElse[ReaderEither[A]](onLeft)
}
func OrElse[A any](onLeft func(error) ReaderEither[A]) func(ReaderEither[A]) ReaderEither[A] {
return RE.OrElse[ReaderEither[A]](onLeft)
}
func OrLeft[A any](onLeft func(error) R.Reader[error]) func(ReaderEither[A]) ReaderEither[A] {
return RE.OrLeft[ReaderEither[A], ReaderEither[A]](onLeft)
}
func Ask() ReaderEither[context.Context] {
return RE.Ask[ReaderEither[context.Context]]()
}
func Asks[A any](r R.Reader[A]) ReaderEither[A] {
return RE.Asks[R.Reader[A], ReaderEither[A]](r)
}
func MonadChainEitherK[A, B any](ma ReaderEither[A], f func(A) ET.Either[error, B]) ReaderEither[B] {
return RE.MonadChainEitherK[ReaderEither[A], ReaderEither[B]](ma, f)
}
@@ -104,3 +90,11 @@ func ChainEitherK[A, B any](f func(A) ET.Either[error, B]) func(ma ReaderEither[
func ChainOptionK[A, B any](onNone func() error) func(func(A) O.Option[B]) func(ReaderEither[A]) ReaderEither[B] {
return RE.ChainOptionK[ReaderEither[A], ReaderEither[B]](onNone)
}
func MonadFlap[B, A any](fab ReaderEither[func(A) B], a A) ReaderEither[B] {
return RE.MonadFlap[ReaderEither[func(A) B], ReaderEither[B]](fab, a)
}
func Flap[B, A any](a A) func(ReaderEither[func(A) B]) ReaderEither[B] {
return RE.Flap[ReaderEither[func(A) B], ReaderEither[B]](a)
}

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readereither
import (

View File

@@ -1,3 +1,18 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package readereither implements a specialization of the Reader monad assuming a golang context as the context of the monad and a standard golang error
package readereither

View File

@@ -1,16 +0,0 @@
package readerio
import (
IO "github.com/IBM/fp-go/io"
R "github.com/IBM/fp-go/readerio/generic"
)
// TraverseArray transforms an array
func TraverseArray[A, B any](f func(A) ReaderIO[B]) func([]A) ReaderIO[[]B] {
return R.TraverseArray[ReaderIO[B], ReaderIO[[]B], IO.IO[B], IO.IO[[]B], []A](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[A any](ma []ReaderIO[A]) ReaderIO[[]A] {
return R.SequenceArray[ReaderIO[A], ReaderIO[[]A]](ma)
}

View File

@@ -1,27 +0,0 @@
package readerio
import (
"context"
IO "github.com/IBM/fp-go/io"
R "github.com/IBM/fp-go/readerio/generic"
)
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
func From0[A any](f func(context.Context) IO.IO[A]) func() ReaderIO[A] {
return R.From0[ReaderIO[A]](f)
}
func From1[T1, A any](f func(context.Context, T1) IO.IO[A]) func(T1) ReaderIO[A] {
return R.From1[ReaderIO[A]](f)
}
func From2[T1, T2, A any](f func(context.Context, T1, T2) IO.IO[A]) func(T1, T2) ReaderIO[A] {
return R.From2[ReaderIO[A]](f)
}
func From3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) IO.IO[A]) func(T1, T2, T3) ReaderIO[A] {
return R.From3[ReaderIO[A]](f)
}

View File

@@ -1,44 +0,0 @@
package readerio
import (
"context"
R "github.com/IBM/fp-go/readerio/generic"
)
func MonadMap[A, B any](fa ReaderIO[A], f func(A) B) ReaderIO[B] {
return R.MonadMap[ReaderIO[A], ReaderIO[B]](fa, f)
}
func Map[A, B any](f func(A) B) func(ReaderIO[A]) ReaderIO[B] {
return R.Map[ReaderIO[A], ReaderIO[B]](f)
}
func MonadChain[A, B any](ma ReaderIO[A], f func(A) ReaderIO[B]) ReaderIO[B] {
return R.MonadChain(ma, f)
}
func Chain[A, B any](f func(A) ReaderIO[B]) func(ReaderIO[A]) ReaderIO[B] {
return R.Chain[ReaderIO[A]](f)
}
func Of[A any](a A) ReaderIO[A] {
return R.Of[ReaderIO[A]](a)
}
func MonadAp[A, B any](fab ReaderIO[func(A) B], fa ReaderIO[A]) ReaderIO[B] {
return R.MonadAp[ReaderIO[A], ReaderIO[B]](fab, fa)
}
func Ap[A, B any](fa ReaderIO[A]) func(ReaderIO[func(A) B]) ReaderIO[B] {
return R.Ap[ReaderIO[A], ReaderIO[B], ReaderIO[func(A) B]](fa)
}
func Ask() ReaderIO[context.Context] {
return R.Ask[ReaderIO[context.Context]]()
}
// Defer creates an IO by creating a brand new IO via a generator function, each time
func Defer[A any](gen func() ReaderIO[A]) ReaderIO[A] {
return R.Defer[ReaderIO[A]](gen)
}

View File

@@ -1,65 +0,0 @@
package readerio
import (
"context"
"fmt"
"strings"
"testing"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io"
T "github.com/IBM/fp-go/tuple"
"github.com/stretchr/testify/assert"
)
func GoFunction(ctx context.Context, data string) IO.IO[string] {
return func() string {
return strings.ToUpper(data)
}
}
func GoIntFunction(ctx context.Context, data string, number int) IO.IO[string] {
return func() string {
return fmt.Sprintf("%s: %d", data, number)
}
}
func TestReaderFrom(t *testing.T) {
ctx := context.Background()
f := From1(GoFunction)
result := f("input")(ctx)
assert.Equal(t, result(), "INPUT")
}
func MyFinalResult(left, right string) string {
return fmt.Sprintf("%s-%s", left, right)
}
func TestReadersFrom(t *testing.T) {
ctx := context.Background()
f1 := From1(GoFunction)
f2 := From2(GoIntFunction)
result1 := f1("input")(ctx)
result2 := f2("input", 10)(ctx)
result3 := MyFinalResult(result1(), result2())
h := F.Pipe1(
SequenceT2(f1("input"), f2("input", 10)),
Map(T.Tupled2(MyFinalResult)),
)
composedResult := h(ctx)
assert.Equal(t, result1(), "INPUT")
assert.Equal(t, result2(), "input: 10")
assert.Equal(t, result3, "INPUT-input: 10")
assert.Equal(t, composedResult(), "INPUT-input: 10")
}

View File

@@ -1,42 +0,0 @@
package readerio
import (
R "github.com/IBM/fp-go/readerio/generic"
T "github.com/IBM/fp-go/tuple"
)
// SequenceT converts n inputs of higher kinded types into a higher kinded types of n strongly typed values, represented as a tuple
func SequenceT1[A any](a ReaderIO[A]) ReaderIO[T.Tuple1[A]] {
return R.SequenceT1[
ReaderIO[A],
ReaderIO[T.Tuple1[A]],
](a)
}
func SequenceT2[A, B any](a ReaderIO[A], b ReaderIO[B]) ReaderIO[T.Tuple2[A, B]] {
return R.SequenceT2[
ReaderIO[A],
ReaderIO[B],
ReaderIO[T.Tuple2[A, B]],
](a, b)
}
func SequenceT3[A, B, C any](a ReaderIO[A], b ReaderIO[B], c ReaderIO[C]) ReaderIO[T.Tuple3[A, B, C]] {
return R.SequenceT3[
ReaderIO[A],
ReaderIO[B],
ReaderIO[C],
ReaderIO[T.Tuple3[A, B, C]],
](a, b, c)
}
func SequenceT4[A, B, C, D any](a ReaderIO[A], b ReaderIO[B], c ReaderIO[C], d ReaderIO[D]) ReaderIO[T.Tuple4[A, B, C, D]] {
return R.SequenceT4[
ReaderIO[A],
ReaderIO[B],
ReaderIO[C],
ReaderIO[D],
ReaderIO[T.Tuple4[A, B, C, D]],
](a, b, c, d)
}

View File

@@ -1,11 +0,0 @@
// Package readerio implements a specialization of the ReaderIO monad assuming a golang context as the context of the monad
package readerio
import (
"context"
R "github.com/IBM/fp-go/readerio"
)
// ReaderIO is a specialization of the ReaderIO monad assuming a golang context as the context of the monad
type ReaderIO[A any] R.ReaderIO[context.Context, A]

View File

@@ -0,0 +1,67 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readerioeither
import (
G "github.com/IBM/fp-go/context/readerioeither/generic"
IOE "github.com/IBM/fp-go/ioeither"
)
// Bind creates an empty context of type [S] to be used with the [Bind] operation
func Do[S any](
empty S,
) ReaderIOEither[S] {
return G.Do[ReaderIOEither[S], IOE.IOEither[error, S], S](empty)
}
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
func Bind[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) ReaderIOEither[T],
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
return G.Bind[ReaderIOEither[S1], ReaderIOEither[S2], ReaderIOEither[T], IOE.IOEither[error, S1], IOE.IOEither[error, S2], IOE.IOEither[error, T], S1, S2, T](setter, f)
}
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
func Let[S1, S2, T any](
setter func(T) func(S1) S2,
f func(S1) T,
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
return G.Let[ReaderIOEither[S1], ReaderIOEither[S2], IOE.IOEither[error, S1], IOE.IOEither[error, S2], S1, S2, T](setter, f)
}
// LetTo attaches the a value to a context [S1] to produce a context [S2]
func LetTo[S1, S2, T any](
setter func(T) func(S1) S2,
b T,
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
return G.LetTo[ReaderIOEither[S1], ReaderIOEither[S2], IOE.IOEither[error, S1], IOE.IOEither[error, S2], S1, S2, T](setter, b)
}
// BindTo initializes a new state [S1] from a value [T]
func BindTo[S1, T any](
setter func(T) S1,
) func(ReaderIOEither[T]) ReaderIOEither[S1] {
return G.BindTo[ReaderIOEither[S1], ReaderIOEither[T], IOE.IOEither[error, S1], IOE.IOEither[error, T], S1, T](setter)
}
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
func ApS[S1, S2, T any](
setter func(T) func(S1) S2,
fa ReaderIOEither[T],
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
return G.ApS[ReaderIOEither[func(T) S2], ReaderIOEither[S1], ReaderIOEither[S2], ReaderIOEither[T], IOE.IOEither[error, func(T) S2], IOE.IOEither[error, S1], IOE.IOEither[error, S2], IOE.IOEither[error, T], S1, S2, T](setter, fa)
}

View File

@@ -0,0 +1,58 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readerioeither
import (
"context"
"testing"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/utils"
"github.com/stretchr/testify/assert"
)
func getLastName(s utils.Initial) ReaderIOEither[string] {
return Of("Doe")
}
func getGivenName(s utils.WithLastName) ReaderIOEither[string] {
return Of("John")
}
func TestBind(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
Bind(utils.SetLastName, getLastName),
Bind(utils.SetGivenName, getGivenName),
Map(utils.GetFullName),
)
assert.Equal(t, res(context.Background())(), E.Of[error]("John Doe"))
}
func TestApS(t *testing.T) {
res := F.Pipe3(
Do(utils.Empty),
ApS(utils.SetLastName, Of("Doe")),
ApS(utils.SetGivenName, Of("John")),
Map(utils.GetFullName),
)
assert.Equal(t, res(context.Background())(), E.Of[error]("John Doe"))
}

View File

@@ -0,0 +1,37 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readerioeither
import (
G "github.com/IBM/fp-go/context/readerioeither/generic"
E "github.com/IBM/fp-go/either"
)
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
// whether the body action returns and error or not.
func Bracket[
A, B, ANY any](
acquire ReaderIOEither[A],
use func(A) ReaderIOEither[B],
release func(A, E.Either[error, B]) ReaderIOEither[ANY],
) ReaderIOEither[B] {
return G.Bracket[ReaderIOEither[A], ReaderIOEither[B], ReaderIOEither[ANY]](
acquire,
use,
release,
)
}

View File

@@ -1,10 +1,25 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readerioeither
import (
G "github.com/IBM/fp-go/context/readerioeither/generic"
)
// WithContext wraps an existing ReaderIOEither and performs a context check for cancellation before delegating
// WithContext wraps an existing [ReaderIOEither] and performs a context check for cancellation before delegating
func WithContext[A any](ma ReaderIOEither[A]) ReaderIOEither[A] {
return G.WithContext(ma)
}

Some files were not shown because too many files have changed in this diff Show More