├── .editorconfig ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── change-request.md │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci.yml ├── .gitignore ├── .tidyrc.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── README.md ├── bower.json ├── packages.dhall ├── spago.dhall └── src └── Data ├── Functor ├── Mu.purs └── Nu.purs └── TacitString.purs /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report an issue 4 | title: "" 5 | labels: bug 6 | assignees: "" 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of the bug. 11 | 12 | **To Reproduce** 13 | A minimal code example (preferably a runnable example on [Try PureScript](https://try.purescript.org)!) or steps to reproduce the issue. 14 | 15 | **Expected behavior** 16 | A clear and concise description of what you expected to happen. 17 | 18 | **Additional context** 19 | Add any other context about the problem here. 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/change-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Change request 3 | about: Propose an improvement to this library 4 | title: "" 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Is your change request related to a problem? Please describe.** 10 | A clear and concise description of the problem. 11 | 12 | Examples: 13 | 14 | - It's frustrating to have to [...] 15 | - I was looking for a function to [...] 16 | 17 | **Describe the solution you'd like** 18 | A clear and concise description of what a good solution to you looks like, including any solutions you've already considered. 19 | 20 | **Additional context** 21 | Add any other context about the change request here. 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: PureScript Discourse 4 | url: https://discourse.purescript.org/ 5 | about: Ask and answer questions on the PureScript discussion forum. 6 | - name: PureScript Discord 7 | url: https://purescript.org/chat 8 | about: Ask and answer questions on the PureScript chat. 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Description of the change** 2 | 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. 3 | 4 | --- 5 | 6 | **Checklist:** 7 | 8 | - [ ] Added the change to the changelog's "Unreleased" section with a link to this PR and your username 9 | - [ ] Linked any existing issues or proposals that this pull request should close 10 | - [ ] Updated or added relevant documentation in the README and/or documentation directory 11 | - [ ] Added a test for the contribution (if applicable) 12 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Set up a PureScript toolchain 17 | uses: purescript-contrib/setup-purescript@main 18 | with: 19 | purescript: "unstable" 20 | purs-tidy: "latest" 21 | 22 | - name: Cache PureScript dependencies 23 | uses: actions/cache@v2 24 | with: 25 | key: ${{ runner.os }}-spago-${{ hashFiles('**/*.dhall') }} 26 | path: | 27 | .spago 28 | output 29 | 30 | - name: Install dependencies 31 | run: spago install 32 | 33 | - name: Build source 34 | run: spago build --no-install --purs-args '--censor-lib --strict' 35 | 36 | - name: Check formatting 37 | run: purs-tidy check src test 38 | 39 | - name: Verify Bower & Pulp 40 | run: | 41 | npm install bower pulp@16.0.0-0 42 | npx bower install 43 | npx pulp build -- --censor-lib --strict 44 | if [ -d "test" ]; then 45 | npx pulp test 46 | fi 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | !.gitignore 3 | !.github 4 | !.editorconfig 5 | !.tidyrc.json 6 | 7 | output 8 | generated-docs 9 | bower_components 10 | -------------------------------------------------------------------------------- /.tidyrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "importSort": "source", 3 | "importWrap": "source", 4 | "indent": 2, 5 | "operatorsFile": null, 6 | "ribbon": 1, 7 | "typeArrowPlacement": "first", 8 | "unicode": "never", 9 | "width": null 10 | } 11 | -------------------------------------------------------------------------------- /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 | ## [v7.0.0](https://github.com/purescript-contrib/purescript-fixed-points/releases/tag/v7.0.0) - 2022-04-27 16 | 17 | Breaking changes: 18 | - Update project and deps to PureScript v0.15.0 (#22 by @JordanMartinez) 19 | 20 | New features: 21 | 22 | Bugfixes: 23 | 24 | Other improvements: 25 | - Added `purs-tidy` formatter (#21 by @thomashoneyman) 26 | 27 | ## [v6.0.0](https://github.com/purescript-contrib/purescript-fixed-points/releases/tag/v6.0.0) - 2021-02-26 28 | 29 | Breaking changes: 30 | - Added support for PureScript 0.14 and dropped support for all previous versions (#17) 31 | - Removed `Newtype` instance for `TacitString` (#16) 32 | 33 | New features: 34 | 35 | Bugfixes: 36 | 37 | Other improvements: 38 | - Changed default branch to `main` from `master` 39 | - Updated to comply with Contributors library guidelines by adding new issue and pull request templates, updating documentation, and migrating to Spago for local development and CI 40 | 41 | ## [v5.1.0](https://github.com/purescript-contrib/purescript-fixed-points/releases/tag/v5.1.0) - 2018-06-19 42 | 43 | - Added `Semigroup` and `Monoid` instances for `Mu` (@eric-corumdigital) 44 | 45 | ## [v5.0.0](https://github.com/purescript-contrib/purescript-fixed-points/releases/tag/v5.0.0) - 2018-05-24 46 | 47 | - Updated for PureScript 0.12 48 | 49 | ## [v4.0.0](https://github.com/purescript-contrib/purescript-fixed-points/releases/tag/v4.0.0) - 2017-04-07 50 | 51 | - Updated for PureScript 0.11 52 | - Exported `transMu` from `Data.Functor.Mu` 53 | - Removed custom `Store` type and used the one from `purescript-transformers` 54 | 55 | ## [v3.0.0](https://github.com/purescript-contrib/purescript-fixed-points/releases/tag/v3.0.0) - 2017-03-06 56 | 57 | - Removed custom `Ord1` and `Eq1` classes 58 | 59 | ## [v2.0.0](https://github.com/purescript-contrib/purescript-fixed-points/releases/tag/v2.0.0) - 2016-11-03 60 | 61 | - Updated for PureScript 0.10 62 | 63 | ## [v1.0.0](https://github.com/purescript-contrib/purescript-fixed-points/releases/tag/v1.0.0) - 2016-07-18 64 | 65 | - Initial release 66 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Fixed Points 2 | 3 | Thanks for your interest in contributing to `fixed-points`! We welcome new contributions regardless of your level of experience or familiarity with PureScript. 4 | 5 | Every library in the Contributors organization shares a simple handbook that helps new contributors get started. With that in mind, please [read the short contributing guide on purescript-contrib/governance](https://github.com/purescript-contrib/governance/blob/main/contributing.md) before contributing to this library. 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Fixed Points 2 | 3 | [![CI](https://github.com/purescript-contrib/purescript-fixed-points/workflows/CI/badge.svg?branch=main)](https://github.com/purescript-contrib/purescript-fixed-points/actions?query=workflow%3ACI+branch%3Amain) 4 | [![Release](https://img.shields.io/github/release/purescript-contrib/purescript-fixed-points.svg)](https://github.com/purescript-contrib/purescript-fixed-points/releases) 5 | [![Pursuit](https://pursuit.purescript.org/packages/purescript-fixed-points/badge)](https://pursuit.purescript.org/packages/purescript-fixed-points) 6 | [![Maintainer: garyb](https://img.shields.io/badge/maintainer-garyb-teal.svg)](https://github.com/garyb) 7 | 8 | Types for the least (`Mu`) and greatest (`Nu`) fixed points of functors. 9 | 10 | ## Installation 11 | 12 | Install `fixed-points` with [Spago](https://github.com/purescript/spago): 13 | 14 | ```sh 15 | spago install fixed-points 16 | ``` 17 | 18 | ## Quick start 19 | 20 | The quick start hasn't been written yet (contributions are welcome!). The quick start covers a common, minimal use case for the library. 21 | 22 | ## Documentation 23 | 24 | Module documentation for `fixed-points` [published on Pursuit](https://pursuit.purescript.org/packages/purescript-fixed-points). 25 | 26 | If you get stuck, there are several ways to get help: 27 | 28 | - [Open an issue](https://github.com/purescript-contrib/purescript-fixed-points/issues) if you have encountered a bug or problem. 29 | - Ask general questions on the [PureScript Discourse](https://discourse.purescript.org) forum or the [PureScript Discord](https://purescript.org/chat) chat. 30 | 31 | ## Contributing 32 | 33 | You can contribute to `fixed-points` in several ways: 34 | 35 | 1. If you encounter a problem or have a question, please [open an issue](https://github.com/purescript-contrib/purescript-fixed-points/issues). We'll do our best to work with you to resolve or answer it. 36 | 37 | 2. If you would like to contribute code, tests, or documentation, please [read the contributor guide](./CONTRIBUTING.md). It's a short, helpful introduction to contributing to this library, including development instructions. 38 | 39 | 3. If you have written a library, tutorial, guide, or other resource based on this package, please share it on the [PureScript Discourse](https://discourse.purescript.org)! Writing libraries and learning resources are a great way to help this library succeed. 40 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "purescript-fixed-points", 3 | "license": "Apache-2.0", 4 | "authors": [ 5 | "Jon Sterling " 6 | ], 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/purescript-contrib/purescript-fixed-points.git" 10 | }, 11 | "ignore": [ 12 | "**/.*", 13 | "bower_components", 14 | "node_modules", 15 | "output", 16 | "test", 17 | "bower.json", 18 | "package.json" 19 | ], 20 | "dependencies": { 21 | "purescript-exists": "^6.0.0", 22 | "purescript-newtype": "^5.0.0", 23 | "purescript-prelude": "^6.0.0", 24 | "purescript-transformers": "^6.0.0" 25 | }, 26 | "devDependencies": { 27 | "purescript-console": "^6.0.0", 28 | "purescript-effect": "^4.0.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages.dhall: -------------------------------------------------------------------------------- 1 | let upstream = 2 | https://raw.githubusercontent.com/purescript/package-sets/prepare-0.15/src/packages.dhall 3 | 4 | in upstream 5 | -------------------------------------------------------------------------------- /spago.dhall: -------------------------------------------------------------------------------- 1 | { name = "fixed-points" 2 | , dependencies = 3 | [ "control", "exists", "newtype", "prelude", "transformers", "tuples" ] 4 | , packages = ./packages.dhall 5 | , sources = [ "src/**/*.purs" ] 6 | } 7 | -------------------------------------------------------------------------------- /src/Data/Functor/Mu.purs: -------------------------------------------------------------------------------- 1 | module Data.Functor.Mu 2 | ( Mu(..) 3 | , roll 4 | , unroll 5 | , transMu 6 | ) where 7 | 8 | import Prelude 9 | 10 | import Control.Alt (class Alt, (<|>)) 11 | import Control.Alternative (class Plus, empty) 12 | import Data.Eq (class Eq1, eq1) 13 | import Data.Newtype (class Newtype) 14 | import Data.Ord (class Ord1, compare1) 15 | import Data.TacitString as TS 16 | 17 | -- | `Mu f` is the least fixed point of a functor `f`, when it exists. 18 | newtype Mu f = In (f (Mu f)) 19 | 20 | -- | Rewrites a tree along a natural transformation. 21 | transMu 22 | :: forall f g 23 | . (Functor g) 24 | => f ~> g 25 | -> Mu f 26 | -> Mu g 27 | transMu η = 28 | roll 29 | <<< map (transMu η) 30 | <<< η 31 | <<< unroll 32 | 33 | roll :: forall f. f (Mu f) -> Mu f 34 | roll = In 35 | 36 | unroll :: forall f. Mu f -> f (Mu f) 37 | unroll (In x) = x 38 | 39 | derive instance newtypeMu :: Newtype (Mu f) _ 40 | 41 | -- | To implement `Eq`, we require `f` to have higher-kinded equality. 42 | instance eqMu :: Eq1 f => Eq (Mu f) where 43 | eq (In x) (In y) = eq1 x y 44 | 45 | -- | To implement `Ord`, we require `f` to have higher-kinded comparison. 46 | instance ordMu :: (Eq1 f, Ord1 f) => Ord (Mu f) where 47 | compare (In x) (In y) = compare1 x y 48 | 49 | -- | `Show` is compositional, so we only `f` to be able to show a single layer of structure. 50 | -- Therefore, there is no need for `Show1`; we use `TacitString` in order to prevent 51 | -- extra quotes from appearing. 52 | instance showMu :: (Show (f TS.TacitString), Functor f) => Show (Mu f) where 53 | show (In x) = show $ x <#> (show >>> TS.hush) 54 | 55 | instance semigroupMu :: Alt f => Semigroup (Mu f) where 56 | append (In x) (In y) = In (x <|> y) 57 | 58 | instance monoidMu :: Plus f => Monoid (Mu f) where 59 | mempty = In empty 60 | -------------------------------------------------------------------------------- /src/Data/Functor/Nu.purs: -------------------------------------------------------------------------------- 1 | module Data.Functor.Nu 2 | ( Nu(..) 3 | , NuF(..) 4 | , unfold 5 | , observe 6 | ) where 7 | 8 | import Prelude 9 | import Data.Exists (Exists, mkExists, runExists) 10 | import Data.Newtype (class Newtype) 11 | import Data.Tuple (Tuple(..)) 12 | import Control.Comonad.Store (Store, store, runStore) 13 | 14 | newtype NuF f a = NuF (Store a (f a)) 15 | 16 | -- | `Nu f` is the greatest fixed point of the functor `f`, when it exists. 17 | newtype Nu f = Nu (Exists (NuF f)) 18 | 19 | derive instance newtypeNu :: Newtype (Nu f) _ 20 | 21 | unfold :: forall f a. a -> (a -> f a) -> Nu f 22 | unfold pos peek = Nu $ mkExists $ NuF $ store peek pos 23 | 24 | observe :: forall f. Functor f => Nu f -> f (Nu f) 25 | observe (Nu e) = runExists observeF e 26 | 27 | observeF :: forall f a. Functor f => NuF f a -> f (Nu f) 28 | observeF (NuF x) = case runStore x of 29 | (Tuple peek pos) -> flip unfold peek <$> peek pos 30 | -------------------------------------------------------------------------------- /src/Data/TacitString.purs: -------------------------------------------------------------------------------- 1 | module Data.TacitString 2 | ( TacitString 3 | , hush 4 | ) where 5 | 6 | import Prelude 7 | 8 | newtype TacitString = TacitString String 9 | 10 | derive instance eqTacitString :: Eq TacitString 11 | derive instance ordTacitString :: Ord TacitString 12 | 13 | instance showTacitString :: Show TacitString where 14 | show (TacitString str) = str 15 | 16 | hush :: String -> TacitString 17 | hush = TacitString 18 | --------------------------------------------------------------------------------