1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-08-24 19:29:11 +02:00

Compare commits

...

126 Commits

Author SHA1 Message Date
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
337 changed files with 24101 additions and 9351 deletions

View File

@@ -17,22 +17,25 @@ on:
env:
# Currently no way to detect automatically
DEFAULT_BRANCH: main
GO_VERSION: 1.20.5 # renovate: datasource=golang-version depName=golang
GO_VERSION: 1.20.6 # renovate: datasource=golang-version depName=golang
NODE_VERSION: 18
DRY_RUN: true
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [ '1.20.x', '1.21.x' ]
steps:
# full checkout for semantic-release
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0
- name: Set up go ${{env.GO_VERSION}}
- name: Set up go ${{ matrix.go-version }}
uses: actions/setup-go@v4
with:
go-version: ${{env.GO_VERSION}}
go-version: ${{ matrix.go-version }}
-
name: Tests
run: |
@@ -52,7 +55,7 @@ jobs:
steps:
# full checkout for semantic-release
- name: Full checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 0

View File

@@ -1,6 +1,6 @@
# Functional programming library for golang
**🚧 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.
**🚧 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.
![logo](resources/images/logo.png)
@@ -12,7 +12,9 @@ This library is strongly influenced by the awesome [fp-ts](https://github.com/gc
go get github.com/IBM/fp-go
```
Refer to the [samples](./samples/).
Refer to the [samples](./samples/).
Find API documentation [here](https://pkg.go.dev/github.com/IBM/fp-go)
## Design Goal
@@ -65,7 +67,7 @@ This library aims to provide a set of data types and functions that make it easy
#### 🧘🏽 Moderation is a virtue
✔️ 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.
✔️ 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.
#### 🧘🏽 Maintainability counts
@@ -73,6 +75,40 @@ This library aims to provide a set of data types and functions that make it easy
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.
## Comparison to Idiomatic Go
In this section we discuss how the functional APIs differ from idiomatic go function signatures and how to convert back and forth.
### Pure functions
Pure functions are functions that take input parameters and that compute an output without changing any global state and without mutating the input parameters. They will always return the same output for the same input.
#### Without Errors
If your pure function does not return an error, the idiomatic signature is just fine and no changes are required.
#### With Errors
If your pure function can return an error, then it will have a `(T, error)` return value in idiomatic go. In functional style the return value is [Either[error, T]](https://pkg.go.dev/github.com/IBM/fp-go/either) because function composition is easier with such a return type. Use the `EitherizeXXX` methods in ["github.com/IBM/fp-go/either"](https://pkg.go.dev/github.com/IBM/fp-go/either) to convert from idiomatic to functional style and `UneitherizeXXX` to convert from functional to idiomatic style.
### Effectful functions
An effectful function (or function with a side effect) is one that changes data outside the scope of the function or that does not always produce the same output for the same input (because it depends on some external, mutable state). There is no special way in idiomatic go to identify such a function other than documentation. In functional style we represent them as functions that do not take an input but that produce an output. The base type for these functions is [IO[T]](https://pkg.go.dev/github.com/IBM/fp-go/io) because in many cases such functions represent `I/O` operations.
#### Without Errors
If your effectful function does not return an error, the functional signature is [IO[T]](https://pkg.go.dev/github.com/IBM/fp-go/io)
#### With Errors
If your effectful function can return an error, the functional signature is [IOEither[error, T]](https://pkg.go.dev/github.com/IBM/fp-go/ioeither). Use `EitherizeXXX` from ["github.com/IBM/fp-go/ioeither"](https://pkg.go.dev/github.com/IBM/fp-go/ioeither) to convert an idiomatic go function to functional style.
### Go Context
Functions that take a [context](https://pkg.go.dev/context) are per definition effectful because they depend on the context parameter that is designed to be mutable (it can e.g. be used to cancel a running operation). Furthermore in idiomatic go the parameter is typically passed as the first parameter to a function.
In functional style we isolate the [context](https://pkg.go.dev/context) and represent the nature of the effectful function as an [IOEither[error, T]](https://pkg.go.dev/github.com/IBM/fp-go/ioeither). The resulting type is [ReaderIOEither[T]](https://pkg.go.dev/github.com/IBM/fp-go/context/readerioeither), a function taking a [context](https://pkg.go.dev/context) that returns a function without parameters returning an [Either[error, T]](https://pkg.go.dev/github.com/IBM/fp-go/either). Use the `EitherizeXXX` methods from ["github.com/IBM/fp-go/context/readerioeither"](https://pkg.go.dev/github.com/IBM/fp-go/context/readerioeither) to convert an idiomatic go function with a [context](https://pkg.go.dev/context) to functional style.
## Implementation Notes
### Generics
@@ -147,7 +183,7 @@ The `Map` operation for `ReaderIOEither` is defined as:
func Map[R, E, A, B any](f func(A) B) func(fa ReaderIOEither[R, E, A]) ReaderIOEither[R, E, B]
```
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):
and in fact the equivalent operations for all other monads 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):
```go
func Map[HKT, R, E, A, B any](f func(A) B) func(HKT[R, E, A]) HKT[R, E, B]
@@ -158,3 +194,14 @@ this would be the completely generic method signature for all possible monads. I
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.
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.
## Map/Ap/Flap
The following table lists the relationship between some selected operators
| Opertator | Parameter | Monad | Result |
| -------- | ---------------- | --------------- | -------- |
| Map | `func(A) B` | `HKT[A]` | `HKT[B]` |
| Chain | `func(A) HKT[B]` | `HKT[A]` | `HKT[B]` |
| Ap | `HKT[A]` | `HKT[func(A)B]` | `HKT[B]` |
| Flap | `A` | `HKT[func(A)B]` | `HKT[B]` |

View File

@@ -108,10 +108,16 @@ func MonadFilterMap[A, B any](fa []A, f func(a A) O.Option[B]) []B {
return G.MonadFilterMap[[]A, []B](fa, f)
}
// FilterChain 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 A) O.Option[B]) func([]A) []B {
return G.FilterMap[[]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)
@@ -144,7 +150,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 {
@@ -181,12 +187,11 @@ func Ap[B, A any](fa []A) func([]func(A) B) []B {
}
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] {
@@ -231,14 +236,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 {
@@ -281,3 +286,33 @@ func IsNonNil[A any](as []A) bool {
func ConstNil[A any]() []A {
return array.ConstNil[[]A]()
}
func SliceRight[A any](start int) func([]A) []A {
return G.SliceRight[[]A](start)
}
func Copy[A any](b []A) []A {
return G.Copy(b)
}
// 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)
}
// 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) func([]A) []A {
return G.Push[[]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)
}

View File

@@ -16,6 +16,7 @@
package array
import (
"fmt"
"strings"
"testing"
@@ -142,3 +143,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
}

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}}]
}

View File

@@ -18,6 +18,8 @@ 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"
)
@@ -27,6 +29,14 @@ func Of[GA ~[]A, A any](value A) GA {
return GA{value}
}
func Reduce[GA ~[]A, A, B any](fa GA, f func(B, A) B, initial B) B {
return array.Reduce(fa, f, initial)
}
func ReduceWithIndex[GA ~[]A, A, B any](fa GA, f func(int, B, A) B, initial B) B {
return array.ReduceWithIndex(fa, f, initial)
}
// From constructs an array from a set of variadic arguments
func From[GA ~[]A, A any](data ...A) GA {
return data
@@ -104,6 +114,10 @@ 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 F.Bind2nd(MonadMap[GA, GB, A, B], f)
}
func Size[GA ~[]A, A any](as GA) int {
return len(as)
}
@@ -118,6 +132,17 @@ func MonadFilterMap[GA ~[]A, GB ~[]B, A, B any](fa GA, f func(a A) O.Option[B])
return filterMap[GA, GB](fa, f)
}
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 A) O.Option[B]) func(GA) GB {
return F.Bind2nd(MonadFilterMap[GA, GB, A, B], f)
}
@@ -158,3 +183,79 @@ func MonadAp[BS ~[]B, ABS ~[]func(A) B, AS ~[]A, B, A any](fab ABS, fa AS) BS {
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 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 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[GA ~[]A, A any](a A) func(GA) GA {
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 F.Bind2nd(MonadFlap[FAB, GFAB, GB, A, B], a)
}

View File

@@ -18,11 +18,17 @@ 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
@@ -34,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],
)
}

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

@@ -16,10 +16,9 @@
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

@@ -20,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)

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

@@ -0,0 +1,124 @@
// 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"
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](as NonEmptyArray[A]) bool {
return false
}
func IsNonEmpty[A any](as 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 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))
}
}

View File

@@ -24,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)
}

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)
}

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 (self bounded[T]) Equals(x, y T) bool {
return self.e(x, y)
}
func (self bounded[T]) Compare(x, y T) int {
return self.c(x, y)
}
func (self bounded[T]) Top() T {
return self.t
}
func (self bounded[T]) Bottom() T {
return self.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

@@ -18,3 +18,7 @@ package bytes
func ToString(a []byte) string {
return string(a)
}
func Size(as []byte) int {
return len(as)
}

View File

@@ -388,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

@@ -266,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

@@ -31,5 +31,8 @@ func Commands() []*C.Command {
ContextReaderIOEitherCommand(),
ReaderIOEitherCommand(),
ReaderCommand(),
IOEitherCommand(),
IOCommand(),
IOOptionCommand(),
}
}

View File

@@ -115,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, "}")
}
@@ -150,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

@@ -27,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

@@ -62,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),
)
},
}
}

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

@@ -148,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

@@ -25,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)
@@ -83,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) {
@@ -144,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) {
@@ -337,7 +371,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)
@@ -347,6 +381,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++ {
@@ -364,6 +400,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

@@ -169,7 +169,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)

View File

@@ -20,6 +20,7 @@ import (
"log"
"os"
"path/filepath"
"strings"
"time"
C "github.com/urfave/cli/v2"
@@ -36,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++ {
@@ -294,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 {
@@ -355,14 +399,16 @@ 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 (
"fmt"
"encoding/json"
M "github.com/IBM/fp-go/monoid"
O "github.com/IBM/fp-go/ord"
O "github.com/IBM/fp-go/ord"
)
`)
@@ -386,11 +432,207 @@ 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 json.Marshal([]any{")
// 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, " var tmp []json.RawMessage\n")
fmt.Fprintf(f, " if err := json.Unmarshal(data, &tmp); err != nil {return err}\n")
fmt.Fprintf(f, " l := len(tmp)\n")
// unmarshal fields
for j := 1; j <= i; j++ {
fmt.Fprintf(f, " if l > %d {\n", j-1)
fmt.Fprintf(f, " if err := json.Unmarshal(tmp[%d], &t.F%d); err != nil {return err}\n", j-1, j)
}
fmt.Fprintf(f, " ")
for j := 1; j <= i; j++ {
fmt.Fprintf(f, "}")
}
fmt.Fprintf(f, "\n return nil\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.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 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",

View File

@@ -34,3 +34,7 @@ type Integer interface {
type Float interface {
~float32 | ~float64
}
type Complex interface {
~complex64 | ~complex128
}

View File

@@ -19,15 +19,14 @@ 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,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,41 +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 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,58 +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"
)
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,75 +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"
"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,57 +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 (
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

@@ -24,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

@@ -34,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

@@ -18,7 +18,6 @@ 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"
@@ -32,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)
}
@@ -48,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)
}
@@ -84,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)
}
@@ -119,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,42 +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 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,59 +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 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,80 +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 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,57 +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 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

@@ -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

@@ -19,7 +19,7 @@ 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)
}

View File

@@ -0,0 +1 @@
Carsten

View File

@@ -23,7 +23,7 @@ import (
EQ "github.com/IBM/fp-go/eq"
)
// Eq implements the equals predicate for values contained in the IOEither monad
// Eq implements the equals predicate for values contained in the [ReaderIOEither] monad
func Eq[A any](eq EQ.Eq[ET.Either[error, A]]) func(context.Context) EQ.Eq[ReaderIOEither[A]] {
return G.Eq[ReaderIOEither[A]](eq)
}

View File

@@ -25,30 +25,36 @@ import (
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/file"
IOE "github.com/IBM/fp-go/ioeither"
IOEF "github.com/IBM/fp-go/ioeither/file"
)
var (
openIOE = IOE.Eitherize1(os.Open)
// Open opens a file for reading within the given context
Open = F.Flow3(
openIOE,
IOEF.Open,
RIOE.FromIOEither[*os.File],
RIOE.WithContext[*os.File],
)
// Remove removes a file by name
Remove = F.Flow2(
IOEF.Remove,
RIOE.FromIOEither[string],
)
)
// Close closes an object
func Close[C io.Closer](c C) RIOE.ReaderIOEither[any] {
return RIOE.FromIOEither(func() ET.Either[error, any] {
return ET.TryCatchError(func() (any, error) {
return c, c.Close()
})
})
return F.Pipe2(
c,
IOEF.Close[C],
RIOE.FromIOEither[any],
)
}
// ReadFile reads a file in the scope of a context
func ReadFile(path string) RIOE.ReaderIOEither[[]byte] {
return RIOE.WithResource[*os.File, []byte](Open(path), Close[*os.File])(func(r *os.File) RIOE.ReaderIOEither[[]byte] {
return RIOE.WithResource[[]byte](Open(path), Close[*os.File])(func(r *os.File) RIOE.ReaderIOEither[[]byte] {
return func(ctx context.Context) IOE.IOEither[error, []byte] {
return IOE.MakeIO(func() ET.Either[error, []byte] {
return file.ReadAll(ctx, r)

View File

@@ -19,9 +19,7 @@ import (
"context"
"fmt"
RIO "github.com/IBM/fp-go/context/readerio"
R "github.com/IBM/fp-go/context/readerioeither"
"github.com/IBM/fp-go/errors"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io"
J "github.com/IBM/fp-go/json"
@@ -37,20 +35,17 @@ func getData(r RecordType) string {
func ExampleReadFile() {
data := F.Pipe4(
data := F.Pipe3(
ReadFile("./data/file.json"),
R.ChainEitherK(J.Unmarshal[RecordType]),
R.ChainFirstIOK(IO.Logf[RecordType]("Log: %v")),
R.Map(getData),
R.GetOrElse(F.Flow2(
errors.ToString,
RIO.Of[string],
)),
)
result := data(context.Background())
fmt.Println(result())
// Output: Carsten
// Output:
// Right[<nil>, string](Carsten)
}

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 file
import (
"os"
RIOE "github.com/IBM/fp-go/context/readerioeither"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io"
IOF "github.com/IBM/fp-go/io/file"
IOEF "github.com/IBM/fp-go/ioeither/file"
)
var (
// onCreateTempFile creates a temp file with sensible defaults
onCreateTempFile = CreateTemp("", "*")
// destroy handler
onReleaseTempFile = F.Flow4(
IOF.Close[*os.File],
IO.Map((*os.File).Name),
RIOE.FromIO[string],
RIOE.Chain(Remove),
)
)
// CreateTemp created a temp file with proper parametrization
func CreateTemp(dir, pattern string) RIOE.ReaderIOEither[*os.File] {
return F.Pipe2(
IOEF.CreateTemp(dir, pattern),
RIOE.FromIOEither[*os.File],
RIOE.WithContext[*os.File],
)
}
// WithTempFile creates a temporary file, then invokes a callback to create a resource based on the file, then close and remove the temp file
func WithTempFile[A any](f func(*os.File) RIOE.ReaderIOEither[A]) RIOE.ReaderIOEither[A] {
return RIOE.WithResource[A](onCreateTempFile, onReleaseTempFile)(f)
}

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 file
import (
"context"
"os"
"testing"
RIOE "github.com/IBM/fp-go/context/readerioeither"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
"github.com/stretchr/testify/assert"
)
func TestWithTempFile(t *testing.T) {
res := WithTempFile(onWriteAll[*os.File]([]byte("Carsten")))
assert.Equal(t, E.Of[error]([]byte("Carsten")), res(context.Background())())
}
func TestWithTempFileOnClosedFile(t *testing.T) {
res := WithTempFile(func(f *os.File) RIOE.ReaderIOEither[[]byte] {
return F.Pipe2(
f,
onWriteAll[*os.File]([]byte("Carsten")),
RIOE.ChainFirst(F.Constant1[[]byte](Close(f))),
)
})
assert.Equal(t, E.Of[error]([]byte("Carsten")), res(context.Background())())
}

View File

@@ -0,0 +1,57 @@
// 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 file
import (
"context"
"io"
RIOE "github.com/IBM/fp-go/context/readerioeither"
F "github.com/IBM/fp-go/function"
)
func onWriteAll[W io.Writer](data []byte) func(w W) RIOE.ReaderIOEither[[]byte] {
return func(w W) RIOE.ReaderIOEither[[]byte] {
return F.Pipe1(
RIOE.TryCatch(func(ctx context.Context) func() ([]byte, error) {
return func() ([]byte, error) {
_, err := w.Write(data)
return data, err
}
}),
RIOE.WithContext[[]byte],
)
}
}
// WriteAll uses a generator function to create a stream, writes data to it and closes it
func WriteAll[W io.WriteCloser](data []byte) func(acquire RIOE.ReaderIOEither[W]) RIOE.ReaderIOEither[[]byte] {
onWrite := onWriteAll[W](data)
return func(onCreate RIOE.ReaderIOEither[W]) RIOE.ReaderIOEither[[]byte] {
return RIOE.WithResource[[]byte](
onCreate,
Close[W])(
onWrite,
)
}
}
// Write uses a generator function to create a stream, writes data to it and closes it
func Write[R any, W io.WriteCloser](acquire RIOE.ReaderIOEither[W]) func(use func(W) RIOE.ReaderIOEither[R]) RIOE.ReaderIOEither[R] {
return RIOE.WithResource[R](
acquire,
Close[W])
}

View File

@@ -1,23 +1,9 @@
// 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
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at
// 2023-07-21 10:22:43.4901011 +0200 CEST m=+0.009264601
// 2023-10-23 08:30:39.012572 +0200 CEST m=+0.008846101
import (
"context"
@@ -29,515 +15,515 @@ import (
// Eitherize0 converts a function with 0 parameters returning a tuple into a function with 0 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize0]
func Eitherize0[F ~func(context.Context) (R, error), R any](f F) func() ReaderIOEither[R] {
return G.Eitherize0[ReaderIOEither[R]](f)
return G.Eitherize0[ReaderIOEither[R]](f)
}
// Eitherize1 converts a function with 1 parameters returning a tuple into a function with 1 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize1]
func Eitherize1[F ~func(context.Context, T0) (R, error), T0, R any](f F) func(T0) ReaderIOEither[R] {
return G.Eitherize1[ReaderIOEither[R]](f)
return G.Eitherize1[ReaderIOEither[R]](f)
}
// SequenceT1 converts 1 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceT1[T1 any](t1 ReaderIOEither[T1]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceT1[ReaderIOEither[T.Tuple1[T1]]](t1)
return G.SequenceT1[ReaderIOEither[T.Tuple1[T1]]](t1)
}
// SequenceSeqT1 converts 1 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceSeqT1[T1 any](t1 ReaderIOEither[T1]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceSeqT1[ReaderIOEither[T.Tuple1[T1]]](t1)
return G.SequenceSeqT1[ReaderIOEither[T.Tuple1[T1]]](t1)
}
// SequenceParT1 converts 1 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceParT1[T1 any](t1 ReaderIOEither[T1]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceParT1[ReaderIOEither[T.Tuple1[T1]]](t1)
return G.SequenceParT1[ReaderIOEither[T.Tuple1[T1]]](t1)
}
// SequenceTuple1 converts a [T.Tuple1] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceTuple1[T1 any](t T.Tuple1[ReaderIOEither[T1]]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
return G.SequenceTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
}
// SequenceSeqTuple1 converts a [T.Tuple1] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceSeqTuple1[T1 any](t T.Tuple1[ReaderIOEither[T1]]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceSeqTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
return G.SequenceSeqTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
}
// SequenceParTuple1 converts a [T.Tuple1] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func SequenceParTuple1[T1 any](t T.Tuple1[ReaderIOEither[T1]]) ReaderIOEither[T.Tuple1[T1]] {
return G.SequenceParTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
return G.SequenceParTuple1[ReaderIOEither[T.Tuple1[T1]]](t)
}
// TraverseTuple1 converts a [T.Tuple1] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func TraverseTuple1[F1 ~func(A1) ReaderIOEither[T1], A1, T1 any](f1 F1) func(T.Tuple1[A1]) ReaderIOEither[T.Tuple1[T1]] {
return G.TraverseTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
return G.TraverseTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
}
// TraverseSeqTuple1 converts a [T.Tuple1] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func TraverseSeqTuple1[F1 ~func(A1) ReaderIOEither[T1], A1, T1 any](f1 F1) func(T.Tuple1[A1]) ReaderIOEither[T.Tuple1[T1]] {
return G.TraverseSeqTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
return G.TraverseSeqTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
}
// TraverseParTuple1 converts a [T.Tuple1] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple1].
func TraverseParTuple1[F1 ~func(A1) ReaderIOEither[T1], A1, T1 any](f1 F1) func(T.Tuple1[A1]) ReaderIOEither[T.Tuple1[T1]] {
return G.TraverseParTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
return G.TraverseParTuple1[ReaderIOEither[T.Tuple1[T1]]](f1)
}
// Eitherize2 converts a function with 2 parameters returning a tuple into a function with 2 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize2]
func Eitherize2[F ~func(context.Context, T0, T1) (R, error), T0, T1, R any](f F) func(T0, T1) ReaderIOEither[R] {
return G.Eitherize2[ReaderIOEither[R]](f)
return G.Eitherize2[ReaderIOEither[R]](f)
}
// SequenceT2 converts 2 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceT2[T1, T2 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
return G.SequenceT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
}
// SequenceSeqT2 converts 2 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceSeqT2[T1, T2 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceSeqT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
return G.SequenceSeqT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
}
// SequenceParT2 converts 2 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceParT2[T1, T2 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceParT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
return G.SequenceParT2[ReaderIOEither[T.Tuple2[T1, T2]]](t1, t2)
}
// SequenceTuple2 converts a [T.Tuple2] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceTuple2[T1, T2 any](t T.Tuple2[ReaderIOEither[T1], ReaderIOEither[T2]]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
return G.SequenceTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
}
// SequenceSeqTuple2 converts a [T.Tuple2] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceSeqTuple2[T1, T2 any](t T.Tuple2[ReaderIOEither[T1], ReaderIOEither[T2]]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceSeqTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
return G.SequenceSeqTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
}
// SequenceParTuple2 converts a [T.Tuple2] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func SequenceParTuple2[T1, T2 any](t T.Tuple2[ReaderIOEither[T1], ReaderIOEither[T2]]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.SequenceParTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
return G.SequenceParTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](t)
}
// TraverseTuple2 converts a [T.Tuple2] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func TraverseTuple2[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], A1, T1, A2, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.TraverseTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
return G.TraverseTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
}
// TraverseSeqTuple2 converts a [T.Tuple2] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func TraverseSeqTuple2[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], A1, T1, A2, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.TraverseSeqTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
return G.TraverseSeqTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
}
// TraverseParTuple2 converts a [T.Tuple2] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple2].
func TraverseParTuple2[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], A1, T1, A2, T2 any](f1 F1, f2 F2) func(T.Tuple2[A1, A2]) ReaderIOEither[T.Tuple2[T1, T2]] {
return G.TraverseParTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
return G.TraverseParTuple2[ReaderIOEither[T.Tuple2[T1, T2]]](f1, f2)
}
// Eitherize3 converts a function with 3 parameters returning a tuple into a function with 3 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize3]
func Eitherize3[F ~func(context.Context, T0, T1, T2) (R, error), T0, T1, T2, R any](f F) func(T0, T1, T2) ReaderIOEither[R] {
return G.Eitherize3[ReaderIOEither[R]](f)
return G.Eitherize3[ReaderIOEither[R]](f)
}
// SequenceT3 converts 3 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceT3[T1, T2, T3 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
return G.SequenceT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
}
// SequenceSeqT3 converts 3 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceSeqT3[T1, T2, T3 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceSeqT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
return G.SequenceSeqT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
}
// SequenceParT3 converts 3 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceParT3[T1, T2, T3 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceParT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
return G.SequenceParT3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t1, t2, t3)
}
// SequenceTuple3 converts a [T.Tuple3] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceTuple3[T1, T2, T3 any](t T.Tuple3[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3]]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
return G.SequenceTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
}
// SequenceSeqTuple3 converts a [T.Tuple3] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceSeqTuple3[T1, T2, T3 any](t T.Tuple3[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3]]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceSeqTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
return G.SequenceSeqTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
}
// SequenceParTuple3 converts a [T.Tuple3] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func SequenceParTuple3[T1, T2, T3 any](t T.Tuple3[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3]]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.SequenceParTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
return G.SequenceParTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](t)
}
// TraverseTuple3 converts a [T.Tuple3] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func TraverseTuple3[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], A1, T1, A2, T2, A3, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.TraverseTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
return G.TraverseTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
}
// TraverseSeqTuple3 converts a [T.Tuple3] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func TraverseSeqTuple3[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], A1, T1, A2, T2, A3, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.TraverseSeqTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
return G.TraverseSeqTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
}
// TraverseParTuple3 converts a [T.Tuple3] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple3].
func TraverseParTuple3[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], A1, T1, A2, T2, A3, T3 any](f1 F1, f2 F2, f3 F3) func(T.Tuple3[A1, A2, A3]) ReaderIOEither[T.Tuple3[T1, T2, T3]] {
return G.TraverseParTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
return G.TraverseParTuple3[ReaderIOEither[T.Tuple3[T1, T2, T3]]](f1, f2, f3)
}
// Eitherize4 converts a function with 4 parameters returning a tuple into a function with 4 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize4]
func Eitherize4[F ~func(context.Context, T0, T1, T2, T3) (R, error), T0, T1, T2, T3, R any](f F) func(T0, T1, T2, T3) ReaderIOEither[R] {
return G.Eitherize4[ReaderIOEither[R]](f)
return G.Eitherize4[ReaderIOEither[R]](f)
}
// SequenceT4 converts 4 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceT4[T1, T2, T3, T4 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
return G.SequenceT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
}
// SequenceSeqT4 converts 4 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceSeqT4[T1, T2, T3, T4 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceSeqT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
return G.SequenceSeqT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
}
// SequenceParT4 converts 4 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceParT4[T1, T2, T3, T4 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceParT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
return G.SequenceParT4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t1, t2, t3, t4)
}
// SequenceTuple4 converts a [T.Tuple4] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceTuple4[T1, T2, T3, T4 any](t T.Tuple4[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4]]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
return G.SequenceTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
}
// SequenceSeqTuple4 converts a [T.Tuple4] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceSeqTuple4[T1, T2, T3, T4 any](t T.Tuple4[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4]]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceSeqTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
return G.SequenceSeqTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
}
// SequenceParTuple4 converts a [T.Tuple4] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func SequenceParTuple4[T1, T2, T3, T4 any](t T.Tuple4[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4]]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.SequenceParTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
return G.SequenceParTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](t)
}
// TraverseTuple4 converts a [T.Tuple4] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func TraverseTuple4[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], A1, T1, A2, T2, A3, T3, A4, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.TraverseTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
return G.TraverseTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
}
// TraverseSeqTuple4 converts a [T.Tuple4] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func TraverseSeqTuple4[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], A1, T1, A2, T2, A3, T3, A4, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.TraverseSeqTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
return G.TraverseSeqTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
}
// TraverseParTuple4 converts a [T.Tuple4] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple4].
func TraverseParTuple4[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], A1, T1, A2, T2, A3, T3, A4, T4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(T.Tuple4[A1, A2, A3, A4]) ReaderIOEither[T.Tuple4[T1, T2, T3, T4]] {
return G.TraverseParTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
return G.TraverseParTuple4[ReaderIOEither[T.Tuple4[T1, T2, T3, T4]]](f1, f2, f3, f4)
}
// Eitherize5 converts a function with 5 parameters returning a tuple into a function with 5 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize5]
func Eitherize5[F ~func(context.Context, T0, T1, T2, T3, T4) (R, error), T0, T1, T2, T3, T4, R any](f F) func(T0, T1, T2, T3, T4) ReaderIOEither[R] {
return G.Eitherize5[ReaderIOEither[R]](f)
return G.Eitherize5[ReaderIOEither[R]](f)
}
// SequenceT5 converts 5 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceT5[T1, T2, T3, T4, T5 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
return G.SequenceT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
}
// SequenceSeqT5 converts 5 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceSeqT5[T1, T2, T3, T4, T5 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceSeqT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
return G.SequenceSeqT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
}
// SequenceParT5 converts 5 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceParT5[T1, T2, T3, T4, T5 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceParT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
return G.SequenceParT5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t1, t2, t3, t4, t5)
}
// SequenceTuple5 converts a [T.Tuple5] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceTuple5[T1, T2, T3, T4, T5 any](t T.Tuple5[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5]]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
return G.SequenceTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
}
// SequenceSeqTuple5 converts a [T.Tuple5] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceSeqTuple5[T1, T2, T3, T4, T5 any](t T.Tuple5[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5]]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceSeqTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
return G.SequenceSeqTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
}
// SequenceParTuple5 converts a [T.Tuple5] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func SequenceParTuple5[T1, T2, T3, T4, T5 any](t T.Tuple5[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5]]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.SequenceParTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
return G.SequenceParTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](t)
}
// TraverseTuple5 converts a [T.Tuple5] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func TraverseTuple5[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.TraverseTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
return G.TraverseTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
}
// TraverseSeqTuple5 converts a [T.Tuple5] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func TraverseSeqTuple5[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.TraverseSeqTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
return G.TraverseSeqTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
}
// TraverseParTuple5 converts a [T.Tuple5] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple5].
func TraverseParTuple5[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(T.Tuple5[A1, A2, A3, A4, A5]) ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]] {
return G.TraverseParTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
return G.TraverseParTuple5[ReaderIOEither[T.Tuple5[T1, T2, T3, T4, T5]]](f1, f2, f3, f4, f5)
}
// Eitherize6 converts a function with 6 parameters returning a tuple into a function with 6 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize6]
func Eitherize6[F ~func(context.Context, T0, T1, T2, T3, T4, T5) (R, error), T0, T1, T2, T3, T4, T5, R any](f F) func(T0, T1, T2, T3, T4, T5) ReaderIOEither[R] {
return G.Eitherize6[ReaderIOEither[R]](f)
return G.Eitherize6[ReaderIOEither[R]](f)
}
// SequenceT6 converts 6 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceT6[T1, T2, T3, T4, T5, T6 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
return G.SequenceT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
}
// SequenceSeqT6 converts 6 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceSeqT6[T1, T2, T3, T4, T5, T6 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceSeqT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
return G.SequenceSeqT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
}
// SequenceParT6 converts 6 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceParT6[T1, T2, T3, T4, T5, T6 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceParT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
return G.SequenceParT6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t1, t2, t3, t4, t5, t6)
}
// SequenceTuple6 converts a [T.Tuple6] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceTuple6[T1, T2, T3, T4, T5, T6 any](t T.Tuple6[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6]]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
return G.SequenceTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
}
// SequenceSeqTuple6 converts a [T.Tuple6] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceSeqTuple6[T1, T2, T3, T4, T5, T6 any](t T.Tuple6[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6]]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceSeqTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
return G.SequenceSeqTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
}
// SequenceParTuple6 converts a [T.Tuple6] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func SequenceParTuple6[T1, T2, T3, T4, T5, T6 any](t T.Tuple6[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6]]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.SequenceParTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
return G.SequenceParTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](t)
}
// TraverseTuple6 converts a [T.Tuple6] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func TraverseTuple6[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.TraverseTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
return G.TraverseTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
}
// TraverseSeqTuple6 converts a [T.Tuple6] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func TraverseSeqTuple6[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.TraverseSeqTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
return G.TraverseSeqTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
}
// TraverseParTuple6 converts a [T.Tuple6] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple6].
func TraverseParTuple6[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(T.Tuple6[A1, A2, A3, A4, A5, A6]) ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]] {
return G.TraverseParTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
return G.TraverseParTuple6[ReaderIOEither[T.Tuple6[T1, T2, T3, T4, T5, T6]]](f1, f2, f3, f4, f5, f6)
}
// Eitherize7 converts a function with 7 parameters returning a tuple into a function with 7 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize7]
func Eitherize7[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6) (R, error), T0, T1, T2, T3, T4, T5, T6, R any](f F) func(T0, T1, T2, T3, T4, T5, T6) ReaderIOEither[R] {
return G.Eitherize7[ReaderIOEither[R]](f)
return G.Eitherize7[ReaderIOEither[R]](f)
}
// SequenceT7 converts 7 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceT7[T1, T2, T3, T4, T5, T6, T7 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
return G.SequenceT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
}
// SequenceSeqT7 converts 7 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceSeqT7[T1, T2, T3, T4, T5, T6, T7 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceSeqT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
return G.SequenceSeqT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
}
// SequenceParT7 converts 7 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceParT7[T1, T2, T3, T4, T5, T6, T7 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceParT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
return G.SequenceParT7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t1, t2, t3, t4, t5, t6, t7)
}
// SequenceTuple7 converts a [T.Tuple7] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceTuple7[T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7]]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
return G.SequenceTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
}
// SequenceSeqTuple7 converts a [T.Tuple7] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceSeqTuple7[T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7]]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceSeqTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
return G.SequenceSeqTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
}
// SequenceParTuple7 converts a [T.Tuple7] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func SequenceParTuple7[T1, T2, T3, T4, T5, T6, T7 any](t T.Tuple7[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7]]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.SequenceParTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
return G.SequenceParTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](t)
}
// TraverseTuple7 converts a [T.Tuple7] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func TraverseTuple7[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(T.Tuple7[A1, A2, A3, A4, A5, A6, A7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.TraverseTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
return G.TraverseTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
}
// TraverseSeqTuple7 converts a [T.Tuple7] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func TraverseSeqTuple7[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(T.Tuple7[A1, A2, A3, A4, A5, A6, A7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.TraverseSeqTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
return G.TraverseSeqTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
}
// TraverseParTuple7 converts a [T.Tuple7] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple7].
func TraverseParTuple7[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(T.Tuple7[A1, A2, A3, A4, A5, A6, A7]) ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]] {
return G.TraverseParTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
return G.TraverseParTuple7[ReaderIOEither[T.Tuple7[T1, T2, T3, T4, T5, T6, T7]]](f1, f2, f3, f4, f5, f6, f7)
}
// Eitherize8 converts a function with 8 parameters returning a tuple into a function with 8 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize8]
func Eitherize8[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) ReaderIOEither[R] {
return G.Eitherize8[ReaderIOEither[R]](f)
return G.Eitherize8[ReaderIOEither[R]](f)
}
// SequenceT8 converts 8 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
return G.SequenceT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
}
// SequenceSeqT8 converts 8 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceSeqT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceSeqT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
return G.SequenceSeqT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
}
// SequenceParT8 converts 8 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceParT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceParT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
return G.SequenceParT8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t1, t2, t3, t4, t5, t6, t7, t8)
}
// SequenceTuple8 converts a [T.Tuple8] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8]]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
return G.SequenceTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
}
// SequenceSeqTuple8 converts a [T.Tuple8] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceSeqTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8]]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceSeqTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
return G.SequenceSeqTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
}
// SequenceParTuple8 converts a [T.Tuple8] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func SequenceParTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t T.Tuple8[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8]]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.SequenceParTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
return G.SequenceParTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](t)
}
// TraverseTuple8 converts a [T.Tuple8] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func TraverseTuple8[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(T.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.TraverseTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
return G.TraverseTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
}
// TraverseSeqTuple8 converts a [T.Tuple8] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func TraverseSeqTuple8[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(T.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.TraverseSeqTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
return G.TraverseSeqTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
}
// TraverseParTuple8 converts a [T.Tuple8] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple8].
func TraverseParTuple8[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(T.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]] {
return G.TraverseParTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
return G.TraverseParTuple8[ReaderIOEither[T.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]](f1, f2, f3, f4, f5, f6, f7, f8)
}
// Eitherize9 converts a function with 9 parameters returning a tuple into a function with 9 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize9]
func Eitherize9[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) ReaderIOEither[R] {
return G.Eitherize9[ReaderIOEither[R]](f)
return G.Eitherize9[ReaderIOEither[R]](f)
}
// SequenceT9 converts 9 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
return G.SequenceT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
}
// SequenceSeqT9 converts 9 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceSeqT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceSeqT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
return G.SequenceSeqT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
}
// SequenceParT9 converts 9 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceParT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceParT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
return G.SequenceParT9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t1, t2, t3, t4, t5, t6, t7, t8, t9)
}
// SequenceTuple9 converts a [T.Tuple9] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9]]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
return G.SequenceTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
}
// SequenceSeqTuple9 converts a [T.Tuple9] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceSeqTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9]]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceSeqTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
return G.SequenceSeqTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
}
// SequenceParTuple9 converts a [T.Tuple9] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func SequenceParTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t T.Tuple9[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9]]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.SequenceParTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
return G.SequenceParTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](t)
}
// TraverseTuple9 converts a [T.Tuple9] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func TraverseTuple9[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(T.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.TraverseTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
return G.TraverseTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
}
// TraverseSeqTuple9 converts a [T.Tuple9] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func TraverseSeqTuple9[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(T.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.TraverseSeqTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
return G.TraverseSeqTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
}
// TraverseParTuple9 converts a [T.Tuple9] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple9].
func TraverseParTuple9[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(T.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] {
return G.TraverseParTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
return G.TraverseParTuple9[ReaderIOEither[T.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]](f1, f2, f3, f4, f5, f6, f7, f8, f9)
}
// Eitherize10 converts a function with 10 parameters returning a tuple into a function with 10 parameters returning a [ReaderIOEither[R]]
// The inverse function is [Uneitherize10]
func Eitherize10[F ~func(context.Context, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) ReaderIOEither[R] {
return G.Eitherize10[ReaderIOEither[R]](f)
return G.Eitherize10[ReaderIOEither[R]](f)
}
// SequenceT10 converts 10 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9], t10 ReaderIOEither[T10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
return G.SequenceT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
}
// SequenceSeqT10 converts 10 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceSeqT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9], t10 ReaderIOEither[T10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceSeqT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
return G.SequenceSeqT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
}
// SequenceParT10 converts 10 [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceParT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 ReaderIOEither[T1], t2 ReaderIOEither[T2], t3 ReaderIOEither[T3], t4 ReaderIOEither[T4], t5 ReaderIOEither[T5], t6 ReaderIOEither[T6], t7 ReaderIOEither[T7], t8 ReaderIOEither[T8], t9 ReaderIOEither[T9], t10 ReaderIOEither[T10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceParT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
return G.SequenceParT10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)
}
// SequenceTuple10 converts a [T.Tuple10] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9], ReaderIOEither[T10]]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
return G.SequenceTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
}
// SequenceSeqTuple10 converts a [T.Tuple10] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceSeqTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9], ReaderIOEither[T10]]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceSeqTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
return G.SequenceSeqTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
}
// SequenceParTuple10 converts a [T.Tuple10] of [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func SequenceParTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t T.Tuple10[ReaderIOEither[T1], ReaderIOEither[T2], ReaderIOEither[T3], ReaderIOEither[T4], ReaderIOEither[T5], ReaderIOEither[T6], ReaderIOEither[T7], ReaderIOEither[T8], ReaderIOEither[T9], ReaderIOEither[T10]]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.SequenceParTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
return G.SequenceParTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](t)
}
// TraverseTuple10 converts a [T.Tuple10] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func TraverseTuple10[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], F10 ~func(A10) ReaderIOEither[T10], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(T.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.TraverseTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
return G.TraverseTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
}
// TraverseSeqTuple10 converts a [T.Tuple10] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func TraverseSeqTuple10[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], F10 ~func(A10) ReaderIOEither[T10], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(T.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.TraverseSeqTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
return G.TraverseSeqTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
}
// TraverseParTuple10 converts a [T.Tuple10] of [A] via transformer functions transforming [A] to a [ReaderIOEither] into a [ReaderIOEither] of a [T.Tuple10].
func TraverseParTuple10[F1 ~func(A1) ReaderIOEither[T1], F2 ~func(A2) ReaderIOEither[T2], F3 ~func(A3) ReaderIOEither[T3], F4 ~func(A4) ReaderIOEither[T4], F5 ~func(A5) ReaderIOEither[T5], F6 ~func(A6) ReaderIOEither[T6], F7 ~func(A7) ReaderIOEither[T7], F8 ~func(A8) ReaderIOEither[T8], F9 ~func(A9) ReaderIOEither[T9], F10 ~func(A10) ReaderIOEither[T10], A1, T1, A2, T2, A3, T3, A4, T4, A5, T5, A6, T6, A7, T7, A8, T8, A9, T9, A10, T10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(T.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] {
return G.TraverseParTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
return G.TraverseParTuple10[ReaderIOEither[T.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]](f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
}

View File

@@ -0,0 +1,53 @@
// 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"
G "github.com/IBM/fp-go/internal/bracket"
I "github.com/IBM/fp-go/readerio/generic"
)
// 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[
GA ~func(context.Context) TA,
GB ~func(context.Context) TB,
GANY ~func(context.Context) TANY,
TA ~func() E.Either[error, A],
TB ~func() E.Either[error, B],
TANY ~func() E.Either[error, ANY],
A, B, ANY any](
acquire GA,
use func(A) GB,
release func(A, E.Either[error, B]) GANY,
) GB {
return G.Bracket[GA, GB, GANY, E.Either[error, B], A, B](
I.Of[GB, TB, context.Context, E.Either[error, B]],
MonadChain[GA, GB, TA, TB, A, B],
I.MonadChain[GB, GB, TB, TB, context.Context, E.Either[error, B], E.Either[error, B]],
MonadChain[GANY, GB, TANY, TB, ANY, B],
acquire,
use,
release,
)
}

File diff suppressed because it is too large Load Diff

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 generic
import (
"context"
ET "github.com/IBM/fp-go/either"
M "github.com/IBM/fp-go/monoid"
)
func ApplicativeMonoid[GRA ~func(context.Context) GIOA, GRFA ~func(context.Context) GIOFA, GIOA ~func() ET.Either[error, A], GIOFA ~func() ET.Either[error, func(A) A], A any](
m M.Monoid[A],
) M.Monoid[GRA] {
return M.ApplicativeMonoid(
Of[GRA],
MonadMap[GRA, GRFA],
MonadAp[GRA, GRA, GRFA],
m,
)
}
func ApplicativeMonoidSeq[GRA ~func(context.Context) GIOA, GRFA ~func(context.Context) GIOFA, GIOA ~func() ET.Either[error, A], GIOFA ~func() ET.Either[error, func(A) A], A any](
m M.Monoid[A],
) M.Monoid[GRA] {
return M.ApplicativeMonoid(
Of[GRA],
MonadMap[GRA, GRFA],
MonadApSeq[GRA, GRA, GRFA],
m,
)
}
func ApplicativeMonoidPar[GRA ~func(context.Context) GIOA, GRFA ~func(context.Context) GIOFA, GIOA ~func() ET.Either[error, A], GIOFA ~func() ET.Either[error, func(A) A], A any](
m M.Monoid[A],
) M.Monoid[GRA] {
return M.ApplicativeMonoid(
Of[GRA],
MonadMap[GRA, GRFA],
MonadApPar[GRA, GRA, GRFA],
m,
)
}

