From f269bcf05c86308582384d8e216c80341093b510 Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Thu, 15 Oct 2026 00:50:42 +0000 Subject: [PATCH 1/6] Migrate repository tooling and CI to Spago --- .github/workflows/ci.yml | 30 +++++++++++++++--------------- .gitignore | 5 ++++- .oxfmtrc.json | 3 +++ .tidyrc.json | 10 ++++++++++ CHANGELOG.md | 11 +++-------- bower.json | 35 ----------------------------------- package.json | 16 ++++++++++------ spago.yaml | 32 ++++++++++++++++++++++++++++++++ 8 files changed, 77 insertions(+), 65 deletions(-) create mode 100644 .oxfmtrc.json create mode 100644 .tidyrc.json delete mode 100644 bower.json create mode 100644 spago.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c69237a..1a2a70b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,30 +6,30 @@ on: pull_request: branches: [master] +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - - uses: purescript-contrib/setup-purescript@main - with: - purescript: "unstable" + - uses: actions/checkout@v6 - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v6 with: - node-version: "14.x" + node-version: "24" - name: Install dependencies - run: | - npm install -g bower - npm install - bower install --production + run: npm install - name: Build source - run: npm run-script build + run: npm run build - name: Run tests - run: | - bower install - npm run-script test --if-present + run: npm test + + - name: Lint + run: npm run lint + + - name: Check formatting + run: npm run format:check diff --git a/.gitignore b/.gitignore index 7ebd961..6f7e45c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ /.* !/.gitignore !/.github/ +!/.tidyrc.json +!/.oxfmtrc.json /bower_components/ /node_modules/ /output/ -package-lock.json +/package-lock.json +/spago.lock diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 0000000..757fd64 --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,3 @@ +{ + "trailingComma": "es5" +} diff --git a/.tidyrc.json b/.tidyrc.json new file mode 100644 index 0000000..9e39cf1 --- /dev/null +++ b/.tidyrc.json @@ -0,0 +1,10 @@ +{ + "importSort": "ide", + "importWrap": "source", + "indent": 2, + "operatorsFile": null, + "ribbon": 1, + "typeArrowPlacement": "first", + "unicode": "never", + "width": null +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e71a18..bdaa359 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,16 +2,12 @@ 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). -## [Unreleased] - -Breaking changes: - -New features: - -Bugfixes: +## [v6.0.2](https://github.com/purescript/purescript-enums/releases/tag/v6.0.2) Other improvements: +- Migrate from Bower/Pulp to Spago and update CI, linting, and formatting. + ## [v6.0.1](https://github.com/purescript/purescript-enums/releases/tag/v6.0.1) - 2022-08-16 Bugfixes: @@ -145,4 +141,3 @@ Complete redesign by @jdegoes. ## [v0.1.0](https://github.com/purescript/purescript-enums/releases/tag/v0.1.0) - 2014-04-25 - diff --git a/bower.json b/bower.json deleted file mode 100644 index 3c238c4..0000000 --- a/bower.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "purescript-enums", - "homepage": "https://github.com/purescript/purescript-enums", - "license": "BSD-3-Clause", - "repository": { - "type": "git", - "url": "https://github.com/purescript/purescript-enums.git" - }, - "ignore": [ - "**/.*", - "bower_components", - "node_modules", - "output", - "test", - "bower.json", - "gulpfile.js", - "package.json" - ], - "dependencies": { - "purescript-control": "^6.0.0", - "purescript-either": "^6.0.0", - "purescript-gen": "^4.0.0", - "purescript-maybe": "^6.0.0", - "purescript-newtype": "^5.0.0", - "purescript-nonempty": "^7.0.0", - "purescript-partial": "^4.0.0", - "purescript-prelude": "^6.0.0", - "purescript-tuples": "^7.0.0", - "purescript-unfoldable": "^6.0.0" - }, - "devDependencies": { - "purescript-assert": "^6.0.0", - "purescript-console": "^6.0.0" - } -} diff --git a/package.json b/package.json index c8e10e0..c0a8ad2 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,17 @@ { "private": true, "scripts": { - "clean": "rimraf output && rimraf .pulp-cache", - "build": "pulp build -- --censor-lib --strict", - "test": "pulp test" + "build": "spago build", + "test": "spago test", + "lint": "oxlint --deny-warnings src test", + "format": "purs-tidy format-in-place src test && oxfmt --write .", + "format:check": "purs-tidy check src test && oxfmt --check ." }, "devDependencies": { - "pulp": "16.0.0-0", - "purescript-psa": "^0.8.2", - "rimraf": "^3.0.2" + "oxfmt": "^0.73.0", + "oxlint": "^1.88.0", + "purescript": "^0.15.16", + "purs-tidy": "^0.11.1", + "spago": "^1.0.5" } } diff --git a/spago.yaml b/spago.yaml new file mode 100644 index 0000000..52524e2 --- /dev/null +++ b/spago.yaml @@ -0,0 +1,32 @@ +package: + name: enums + description: Operations for sequentially ordered types. + build: + strict: true + pedanticPackages: true + publish: + version: 6.0.2 + license: BSD-3-Clause + location: + githubOwner: purescript + githubRepo: purescript-enums + dependencies: + - control: ">=6.0.0 <7.0.0" + - either: ">=6.0.0 <7.0.0" + - gen: ">=4.0.0 <5.0.0" + - maybe: ">=6.0.0 <7.0.0" + - newtype: ">=5.0.0 <6.0.0" + - nonempty: ">=7.0.0 <8.0.0" + - partial: ">=4.0.0 <5.0.0" + - prelude: ">=6.0.0 <7.0.0" + - tuples: ">=7.0.0 <8.0.0" + - unfoldable: ">=6.0.0 <7.0.0" + test: + main: Test.Main + strict: true + pedanticPackages: true + dependencies: + - assert: ">=6.0.0 <7.0.0" + - console: ">=6.0.0 <7.0.0" + - effect: ">=4.0.0 <5.0.0" +workspace: {} From e0b7b546bd61411166bc19b71c818bb089ea79b7 Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Thu, 15 Oct 2026 00:51:20 +0000 Subject: [PATCH 2/6] Format PureScript and repository files --- CHANGELOG.md | 14 ++++----- src/Data/Enum.purs | 45 +++++++++++++++------------- src/Data/Enum/Gen.purs | 12 ++++---- src/Data/Enum/Generic.purs | 19 ++++++------ test/Test/Data/Enum.purs | 50 ++++++++++++++++---------------- test/Test/Data/Enum/Generic.purs | 37 +++++++++++++++++++---- 6 files changed, 105 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bdaa359..12a4024 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,11 +11,13 @@ Other improvements: ## [v6.0.1](https://github.com/purescript/purescript-enums/releases/tag/v6.0.1) - 2022-08-16 Bugfixes: + - Fix `Char`'s `toEnum` implementation (#55 by @JordanMartinez) ## [v6.0.0](https://github.com/purescript/purescript-enums/releases/tag/v6.0.0) - 2022-04-27 Breaking changes: + - Migrate FFI to ES modules (#51 by @sigma-andex and @JordanMartinez) New features: @@ -27,20 +29,23 @@ Other improvements: ## [v5.0.0](https://github.com/purescript/purescript-enums/releases/tag/v5.0.0) - 2021-02-26 Breaking changes: + - Added support for PureScript 0.14 and dropped support for all previous versions (#44) New features: + - Absorbed `Data.Enum.Generic` from `generics-rep` (#46) Bugfixes: Other improvements: + - Migrated CI to GitHub Actions and updated installation instructions to use Spago (#45) - Added a CHANGELOG.md file and pull request template (#47, #48) ## [v4.0.1](https://github.com/purescript/purescript-enums/releases/tag/v4.0.1) - 2019-01-31 -* Fix stack-safety issues in `defaultCardinality`, `defaultToEnum`, and `defaultFromEnum`. +- Fix stack-safety issues in `defaultCardinality`, `defaultToEnum`, and `defaultFromEnum`. ## [v4.0.0](https://github.com/purescript/purescript-enums/releases/tag/v4.0.0) - 2018-05-23 @@ -108,20 +113,17 @@ Initial release candidate of the library intended for the 0.7 compiler. ## [v0.4.0](https://github.com/purescript/purescript-enums/releases/tag/v0.4.0) - 2015-02-21 **This release requires PureScript v0.6.8 or later** + - Updated dependencies ## [v0.3.1](https://github.com/purescript/purescript-enums/releases/tag/v0.3.1) - 2015-02-16 - - ## [v0.3.0](https://github.com/purescript/purescript-enums/releases/tag/v0.3.0) - 2014-12-01 - Moved `toEnum` and `fromEnum` into the `Enum` class (@NightRa) ## [v0.2.4](https://github.com/purescript/purescript-enums/releases/tag/v0.2.4) - 2014-10-31 - - ## [v0.2.3](https://github.com/purescript/purescript-enums/releases/tag/v0.2.3) - 2014-10-18 - Add `Enum` instance for `Either` (@jdegoes) @@ -139,5 +141,3 @@ Initial release candidate of the library intended for the 0.7 compiler. Complete redesign by @jdegoes. ## [v0.1.0](https://github.com/purescript/purescript-enums/releases/tag/v0.1.0) - 2014-04-25 - - diff --git a/src/Data/Enum.purs b/src/Data/Enum.purs index 0d4b097..0fddf64 100644 --- a/src/Data/Enum.purs +++ b/src/Data/Enum.purs @@ -1,6 +1,11 @@ module Data.Enum - ( class Enum, succ, pred - , class BoundedEnum, cardinality, toEnum, fromEnum + ( class Enum + , succ + , pred + , class BoundedEnum + , cardinality + , toEnum + , fromEnum , toEnumWithDefaults , Cardinality(..) , enumFromTo @@ -20,7 +25,7 @@ import Prelude import Control.MonadPlus (guard) import Data.Either (Either(..)) -import Data.Maybe (Maybe(..), maybe, fromJust) +import Data.Maybe (Maybe(..), fromJust, maybe) import Data.Newtype (class Newtype) import Data.Tuple (Tuple(..)) import Data.Unfoldable (class Unfoldable, singleton, unfoldr) @@ -55,7 +60,7 @@ instance enumBoolean :: Enum Boolean where succ false = Just true succ _ = Nothing pred true = Just false - pred _= Nothing + pred _ = Nothing instance enumInt :: Enum Int where succ n = if n < top then Just (n + 1) else Nothing @@ -189,7 +194,7 @@ enumFromTo = case _, _ of | from < to -> unfoldr1 (go succ (<=) to) from | otherwise -> unfoldr1 (go pred (>=) to) from where - go step op to a = Tuple a (step a >>= \a' -> guard (a' `op` to) $> a') + go step op to a = Tuple a (step a >>= \a' -> guard (a' `op` to) $> a') -- | Returns a sequence of elements from the first value, taking steps -- | according to the difference between the first and second value, up to @@ -214,9 +219,9 @@ enumFromThenTo = unsafePartial \a b c -> in (toEnum >>> fromJust) <$> unfoldr (go (b' - a') c') a' where - go step to e - | e <= to = Just (Tuple e (e + step)) - | otherwise = Nothing + go step to e + | e <= to = Just (Tuple e (e + step)) + | otherwise = Nothing -- | Produces all successors of an `Enum` value, excluding the start value. upFrom :: forall a u. Enum a => Unfoldable u => a -> u a @@ -225,7 +230,7 @@ upFrom = unfoldr (map diag <<< succ) -- | Produces all successors of an `Enum` value, including the start value. -- | -- | `upFromIncluding bottom` will return all values in an `Enum`. -upFromIncluding :: ∀ a u. Enum a => Unfoldable1 u => a -> u a +upFromIncluding :: forall a u. Enum a => Unfoldable1 u => a -> u a upFromIncluding = unfoldr1 (Tuple <*> succ) -- | Produces all predecessors of an `Enum` value, excluding the start value. @@ -271,7 +276,8 @@ defaultPred toEnum' fromEnum' a = toEnum' (fromEnum' a - 1) -- | -- | Runs in `O(n)` where `n` is `fromEnum top` defaultCardinality :: forall a. Bounded a => Enum a => Cardinality a -defaultCardinality = Cardinality $ go 1 (bottom :: a) where +defaultCardinality = Cardinality $ go 1 (bottom :: a) + where go i x = case succ x of Just x' -> go (i + 1) x' @@ -285,17 +291,15 @@ defaultCardinality = Cardinality $ go 1 (bottom :: a) where -- | Runs in `O(n)` where `n` is `fromEnum a`. defaultToEnum :: forall a. Bounded a => Enum a => Int -> Maybe a defaultToEnum i' = - if i' < 0 - then Nothing - else go i' bottom + if i' < 0 then Nothing + else go i' bottom where go i x = - if i == 0 - then Just x - -- We avoid using >>= here because it foils tail-call optimization - else case succ x of - Just x' -> go (i - 1) x' - Nothing -> Nothing + if i == 0 then Just x + -- We avoid using >>= here because it foils tail-call optimization + else case succ x of + Just x' -> go (i - 1) x' + Nothing -> Nothing -- | Provides a default implementation for `fromEnum`. -- | @@ -304,7 +308,8 @@ defaultToEnum i' = -- | -- | Runs in `O(n)` where `n` is `fromEnum a`. defaultFromEnum :: forall a. Enum a => a -> Int -defaultFromEnum = go 0 where +defaultFromEnum = go 0 + where go i x = case pred x of Just x' -> go (i + 1) x' diff --git a/src/Data/Enum/Gen.purs b/src/Data/Enum/Gen.purs index 86caebd..f1de0fc 100644 --- a/src/Data/Enum/Gen.purs +++ b/src/Data/Enum/Gen.purs @@ -3,7 +3,7 @@ module Data.Enum.Gen where import Prelude import Control.Monad.Gen (class MonadGen, elements) -import Data.Enum (class BoundedEnum, succ, enumFromTo) +import Data.Enum (class BoundedEnum, enumFromTo, succ) import Data.Maybe (Maybe(..)) import Data.NonEmpty ((:|)) @@ -11,8 +11,10 @@ import Data.NonEmpty ((:|)) genBoundedEnum :: forall m a. MonadGen m => BoundedEnum a => m a genBoundedEnum = case succ bottom of - Just a → - let possibilities = enumFromTo a top :: Array a - in elements (bottom :| possibilities) - Nothing → + Just a -> + let + possibilities = enumFromTo a top :: Array a + in + elements (bottom :| possibilities) + Nothing -> pure bottom diff --git a/src/Data/Enum/Generic.purs b/src/Data/Enum/Generic.purs index 0d59cca..0f33185 100644 --- a/src/Data/Enum/Generic.purs +++ b/src/Data/Enum/Generic.purs @@ -2,9 +2,9 @@ module Data.Enum.Generic where import Prelude +import Data.Bounded.Generic (class GenericBottom, class GenericTop, genericBottom', genericTop') import Data.Enum (class BoundedEnum, class Enum, Cardinality(..), cardinality, fromEnum, pred, succ, toEnum) import Data.Generic.Rep (class Generic, Argument(..), Constructor(..), NoArguments(..), Product(..), Sum(..), from, to) -import Data.Bounded.Generic (class GenericBottom, class GenericTop, genericBottom', genericTop') import Data.Maybe (Maybe(..)) import Data.Newtype (unwrap) @@ -44,7 +44,6 @@ instance genericEnumProduct :: (GenericEnum a, GenericTop a, GenericBottom a, Ge Just s -> Just $ Product a s Nothing -> flip Product genericBottom' <$> genericSucc' a - -- | A `Generic` implementation of the `pred` member from the `Enum` type class. genericPred :: forall a rep. Generic a rep => GenericEnum rep => a -> Maybe a genericPred = map to <<< genericPred' <<< from @@ -77,7 +76,7 @@ instance genericBoundedEnumSum :: (GenericBoundedEnum a, GenericBoundedEnum b) = genericCardinality' = Cardinality $ unwrap (genericCardinality' :: Cardinality a) - + unwrap (genericCardinality' :: Cardinality b) + + unwrap (genericCardinality' :: Cardinality b) genericToEnum' n = to genericCardinality' where to :: Cardinality a -> Maybe (Sum a b) @@ -88,19 +87,19 @@ instance genericBoundedEnumSum :: (GenericBoundedEnum a, GenericBoundedEnum b) = Inl a -> genericFromEnum' a Inr b -> genericFromEnum' b + unwrap (genericCardinality' :: Cardinality a) - instance genericBoundedEnumProduct :: (GenericBoundedEnum a, GenericBoundedEnum b) => GenericBoundedEnum (Product a b) where genericCardinality' = Cardinality $ unwrap (genericCardinality' :: Cardinality a) - * unwrap (genericCardinality' :: Cardinality b) + * unwrap (genericCardinality' :: Cardinality b) genericToEnum' n = to genericCardinality' - where to :: Cardinality b -> Maybe (Product a b) - to (Cardinality cb) = Product <$> (genericToEnum' $ n `div` cb) <*> (genericToEnum' $ n `mod` cb) + where + to :: Cardinality b -> Maybe (Product a b) + to (Cardinality cb) = Product <$> (genericToEnum' $ n `div` cb) <*> (genericToEnum' $ n `mod` cb) genericFromEnum' = from genericCardinality' - where from :: Cardinality b -> (Product a b) -> Int - from (Cardinality cb) (Product a b) = genericFromEnum' a * cb + genericFromEnum' b - + where + from :: Cardinality b -> (Product a b) -> Int + from (Cardinality cb) (Product a b) = genericFromEnum' a * cb + genericFromEnum' b -- | A `Generic` implementation of the `cardinality` member from the -- | `BoundedEnum` type class. diff --git a/test/Test/Data/Enum.purs b/test/Test/Data/Enum.purs index a71d2c2..fd25994 100644 --- a/test/Test/Data/Enum.purs +++ b/test/Test/Data/Enum.purs @@ -12,7 +12,7 @@ import Test.Assert (assertEqual) data T = A | B | C | D | E -derive instance eqT :: Eq T +derive instance eqT :: Eq T derive instance ordT :: Ord T instance showT :: Show T where @@ -59,8 +59,8 @@ instance boundedUpto100k :: Bounded Upto100k where bottom = Upto100k 0 instance enumUpto100k :: Enum Upto100k where - succ (Upto100k x) = if (x+1) > 100000 then Nothing else Just (Upto100k (x+1)) - pred (Upto100k x) = if (x-1) < 0 then Nothing else Just (Upto100k (x-1)) + succ (Upto100k x) = if (x + 1) > 100000 then Nothing else Just (Upto100k (x + 1)) + pred (Upto100k x) = if (x - 1) < 0 then Nothing else Just (Upto100k (x - 1)) instance boundedEnumUpto100k :: BoundedEnum Upto100k where cardinality = defaultCardinality @@ -72,59 +72,59 @@ testEnum = do log "enumFromTo" assertEqual { actual: enumFromTo A A - , expected: [A] + , expected: [ A ] } assertEqual { actual: enumFromTo B A - , expected: [B, A] + , expected: [ B, A ] } assertEqual { actual: enumFromTo A C - , expected: [A, B, C] + , expected: [ A, B, C ] } assertEqual { actual: enumFromTo A E - , expected: [A, B, C, D, E] + , expected: [ A, B, C, D, E ] } assertEqual { actual: enumFromTo 0 3 - , expected: [0, 1, 2, 3] + , expected: [ 0, 1, 2, 3 ] } assertEqual { actual: enumFromTo 'c' 'a' - , expected: ['c', 'b', 'a'] + , expected: [ 'c', 'b', 'a' ] } log "enumFromThenTo" assertEqual { actual: enumFromThenTo A B E - , expected: [A, B, C, D, E] + , expected: [ A, B, C, D, E ] } assertEqual { actual: enumFromThenTo A C E - , expected: [A, C, E] + , expected: [ A, C, E ] } assertEqual { actual: enumFromThenTo A E E - , expected: [A, E] + , expected: [ A, E ] } assertEqual { actual: enumFromThenTo A C C - , expected: [A, C] + , expected: [ A, C ] } assertEqual { actual: enumFromThenTo A C D - , expected: [A, C] + , expected: [ A, C ] } log "upFrom" assertEqual { actual: upFrom B - , expected: [C, D, E] + , expected: [ C, D, E ] } assertEqual { actual: upFrom D - , expected: [E] + , expected: [ E ] } assertEqual { actual: upFrom E @@ -134,15 +134,15 @@ testEnum = do log "upFromIncluding" assertEqual { actual: upFromIncluding B - , expected: [B, C, D, E] + , expected: [ B, C, D, E ] } assertEqual { actual: upFromIncluding B - , expected: B :| [C, D, E] + , expected: B :| [ C, D, E ] } assertEqual { actual: upFromIncluding D - , expected: D :| [E] + , expected: D :| [ E ] } assertEqual { actual: upFromIncluding E @@ -152,11 +152,11 @@ testEnum = do log "downFrom" assertEqual { actual: downFrom D - , expected: [C, B, A] + , expected: [ C, B, A ] } assertEqual { actual: downFrom B - , expected: [A] + , expected: [ A ] } assertEqual { actual: downFrom A @@ -166,15 +166,15 @@ testEnum = do log "downFromIncluding" assertEqual { actual: downFromIncluding D - , expected: [D, C, B, A] + , expected: [ D, C, B, A ] } assertEqual { actual: downFromIncluding B - , expected: [B, A] + , expected: [ B, A ] } assertEqual { actual: downFromIncluding A - , expected: [A] + , expected: [ A ] } log "defaultCardinality is stack safe" @@ -194,7 +194,7 @@ testEnum = do { actual: defaultFromEnum (Upto100k 100000) , expected: 100000 } - + log "charToEnum" assertEqual { actual: Nothing :: Maybe Char diff --git a/test/Test/Data/Enum/Generic.purs b/test/Test/Data/Enum/Generic.purs index 7472119..a5b56bc 100644 --- a/test/Test/Data/Enum/Generic.purs +++ b/test/Test/Data/Enum/Generic.purs @@ -2,89 +2,113 @@ module Test.Data.Enum.Generic where import Prelude -import Data.Enum (class BoundedEnum, class Enum, Cardinality(..), cardinality, fromEnum, pred, succ, toEnum, enumFromTo) -import Data.Generic.Rep as G import Data.Bounded.Generic as GBounded +import Data.Enum (class BoundedEnum, class Enum, Cardinality(..), cardinality, enumFromTo, fromEnum, pred, succ, toEnum) import Data.Enum.Generic as GEnum import Data.Eq.Generic as GEq +import Data.Generic.Rep as G +import Data.Maybe (Maybe(..)) import Data.Ord.Generic as GOrd import Data.Show.Generic as GShow -import Data.Maybe (Maybe(..)) import Effect (Effect) import Effect.Console (log) import Test.Assert (assert) data SimpleBounded = A | B | C | D + derive instance genericSimpleBounded :: G.Generic SimpleBounded _ instance eqSimpleBounded :: Eq SimpleBounded where eq x y = GEq.genericEq x y + instance ordSimpleBounded :: Ord SimpleBounded where compare x y = GOrd.genericCompare x y + instance showSimpleBounded :: Show SimpleBounded where show x = GShow.genericShow x + instance boundedSimpleBounded :: Bounded SimpleBounded where bottom = GBounded.genericBottom top = GBounded.genericTop + instance enumSimpleBounded :: Enum SimpleBounded where pred = GEnum.genericPred succ = GEnum.genericSucc + instance boundedEnumSimpleBounded :: BoundedEnum SimpleBounded where cardinality = GEnum.genericCardinality toEnum = GEnum.genericToEnum fromEnum = GEnum.genericFromEnum data Option a = None | Some a + derive instance genericOption :: G.Generic (Option a) _ instance eqOption :: Eq a => Eq (Option a) where eq x y = GEq.genericEq x y + instance ordOption :: Ord a => Ord (Option a) where compare x y = GOrd.genericCompare x y + instance showOption :: Show a => Show (Option a) where show x = GShow.genericShow x + instance boundedOption :: Bounded a => Bounded (Option a) where bottom = GBounded.genericBottom top = GBounded.genericTop + instance enumOption :: (Bounded a, Enum a) => Enum (Option a) where pred = GEnum.genericPred succ = GEnum.genericSucc + instance boundedEnumOption :: BoundedEnum a => BoundedEnum (Option a) where cardinality = GEnum.genericCardinality toEnum = GEnum.genericToEnum fromEnum = GEnum.genericFromEnum data Bit = Zero | One + derive instance genericBit :: G.Generic Bit _ instance eqBit :: Eq Bit where eq x y = GEq.genericEq x y + instance ordBit :: Ord Bit where compare x y = GOrd.genericCompare x y + instance showBit :: Show Bit where show x = GShow.genericShow x + instance boundedBit :: Bounded Bit where bottom = GBounded.genericBottom top = GBounded.genericTop + instance enumBit :: Enum Bit where pred = GEnum.genericPred succ = GEnum.genericSucc + instance boundedEnumBit :: BoundedEnum Bit where cardinality = GEnum.genericCardinality toEnum = GEnum.genericToEnum fromEnum = GEnum.genericFromEnum data Pair a b = Pair a b + derive instance genericPair :: G.Generic (Pair a b) _ instance eqPair :: (Eq a, Eq b) => Eq (Pair a b) where eq = GEq.genericEq + instance ordPair :: (Ord a, Ord b) => Ord (Pair a b) where compare = GOrd.genericCompare + instance showPair :: (Show a, Show b) => Show (Pair a b) where show = GShow.genericShow + instance boundedPair :: (Bounded a, Bounded b) => Bounded (Pair a b) where bottom = GBounded.genericBottom top = GBounded.genericTop + instance enumPair :: (Bounded a, Enum a, Bounded b, Enum b) => Enum (Pair a b) where pred = GEnum.genericPred succ = GEnum.genericSucc + instance boundedEnumPair :: (BoundedEnum a, BoundedEnum b) => BoundedEnum (Pair a b) where cardinality = GEnum.genericCardinality toEnum = GEnum.genericToEnum @@ -146,5 +170,8 @@ testGenericEnum = do assert $ toEnum (fromEnum (Some A)) == Just (Some A) log "Checking product toEnum/fromEnum roundtrip" - assert $ let allPairs = enumFromTo bottom top :: Array (Pair Bit SimpleBounded) - in (toEnum <<< fromEnum <$> allPairs) == (Just <$> allPairs) + assert $ + let + allPairs = enumFromTo bottom top :: Array (Pair Bit SimpleBounded) + in + (toEnum <<< fromEnum <$> allPairs) == (Just <$> allPairs) From eede60f43d424f4cf0d1996325cf07f0a2a065ec Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Thu, 15 Oct 2026 00:53:56 +0000 Subject: [PATCH 3/6] Credit migration pull request in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12a4024..60090a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ Notable changes to this project are documented in this file. The format is based Other improvements: -- Migrate from Bower/Pulp to Spago and update CI, linting, and formatting. +- Migrate from Bower/Pulp to Spago and update CI, linting, and formatting (#56 by @thomashoneyman). ## [v6.0.1](https://github.com/purescript/purescript-enums/releases/tag/v6.0.1) - 2022-08-16 From 4345fbfd461a7b8bb63bfe043752c0139beb70f9 Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Thu, 15 Oct 2026 21:26:06 +0000 Subject: [PATCH 4/6] Prepare changelog release date and unreleased section --- CHANGELOG.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60090a4..463dbfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,17 @@ 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). -## [v6.0.2](https://github.com/purescript/purescript-enums/releases/tag/v6.0.2) +## [Unreleased] + +Breaking changes: + +New features: + +Bugfixes: + +Other improvements: + +## [v6.0.2](https://github.com/purescript/purescript-enums/releases/tag/v6.0.2) - 2026-10-17 Other improvements: From 644ee6f3fb3121e729aba222b66da6a3e8d010b7 Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Sat, 17 Oct 2026 13:07:05 +0000 Subject: [PATCH 5/6] Apply reviewed enum source and test layouts --- src/Data/Enum.purs | 106 ++++++++++++++++++------------- src/Data/Enum/Gen.purs | 8 +-- src/Data/Enum/Generic.purs | 18 ++---- test/Test/Data/Enum.purs | 24 +++---- test/Test/Data/Enum/Generic.purs | 7 +- 5 files changed, 88 insertions(+), 75 deletions(-) diff --git a/src/Data/Enum.purs b/src/Data/Enum.purs index 0fddf64..08119f4 100644 --- a/src/Data/Enum.purs +++ b/src/Data/Enum.purs @@ -57,10 +57,12 @@ class Ord a <= Enum a where pred :: a -> Maybe a instance enumBoolean :: Enum Boolean where - succ false = Just true - succ _ = Nothing - pred true = Just false - pred _ = Nothing + succ = case _ of + false -> Just true + _ -> Nothing + pred = case _ of + true -> Just false + _ -> Nothing instance enumInt :: Enum Int where succ n = if n < top then Just (n + 1) else Nothing @@ -75,24 +77,30 @@ instance enumUnit :: Enum Unit where pred = const Nothing instance enumOrdering :: Enum Ordering where - succ LT = Just EQ - succ EQ = Just GT - succ GT = Nothing - pred LT = Nothing - pred EQ = Just LT - pred GT = Just EQ + succ = case _ of + LT -> Just EQ + EQ -> Just GT + GT -> Nothing + pred = case _ of + LT -> Nothing + EQ -> Just LT + GT -> Just EQ instance enumMaybe :: BoundedEnum a => Enum (Maybe a) where - succ Nothing = Just (Just bottom) - succ (Just a) = Just <$> succ a - pred Nothing = Nothing - pred (Just a) = Just (pred a) + succ = case _ of + Nothing -> Just (Just bottom) + Just a -> Just <$> succ a + pred = case _ of + Nothing -> Nothing + Just a -> Just (pred a) instance enumEither :: (BoundedEnum a, BoundedEnum b) => Enum (Either a b) where - succ (Left a) = maybe (Just (Right bottom)) (Just <<< Left) (succ a) - succ (Right b) = maybe Nothing (Just <<< Right) (succ b) - pred (Left a) = maybe Nothing (Just <<< Left) (pred a) - pred (Right b) = maybe (Just (Left top)) (Just <<< Right) (pred b) + succ = case _ of + Left a -> maybe (Just (Right bottom)) (Just <<< Left) (succ a) + Right b -> maybe Nothing (Just <<< Right) (succ b) + pred = case _ of + Left a -> maybe Nothing (Just <<< Left) (pred a) + Right b -> maybe (Just (Left top)) (Just <<< Right) (pred b) instance enumTuple :: (Enum a, BoundedEnum b) => Enum (Tuple a b) where succ (Tuple a b) = maybe (flip Tuple bottom <$> succ a) (Just <<< Tuple a) (succ b) @@ -122,11 +130,13 @@ class (Bounded a, Enum a) <= BoundedEnum a where instance boundedEnumBoolean :: BoundedEnum Boolean where cardinality = Cardinality 2 - toEnum 0 = Just false - toEnum 1 = Just true - toEnum _ = Nothing - fromEnum false = 0 - fromEnum true = 1 + toEnum = case _ of + 0 -> Just false + 1 -> Just true + _ -> Nothing + fromEnum = case _ of + false -> 0 + true -> 1 instance boundedEnumChar :: BoundedEnum Char where cardinality = Cardinality (toCharCode top - toCharCode bottom) @@ -135,19 +145,22 @@ instance boundedEnumChar :: BoundedEnum Char where instance boundedEnumUnit :: BoundedEnum Unit where cardinality = Cardinality 1 - toEnum 0 = Just unit - toEnum _ = Nothing + toEnum = case _ of + 0 -> Just unit + _ -> Nothing fromEnum = const 0 instance boundedEnumOrdering :: BoundedEnum Ordering where cardinality = Cardinality 3 - toEnum 0 = Just LT - toEnum 1 = Just EQ - toEnum 2 = Just GT - toEnum _ = Nothing - fromEnum LT = 0 - fromEnum EQ = 1 - fromEnum GT = 2 + toEnum = case _ of + 0 -> Just LT + 1 -> Just EQ + 2 -> Just GT + _ -> Nothing + fromEnum = case _ of + LT -> 0 + EQ -> 1 + GT -> 2 -- | Like `toEnum` but returns the first argument if `x` is less than -- | `fromEnum bottom` and the second argument if `x` is greater than @@ -211,17 +224,18 @@ enumFromTo = case _, _ of -- | The example shows `Array` return values, but the result can be any type -- | with an `Unfoldable1` instance. enumFromThenTo :: forall f a. Unfoldable f => Functor f => BoundedEnum a => a -> a -> a -> f a -enumFromThenTo = unsafePartial \a b c -> +enumFromThenTo = unsafePartial \a b c -> do let a' = fromEnum a b' = fromEnum b c' = fromEnum c - in - (toEnum >>> fromJust) <$> unfoldr (go (b' - a') c') a' + (toEnum >>> fromJust) <$> unfoldr (go (b' - a') c') a' where - go step to e - | e <= to = Just (Tuple e (e + step)) - | otherwise = Nothing + go step to e = + if e <= to then + Just (Tuple e (e + step)) + else + Nothing -- | Produces all successors of an `Enum` value, excluding the start value. upFrom :: forall a u. Enum a => Unfoldable u => a -> u a @@ -291,11 +305,14 @@ defaultCardinality = Cardinality $ go 1 (bottom :: a) -- | Runs in `O(n)` where `n` is `fromEnum a`. defaultToEnum :: forall a. Bounded a => Enum a => Int -> Maybe a defaultToEnum i' = - if i' < 0 then Nothing - else go i' bottom + if i' < 0 then + Nothing + else + go i' bottom where go i x = - if i == 0 then Just x + if i == 0 then + Just x -- We avoid using >>= here because it foils tail-call optimization else case succ x of Just x' -> go (i - 1) x' @@ -319,8 +336,11 @@ diag :: forall a. a -> Tuple a a diag a = Tuple a a charToEnum :: Int -> Maybe Char -charToEnum n | n >= toCharCode bottom && n <= toCharCode top = Just (fromCharCode n) -charToEnum _ = Nothing +charToEnum n = + if n >= toCharCode bottom && n <= toCharCode top then + Just (fromCharCode n) + else + Nothing foreign import toCharCode :: Char -> Int foreign import fromCharCode :: Int -> Char diff --git a/src/Data/Enum/Gen.purs b/src/Data/Enum/Gen.purs index f1de0fc..0654e14 100644 --- a/src/Data/Enum/Gen.purs +++ b/src/Data/Enum/Gen.purs @@ -11,10 +11,8 @@ import Data.NonEmpty ((:|)) genBoundedEnum :: forall m a. MonadGen m => BoundedEnum a => m a genBoundedEnum = case succ bottom of - Just a -> - let - possibilities = enumFromTo a top :: Array a - in - elements (bottom :| possibilities) + Just a -> do + let possibilities = enumFromTo a top :: Array a + elements (bottom :| possibilities) Nothing -> pure bottom diff --git a/src/Data/Enum/Generic.purs b/src/Data/Enum/Generic.purs index 0f33185..1b72bc1 100644 --- a/src/Data/Enum/Generic.purs +++ b/src/Data/Enum/Generic.purs @@ -73,25 +73,21 @@ instance genericBoundedEnumConstructor :: GenericBoundedEnum a => GenericBounded genericFromEnum' (Constructor a) = genericFromEnum' a instance genericBoundedEnumSum :: (GenericBoundedEnum a, GenericBoundedEnum b) => GenericBoundedEnum (Sum a b) where - genericCardinality' = - Cardinality - $ unwrap (genericCardinality' :: Cardinality a) - + unwrap (genericCardinality' :: Cardinality b) + genericCardinality' = Cardinality (unwrap (genericCardinality' :: Cardinality a) + unwrap (genericCardinality' :: Cardinality b)) genericToEnum' n = to genericCardinality' where to :: Cardinality a -> Maybe (Sum a b) - to (Cardinality ca) - | n >= 0 && n < ca = Inl <$> genericToEnum' n - | otherwise = Inr <$> genericToEnum' (n - ca) + to (Cardinality ca) = + if n >= 0 && n < ca then + Inl <$> genericToEnum' n + else + Inr <$> genericToEnum' (n - ca) genericFromEnum' = case _ of Inl a -> genericFromEnum' a Inr b -> genericFromEnum' b + unwrap (genericCardinality' :: Cardinality a) instance genericBoundedEnumProduct :: (GenericBoundedEnum a, GenericBoundedEnum b) => GenericBoundedEnum (Product a b) where - genericCardinality' = - Cardinality - $ unwrap (genericCardinality' :: Cardinality a) - * unwrap (genericCardinality' :: Cardinality b) + genericCardinality' = Cardinality (unwrap (genericCardinality' :: Cardinality a) * unwrap (genericCardinality' :: Cardinality b)) genericToEnum' n = to genericCardinality' where to :: Cardinality b -> Maybe (Product a b) diff --git a/test/Test/Data/Enum.purs b/test/Test/Data/Enum.purs index fd25994..c9d7f1b 100644 --- a/test/Test/Data/Enum.purs +++ b/test/Test/Data/Enum.purs @@ -24,17 +24,19 @@ instance showT :: Show T where E -> "E" instance enumT :: Enum T where - succ A = Just B - succ B = Just C - succ C = Just D - succ D = Just E - succ E = Nothing - - pred A = Nothing - pred B = Just A - pred C = Just B - pred D = Just C - pred E = Just D + succ = case _ of + A -> Just B + B -> Just C + C -> Just D + D -> Just E + E -> Nothing + + pred = case _ of + A -> Nothing + B -> Just A + C -> Just B + D -> Just C + E -> Just D instance boundedT :: Bounded T where bottom = A diff --git a/test/Test/Data/Enum/Generic.purs b/test/Test/Data/Enum/Generic.purs index a5b56bc..4cd1415 100644 --- a/test/Test/Data/Enum/Generic.purs +++ b/test/Test/Data/Enum/Generic.purs @@ -170,8 +170,5 @@ testGenericEnum = do assert $ toEnum (fromEnum (Some A)) == Just (Some A) log "Checking product toEnum/fromEnum roundtrip" - assert $ - let - allPairs = enumFromTo bottom top :: Array (Pair Bit SimpleBounded) - in - (toEnum <<< fromEnum <$> allPairs) == (Just <$> allPairs) + let allPairs = enumFromTo bottom top :: Array (Pair Bit SimpleBounded) + assert $ (toEnum <<< fromEnum <$> allPairs) == (Just <$> allPairs) From 564fa54aa3cc8a1ace7834866bebf007d7d31c25 Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Sat, 17 Oct 2026 16:20:35 +0000 Subject: [PATCH 6/6] Link unreleased changelog comparison --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 463dbfc..222b59b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ 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). -## [Unreleased] +## [Unreleased](https://github.com/purescript/purescript-enums/compare/v6.0.2...HEAD) Breaking changes: