├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bower.json ├── package.json ├── src └── Data │ ├── Either.purs │ └── Either │ ├── Inject.purs │ └── Nested.purs └── test └── Main.purs /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Description of the change** 2 | 3 | Clearly and concisely describe the purpose of the pull request. If this PR relates to an existing issue or change proposal, please link to it. Include any other background context that would help reviewers understand the motivation for this PR. 4 | 5 | --- 6 | 7 | **Checklist:** 8 | 9 | - [ ] Added the change to the changelog's "Unreleased" section with a reference to this PR (e.g. "- Made a change (#0000)") 10 | - [ ] Linked any existing issues or proposals that this pull request should close 11 | - [ ] Updated or added relevant documentation 12 | - [ ] Added a test for the contribution (if applicable) 13 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | 15 | - uses: purescript-contrib/setup-purescript@main 16 | with: 17 | purescript: "unstable" 18 | 19 | - uses: actions/setup-node@v2 20 | with: 21 | node-version: "14.x" 22 | 23 | - name: Install dependencies 24 | run: | 25 | npm install -g bower 26 | npm install 27 | bower install --production 28 | 29 | - name: Build source 30 | run: npm run-script build 31 | 32 | - name: Run tests 33 | run: | 34 | bower install 35 | npm run-script test --if-present 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.* 2 | !/.gitignore 3 | !/.github/ 4 | /bower_components/ 5 | /node_modules/ 6 | /output/ 7 | package-lock.json 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | Notable changes to this project are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 4 | 5 | ## [Unreleased] 6 | 7 | Breaking changes: 8 | 9 | New features: 10 | 11 | Bugfixes: 12 | 13 | Other improvements: 14 | 15 | ## [v6.1.0](https://github.com/purescript/purescript-either/releases/tag/v6.1.0) - 2022-05-16 16 | 17 | New features: 18 | - Add `blush` which is a left-biased `hush`, thus turns `Right`s into `Nothing`s but `Left`s into `Just`s (#69 by @i-am-the-slime). 19 | 20 | ## [v6.0.0](https://github.com/purescript/purescript-either/releases/tag/v6.0.0) - 2022-04-27 21 | 22 | Breaking changes: 23 | - Update project and deps to PureScript v0.15.0 (#66 by @JordanMartinez) 24 | 25 | New features: 26 | 27 | Bugfixes: 28 | 29 | Other improvements: 30 | 31 | ## [v5.0.0](https://github.com/purescript/purescript-either/releases/tag/v5.0.0) - 2021-02-26 32 | 33 | Breaking changes: 34 | - Added support for PureScript 0.14 and dropped support for all previous versions (#55) 35 | - Added default parameter to `fromLeft` and `fromRight` and removed `Partial` constraint (#48) 36 | 37 | New features: 38 | - Added `\/` alias for `either` (#51) 39 | - Added lazy versions of `fromRight` and `fromLeft` (#59) 40 | - This package no longer depends on the `purescript-bifunctors` and `purescript-foldable-traversable` packages. Relevant instances have been moved to those packages. (#64) 41 | 42 | Bugfixes: 43 | 44 | Other improvements: 45 | - Migrated CI to GitHub Actions and updated installation instructions to use Spago (#58) 46 | - Added a CHANGELOG.md file and pull request template (#62, #63) 47 | - Corrected docs for `Apply` instance (#49) 48 | - Improved documentation of `Either`s "do notation" (#52) 49 | 50 | ## [v4.1.1](https://github.com/purescript/purescript-either/releases/tag/v4.1.1) - 2018-11-30 51 | 52 | Reordered instance chain for `Inject` so that `inj :: a -> a` succeeds (@hdgarrood) 53 | 54 | ## [v4.1.0](https://github.com/purescript/purescript-either/releases/tag/v4.1.0) - 2018-10-28 55 | 56 | Added `FunctorWithIndex`, `FoldableWithIndex`, `TraversableWithIndex` instances (@MonoidMusician) 57 | 58 | ## [v4.0.0](https://github.com/purescript/purescript-either/releases/tag/v4.0.0) - 2018-05-23 59 | 60 | - Updated for PureScript 0.12 61 | - Added `\/` type synonym to `Data.Either.Nested` 62 | - Added `Inject` class for injecting values into/projecting values out of nested `Eithers` 63 | 64 | ## [v3.2.0](https://github.com/purescript/purescript-either/releases/tag/v3.2.0) - 2018-04-15 65 | 66 | - Added `note'` (lazy `note`) (@matthewleon) 67 | 68 | ## [v3.1.0](https://github.com/purescript/purescript-either/releases/tag/v3.1.0) - 2017-06-23 69 | 70 | - Added `note` and `hush` functions (@kRITZCREEK) 71 | 72 | ## [v3.0.0](https://github.com/purescript/purescript-either/releases/tag/v3.0.0) - 2017-03-26 73 | 74 | - Updated for PureScript 0.11 75 | 76 | ## [v2.2.1](https://github.com/purescript/purescript-either/releases/tag/v2.2.1) - 2017-03-05 77 | 78 | - Fix lower bound of prelude dependency (@passy) 79 | 80 | ## [v2.2.0](https://github.com/purescript/purescript-either/releases/tag/v2.2.0) - 2017-03-02 81 | 82 | - Added `Eq1` and `Ord1` instances 83 | 84 | ## [v2.1.0](https://github.com/purescript/purescript-either/releases/tag/v2.1.0) - 2016-12-24 85 | 86 | Add `choose` function (@tmcgilchrist) 87 | 88 | ## [v2.0.0](https://github.com/purescript/purescript-either/releases/tag/v2.0.0) - 2016-10-03 89 | 90 | - Updated dependencies 91 | - The `Nested` module has been reworked for "open" nesting #20 (@natefaubion) 92 | 93 | ## [v1.0.0](https://github.com/purescript/purescript-either/releases/tag/v1.0.0) - 2016-06-01 94 | 95 | This release is intended for the PureScript 0.9.1 compiler and newer. 96 | 97 | **Note**: The v1.0.0 tag is not meant to indicate the library is “finished”, the core libraries are all being bumped to this for the 0.9 compiler release so as to use semver more correctly. 98 | 99 | ## [v1.0.0-rc.1](https://github.com/purescript/purescript-either/releases/tag/v1.0.0-rc.1) - 2016-03-13 100 | 101 | - Release candidate for the psc 0.8+ core libraries 102 | 103 | ## [v0.2.3](https://github.com/purescript/purescript-either/releases/tag/v0.2.3) - 2015-09-26 104 | 105 | Fixed error message (@zudov) 106 | 107 | ## [v0.2.2](https://github.com/purescript/purescript-either/releases/tag/v0.2.2) - 2015-08-14 108 | 109 | - Added `Semiring` and `Semigroup` instances (@anttih) 110 | 111 | ## [v0.2.1](https://github.com/purescript/purescript-either/releases/tag/v0.2.1) - 2015-08-13 112 | 113 | - Fixed warnings about partial functions 114 | 115 | ## [v0.2.0](https://github.com/purescript/purescript-either/releases/tag/v0.2.0) - 2015-06-30 116 | 117 | This release works with versions 0.7.\* of the PureScript compiler. It will not work with older versions. If you are using an older version, you should require an older, compatible version of this library. 118 | 119 | ## [v0.2.0-rc.1](https://github.com/purescript/purescript-either/releases/tag/v0.2.0-rc.1) - 2015-06-06 120 | 121 | Initial release candidate of the library intended for the 0.7 compiler. 122 | 123 | ## [v0.1.8](https://github.com/purescript/purescript-either/releases/tag/v0.1.8) - 2015-03-25 124 | 125 | More helper functions for nested sums (@jdegoes) 126 | 127 | ## [v0.1.7](https://github.com/purescript/purescript-either/releases/tag/v0.1.7) - 2015-03-24 128 | 129 | Reworked nested sums (@jdegoes) 130 | 131 | ## [v0.1.6](https://github.com/purescript/purescript-either/releases/tag/v0.1.6) - 2015-03-18 132 | 133 | Add `fromLeft` and `fromRight` (@pseudonom) 134 | 135 | ## [v0.1.5](https://github.com/purescript/purescript-either/releases/tag/v0.1.5) - 2015-03-17 136 | 137 | Update docs 138 | 139 | ## [v0.1.4](https://github.com/purescript/purescript-either/releases/tag/v0.1.4) - 2014-11-05 140 | 141 | 142 | 143 | ## [v0.1.3](https://github.com/purescript/purescript-either/releases/tag/v0.1.3) - 2014-08-26 144 | 145 | Add `Alt` instance 146 | 147 | ## [v0.1.2](https://github.com/purescript/purescript-either/releases/tag/v0.1.2) - 2014-05-22 148 | 149 | - Fixed `show` output (paf31) 150 | 151 | ## [v0.1.1](https://github.com/purescript/purescript-either/releases/tag/v0.1.1) - 2014-04-25 152 | 153 | 154 | 155 | ## [v0.1.0](https://github.com/purescript/purescript-either/releases/tag/v0.1.0) - 2014-04-21 156 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 PureScript 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software without 15 | specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # purescript-either 2 | 3 | [![Latest release](http://img.shields.io/github/release/purescript/purescript-either.svg)](https://github.com/purescript/purescript-either/releases) 4 | [![Build status](https://github.com/purescript/purescript-either/workflows/CI/badge.svg?branch=master)](https://github.com/purescript/purescript-either/actions?query=workflow%3ACI+branch%3Amaster) 5 | [![Pursuit](https://pursuit.purescript.org/packages/purescript-either/badge)](https://pursuit.purescript.org/packages/purescript-either) 6 | 7 | The `Either` type provides is used to represent values that can be one of two possibilities. For example, `Either Int Number` can be used in a place where either integers or floating point numbers are acceptable. 8 | 9 | A common use for this type is error handling, where by convention the `Left` constructor carries error messages and the `Right` constructor carries expected values (“`Right` is right”). This convention is used as the `Functor`, `Applicative`, `Monad`, etc. instances all operate on the `Right` part of the `Either`. 10 | 11 | ## Installation 12 | 13 | ``` 14 | spago install either 15 | ``` 16 | 17 | ## Documentation 18 | 19 | Module documentation is [published on Pursuit](http://pursuit.purescript.org/packages/purescript-either). 20 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "purescript-either", 3 | "homepage": "https://github.com/purescript/purescript-either", 4 | "license": "BSD-3-Clause", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/purescript/purescript-either.git" 8 | }, 9 | "ignore": [ 10 | "**/.*", 11 | "bower_components", 12 | "node_modules", 13 | "output", 14 | "test", 15 | "bower.json", 16 | "package.json" 17 | ], 18 | "dependencies": { 19 | "purescript-control": "^6.0.0", 20 | "purescript-invariant": "^6.0.0", 21 | "purescript-maybe": "^6.0.0", 22 | "purescript-prelude": "^6.0.0" 23 | }, 24 | "devDependencies": { 25 | "purescript-assert": "^6.0.0", 26 | "purescript-console": "^6.0.0", 27 | "purescript-effect": "^4.0.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "clean": "rimraf output && rimraf .pulp-cache", 5 | "build": "pulp build -- --censor-lib --strict", 6 | "test": "pulp test" 7 | }, 8 | "devDependencies": { 9 | "pulp": "16.0.0-0", 10 | "purescript-psa": "^0.8.2", 11 | "rimraf": "^3.0.2" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Data/Either.purs: -------------------------------------------------------------------------------- 1 | module Data.Either where 2 | 3 | import Prelude 4 | 5 | import Control.Alt (class Alt, (<|>)) 6 | import Control.Extend (class Extend) 7 | import Data.Eq (class Eq1) 8 | import Data.Functor.Invariant (class Invariant, imapF) 9 | import Data.Generic.Rep (class Generic) 10 | import Data.Maybe (Maybe(..), maybe, maybe') 11 | import Data.Ord (class Ord1) 12 | 13 | -- | The `Either` type is used to represent a choice between two types of value. 14 | -- | 15 | -- | A common use case for `Either` is error handling, where `Left` is used to 16 | -- | carry an error value and `Right` is used to carry a success value. 17 | data Either a b = Left a | Right b 18 | 19 | -- | The `Functor` instance allows functions to transform the contents of a 20 | -- | `Right` with the `<$>` operator: 21 | -- | 22 | -- | ``` purescript 23 | -- | f <$> Right x == Right (f x) 24 | -- | ``` 25 | -- | 26 | -- | `Left` values are untouched: 27 | -- | 28 | -- | ``` purescript 29 | -- | f <$> Left y == Left y 30 | -- | ``` 31 | derive instance functorEither :: Functor (Either a) 32 | 33 | derive instance genericEither :: Generic (Either a b) _ 34 | 35 | instance invariantEither :: Invariant (Either a) where 36 | imap = imapF 37 | 38 | -- | The `Apply` instance allows functions contained within a `Right` to 39 | -- | transform a value contained within a `Right` using the `(<*>)` operator: 40 | -- | 41 | -- | ``` purescript 42 | -- | Right f <*> Right x == Right (f x) 43 | -- | ``` 44 | -- | 45 | -- | `Left` values are left untouched: 46 | -- | 47 | -- | ``` purescript 48 | -- | Left f <*> Right x == Left f 49 | -- | Right f <*> Left y == Left y 50 | -- | ``` 51 | -- | 52 | -- | Combining `Functor`'s `<$>` with `Apply`'s `<*>` can be used to transform a 53 | -- | pure function to take `Either`-typed arguments so `f :: a -> b -> c` 54 | -- | becomes `f :: Either l a -> Either l b -> Either l c`: 55 | -- | 56 | -- | ``` purescript 57 | -- | f <$> Right x <*> Right y == Right (f x y) 58 | -- | ``` 59 | -- | 60 | -- | The `Left`-preserving behaviour of both operators means the result of 61 | -- | an expression like the above but where any one of the values is `Left` 62 | -- | means the whole result becomes `Left` also, taking the first `Left` value 63 | -- | found: 64 | -- | 65 | -- | ``` purescript 66 | -- | f <$> Left x <*> Right y == Left x 67 | -- | f <$> Right x <*> Left y == Left y 68 | -- | f <$> Left x <*> Left y == Left x 69 | -- | ``` 70 | instance applyEither :: Apply (Either e) where 71 | apply (Left e) _ = Left e 72 | apply (Right f) r = f <$> r 73 | 74 | -- | The `Applicative` instance enables lifting of values into `Either` with the 75 | -- | `pure` function: 76 | -- | 77 | -- | ``` purescript 78 | -- | pure x :: Either _ _ == Right x 79 | -- | ``` 80 | -- | 81 | -- | Combining `Functor`'s `<$>` with `Apply`'s `<*>` and `Applicative`'s 82 | -- | `pure` can be used to pass a mixture of `Either` and non-`Either` typed 83 | -- | values to a function that does not usually expect them, by using `pure` 84 | -- | for any value that is not already `Either` typed: 85 | -- | 86 | -- | ``` purescript 87 | -- | f <$> Right x <*> pure y == Right (f x y) 88 | -- | ``` 89 | -- | 90 | -- | Even though `pure = Right` it is recommended to use `pure` in situations 91 | -- | like this as it allows the choice of `Applicative` to be changed later 92 | -- | without having to go through and replace `Right` with a new constructor. 93 | instance applicativeEither :: Applicative (Either e) where 94 | pure = Right 95 | 96 | -- | The `Alt` instance allows for a choice to be made between two `Either` 97 | -- | values with the `<|>` operator, where the first `Right` encountered 98 | -- | is taken. 99 | -- | 100 | -- | ``` purescript 101 | -- | Right x <|> Right y == Right x 102 | -- | Left x <|> Right y == Right y 103 | -- | Left x <|> Left y == Left y 104 | -- | ``` 105 | instance altEither :: Alt (Either e) where 106 | alt (Left _) r = r 107 | alt l _ = l 108 | 109 | -- | The `Bind` instance allows sequencing of `Either` values and functions that 110 | -- | return an `Either` by using the `>>=` operator: 111 | -- | 112 | -- | ``` purescript 113 | -- | Left x >>= f = Left x 114 | -- | Right x >>= f = f x 115 | -- | ``` 116 | -- | 117 | -- | `Either`'s "do notation" can be understood to work like this: 118 | -- | ``` purescript 119 | -- | x :: forall e a. Either e a 120 | -- | x = -- 121 | -- | 122 | -- | y :: forall e b. Either e b 123 | -- | y = -- 124 | -- | 125 | -- | foo :: forall e a. (a -> b -> c) -> Either e c 126 | -- | foo f = do 127 | -- | x' <- x 128 | -- | y' <- y 129 | -- | pure (f x' y') 130 | -- | ``` 131 | -- | 132 | -- | ...which is equivalent to... 133 | -- | 134 | -- | ``` purescript 135 | -- | x >>= (\x' -> y >>= (\y' -> pure (f x' y'))) 136 | -- | ``` 137 | -- | 138 | -- | ...and is the same as writing... 139 | -- | 140 | -- | ``` 141 | -- | foo :: forall e a. (a -> b -> c) -> Either e c 142 | -- | foo f = case x of 143 | -- | Left e -> 144 | -- | Left e 145 | -- | Right x -> case y of 146 | -- | Left e -> 147 | -- | Left e 148 | -- | Right y -> 149 | -- | Right (f x y) 150 | -- | ``` 151 | instance bindEither :: Bind (Either e) where 152 | bind = either (\e _ -> Left e) (\a f -> f a) 153 | 154 | -- | The `Monad` instance guarantees that there are both `Applicative` and 155 | -- | `Bind` instances for `Either`. 156 | instance monadEither :: Monad (Either e) 157 | 158 | -- | The `Extend` instance allows sequencing of `Either` values and functions 159 | -- | that accept an `Either` and return a non-`Either` result using the 160 | -- | `<<=` operator. 161 | -- | 162 | -- | ``` purescript 163 | -- | f <<= Left x = Left x 164 | -- | f <<= Right x = Right (f (Right x)) 165 | -- | ``` 166 | instance extendEither :: Extend (Either e) where 167 | extend _ (Left y) = Left y 168 | extend f x = Right (f x) 169 | 170 | -- | The `Show` instance allows `Either` values to be rendered as a string with 171 | -- | `show` whenever there is an `Show` instance for both type the `Either` can 172 | -- | contain. 173 | instance showEither :: (Show a, Show b) => Show (Either a b) where 174 | show (Left x) = "(Left " <> show x <> ")" 175 | show (Right y) = "(Right " <> show y <> ")" 176 | 177 | -- | The `Eq` instance allows `Either` values to be checked for equality with 178 | -- | `==` and inequality with `/=` whenever there is an `Eq` instance for both 179 | -- | types the `Either` can contain. 180 | derive instance eqEither :: (Eq a, Eq b) => Eq (Either a b) 181 | 182 | derive instance eq1Either :: Eq a => Eq1 (Either a) 183 | 184 | -- | The `Ord` instance allows `Either` values to be compared with 185 | -- | `compare`, `>`, `>=`, `<` and `<=` whenever there is an `Ord` instance for 186 | -- | both types the `Either` can contain. 187 | -- | 188 | -- | Any `Left` value is considered to be less than a `Right` value. 189 | derive instance ordEither :: (Ord a, Ord b) => Ord (Either a b) 190 | 191 | derive instance ord1Either :: Ord a => Ord1 (Either a) 192 | 193 | instance boundedEither :: (Bounded a, Bounded b) => Bounded (Either a b) where 194 | top = Right top 195 | bottom = Left bottom 196 | 197 | instance semigroupEither :: (Semigroup b) => Semigroup (Either a b) where 198 | append x y = append <$> x <*> y 199 | 200 | -- | Takes two functions and an `Either` value, if the value is a `Left` the 201 | -- | inner value is applied to the first function, if the value is a `Right` 202 | -- | the inner value is applied to the second function. 203 | -- | 204 | -- | ``` purescript 205 | -- | either f g (Left x) == f x 206 | -- | either f g (Right y) == g y 207 | -- | ``` 208 | either :: forall a b c. (a -> c) -> (b -> c) -> Either a b -> c 209 | either f _ (Left a) = f a 210 | either _ g (Right b) = g b 211 | 212 | -- | Combine two alternatives. 213 | choose :: forall m a b. Alt m => m a -> m b -> m (Either a b) 214 | choose a b = Left <$> a <|> Right <$> b 215 | 216 | -- | Returns `true` when the `Either` value was constructed with `Left`. 217 | isLeft :: forall a b. Either a b -> Boolean 218 | isLeft = either (const true) (const false) 219 | 220 | -- | Returns `true` when the `Either` value was constructed with `Right`. 221 | isRight :: forall a b. Either a b -> Boolean 222 | isRight = either (const false) (const true) 223 | 224 | -- | A function that extracts the value from the `Left` data constructor. 225 | -- | The first argument is a default value, which will be returned in the 226 | -- | case where a `Right` is passed to `fromLeft`. 227 | fromLeft :: forall a b. a -> Either a b -> a 228 | fromLeft _ (Left a) = a 229 | fromLeft default _ = default 230 | 231 | -- | Similar to `fromLeft` but for use in cases where the default value may be 232 | -- | expensive to compute. As PureScript is not lazy, the standard `fromLeft` 233 | -- | has to evaluate the default value before returning the result, 234 | -- | whereas here the value is only computed when the `Either` is known 235 | -- | to be `Right`. 236 | fromLeft' :: forall a b. (Unit -> a) -> Either a b -> a 237 | fromLeft' _ (Left a) = a 238 | fromLeft' default _ = default unit 239 | 240 | -- | A function that extracts the value from the `Right` data constructor. 241 | -- | The first argument is a default value, which will be returned in the 242 | -- | case where a `Left` is passed to `fromRight`. 243 | fromRight :: forall a b. b -> Either a b -> b 244 | fromRight _ (Right b) = b 245 | fromRight default _ = default 246 | 247 | -- | Similar to `fromRight` but for use in cases where the default value may be 248 | -- | expensive to compute. As PureScript is not lazy, the standard `fromRight` 249 | -- | has to evaluate the default value before returning the result, 250 | -- | whereas here the value is only computed when the `Either` is known 251 | -- | to be `Left`. 252 | fromRight' :: forall a b. (Unit -> b) -> Either a b -> b 253 | fromRight' _ (Right b) = b 254 | fromRight' default _ = default unit 255 | 256 | -- | Takes a default and a `Maybe` value, if the value is a `Just`, turn it into 257 | -- | a `Right`, if the value is a `Nothing` use the provided default as a `Left` 258 | -- | 259 | -- | ```purescript 260 | -- | note "default" Nothing = Left "default" 261 | -- | note "default" (Just 1) = Right 1 262 | -- | ``` 263 | note :: forall a b. a -> Maybe b -> Either a b 264 | note a = maybe (Left a) Right 265 | 266 | -- | Similar to `note`, but for use in cases where the default value may be 267 | -- | expensive to compute. 268 | -- | 269 | -- | ```purescript 270 | -- | note' (\_ -> "default") Nothing = Left "default" 271 | -- | note' (\_ -> "default") (Just 1) = Right 1 272 | -- | ``` 273 | note' :: forall a b. (Unit -> a) -> Maybe b -> Either a b 274 | note' f = maybe' (Left <<< f) Right 275 | 276 | -- | Turns an `Either` into a `Maybe`, by throwing potential `Left` values away and converting 277 | -- | them into `Nothing`. `Right` values get turned into `Just`s. 278 | -- | 279 | -- | ```purescript 280 | -- | hush (Left "ParseError") = Nothing 281 | -- | hush (Right 42) = Just 42 282 | -- | ``` 283 | hush :: forall a b. Either a b -> Maybe b 284 | hush = either (const Nothing) Just 285 | 286 | -- | Turns an `Either` into a `Maybe`, by throwing potential `Right` values away and converting 287 | -- | them into `Nothing`. `Left` values get turned into `Just`s. 288 | -- | 289 | -- | ```purescript 290 | -- | blush (Left "ParseError") = Just "Parse Error" 291 | -- | blush (Right 42) = Nothing 292 | -- | ``` 293 | blush :: forall a b. Either a b -> Maybe a 294 | blush = either Just (const Nothing) 295 | -------------------------------------------------------------------------------- /src/Data/Either/Inject.purs: -------------------------------------------------------------------------------- 1 | module Data.Either.Inject where 2 | 3 | import Prelude 4 | 5 | import Data.Either (Either(..), either) 6 | import Data.Maybe (Maybe(..)) 7 | 8 | class Inject a b where 9 | inj :: a -> b 10 | prj :: b -> Maybe a 11 | 12 | instance injectReflexive :: Inject a a where 13 | inj = identity 14 | prj = Just 15 | 16 | else instance injectLeft :: Inject a (Either a b) where 17 | inj = Left 18 | prj = either Just (const Nothing) 19 | 20 | else instance injectRight :: Inject a b => Inject a (Either c b) where 21 | inj = Right <<< inj 22 | prj = either (const Nothing) prj 23 | 24 | -------------------------------------------------------------------------------- /src/Data/Either/Nested.purs: -------------------------------------------------------------------------------- 1 | -- | Utilities for n-eithers: sums types with more than two terms built from nested eithers. 2 | -- | 3 | -- | Nested eithers arise naturally in sum combinators. You shouldn't 4 | -- | represent sum data using nested eithers, but if combinators you're working with 5 | -- | create them, utilities in this module will allow to to more easily work 6 | -- | with them, including translating to and from more traditional sum types. 7 | -- | 8 | -- | ```purescript 9 | -- | data Color = Red Number | Green Number | Blue Number 10 | -- | 11 | -- | fromEither3 :: Either3 Number Number Number -> Color 12 | -- | fromEither3 = either3 Red Green Blue 13 | -- | 14 | -- | toEither3 :: Color -> Either3 Number Number Number 15 | -- | toEither3 (Red v) = in1 v 16 | -- | toEither3 (Green v) = in2 v 17 | -- | toEither3 (Blue v) = in3 v 18 | -- | ``` 19 | module Data.Either.Nested 20 | ( type (\/), (\/) 21 | , in1, in2, in3, in4, in5, in6, in7, in8, in9, in10 22 | , at1, at2, at3, at4, at5, at6, at7, at8, at9, at10 23 | , Either1, Either2, Either3, Either4, Either5, Either6, Either7, Either8, Either9, Either10 24 | , either1, either2, either3, either4, either5, either6, either7, either8, either9, either10 25 | ) where 26 | 27 | import Data.Either (Either(..), either) 28 | import Data.Void (Void, absurd) 29 | 30 | infixr 6 type Either as \/ 31 | 32 | -- | The `\/` operator alias for the `either` function allows easy matching on nested Eithers. For example, consider the function 33 | -- | 34 | -- | ```purescript 35 | -- | f :: (Int \/ String \/ Boolean) -> String 36 | -- | f (Left x) = show x 37 | -- | f (Right (Left y)) = y 38 | -- | f (Right (Right z)) = if z then "Yes" else "No" 39 | -- | ``` 40 | -- | 41 | -- | The `\/` operator alias allows us to rewrite this function as 42 | -- | 43 | -- | ```purescript 44 | -- | f :: (Int \/ String \/ Boolean) -> String 45 | -- | f = show \/ identity \/ if _ then "Yes" else "No" 46 | -- | ``` 47 | infixr 6 either as \/ 48 | 49 | type Either1 a = a \/ Void 50 | type Either2 a b = a \/ b \/ Void 51 | type Either3 a b c = a \/ b \/ c \/ Void 52 | type Either4 a b c d = a \/ b \/ c \/ d \/ Void 53 | type Either5 a b c d e = a \/ b \/ c \/ d \/ e \/ Void 54 | type Either6 a b c d e f = a \/ b \/ c \/ d \/ e \/ f \/ Void 55 | type Either7 a b c d e f g = a \/ b \/ c \/ d \/ e \/ f \/ g \/ Void 56 | type Either8 a b c d e f g h = a \/ b \/ c \/ d \/ e \/ f \/ g \/ h \/ Void 57 | type Either9 a b c d e f g h i = a \/ b \/ c \/ d \/ e \/ f \/ g \/ h \/ i \/ Void 58 | type Either10 a b c d e f g h i j = a \/ b \/ c \/ d \/ e \/ f \/ g \/ h \/ i \/ j \/ Void 59 | 60 | in1 :: forall a z. a -> a \/ z 61 | in1 = Left 62 | 63 | in2 :: forall a b z. b -> a \/ b \/ z 64 | in2 v = Right (Left v) 65 | 66 | in3 :: forall a b c z. c -> a \/ b \/ c \/ z 67 | in3 v = Right (Right (Left v)) 68 | 69 | in4 :: forall a b c d z. d -> a \/ b \/ c \/ d \/ z 70 | in4 v = Right (Right (Right (Left v))) 71 | 72 | in5 :: forall a b c d e z. e -> a \/ b \/ c \/ d \/ e \/ z 73 | in5 v = Right (Right (Right (Right (Left v)))) 74 | 75 | in6 :: forall a b c d e f z. f -> a \/ b \/ c \/ d \/ e \/ f \/ z 76 | in6 v = Right (Right (Right (Right (Right (Left v))))) 77 | 78 | in7 :: forall a b c d e f g z. g -> a \/ b \/ c \/ d \/ e \/ f \/ g \/ z 79 | in7 v = Right (Right (Right (Right (Right (Right (Left v)))))) 80 | 81 | in8 :: forall a b c d e f g h z. h -> a \/ b \/ c \/ d \/ e \/ f \/ g \/ h \/ z 82 | in8 v = Right (Right (Right (Right (Right (Right (Right (Left v))))))) 83 | 84 | in9 :: forall a b c d e f g h i z. i -> a \/ b \/ c \/ d \/ e \/ f \/ g \/ h \/ i \/ z 85 | in9 v = Right (Right (Right (Right (Right (Right (Right (Right (Left v)))))))) 86 | 87 | in10 :: forall a b c d e f g h i j z. j -> a \/ b \/ c \/ d \/ e \/ f \/ g \/ h \/ i \/ j \/ z 88 | in10 v = Right (Right (Right (Right (Right (Right (Right (Right (Right (Left v))))))))) 89 | 90 | at1 :: forall r a z. r -> (a -> r) -> a \/ z -> r 91 | at1 b f y = case y of 92 | Left r -> f r 93 | _ -> b 94 | 95 | at2 :: forall r a b z. r -> (b -> r) -> a \/ b \/ z -> r 96 | at2 b f y = case y of 97 | Right (Left r) -> f r 98 | _ -> b 99 | 100 | at3 :: forall r a b c z. r -> (c -> r) -> a \/ b \/ c \/ z -> r 101 | at3 b f y = case y of 102 | Right (Right (Left r)) -> f r 103 | _ -> b 104 | 105 | at4 :: forall r a b c d z. r -> (d -> r) -> a \/ b \/ c \/ d \/ z -> r 106 | at4 b f y = case y of 107 | Right (Right (Right (Left r))) -> f r 108 | _ -> b 109 | 110 | at5 :: forall r a b c d e z. r -> (e -> r) -> a \/ b \/ c \/ d \/ e \/ z -> r 111 | at5 b f y = case y of 112 | Right (Right (Right (Right (Left r)))) -> f r 113 | _ -> b 114 | 115 | at6 :: forall r a b c d e f z. r -> (f -> r) -> a \/ b \/ c \/ d \/ e \/ f \/ z -> r 116 | at6 b f y = case y of 117 | Right (Right (Right (Right (Right (Left r))))) -> f r 118 | _ -> b 119 | 120 | at7 :: forall r a b c d e f g z. r -> (g -> r) -> a \/ b \/ c \/ d \/ e \/ f \/ g \/ z -> r 121 | at7 b f y = case y of 122 | Right (Right (Right (Right (Right (Right (Left r)))))) -> f r 123 | _ -> b 124 | 125 | at8 :: forall r a b c d e f g h z. r -> (h -> r) -> a \/ b \/ c \/ d \/ e \/ f \/ g \/ h \/ z -> r 126 | at8 b f y = case y of 127 | Right (Right (Right (Right (Right (Right (Right (Left r))))))) -> f r 128 | _ -> b 129 | 130 | at9 :: forall r a b c d e f g h i z. r -> (i -> r) -> a \/ b \/ c \/ d \/ e \/ f \/ g \/ h \/ i \/ z -> r 131 | at9 b f y = case y of 132 | Right (Right (Right (Right (Right (Right (Right (Right (Left r)))))))) -> f r 133 | _ -> b 134 | 135 | at10 :: forall r a b c d e f g h i j z. r -> (j -> r) -> a \/ b \/ c \/ d \/ e \/ f \/ g \/ h \/ i \/ j \/ z -> r 136 | at10 b f y = case y of 137 | Right (Right (Right (Right (Right (Right (Right (Right (Right (Left r))))))))) -> f r 138 | _ -> b 139 | 140 | either1 :: forall a. Either1 a -> a 141 | either1 y = case y of 142 | Left r -> r 143 | Right _1 -> absurd _1 144 | 145 | either2 :: forall r a b. (a -> r) -> (b -> r) -> Either2 a b -> r 146 | either2 a b y = case y of 147 | Left r -> a r 148 | Right _1 -> case _1 of 149 | Left r -> b r 150 | Right _2 -> absurd _2 151 | 152 | either3 :: forall r a b c. (a -> r) -> (b -> r) -> (c -> r) -> Either3 a b c -> r 153 | either3 a b c y = case y of 154 | Left r -> a r 155 | Right _1 -> case _1 of 156 | Left r -> b r 157 | Right _2 -> case _2 of 158 | Left r -> c r 159 | Right _3 -> absurd _3 160 | 161 | either4 :: forall r a b c d. (a -> r) -> (b -> r) -> (c -> r) -> (d -> r) -> Either4 a b c d -> r 162 | either4 a b c d y = case y of 163 | Left r -> a r 164 | Right _1 -> case _1 of 165 | Left r -> b r 166 | Right _2 -> case _2 of 167 | Left r -> c r 168 | Right _3 -> case _3 of 169 | Left r -> d r 170 | Right _4 -> absurd _4 171 | 172 | either5 :: forall r a b c d e. (a -> r) -> (b -> r) -> (c -> r) -> (d -> r) -> (e -> r) -> Either5 a b c d e -> r 173 | either5 a b c d e y = case y of 174 | Left r -> a r 175 | Right _1 -> case _1 of 176 | Left r -> b r 177 | Right _2 -> case _2 of 178 | Left r -> c r 179 | Right _3 -> case _3 of 180 | Left r -> d r 181 | Right _4 -> case _4 of 182 | Left r -> e r 183 | Right _5 -> absurd _5 184 | 185 | either6 :: forall r a b c d e f. (a -> r) -> (b -> r) -> (c -> r) -> (d -> r) -> (e -> r) -> (f -> r) -> Either6 a b c d e f -> r 186 | either6 a b c d e f y = case y of 187 | Left r -> a r 188 | Right _1 -> case _1 of 189 | Left r -> b r 190 | Right _2 -> case _2 of 191 | Left r -> c r 192 | Right _3 -> case _3 of 193 | Left r -> d r 194 | Right _4 -> case _4 of 195 | Left r -> e r 196 | Right _5 -> case _5 of 197 | Left r -> f r 198 | Right _6 -> absurd _6 199 | 200 | either7 :: forall r a b c d e f g. (a -> r) -> (b -> r) -> (c -> r) -> (d -> r) -> (e -> r) -> (f -> r) -> (g -> r) -> Either7 a b c d e f g -> r 201 | either7 a b c d e f g y = case y of 202 | Left r -> a r 203 | Right _1 -> case _1 of 204 | Left r -> b r 205 | Right _2 -> case _2 of 206 | Left r -> c r 207 | Right _3 -> case _3 of 208 | Left r -> d r 209 | Right _4 -> case _4 of 210 | Left r -> e r 211 | Right _5 -> case _5 of 212 | Left r -> f r 213 | Right _6 -> case _6 of 214 | Left r -> g r 215 | Right _7 -> absurd _7 216 | 217 | either8 :: forall r a b c d e f g h. (a -> r) -> (b -> r) -> (c -> r) -> (d -> r) -> (e -> r) -> (f -> r) -> (g -> r) -> (h -> r) -> Either8 a b c d e f g h -> r 218 | either8 a b c d e f g h y = case y of 219 | Left r -> a r 220 | Right _1 -> case _1 of 221 | Left r -> b r 222 | Right _2 -> case _2 of 223 | Left r -> c r 224 | Right _3 -> case _3 of 225 | Left r -> d r 226 | Right _4 -> case _4 of 227 | Left r -> e r 228 | Right _5 -> case _5 of 229 | Left r -> f r 230 | Right _6 -> case _6 of 231 | Left r -> g r 232 | Right _7 -> case _7 of 233 | Left r -> h r 234 | Right _8 -> absurd _8 235 | 236 | either9 :: forall r a b c d e f g h i. (a -> r) -> (b -> r) -> (c -> r) -> (d -> r) -> (e -> r) -> (f -> r) -> (g -> r) -> (h -> r) -> (i -> r) -> Either9 a b c d e f g h i -> r 237 | either9 a b c d e f g h i y = case y of 238 | Left r -> a r 239 | Right _1 -> case _1 of 240 | Left r -> b r 241 | Right _2 -> case _2 of 242 | Left r -> c r 243 | Right _3 -> case _3 of 244 | Left r -> d r 245 | Right _4 -> case _4 of 246 | Left r -> e r 247 | Right _5 -> case _5 of 248 | Left r -> f r 249 | Right _6 -> case _6 of 250 | Left r -> g r 251 | Right _7 -> case _7 of 252 | Left r -> h r 253 | Right _8 -> case _8 of 254 | Left r -> i r 255 | Right _9 -> absurd _9 256 | 257 | either10 :: forall r a b c d e f g h i j. (a -> r) -> (b -> r) -> (c -> r) -> (d -> r) -> (e -> r) -> (f -> r) -> (g -> r) -> (h -> r) -> (i -> r) -> (j -> r) -> Either10 a b c d e f g h i j -> r 258 | either10 a b c d e f g h i j y = case y of 259 | Left r -> a r 260 | Right _1 -> case _1 of 261 | Left r -> b r 262 | Right _2 -> case _2 of 263 | Left r -> c r 264 | Right _3 -> case _3 of 265 | Left r -> d r 266 | Right _4 -> case _4 of 267 | Left r -> e r 268 | Right _5 -> case _5 of 269 | Left r -> f r 270 | Right _6 -> case _6 of 271 | Left r -> g r 272 | Right _7 -> case _7 of 273 | Left r -> h r 274 | Right _8 -> case _8 of 275 | Left r -> i r 276 | Right _9 -> case _9 of 277 | Left r -> j r 278 | Right _10 -> absurd _10 279 | -------------------------------------------------------------------------------- /test/Main.purs: -------------------------------------------------------------------------------- 1 | module Test.Main where 2 | 3 | import Prelude 4 | 5 | import Data.Either.Inject (inj, prj) 6 | import Data.Either.Nested (Either3, in1, in2, in3) 7 | import Data.Maybe (Maybe(..)) 8 | import Effect (Effect) 9 | import Effect.Console (log) 10 | import Test.Assert (assertEqual) 11 | 12 | type MySum = Either3 Boolean String Int 13 | 14 | main :: Effect Unit 15 | main = do 16 | log "Test injection" 17 | assertEqual 18 | { actual: inj true :: MySum 19 | , expected: in1 true 20 | } 21 | assertEqual 22 | { actual: inj "hello" :: MySum 23 | , expected: in2 "hello" 24 | } 25 | assertEqual 26 | { actual: inj 100 :: MySum 27 | , expected: in3 100 28 | } 29 | log "Test injection with the injectReflexive instance" 30 | assertEqual 31 | let 32 | x = inj 100 :: MySum 33 | in 34 | { actual: inj x :: MySum 35 | , expected: x 36 | } 37 | log "Test that injection picks the left-most option" 38 | assertEqual 39 | { actual: inj 100 :: Either3 Int Int Int 40 | , expected: in1 100 41 | } 42 | log "Test projection" 43 | assertEqual 44 | { actual: prj (in1 true :: MySum) 45 | , expected: Just true 46 | } 47 | assertEqual 48 | { actual: prj (in2 "hello" :: MySum) 49 | , expected: Just "hello" 50 | } 51 | assertEqual 52 | { actual: prj (in3 100 :: MySum) 53 | , expected: Just 100 54 | } 55 | assertEqual 56 | { actual: prj (in1 true :: MySum) 57 | , expected: Nothing :: Maybe String 58 | } 59 | assertEqual 60 | { actual: prj (in2 "hello" :: MySum) 61 | , expected: Nothing :: Maybe Int 62 | } 63 | assertEqual 64 | { actual: prj (in3 100 :: MySum) 65 | , expected: Nothing :: Maybe Boolean 66 | } 67 | --------------------------------------------------------------------------------