View File

@@ -100,6 +100,28 @@ func Map[
return RIE.Map[GRA, GRB](f)
}
func MonadMapTo[
GRA ~func(context.Context) GIOA,
GRB ~func(context.Context) GIOB,
GIOA ~func() E.Either[error, A],
GIOB ~func() E.Either[error, B],
A, B any](fa GRA, b B) GRB {
return RIE.MonadMapTo[GRA, GRB](fa, b)
}
func MapTo[
GRA ~func(context.Context) GIOA,
GRB ~func(context.Context) GIOB,
GIOA ~func() E.Either[error, A],
GIOB ~func() E.Either[error, B],
A, B any](b B) func(GRA) GRB {
return RIE.MapTo[GRA, GRB](b)
}
func MonadChain[
GRA ~func(context.Context) GIOA,
GRB ~func(context.Context) GIOB,
@@ -220,7 +242,7 @@ func MonadApPar[
fabIOE := withCancelCauseFunc(cancelSub, cfab(ctxSub))
faIOE := withCancelCauseFunc(cancelSub, cfa(ctxSub))
return IOE.MonadApPar[GIOA, GIOB, GIOAB](fabIOE, faIOE)()
return IOE.MonadApPar[GIOB, GIOAB](fabIOE, faIOE)()
}
}
}
@@ -410,10 +432,10 @@ func FromIOEither[
func FromIO[
GRA ~func(context.Context) GIOA,
GIOA ~func() E.Either[error, A],
GIOB ~func() A,
GIOA ~func() E.Either[error, A],
A any](t GIOB) GRA {
return RIE.FromIO[GRA](t)
}
@@ -458,6 +480,34 @@ func ChainIOK[
return RIE.ChainIOK[GRA, GRB](f)
}
func MonadChainReaderIOK[
GRB ~func(context.Context) GIOB,
GRA ~func(context.Context) GIOA,
GRIO ~func(context.Context) GIO,
GIOA ~func() E.Either[error, A],
GIOB ~func() E.Either[error, B],
GIO ~func() B,
A, B any](ma GRA, f func(A) GRIO) GRB {
return RIE.MonadChainReaderIOK[GRA, GRB](ma, f)
}
func ChainReaderIOK[
GRB ~func(context.Context) GIOB,
GRA ~func(context.Context) GIOA,
GRIO ~func(context.Context) GIO,
GIOA ~func() E.Either[error, A],
GIOB ~func() E.Either[error, B],
GIO ~func() B,
A, B any](f func(A) GRIO) func(ma GRA) GRB {
return RIE.ChainReaderIOK[GRA, GRB](f)
}
func MonadChainFirstIOK[
GRA ~func(context.Context) GIOA,
GIOA ~func() E.Either[error, A],
@@ -521,7 +571,7 @@ func Timer[
](delay time.Duration) GRA {
return F.Pipe2(
IO.Now[func() time.Time](),
FromIO[GRA, GIOA, func() time.Time],
FromIO[GRA, func() time.Time],
Delay[GRA](delay),
)
}
@@ -543,3 +593,82 @@ func TryCatch[
A any](f func(context.Context) func() (A, error)) GRA {
return RIE.TryCatch[GRA](f, ER.IdentityError)
}
func MonadAlt[LAZY ~func() GEA, GEA ~func(context.Context) GIOA, GIOA ~func() E.Either[error, A], A any](first GEA, second LAZY) GEA {
return RIE.MonadAlt(first, second)
}
func Alt[LAZY ~func() GEA, GEA ~func(context.Context) GIOA, GIOA ~func() E.Either[error, A], A any](second LAZY) func(GEA) GEA {
return RIE.Alt(second)
}
// Memoize computes the value of the provided monad lazily but exactly once
// The context used to compute the value is the context of the first call, so do not use this
// method if the value has a functional dependency on the content of the context
func Memoize[
GRA ~func(context.Context) GIOA,
GIOA ~func() E.Either[error, A],
A any](rdr GRA) GRA {
return RIE.Memoize[GRA](rdr)
}
func Flatten[
GGRA ~func(context.Context) GGIOA,
GGIOA ~func() E.Either[error, GRA],
GRA ~func(context.Context) GIOA,
GIOA ~func() E.Either[error, A],
A any](rdr GGRA) GRA {
return RIE.Flatten[GRA](rdr)
}
func MonadFromReaderIO[
GRIOEA ~func(context.Context) GIOEA,
GIOEA ~func() E.Either[error, A],
GRIOA ~func(context.Context) GIOA,
GIOA ~func() A,
A any](a A, f func(A) GRIOA) GRIOEA {
return RIE.MonadFromReaderIO[GRIOEA](a, f)
}
func FromReaderIO[
GRIOEA ~func(context.Context) GIOEA,
GIOEA ~func() E.Either[error, A],
GRIOA ~func(context.Context) GIOA,
GIOA ~func() A,
A any](f func(A) GRIOA) func(A) GRIOEA {
return RIE.FromReaderIO[GRIOEA](f)
}
func RightReaderIO[
GRIOEA ~func(context.Context) GIOEA,
GIOEA ~func() E.Either[error, A],
GRIOA ~func(context.Context) GIOA,
GIOA ~func() A,
A any](ma GRIOA) GRIOEA {
return RIE.RightReaderIO[GRIOEA](ma)
}
func LeftReaderIO[
GRIOEA ~func(context.Context) GIOEA,
GIOEA ~func() E.Either[error, A],
GRIOE ~func(context.Context) GIOE,
GIOE ~func() error,
A any](ma GRIOE) GRIOEA {
return RIE.LeftReaderIO[GRIOEA](ma)
}
func MonadFlap[GREAB ~func(context.Context) GEAB, GREB ~func(context.Context) GEB, GEAB ~func() E.Either[error, func(A) B], GEB ~func() E.Either[error, B], B, A any](fab GREAB, a A) GREB {
return RIE.MonadFlap[GREAB, GREB](fab, a)
}
func Flap[GREAB ~func(context.Context) GEAB, GREB ~func(context.Context) GEB, GEAB ~func() E.Either[error, func(A) B], GEB ~func() E.Either[error, B], B, A any](a A) func(GREAB) GREB {
return RIE.Flap[GREAB, GREB](a)
}

View File

@@ -13,18 +13,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package reader
package generic
import (
R "github.com/IBM/fp-go/reader/generic"
"context"
ET "github.com/IBM/fp-go/either"
S "github.com/IBM/fp-go/semigroup"
)
// TraverseArray transforms an array
func TraverseArray[A, B any](f func(A) Reader[B]) func([]A) Reader[[]B] {
return R.TraverseArray[Reader[B], Reader[[]B], []A](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[A any](ma []Reader[A]) Reader[[]A] {
return R.SequenceArray[Reader[A], Reader[[]A]](ma)
func AltSemigroup[GRA ~func(context.Context) GIOA, GIOA ~func() ET.Either[error, A], A any]() S.Semigroup[GRA] {
return S.AltSemigroup(
MonadAlt[func() GRA],
)
}

View File

@@ -0,0 +1,44 @@
// 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"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io/generic"
)
// WithLock executes the provided IO operation in the scope of a lock
func WithLock[
GRA ~func(context.Context) GIOA,
GIOA ~func() E.Either[error, A],
GRCANCEL ~func(context.Context) GIOCANCEL,
GIOCANCEL ~func() E.Either[error, context.CancelFunc],
A any](lock GRCANCEL) func(fa GRA) GRA {
type GRANY func(ctx context.Context) func() E.Either[error, any]
type IOANY func() any
return F.Flow2(
F.Constant1[context.CancelFunc, GRA],
WithResource[GRA, GRCANCEL, GRANY](lock, F.Flow2(
IO.FromImpure[IOANY, context.CancelFunc],
FromIO[GRANY, IOANY],
)),
)
}

View File

@@ -62,6 +62,25 @@ func TraverseArray[
)
}
// TraverseArrayWithIndex transforms an array
func TraverseArrayWithIndex[
AS ~[]A,
GRBS ~func(context.Context) GIOBS,
GRB ~func(context.Context) GIOB,
GIOBS ~func() E.Either[error, BS],
GIOB ~func() E.Either[error, B],
BS ~[]B,
A, B any](f func(int, A) GRB) func(AS) GRBS {
return RA.TraverseWithIndex[AS](
Of[GRBS, GIOBS, BS],
Map[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GIOBS, func() E.Either[error, func(B) BS], BS, func(B) BS],
Ap[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
f,
)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[
AS ~[]A,
@@ -115,6 +134,26 @@ func TraverseRecord[K comparable,
)
}
// TraverseRecordWithIndex transforms a record
func TraverseRecordWithIndex[K comparable,
AS ~map[K]A,
GRBS ~func(context.Context) GIOBS,
GRB ~func(context.Context) GIOB,
GIOBS ~func() E.Either[error, BS],
GIOB ~func() E.Either[error, B],
BS ~map[K]B,
A, B any](f func(K, A) GRB) func(AS) GRBS {
return RR.TraverseWithIndex[AS](
Of[GRBS, GIOBS, BS],
Map[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GIOBS, func() E.Either[error, func(B) BS], BS, func(B) BS],
Ap[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
f,
)
}
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
func SequenceRecord[K comparable,
AS ~map[K]A,

View File

@@ -21,6 +21,13 @@ import (
"testing"
H "net/http"
R "github.com/IBM/fp-go/context/readerioeither"
E "github.com/IBM/fp-go/either"
"github.com/IBM/fp-go/errors"
F "github.com/IBM/fp-go/function"
IOE "github.com/IBM/fp-go/ioeither"
"github.com/stretchr/testify/assert"
)
type PostItem struct {
@@ -30,6 +37,47 @@ type PostItem struct {
Body string `json:"body"`
}
func getTitle(item PostItem) string {
return item.Title
}
type simpleRequestBuilder struct {
method string
url string
headers H.Header
}
func requestBuilder() simpleRequestBuilder {
return simpleRequestBuilder{method: "GET"}
}
func (b simpleRequestBuilder) WithURL(url string) simpleRequestBuilder {
b.url = url
return b
}
func (b simpleRequestBuilder) WithHeader(key, value string) simpleRequestBuilder {
if b.headers == nil {
b.headers = make(H.Header)
} else {
b.headers = b.headers.Clone()
}
b.headers.Set(key, value)
return b
}
func (b simpleRequestBuilder) Build() R.ReaderIOEither[*H.Request] {
return func(ctx context.Context) IOE.IOEither[error, *H.Request] {
return IOE.TryCatchError(func() (*H.Request, error) {
req, err := H.NewRequestWithContext(ctx, b.method, b.url, nil)
if err == nil {
req.Header = b.headers
}
return req, err
})
}
}
func TestSendSingleRequest(t *testing.T) {
client := MakeClient(H.DefaultClient)
@@ -40,7 +88,70 @@ func TestSendSingleRequest(t *testing.T) {
resp1 := readItem(req1)
resE := resp1(context.Background())()
resE := resp1(context.TODO())()
fmt.Println(resE)
}
// setHeaderUnsafe updates a header value in a request object by mutating the request object
func setHeaderUnsafe(key, value string) func(*H.Request) *H.Request {
return func(req *H.Request) *H.Request {
req.Header.Set(key, value)
return req
}
}
func TestSendSingleRequestWithHeaderUnsafe(t *testing.T) {
client := MakeClient(H.DefaultClient)
// this is not safe from a puristic perspective, because the map call mutates the request object
req1 := F.Pipe2(
"https://jsonplaceholder.typicode.com/posts/1",
MakeGetRequest,
R.Map(setHeaderUnsafe("Content-Type", "text/html")),
)
readItem := ReadJson[PostItem](client)
resp1 := F.Pipe2(
req1,
readItem,
R.Map(getTitle),
)
res := F.Pipe1(
resp1(context.TODO())(),
E.GetOrElse(errors.ToString),
)
assert.Equal(t, "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", res)
}
func TestSendSingleRequestWithHeaderSafe(t *testing.T) {
client := MakeClient(H.DefaultClient)
// the request builder assembles config values to construct
// the final http request. Each `With` step creates a copy of the settings
// so the flow is pure
request := requestBuilder().
WithURL("https://jsonplaceholder.typicode.com/posts/1").
WithHeader("Content-Type", "text/html").
Build()
readItem := ReadJson[PostItem](client)
response := F.Pipe2(
request,
readItem,
R.Map(getTitle),
)
res := F.Pipe1(
response(context.TODO())(),
E.GetOrElse(errors.ToString),
)
assert.Equal(t, "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", res)
}

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 readerioeither
import (
G "github.com/IBM/fp-go/context/readerioeither/generic"
L "github.com/IBM/fp-go/lazy"
M "github.com/IBM/fp-go/monoid"
)
// ApplicativeMonoid returns a [Monoid] that concatenates [ReaderIOEither] instances via their applicative
func ApplicativeMonoid[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
return G.ApplicativeMonoid[ReaderIOEither[A], ReaderIOEither[func(A) A]](m)
}
// ApplicativeMonoidSeq returns a [Monoid] that concatenates [ReaderIOEither] instances via their applicative
func ApplicativeMonoidSeq[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
return G.ApplicativeMonoidSeq[ReaderIOEither[A], ReaderIOEither[func(A) A]](m)
}
// ApplicativeMonoidPar returns a [Monoid] that concatenates [ReaderIOEither] instances via their applicative
func ApplicativeMonoidPar[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
return G.ApplicativeMonoidPar[ReaderIOEither[A], ReaderIOEither[func(A) A]](m)
}
// AlternativeMonoid is the alternative [Monoid] for [ReaderIOEither]
func AlternativeMonoid[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
return M.AlternativeMonoid(
Of[A],
MonadMap[A, func(A) A],
MonadAp[A, A],
MonadAlt[A],
m,
)
}
// AltMonoid is the alternative [Monoid] for an [ReaderIOEither]
func AltMonoid[A any](zero L.Lazy[ReaderIOEither[A]]) M.Monoid[ReaderIOEither[A]] {
return M.AltMonoid(
zero,
MonadAlt[A],
)
}

View File

@@ -19,12 +19,11 @@ import (
"context"
"time"
R "github.com/IBM/fp-go/context/reader"
RIO "github.com/IBM/fp-go/context/readerio"
G "github.com/IBM/fp-go/context/readerioeither/generic"
ET "github.com/IBM/fp-go/either"
IO "github.com/IBM/fp-go/io"
IOE "github.com/IBM/fp-go/ioeither"
L "github.com/IBM/fp-go/lazy"
O "github.com/IBM/fp-go/option"
)
@@ -32,14 +31,6 @@ func FromEither[A any](e ET.Either[error, A]) ReaderIOEither[A] {
return G.FromEither[ReaderIOEither[A]](e)
}
func RightReader[A any](r R.Reader[A]) ReaderIOEither[A] {
return G.RightReader[ReaderIOEither[A]](r)
}
func LeftReader[A any](l R.Reader[error]) ReaderIOEither[A] {
return G.LeftReader[ReaderIOEither[A]](l)
}
func Left[A any](l error) ReaderIOEither[A] {
return G.Left[ReaderIOEither[A]](l)
}
@@ -48,10 +39,6 @@ func Right[A any](r A) ReaderIOEither[A] {
return G.Right[ReaderIOEither[A]](r)
}
func FromReader[A any](r R.Reader[A]) ReaderIOEither[A] {
return G.FromReader[ReaderIOEither[A]](r)
}
func MonadMap[A, B any](fa ReaderIOEither[A], f func(A) B) ReaderIOEither[B] {
return G.MonadMap[ReaderIOEither[A], ReaderIOEither[B]](fa, f)
}
@@ -60,6 +47,14 @@ func Map[A, B any](f func(A) B) func(ReaderIOEither[A]) ReaderIOEither[B] {
return G.Map[ReaderIOEither[A], ReaderIOEither[B]](f)
}
func MonadMapTo[A, B any](fa ReaderIOEither[A], b B) ReaderIOEither[B] {
return G.MonadMapTo[ReaderIOEither[A], ReaderIOEither[B]](fa, b)
}
func MapTo[A, B any](b B) func(ReaderIOEither[A]) ReaderIOEither[B] {
return G.MapTo[ReaderIOEither[A], ReaderIOEither[B]](b)
}
func MonadChain[A, B any](ma ReaderIOEither[A], f func(A) ReaderIOEither[B]) ReaderIOEither[B] {
return G.MonadChain(ma, f)
}
@@ -94,30 +89,14 @@ func FromPredicate[A any](pred func(A) bool, onFalse func(A) error) func(A) Read
return G.FromPredicate[ReaderIOEither[A]](pred, onFalse)
}
func Fold[A, B any](onLeft func(error) RIO.ReaderIO[B], onRight func(A) RIO.ReaderIO[B]) func(ReaderIOEither[A]) RIO.ReaderIO[B] {
return G.Fold[RIO.ReaderIO[B], ReaderIOEither[A]](onLeft, onRight)
}
func GetOrElse[A any](onLeft func(error) RIO.ReaderIO[A]) func(ReaderIOEither[A]) RIO.ReaderIO[A] {
return G.GetOrElse[RIO.ReaderIO[A], ReaderIOEither[A]](onLeft)
}
func OrElse[A any](onLeft func(error) ReaderIOEither[A]) func(ReaderIOEither[A]) ReaderIOEither[A] {
return G.OrElse[ReaderIOEither[A]](onLeft)
}
func OrLeft[A any](onLeft func(error) RIO.ReaderIO[error]) func(ReaderIOEither[A]) ReaderIOEither[A] {
return G.OrLeft[ReaderIOEither[A], RIO.ReaderIO[error]](onLeft)
}
func Ask() ReaderIOEither[context.Context] {
return G.Ask[ReaderIOEither[context.Context]]()
}
func Asks[A any](r R.Reader[A]) ReaderIOEither[A] {
return G.Asks[ReaderIOEither[A]](r)
}
func MonadChainEitherK[A, B any](ma ReaderIOEither[A], f func(A) ET.Either[error, B]) ReaderIOEither[B] {
return G.MonadChainEitherK[ReaderIOEither[A], ReaderIOEither[B]](ma, f)
}
@@ -146,6 +125,10 @@ func FromIO[A any](t IO.IO[A]) ReaderIOEither[A] {
return G.FromIO[ReaderIOEither[A]](t)
}
func FromLazy[A any](t L.Lazy[A]) ReaderIOEither[A] {
return G.FromIO[ReaderIOEither[A]](t)
}
// Never returns a 'ReaderIOEither' that never returns, except if its context gets canceled
func Never[A any]() ReaderIOEither[A] {
return G.Never[ReaderIOEither[A]]()
@@ -182,7 +165,7 @@ func Timer(delay time.Duration) ReaderIOEither[time.Time] {
}
// Defer creates an IO by creating a brand new IO via a generator function, each time
func Defer[A any](gen func() ReaderIOEither[A]) ReaderIOEither[A] {
func Defer[A any](gen L.Lazy[ReaderIOEither[A]]) ReaderIOEither[A] {
return G.Defer[ReaderIOEither[A]](gen)
}
@@ -190,3 +173,34 @@ func Defer[A any](gen func() ReaderIOEither[A]) ReaderIOEither[A] {
func TryCatch[A any](f func(context.Context) func() (A, error)) ReaderIOEither[A] {
return G.TryCatch[ReaderIOEither[A]](f)
}
// MonadAlt identifies an associative operation on a type constructor
func MonadAlt[A any](first ReaderIOEither[A], second L.Lazy[ReaderIOEither[A]]) ReaderIOEither[A] {
return G.MonadAlt(first, second)
}
// Alt identifies an associative operation on a type constructor
func Alt[A any](second L.Lazy[ReaderIOEither[A]]) func(ReaderIOEither[A]) ReaderIOEither[A] {
return G.Alt(second)
}
// Memoize computes the value of the provided [ReaderIOEither] monad lazily but exactly once
// The context used to compute the value is the context of the first call, so do not use this
// method if the value has a functional dependency on the content of the context
func Memoize[A any](rdr ReaderIOEither[A]) ReaderIOEither[A] {
return G.Memoize[ReaderIOEither[A]](rdr)
}
// Flatten converts a nested [ReaderIOEither] into a [ReaderIOEither]
func Flatten[
A any](rdr ReaderIOEither[ReaderIOEither[A]]) ReaderIOEither[A] {
return G.Flatten[ReaderIOEither[ReaderIOEither[A]]](rdr)
}
func MonadFlap[B, A any](fab ReaderIOEither[func(A) B], a A) ReaderIOEither[B] {
return G.MonadFlap[ReaderIOEither[func(A) B], ReaderIOEither[B]](fab, a)
}
func Flap[B, A any](a A) func(ReaderIOEither[func(A) B]) ReaderIOEither[B] {
return G.Flap[ReaderIOEither[func(A) B], ReaderIOEither[B]](a)
}

View File

@@ -162,3 +162,125 @@ func TestRegularApply(t *testing.T) {
res := applied(context.Background())()
assert.Equal(t, E.Of[error]("CARSTEN"), res)
}
func TestWithResourceNoErrors(t *testing.T) {
var countAcquire, countBody, countRelease int
acquire := FromLazy(func() int {
countAcquire++
return countAcquire
})
release := func(int) ReaderIOEither[int] {
return FromLazy(func() int {
countRelease++
return countRelease
})
}
body := func(int) ReaderIOEither[int] {
return FromLazy(func() int {
countBody++
return countBody
})
}
resRIOE := WithResource[int](acquire, release)(body)
res := resRIOE(context.Background())()
assert.Equal(t, 1, countAcquire)
assert.Equal(t, 1, countBody)
assert.Equal(t, 1, countRelease)
assert.Equal(t, E.Of[error](1), res)
}
func TestWithResourceErrorInBody(t *testing.T) {
var countAcquire, countBody, countRelease int
acquire := FromLazy(func() int {
countAcquire++
return countAcquire
})
release := func(int) ReaderIOEither[int] {
return FromLazy(func() int {
countRelease++
return countRelease
})
}
err := fmt.Errorf("error in body")
body := func(int) ReaderIOEither[int] {
return Left[int](err)
}
resRIOE := WithResource[int](acquire, release)(body)
res := resRIOE(context.Background())()
assert.Equal(t, 1, countAcquire)
assert.Equal(t, 0, countBody)
assert.Equal(t, 1, countRelease)
assert.Equal(t, E.Left[int](err), res)
}
func TestWithResourceErrorInAcquire(t *testing.T) {
var countAcquire, countBody, countRelease int
err := fmt.Errorf("error in acquire")
acquire := Left[int](err)
release := func(int) ReaderIOEither[int] {
return FromLazy(func() int {
countRelease++
return countRelease
})
}
body := func(int) ReaderIOEither[int] {
return FromLazy(func() int {
countBody++
return countBody
})
}
resRIOE := WithResource[int](acquire, release)(body)
res := resRIOE(context.Background())()
assert.Equal(t, 0, countAcquire)
assert.Equal(t, 0, countBody)
assert.Equal(t, 0, countRelease)
assert.Equal(t, E.Left[int](err), res)
}
func TestWithResourceErrorInRelease(t *testing.T) {
var countAcquire, countBody, countRelease int
acquire := FromLazy(func() int {
countAcquire++
return countAcquire
})
err := fmt.Errorf("error in release")
release := func(int) ReaderIOEither[int] {
return Left[int](err)
}
body := func(int) ReaderIOEither[int] {
return FromLazy(func() int {
countBody++
return countBody
})
}
resRIOE := WithResource[int](acquire, release)(body)
res := resRIOE(context.Background())()
assert.Equal(t, 1, countAcquire)
assert.Equal(t, 1, countBody)
assert.Equal(t, 0, countRelease)
assert.Equal(t, E.Left[int](err), res)
}

View File

@@ -20,7 +20,7 @@ import (
)
// WithResource constructs a function that creates a resource, then operates on it and then releases the resource
func WithResource[R, A, ANY any](onCreate ReaderIOEither[R], onRelease func(R) ReaderIOEither[ANY]) func(func(R) ReaderIOEither[A]) ReaderIOEither[A] {
func WithResource[A, R, ANY any](onCreate ReaderIOEither[R], onRelease func(R) ReaderIOEither[ANY]) func(func(R) ReaderIOEither[A]) ReaderIOEither[A] {
// wraps the callback functions with a context check
return G.WithResource[ReaderIOEither[A]](onCreate, onRelease)
}

View File

@@ -0,0 +1,79 @@
// 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"
"io"
"os"
B "github.com/IBM/fp-go/bytes"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io"
IOE "github.com/IBM/fp-go/ioeither"
)
var (
openFile = F.Flow3(
IOE.Eitherize1(os.Open),
FromIOEither[*os.File],
ChainFirstIOK(F.Flow2(
(*os.File).Name,
IO.Logf[string]("Opened file [%s]"),
)),
)
)
func closeFile(f *os.File) ReaderIOEither[string] {
return F.Pipe1(
TryCatch(func(_ context.Context) func() (string, error) {
return func() (string, error) {
return f.Name(), f.Close()
}
}),
ChainFirstIOK(IO.Logf[string]("Closed file [%s]")),
)
}
func ExampleWithResource() {
stringReader := WithResource[string](openFile("data/file.txt"), closeFile)
rdr := stringReader(func(f *os.File) ReaderIOEither[string] {
return F.Pipe2(
TryCatch(func(_ context.Context) func() ([]byte, error) {
return func() ([]byte, error) {
return io.ReadAll(f)
}
}),
ChainFirstIOK(F.Flow2(
B.Size,
IO.Logf[int]("Read content of length [%d]"),
)),
Map(B.ToString),
)
})
contentIOE := F.Pipe2(
context.Background(),
rdr,
IOE.ChainFirstIOK[error](IO.Printf[string]("Content: %s")),
)
contentIOE()
// Output: Content: Carsten
}

View File

@@ -0,0 +1,26 @@
// 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"
S "github.com/IBM/fp-go/semigroup"
)
// AltSemigroup is a [Semigroup] that tries the first item and then the second one using an alternative
func AltSemigroup[A any]() S.Semigroup[ReaderIOEither[A]] {
return G.AltSemigroup[ReaderIOEither[A]]()
}

View File

@@ -13,14 +13,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package reader implements a specialization of the Reader monad assuming a golang context as the context of the monad
package reader
package readerioeither
import (
"context"
R "github.com/IBM/fp-go/reader"
G "github.com/IBM/fp-go/context/readerioeither/generic"
)
// 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]
// WithLock executes the provided IO operation in the scope of a lock
func WithLock[A any](lock ReaderIOEither[context.CancelFunc]) func(fa ReaderIOEither[A]) ReaderIOEither[A] {
return G.WithLock[ReaderIOEither[A]](lock)
}

View File

@@ -24,6 +24,11 @@ func TraverseArray[A, B any](f func(A) ReaderIOEither[B]) func([]A) ReaderIOEith
return G.TraverseArray[[]A, ReaderIOEither[[]B]](f)
}
// TraverseArrayWithIndex uses transforms an array [[]A] into [[]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[[]B]]
func TraverseArrayWithIndex[A, B any](f func(int, A) ReaderIOEither[B]) func([]A) ReaderIOEither[[]B] {
return G.TraverseArrayWithIndex[[]A, ReaderIOEither[[]B]](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[A any](ma []ReaderIOEither[A]) ReaderIOEither[[]A] {
return G.SequenceArray[[]A, []ReaderIOEither[A], ReaderIOEither[[]A]](ma)
@@ -34,6 +39,11 @@ func TraverseRecord[K comparable, A, B any](f func(A) ReaderIOEither[B]) func(ma
return G.TraverseRecord[K, map[K]A, ReaderIOEither[map[K]B]](f)
}
// TraverseRecordWithIndex uses transforms a record [map[K]A] into [map[K]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[map[K]B]]
func TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) ReaderIOEither[B]) func(map[K]A) ReaderIOEither[map[K]B] {
return G.TraverseRecordWithIndex[K, map[K]A, ReaderIOEither[map[K]B]](f)
}
// SequenceRecord converts a homogeneous sequence of either into an either of sequence
func SequenceRecord[K comparable, A any](ma map[K]ReaderIOEither[A]) ReaderIOEither[map[K]A] {
return G.SequenceRecord[K, map[K]A, map[K]ReaderIOEither[A], ReaderIOEither[map[K]A]](ma)

View File

@@ -21,5 +21,6 @@ import (
RE "github.com/IBM/fp-go/readerioeither"
)
// ReaderIOEither is a specialization of the Reader monad for the typical golang scenario
// ReaderIOEither is a specialization of the [RE.ReaderIOEither] monad for the typical golang scenario in which the
// left value is an [error] and the context is a [context.Context]
type ReaderIOEither[A any] RE.ReaderIOEither[context.Context, error, A]

2
coverage.bat Normal file
View File

@@ -0,0 +1,2 @@
@echo off
go tool cover -html=build/cover.out -o build/cover.html

View File

@@ -24,6 +24,7 @@ func ApplySemigroup[E, A any](s S.Semigroup[A]) S.Semigroup[Either[E, A]] {
return S.ApplySemigroup(MonadMap[E, A, func(A) A], MonadAp[A, E, A], s)
}
// ApplicativeMonoid returns a [Monoid] that concatenates [Either] instances via their applicative
func ApplicativeMonoid[E, A any](m M.Monoid[A]) M.Monoid[Either[E, A]] {
return M.ApplicativeMonoid(Of[E, A], MonadMap[E, A, func(A) A], MonadAp[A, E, A], m)
}

74
either/array.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 either
import (
F "github.com/IBM/fp-go/function"
RA "github.com/IBM/fp-go/internal/array"
)
// TraverseArrayG transforms an array
func TraverseArrayG[GA ~[]A, GB ~[]B, E, A, B any](f func(A) Either[E, B]) func(GA) Either[E, GB] {
return RA.Traverse[GA](
Of[E, GB],
Map[E, GB, func(B) GB],
Ap[GB, E, B],
f,
)
}
// TraverseArray transforms an array
func TraverseArray[E, A, B any](f func(A) Either[E, B]) func([]A) Either[E, []B] {
return TraverseArrayG[[]A, []B](f)
}
// TraverseArrayWithIndexG transforms an array
func TraverseArrayWithIndexG[GA ~[]A, GB ~[]B, E, A, B any](f func(int, A) Either[E, B]) func(GA) Either[E, GB] {
return RA.TraverseWithIndex[GA](
Of[E, GB],
Map[E, GB, func(B) GB],
Ap[GB, E, B],
f,
)
}
// TraverseArrayWithIndex transforms an array
func TraverseArrayWithIndex[E, A, B any](f func(int, A) Either[E, B]) func([]A) Either[E, []B] {
return TraverseArrayWithIndexG[[]A, []B](f)
}
func SequenceArrayG[GA ~[]A, GOA ~[]Either[E, A], E, A any](ma GOA) Either[E, GA] {
return TraverseArrayG[GOA, GA](F.Identity[Either[E, A]])(ma)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[E, A any](ma []Either[E, A]) Either[E, []A] {
return SequenceArrayG[[]A](ma)
}
// CompactArrayG discards the none values and keeps the some values
func CompactArrayG[A1 ~[]Either[E, A], A2 ~[]A, E, A any](fa A1) A2 {
return RA.Reduce(fa, func(out A2, value Either[E, A]) A2 {
return MonadFold(value, F.Constant1[E](out), F.Bind1st(RA.Append[A2, A], out))
}, make(A2, len(fa)))
}
// CompactArray discards the none values and keeps the some values
func CompactArray[E, A any](fa []Either[E, A]) []A {
return CompactArrayG[[]Either[E, A], []A](fa)
}

View File

@@ -13,6 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package option defines the [Either] datastructure and its monadic operations
package either
//go:generate go run .. either --count 10 --filename gen.go

View File

@@ -22,6 +22,8 @@ package either
import (
E "github.com/IBM/fp-go/errors"
F "github.com/IBM/fp-go/function"
FC "github.com/IBM/fp-go/internal/functor"
L "github.com/IBM/fp-go/lazy"
O "github.com/IBM/fp-go/option"
)
@@ -91,12 +93,12 @@ func MonadChainTo[E, A, B any](ma Either[E, A], mb Either[E, B]) Either[E, B] {
return mb
}
func MonadChainOptionK[E, A, B any](onNone func() E, ma Either[E, A], f func(A) O.Option[B]) Either[E, B] {
return MonadChain(ma, F.Flow2(f, FromOption[E, B](onNone)))
func MonadChainOptionK[A, B, E any](onNone func() E, ma Either[E, A], f func(A) O.Option[B]) Either[E, B] {
return MonadChain(ma, F.Flow2(f, FromOption[B](onNone)))
}
func ChainOptionK[E, A, B any](onNone func() E) func(func(A) O.Option[B]) func(Either[E, A]) Either[E, B] {
from := FromOption[E, B](onNone)
func ChainOptionK[A, B, E any](onNone func() E) func(func(A) O.Option[B]) func(Either[E, A]) Either[E, B] {
from := FromOption[B](onNone)
return func(f func(A) O.Option[B]) func(Either[E, A]) Either[E, B] {
return Chain(F.Flow2(f, from))
}
@@ -118,16 +120,15 @@ func Flatten[E, A any](mma Either[E, Either[E, A]]) Either[E, A] {
return MonadChain(mma, F.Identity[Either[E, A]])
}
func TryCatch[FA ~func() (A, error), FE func(error) E, E, A any](f FA, onThrow FE) Either[E, A] {
val, err := f()
func TryCatch[FE func(error) E, E, A any](val A, err error, onThrow FE) Either[E, A] {
if err != nil {
return F.Pipe2(err, onThrow, Left[A, E])
}
return F.Pipe1(val, Right[E, A])
}
func TryCatchError[F ~func() (A, error), A any](f F) Either[error, A] {
return TryCatch(f, E.IdentityError)
func TryCatchError[A any](val A, err error) Either[error, A] {
return TryCatch(val, err, E.IdentityError)
}
func Sequence2[E, T1, T2, R any](f func(T1, T2) Either[E, R]) func(Either[E, T1], Either[E, T2]) Either[E, R] {
@@ -142,19 +143,17 @@ func Sequence3[E, T1, T2, T3, R any](f func(T1, T2, T3) Either[E, R]) func(Eithe
}
}
func FromOption[E, A any](onNone func() E) func(O.Option[A]) Either[E, A] {
func FromOption[A, E any](onNone func() E) func(O.Option[A]) Either[E, A] {
return O.Fold(F.Nullary2(onNone, Left[A, E]), Right[E, A])
}
func ToOption[E, A any]() func(Either[E, A]) O.Option[A] {
return Fold(F.Ignore1of1[E](O.None[A]), O.Some[A])
func ToOption[E, A any](ma Either[E, A]) O.Option[A] {
return MonadFold(ma, F.Ignore1of1[E](O.None[A]), O.Some[A])
}
func FromError[A any](f func(a A) error) func(A) Either[error, A] {
return func(a A) Either[error, A] {
return TryCatchError(func() (A, error) {
return a, f(a)
})
return TryCatchError(a, f(a))
}
}
@@ -182,7 +181,7 @@ func FromPredicate[E, A any](pred func(A) bool, onFalse func(A) E) func(A) Eithe
}
}
func FromNillable[E, A any](e E) func(*A) Either[E, *A] {
func FromNillable[A, E any](e E) func(*A) Either[E, *A] {
return FromPredicate(F.IsNonNil[A], F.Constant1[*A](e))
}
@@ -197,11 +196,11 @@ func Reduce[E, A, B any](f func(B, A) B, initial B) func(Either[E, A]) B {
)
}
func AltW[E, E1, A any](that func() Either[E1, A]) func(Either[E, A]) Either[E1, A] {
func AltW[E, E1, A any](that L.Lazy[Either[E1, A]]) func(Either[E, A]) Either[E1, A] {
return Fold(F.Ignore1of1[E](that), Right[E1, A])
}
func Alt[E, A any](that func() Either[E, A]) func(Either[E, A]) Either[E, A] {
func Alt[E, A any](that L.Lazy[Either[E, A]]) func(Either[E, A]) Either[E, A] {
return AltW[E](that)
}
@@ -209,7 +208,7 @@ func OrElse[E, A any](onLeft func(e E) Either[E, A]) func(Either[E, A]) Either[E
return Fold(onLeft, Of[E, A])
}
func ToType[E, A any](onError func(any) E) func(any) Either[E, A] {
func ToType[A, E any](onError func(any) E) func(any) Either[E, A] {
return func(value any) Either[E, A] {
return F.Pipe2(
value,
@@ -245,3 +244,15 @@ func MonadSequence3[E, T1, T2, T3, R any](e1 Either[E, T1], e2 Either[E, T2], e3
func Swap[E, A any](val Either[E, A]) Either[A, E] {
return MonadFold(val, Right[A, E], Left[E, A])
}
func MonadFlap[E, B, A any](fab Either[E, func(A) B], a A) Either[E, B] {
return FC.MonadFlap(MonadMap[E, func(A) B, B], fab, a)
}
func Flap[E, B, A any](a A) func(Either[E, func(A) B]) Either[E, B] {
return F.Bind2nd(MonadFlap[E, B, A], a)
}
func MonadAlt[E, A any](fa Either[E, A], that L.Lazy[Either[E, A]]) Either[E, A] {
return MonadFold(fa, F.Ignore1of1[E](that), Of[E, A])
}

View File

@@ -100,7 +100,7 @@ func TestChainFirst(t *testing.T) {
}
func TestChainOptionK(t *testing.T) {
f := ChainOptionK[string, int, int](F.Constant("a"))(func(n int) O.Option[int] {
f := ChainOptionK[int, int](F.Constant("a"))(func(n int) O.Option[int] {
if n > 0 {
return O.Some(n)
}
@@ -112,6 +112,6 @@ func TestChainOptionK(t *testing.T) {
}
func TestFromOption(t *testing.T) {
assert.Equal(t, Left[int]("none"), FromOption[string, int](F.Constant("none"))(O.None[int]()))
assert.Equal(t, Right[string](1), FromOption[string, int](F.Constant("none"))(O.Some(1)))
assert.Equal(t, Left[int]("none"), FromOption[int](F.Constant("none"))(O.None[int]()))
assert.Equal(t, Right[string](1), FromOption[int](F.Constant("none"))(O.Some(1)))
}

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 either
import (
"fmt"
"github.com/IBM/fp-go/errors"
)
func ExampleEither_creation() {
// Build an Either
leftValue := Left[string](fmt.Errorf("some error"))
rightValue := Right[error]("value")
// Build from a value
fromNillable := FromNillable[string](fmt.Errorf("value was nil"))
leftFromNil := fromNillable(nil)
value := "value"
rightFromPointer := fromNillable(&value)
// some predicate
isEven := func(num int) bool {
return num%2 == 0
}
fromEven := FromPredicate(isEven, errors.OnSome[int]("%d is an odd number"))
leftFromPred := fromEven(3)
rightFromPred := fromEven(4)
fmt.Println(leftValue)
fmt.Println(rightValue)
fmt.Println(leftFromNil)
fmt.Println(IsRight(rightFromPointer))
fmt.Println(leftFromPred)
fmt.Println(rightFromPred)
// Output:
// Left[*errors.errorString, string](some error)
// Right[<nil>, string](value)
// Left[*errors.errorString, *string](value was nil)
// true
// Left[*errors.errorString, int](3 is an odd number)
// Right[<nil>, int](4)
}

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 either
import (
"fmt"
F "github.com/IBM/fp-go/function"
N "github.com/IBM/fp-go/number"
)
func ExampleEither_extraction() {
leftValue := Left[int](fmt.Errorf("Division by Zero!"))
rightValue := Right[error](10)
// Convert Either[E, A] to A with a default value
leftWithDefault := GetOrElse(F.Constant1[error](0))(leftValue) // 0
rightWithDefault := GetOrElse(F.Constant1[error](0))(rightValue) // 10
// Apply a different function on Left(...)/Right(...)
doubleOrZero := Fold(F.Constant1[error](0), N.Mul(2)) // func(Either[error, int]) int
doubleFromLeft := doubleOrZero(leftValue) // 0
doubleFromRight := doubleOrZero(rightValue) // 20
// Pro-tip: Fold is short for the following:
doubleOrZeroBis := F.Flow2(
Map[error](N.Mul(2)),
GetOrElse(F.Constant1[error](0)),
)
doubleFromLeftBis := doubleOrZeroBis(leftValue) // 0
doubleFromRightBis := doubleOrZeroBis(rightValue) // 20
fmt.Println(leftValue)
fmt.Println(rightValue)
fmt.Println(leftWithDefault)
fmt.Println(rightWithDefault)
fmt.Println(doubleFromLeft)
fmt.Println(doubleFromRight)
fmt.Println(doubleFromLeftBis)
fmt.Println(doubleFromRightBis)
// Output:
// Left[*errors.errorString, int](Division by Zero!)
// Right[<nil>, int](10)
// 0
// 10
// 0
// 20
// 0
// 20
}

View File

@@ -27,12 +27,10 @@ import (
var (
// Command executes a command
// use this version if the command does not produce any side effect, i.e. if the output is uniquely determined by by the input
// typically you'd rather use the IOEither version of the command
// typically you'd rather use the [IOEither] version of the command
Command = F.Curry3(command)
)
func command(name string, args []string, in []byte) E.Either[error, exec.CommandOutput] {
return E.TryCatchError(func() (exec.CommandOutput, error) {
return GE.Exec(context.Background(), name, args, in)
})
return E.TryCatchError(GE.Exec(context.Background(), name, args, in))
}

File diff suppressed because it is too large Load Diff

View File

@@ -35,17 +35,13 @@ var (
func bodyRequest(method string) func(string) func([]byte) E.Either[error, *http.Request] {
return func(url string) func([]byte) E.Either[error, *http.Request] {
return func(body []byte) E.Either[error, *http.Request] {
return E.TryCatchError(func() (*http.Request, error) {
return http.NewRequest(method, url, bytes.NewReader(body))
})
return E.TryCatchError(http.NewRequest(method, url, bytes.NewReader(body)))
}
}
}
func noBodyRequest(method string) func(string) E.Either[error, *http.Request] {
return func(url string) E.Either[error, *http.Request] {
return E.TryCatchError(func() (*http.Request, error) {
return http.NewRequest(method, url, nil)
})
return E.TryCatchError(http.NewRequest(method, url, nil))
}
}

40
either/monoid.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 either
import (
L "github.com/IBM/fp-go/lazy"
M "github.com/IBM/fp-go/monoid"
)
// AlternativeMonoid is the alternative [Monoid] for an [Either]
func AlternativeMonoid[E, A any](m M.Monoid[A]) M.Monoid[Either[E, A]] {
return M.AlternativeMonoid(
Of[E, A],
MonadMap[E, A, func(A) A],
MonadAp[A, E, A],
MonadAlt[E, A],
m,
)
}
// AltMonoid is the alternative [Monoid] for an [Either]
func AltMonoid[E, A any](zero L.Lazy[Either[E, A]]) M.Monoid[Either[E, A]] {
return M.AltMonoid(
zero,
MonadAlt[E, A],
)
}

View File

@@ -20,7 +20,7 @@ import (
RR "github.com/IBM/fp-go/internal/record"
)
// TraverseRecord transforms a record of options into an option of a record
// TraverseRecordG transforms a record of options into an option of a record
func TraverseRecordG[GA ~map[K]A, GB ~map[K]B, K comparable, E, A, B any](f func(A) Either[E, B]) func(GA) Either[E, GB] {
return RR.Traverse[GA](
Of[E, GB],
@@ -35,6 +35,21 @@ func TraverseRecord[K comparable, E, A, B any](f func(A) Either[E, B]) func(map[
return TraverseRecordG[map[K]A, map[K]B](f)
}
// TraverseRecordWithIndexG transforms a record of options into an option of a record
func TraverseRecordWithIndexG[GA ~map[K]A, GB ~map[K]B, K comparable, E, A, B any](f func(K, A) Either[E, B]) func(GA) Either[E, GB] {
return RR.TraverseWithIndex[GA](
Of[E, GB],
Map[E, GB, func(B) GB],
Ap[GB, E, B],
f,
)
}
// TraverseRecordWithIndex transforms a record of eithers into an either of a record
func TraverseRecordWithIndex[K comparable, E, A, B any](f func(K, A) Either[E, B]) func(map[K]A) Either[E, map[K]B] {
return TraverseRecordWithIndexG[map[K]A, map[K]B](f)
}
func SequenceRecordG[GA ~map[K]A, GOA ~map[K]Either[E, A], K comparable, E, A any](ma GOA) Either[E, GA] {
return TraverseRecordG[GOA, GA](F.Identity[Either[E, A]])(ma)
}
@@ -43,3 +58,24 @@ func SequenceRecordG[GA ~map[K]A, GOA ~map[K]Either[E, A], K comparable, E, A an
func SequenceRecord[K comparable, E, A any](ma map[K]Either[E, A]) Either[E, map[K]A] {
return SequenceRecordG[map[K]A](ma)
}
func upsertAtReadWrite[M ~map[K]V, K comparable, V any](r M, k K, v V) M {
r[k] = v
return r
}
// CompactRecordG discards the noe values and keeps the some values
func CompactRecordG[M1 ~map[K]Either[E, A], M2 ~map[K]A, K comparable, E, A any](m M1) M2 {
out := make(M2)
onLeft := F.Constant1[E](out)
return RR.ReduceWithIndex(m, func(key K, _ M2, value Either[E, A]) M2 {
return MonadFold(value, onLeft, func(v A) M2 {
return upsertAtReadWrite(out, key, v)
})
}, out)
}
// CompactRecord discards all none values and keeps the somes
func CompactRecord[K comparable, E, A any](m map[K]Either[E, A]) map[K]A {
return CompactRecordG[map[K]Either[E, A], map[K]A](m)
}

37
either/record_test.go Normal file
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 either
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCompactRecord(t *testing.T) {
// make the map
m := make(map[string]Either[string, int])
m["foo"] = Left[int]("error")
m["bar"] = Right[string](1)
// compact it
m1 := CompactRecord(m)
// check expected
exp := map[string]int{
"bar": 1,
}
assert.Equal(t, exp, m1)
}

View File

@@ -25,20 +25,14 @@ import (
func TestWithResource(t *testing.T) {
onCreate := func() Either[error, *os.File] {
return TryCatchError(func() (*os.File, error) {
return os.CreateTemp("", "*")
})
return TryCatchError(os.CreateTemp("", "*"))
}
onDelete := F.Flow2(
func(f *os.File) Either[error, string] {
return TryCatchError(func() (string, error) {
return f.Name(), f.Close()
})
return TryCatchError(f.Name(), f.Close())
},
Chain(func(name string) Either[error, any] {
return TryCatchError(func() (any, error) {
return name, os.Remove(name)
})
return TryCatchError(any(name), os.Remove(name))
}),
)

27
either/semigroup.go Normal file
View File

@@ -0,0 +1,27 @@
// 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 either
import (
S "github.com/IBM/fp-go/semigroup"
)
// AltSemigroup is the alternative [Semigroup] for an [Either]
func AltSemigroup[E, A any]() S.Semigroup[Either[E, A]] {
return S.AltSemigroup(
MonadAlt[E, A],
)
}

View File

@@ -27,13 +27,13 @@ HKTRB = HKT<Either[B]>
HKTA = HKT<A>
HKTB = HKT<B>
*/
func traverse[E, A, B, HKTA, HKTB, HKTRB any](
_of func(Either[E, B]) HKTRB,
_map func(HKTB, func(B) Either[E, B]) HKTRB,
func traverse[E, A, B, HKTB, HKTRB any](
mof func(Either[E, B]) HKTRB,
mmap func(func(B) Either[E, B]) func(HKTB) HKTRB,
) func(Either[E, A], func(A) HKTB) HKTRB {
left := F.Flow2(Left[B, E], _of)
right := F.Bind2nd(_map, Right[E, B])
left := F.Flow2(Left[B, E], mof)
right := mmap(Right[E, B])
return func(ta Either[E, A], f func(A) HKTB) HKTRB {
return MonadFold(ta,
@@ -43,27 +43,21 @@ func traverse[E, A, B, HKTA, HKTB, HKTRB any](
}
}
func Traverse[E, A, B, HKTA, HKTB, HKTRB any](
_of func(Either[E, B]) HKTRB,
_map func(HKTB, func(B) Either[E, B]) HKTRB,
// Traverse converts an [Either] of some higher kinded type into the higher kinded type of an [Either]
func Traverse[A, E, B, HKTB, HKTRB any](
mof func(Either[E, B]) HKTRB,
mmap func(func(B) Either[E, B]) func(HKTB) HKTRB,
) func(func(A) HKTB) func(Either[E, A]) HKTRB {
delegate := traverse[E, A, B, HKTA](_of, _map)
delegate := traverse[E, A, B](mof, mmap)
return func(f func(A) HKTB) func(Either[E, A]) HKTRB {
return F.Bind2nd(delegate, f)
}
}
/*
*
We need to pass the members of the applicative explicitly, because golang does neither support higher kinded types nor template methods on structs or interfaces
HKTRA = HKT<Either[A]>
HKTA = HKT<A>
HKTB = HKT<B>
*/
// Sequence converts an [Either] of some higher kinded type into the higher kinded type of an [Either]
func Sequence[E, A, HKTA, HKTRA any](
_of func(Either[E, A]) HKTRA,
_map func(HKTA, func(A) Either[E, A]) HKTRA,
mof func(Either[E, A]) HKTRA,
mmap func(func(A) Either[E, A]) func(HKTA) HKTRA,
) func(Either[E, HKTA]) HKTRA {
return Fold(F.Flow2(Left[A, E], _of), F.Bind2nd(_map, Right[E, A]))
return Fold(F.Flow2(Left[A, E], mof), mmap(Right[E, A]))
}

View File

@@ -30,9 +30,9 @@ func TestTraverse(t *testing.T) {
}
return O.None[int]()
}
trav := Traverse[string, int, int, O.Option[Either[string, int]]](
trav := Traverse[int](
O.Of[Either[string, int]],
O.MonadMap[int, Either[string, int]],
O.Map[int, Either[string, int]],
)(f)
assert.Equal(t, O.Of(Left[int]("a")), F.Pipe1(Left[int]("a"), trav))
@@ -44,7 +44,7 @@ func TestSequence(t *testing.T) {
seq := Sequence(
O.Of[Either[string, int]],
O.MonadMap[int, Either[string, int]],
O.Map[int, Either[string, int]],
)
assert.Equal(t, O.Of(Right[string](1)), seq(Right[string](O.Of(1))))

View File

@@ -17,80 +17,60 @@ package either
func Variadic0[V, R any](f func([]V) (R, error)) func(...V) Either[error, R] {
return func(v ...V) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(v)
})
return TryCatchError(f(v))
}
}
func Variadic1[T1, V, R any](f func(T1, []V) (R, error)) func(T1, ...V) Either[error, R] {
return func(t1 T1, v ...V) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t1, v)
})
return TryCatchError(f(t1, v))
}
}
func Variadic2[T1, T2, V, R any](f func(T1, T2, []V) (R, error)) func(T1, T2, ...V) Either[error, R] {
return func(t1 T1, t2 T2, v ...V) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t1, t2, v)
})
return TryCatchError(f(t1, t2, v))
}
}
func Variadic3[T1, T2, T3, V, R any](f func(T1, T2, T3, []V) (R, error)) func(T1, T2, T3, ...V) Either[error, R] {
return func(t1 T1, t2 T2, t3 T3, v ...V) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t1, t2, t3, v)
})
return TryCatchError(f(t1, t2, t3, v))
}
}
func Variadic4[T1, T2, T3, T4, V, R any](f func(T1, T2, T3, T4, []V) (R, error)) func(T1, T2, T3, T4, ...V) Either[error, R] {
return func(t1 T1, t2 T2, t3 T3, t4 T4, v ...V) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t1, t2, t3, t4, v)
})
return TryCatchError(f(t1, t2, t3, t4, v))
}
}
func Unvariadic0[V, R any](f func(...V) (R, error)) func([]V) Either[error, R] {
return func(v []V) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(v...)
})
return TryCatchError(f(v...))
}
}
func Unvariadic1[T1, V, R any](f func(T1, ...V) (R, error)) func(T1, []V) Either[error, R] {
return func(t1 T1, v []V) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t1, v...)
})
return TryCatchError(f(t1, v...))
}
}
func Unvariadic2[T1, T2, V, R any](f func(T1, T2, ...V) (R, error)) func(T1, T2, []V) Either[error, R] {
return func(t1 T1, t2 T2, v []V) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t1, t2, v...)
})
return TryCatchError(f(t1, t2, v...))
}
}
func Unvariadic3[T1, T2, T3, V, R any](f func(T1, T2, T3, ...V) (R, error)) func(T1, T2, T3, []V) Either[error, R] {
return func(t1 T1, t2 T2, t3 T3, v []V) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t1, t2, t3, v...)
})
return TryCatchError(f(t1, t2, t3, v...))
}
}
func Unvariadic4[T1, T2, T3, T4, V, R any](f func(T1, T2, T3, T4, ...V) (R, error)) func(T1, T2, T3, T4, []V) Either[error, R] {
return func(t1 T1, t2 T2, t3 T3, t4 T4, v []V) Either[error, R] {
return TryCatchError(func() (R, error) {
return f(t1, t2, t3, t4, v...)
})
return TryCatchError(f(t1, t2, t3, t4, v...))
}
}

View File

@@ -21,16 +21,12 @@ import (
S "github.com/IBM/fp-go/semigroup"
)
func concat[A any](first, second func(A) A) func(A) A {
return F.Flow2(first, second)
}
// Semigroup for the Endomorphism where the `concat` operation is the usual function composition.
func Semigroup[A any]() S.Semigroup[func(A) A] {
return S.MakeSemigroup(concat[A])
return S.MakeSemigroup(F.Flow2[func(A) A, func(A) A])
}
// Monoid for the Endomorphism where the `concat` operation is the usual function composition.
func Monoid[A any]() M.Monoid[func(A) A] {
return M.MakeMonoid(concat[A], F.Identity[A])
return M.MakeMonoid(F.Flow2[func(A) A, func(A) A], F.Identity[A])
}

51
erasure/erasure.go Normal file
View File

@@ -0,0 +1,51 @@
// 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 erasure
import (
F "github.com/IBM/fp-go/function"
)
// Erase converts a variable of type T to an any by returning a pointer to that variable
func Erase[T any](t T) any {
return &t
}
// Unerase converts an erased variable back to its original value
func Unerase[T any](t any) T {
return *t.(*T)
}
// Erase0 converts a type safe function into an erased function
func Erase0[T1 any](f func() T1) func() any {
return F.Nullary2(f, Erase[T1])
}
// Erase1 converts a type safe function into an erased function
func Erase1[T1, T2 any](f func(T1) T2) func(any) any {
return F.Flow3(
Unerase[T1],
f,
Erase[T2],
)
}
// Erase2 converts a type safe function into an erased function
func Erase2[T1, T2, T3 any](f func(T1, T2) T3) func(any, any) any {
return func(t1, t2 any) any {
return Erase(f(Unerase[T1](t1), Unerase[T2](t2)))
}
}

39
erasure/erasure_test.go Normal file
View File

@@ -0,0 +1,39 @@
// 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 erasure
import (
"fmt"
"strings"
"testing"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
)
func TestEither(t *testing.T) {
e1 := F.Pipe3(
E.Of[error](Erase("Carsten")),
E.Map[error](Erase1(strings.ToUpper)),
E.GetOrElse(func(e error) any {
return Erase("Error")
}),
Unerase[string],
)
fmt.Println(e1)
}

View File

@@ -28,6 +28,22 @@ func OnNone(msg string, args ...any) func() error {
}
}
// OnSome generates a unary function that produces a formatted error
func OnSome[T any](msg string, args ...any) func(T) error {
l := len(args)
if l == 0 {
return func(value T) error {
return fmt.Errorf(msg, value)
}
}
return func(value T) error {
data := make([]any, l)
copy(data[1:], args)
data[0] = value
return fmt.Errorf(msg, data...)
}
}
// OnError generates a unary function that produces a formatted error. The argument
// to that function is the root cause of the error and the message will be augmented with
// a format string containing %w

View File

@@ -20,11 +20,14 @@ import (
)
type (
// command output
// CommandOutput represents the output of executing a command. The first field in the [Tuple2] is
// stdout, the second one is stderr. Use [StdOut] and [StdErr] to access these fields
CommandOutput = T.Tuple2[[]byte, []byte]
)
var (
// StdOut returns the field of a [CommandOutput] representing `stdout`
StdOut = T.First[[]byte, []byte]
// StdErr returns the field of a [CommandOutput] representing `stderr`
StdErr = T.Second[[]byte, []byte]
)

View File

@@ -15,14 +15,11 @@
package file
import (
"io"
import "path/filepath"
IOE "github.com/IBM/fp-go/ioeither"
)
func onClose[R io.Closer](r R) IOE.IOEither[error, R] {
return IOE.TryCatchError(func() (R, error) {
return r, r.Close()
})
// Join appends a filename to a root path
func Join(name string) func(root string) string {
return func(root string) string {
return filepath.Join(root, name)
}
}

View File

@@ -26,6 +26,7 @@ func Bind2nd[T1, T2, R any](f func(T1, T2) R, t2 T2) func(T1) R {
}
}
// SK function (SKI combinator calculus).
func SK[T1, T2 any](_ T1, t2 T2) T2 {
return t2
}

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