diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..960376b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +**Description of the change** + +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. + +--- + +**Checklist:** + +- [ ] Added the change to the changelog's "Unreleased" section with a reference to this PR (e.g. "- Made change (#0000)") +- [ ] Linked any existing issues or proposals that this pull request should close +- [ ] Updated or added relevant documentation +- [ ] Added a test for the contribution (if applicable) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e2972ba..c69237a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,10 @@ name: CI -on: push +on: + push: + branches: [master] + pull_request: + branches: [master] jobs: build: @@ -10,11 +14,11 @@ jobs: - uses: purescript-contrib/setup-purescript@main with: - purescript: "0.14.0-rc3" + purescript: "unstable" - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v2 with: - node-version: "12" + node-version: "14.x" - name: Install dependencies run: | diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..be52e34 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,73 @@ +# Changelog + +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: + +Other improvements: +- Remove incorrect newtype deriving from `over2` docs (#33 by @ptrfrncsmrph) + +## [v5.0.0](https://github.com/purescript/purescript-newtype/releases/tag/v5.0.0) - 2022-04-27 + +Breaking changes: +- Update project and deps to PureScript v0.15.0 (#30 by @JordanMartinez) + +New features: +- Added `modify` (#19 by @dwhitney) + +Bugfixes: + +Other improvements: + +## [v4.0.0](https://github.com/purescript/purescript-newtype/releases/tag/v4.0.0) - 2021-02-26 + +Breaking changes: +- Added support for PureScript 0.14 and dropped support for all previous versions (#24) +- Removed `op`, which was deprecated in v1.1.0 in favor of `un` (#24) +- Replaced explicit wrapping and unwrapping of newtypes by coercions (#22) +- Added `Coercible` as a superclass of `Newtype` and removed the `wrap` and `unwrap` class members (#22) + The `wrap` and `unwrap` functions still exist, but they are no longer members of the `Newtype` class and are simple aliases for `coerce`. + +New features: + +Bugfixes: + +Other improvements: +- Migrated CI to GitHub Actions and updated installation instructions to use Spago (#25) +- Added a changelog and pull request template (#26) + +## [v3.0.0](https://github.com/purescript/purescript-newtype/releases/tag/v3.0.0) - 2018-05-22 + +- Updated for PureScript 0.12 + +## [v2.0.0](https://github.com/purescript/purescript-newtype/releases/tag/v2.0.0) - 2017-03-25 + +- Update for PureScript 0.11 + +## [v1.3.0](https://github.com/purescript/purescript-newtype/releases/tag/v1.3.0) - 2017-02-03 + +- Added `over` and `under` variants for binary operations (@mlang) + +## [v1.2.0](https://github.com/purescript/purescript-newtype/releases/tag/v1.2.0) - 2016-12-31 + +- Added `traverse` and `collect` functions + +## [v1.1.0](https://github.com/purescript/purescript-newtype/releases/tag/v1.1.0) - 2016-10-28 + +- Introduced `un` as a replacement for `op` - `op` is still present but will be removed in the next major release (#4) +- Documented the class law (#3) +- Fixed a code block in the documentation + +## [v1.0.0](https://github.com/purescript/purescript-newtype/releases/tag/v1.0.0) - 2016-10-02 + +- Initial release for the 0.10 compiler. + +## [v0.1.0](https://github.com/purescript/purescript-newtype/releases/tag/v0.1.0) - 2016-09-23 + +- Initial versioned release. diff --git a/README.md b/README.md index fffa5f8..533a96a 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Latest release](http://img.shields.io/github/release/purescript/purescript-newtype.svg)](https://github.com/purescript/purescript-newtype/releases) [![Build status](https://github.com/purescript/purescript-newtype/workflows/CI/badge.svg?branch=master)](https://github.com/purescript/purescript-newtype/actions?query=workflow%3ACI+branch%3Amaster) +[![Pursuit](https://pursuit.purescript.org/packages/purescript-newtype/badge)](https://pursuit.purescript.org/packages/purescript-newtype) Type class and functions for working with `newtype`s. diff --git a/bower.json b/bower.json index fa89943..427c93a 100644 --- a/bower.json +++ b/bower.json @@ -5,7 +5,7 @@ "license": "BSD-3-Clause", "repository": { "type": "git", - "url": "git://github.com/purescript/purescript-newtype.git" + "url": "https://github.com/purescript/purescript-newtype.git" }, "ignore": [ "**/.*", @@ -17,6 +17,7 @@ "package.json" ], "dependencies": { - "purescript-prelude": "master" + "purescript-prelude": "^6.0.0", + "purescript-safe-coerce": "^2.0.0" } } diff --git a/package.json b/package.json index b8d0c47..3e28704 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "build": "pulp build -- --censor-lib --strict" }, "devDependencies": { - "pulp": "^15.0.0", - "purescript-psa": "^0.8.0", - "rimraf": "^2.6.2" + "pulp": "16.0.0-0", + "purescript-psa": "^0.8.2", + "rimraf": "^3.0.2" } } diff --git a/src/Data/Newtype.purs b/src/Data/Newtype.purs index 14913a7..b16e614 100644 --- a/src/Data/Newtype.purs +++ b/src/Data/Newtype.purs @@ -1,8 +1,5 @@ module Data.Newtype where -import Prelude - -import Data.Function (on) import Data.Monoid.Additive (Additive(..)) import Data.Monoid.Conj (Conj(..)) import Data.Monoid.Disj (Disj(..)) @@ -11,6 +8,7 @@ import Data.Monoid.Endo (Endo(..)) import Data.Monoid.Multiplicative (Multiplicative(..)) import Data.Semigroup.First (First(..)) import Data.Semigroup.Last (Last(..)) +import Safe.Coerce (class Coercible, coerce) -- | A type class for `newtype`s to enable convenient wrapping and unwrapping, -- | and the use of the other functions in this module. @@ -27,54 +25,41 @@ import Data.Semigroup.Last (Last(..)) -- | defined as `newtype` rather than `data` declaration (even if the `data` -- | structurally fits the rules of a `newtype`), and the use of a wildcard for -- | the wrapped type. --- | --- | Instances must obey the following laws: --- | ``` purescript --- | unwrap <<< wrap = id --- | wrap <<< unwrap = id --- | ``` class Newtype :: Type -> Type -> Constraint -class Newtype t a | t -> a where - wrap :: a -> t - unwrap :: t -> a +class Coercible t a <= Newtype t a | t -> a -instance newtypeAdditive :: Newtype (Additive a) a where - wrap = Additive - unwrap (Additive a) = a +wrap :: forall t a. Newtype t a => a -> t +wrap = coerce -instance newtypeMultiplicative :: Newtype (Multiplicative a) a where - wrap = Multiplicative - unwrap (Multiplicative a) = a +unwrap :: forall t a. Newtype t a => t -> a +unwrap = coerce -instance newtypeConj :: Newtype (Conj a) a where - wrap = Conj - unwrap (Conj a) = a +instance newtypeAdditive :: Newtype (Additive a) a -instance newtypeDisj :: Newtype (Disj a) a where - wrap = Disj - unwrap (Disj a) = a +instance newtypeMultiplicative :: Newtype (Multiplicative a) a -instance newtypeDual :: Newtype (Dual a) a where - wrap = Dual - unwrap (Dual a) = a +instance newtypeConj :: Newtype (Conj a) a -instance newtypeEndo :: Newtype (Endo c a) (c a a) where - wrap = Endo - unwrap (Endo a) = a +instance newtypeDisj :: Newtype (Disj a) a -instance newtypeFirst :: Newtype (First a) a where - wrap = First - unwrap (First a) = a +instance newtypeDual :: Newtype (Dual a) a -instance newtypeLast :: Newtype (Last a) a where - wrap = Last - unwrap (Last a) = a +instance newtypeEndo :: Newtype (Endo c a) (c a a) + +instance newtypeFirst :: Newtype (First a) a + +instance newtypeLast :: Newtype (Last a) a -- | Given a constructor for a `Newtype`, this returns the appropriate `unwrap` -- | function. un :: forall t a. Newtype t a => (a -> t) -> t -> a un _ = unwrap +-- | This combinator unwraps the newtype, applies a monomorphic function to the +-- | contained value and wraps the result back in the newtype +modify :: forall t a. Newtype t a => (a -> a) -> t -> t +modify fn t = wrap (fn (unwrap t)) + -- | This combinator is for when you have a higher order function that you want -- | to use in the context of some newtype - `foldMap` being a common example: -- | @@ -86,13 +71,13 @@ un _ = unwrap -- | ``` ala :: forall f t a s b - . Functor f + . Coercible (f t) (f a) => Newtype t a => Newtype s b => (a -> t) -> ((b -> s) -> f t) -> f a -ala _ f = map unwrap (f wrap) +ala _ f = coerce (f wrap) -- | Similar to `ala` but useful for cases where you want to use an additional -- | projection with the higher order function: @@ -107,15 +92,15 @@ ala _ f = map unwrap (f wrap) -- | `Functor`. alaF :: forall f g t a s b - . Functor f - => Functor g + . Coercible (f t) (f a) + => Coercible (g s) (g b) => Newtype t a => Newtype s b => (a -> t) -> (f t -> g s) -> f a -> g b -alaF _ f = map unwrap <<< f <<< map wrap +alaF _ = coerce -- | Lifts a function operate over newtypes. This can be used to lift a -- | function to manipulate the contents of a single newtype, somewhat like @@ -147,7 +132,7 @@ over -> (a -> b) -> t -> s -over _ f = wrap <<< f <<< unwrap +over _ = coerce -- | Much like `over`, but where the lifted function operates on values in a -- | `Functor`: @@ -161,15 +146,15 @@ over _ f = wrap <<< f <<< unwrap -- | here too, the input is an `Array` but the result is a `Maybe`. overF :: forall f g t a s b - . Functor f - => Functor g + . Coercible (f a) (f t) + => Coercible (g b) (g s) => Newtype t a => Newtype s b => (a -> t) -> (f a -> g b) -> f t -> g s -overF _ f = map wrap <<< f <<< map unwrap +overF _ = coerce -- | The opposite of `over`: lowers a function that operates on `Newtype`d -- | values to operate on the wrapped value instead. @@ -200,7 +185,7 @@ under -> (t -> s) -> a -> b -under _ f = unwrap <<< f <<< wrap +under _ = coerce -- | Much like `under`, but where the lifted function operates on values in a -- | `Functor`: @@ -220,23 +205,23 @@ under _ f = unwrap <<< f <<< wrap -- | here too, the input is an `Array` but the result is a `Maybe`. underF :: forall f g t a s b - . Functor f - => Functor g + . Coercible (f t) (f a) + => Coercible (g s) (g b) => Newtype t a => Newtype s b => (a -> t) -> (f t -> g s) -> f a -> g b -underF _ f = map unwrap <<< f <<< map wrap +underF _ = coerce -- | Lifts a binary function to operate over newtypes. -- | -- | ``` purescript -- | newtype Meter = Meter Int --- | derive newtype instance newtypeMeter :: Newtype Meter _ +-- | derive instance newtypeMeter :: Newtype Meter _ -- | newtype SquareMeter = SquareMeter Int --- | derive newtype instance newtypeSquareMeter :: Newtype SquareMeter _ +-- | derive instance newtypeSquareMeter :: Newtype SquareMeter _ -- | -- | area :: Meter -> Meter -> SquareMeter -- | area = over2 Meter (*) @@ -253,14 +238,14 @@ over2 -> t -> t -> s -over2 _ f = compose wrap <<< f `on` unwrap +over2 _ = coerce -- | Much like `over2`, but where the lifted binary function operates on -- | values in a `Functor`. overF2 :: forall f g t a s b - . Functor f - => Functor g + . Coercible (f a) (f t) + => Coercible (g b) (g s) => Newtype t a => Newtype s b => (a -> t) @@ -268,7 +253,7 @@ overF2 -> f t -> f t -> g s -overF2 _ f = compose (map wrap) <<< f `on` map unwrap +overF2 _ = coerce -- | The opposite of `over2`: lowers a binary function that operates on `Newtype`d -- | values to operate on the wrapped value instead. @@ -281,14 +266,14 @@ under2 -> a -> a -> b -under2 _ f = compose unwrap <<< f `on` wrap +under2 _ = coerce -- | Much like `under2`, but where the lifted binary function operates on -- | values in a `Functor`. underF2 :: forall f g t a s b - . Functor f - => Functor g + . Coercible (f t) (f a) + => Coercible (g s) (g b) => Newtype t a => Newtype s b => (a -> t) @@ -296,28 +281,28 @@ underF2 -> f a -> f a -> g b -underF2 _ f = compose (map unwrap) <<< f `on` map wrap +underF2 _ = coerce -- | Similar to the function from the `Traversable` class, but operating within -- | a newtype instead. traverse :: forall f t a - . Functor f + . Coercible (f a) (f t) => Newtype t a => (a -> t) -> (a -> f a) -> t -> f t -traverse _ f = map wrap <<< f <<< unwrap +traverse _ = coerce -- | Similar to the function from the `Distributive` class, but operating within -- | a newtype instead. collect :: forall f t a - . Functor f + . Coercible (f a) (f t) => Newtype t a => (a -> t) -> (f a -> a) -> f t -> t -collect _ f = wrap <<< f <<< map unwrap +collect _ = coerce