Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 12 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,27 @@ on:
branches: [main]
pull_request:

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: Check formatting
run: npm run format:check
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
.*
!.gitignore
!.github
!/.tidyrc.json
!/.oxfmtrc.json

output
generated-docs
bower_components
node_modules

package-lock.json
*.lock
/package-lock.json
/spago.lock
3 changes: 3 additions & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"trailingComma": "es5"
}
10 changes: 10 additions & 0 deletions .tidyrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"importSort": "ide",
"importWrap": "source",
"indent": 2,
"operatorsFile": null,
"ribbon": 1,
"typeArrowPlacement": "first",
"unicode": "never",
"width": null
}
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-filterable/compare/v5.0.1...HEAD)

Breaking changes:

Expand All @@ -12,9 +12,16 @@ Bugfixes:

Other improvements:

## [v5.0.1](https://github.com/purescript/purescript-filterable/releases/tag/v5.0.1) - 2026-10-17

Other improvements:

- Migrate from Bower/Pulp to Spago and update CI, tooling, and formatting (#25 by @thomashoneyman)

## [v5.0.0](https://github.com/purescript/purescript-filterable/releases/tag/v5.0.0) - 2022-04-27

Breaking changes:

- Update project and deps to PureScript v0.15.0 (#23 by @JordanMartinez)

New features:
Expand All @@ -26,6 +33,7 @@ Other improvements:
## [v4.0.1](https://github.com/purescript/purescript-filterable/releases/tag/v4.0.1) - 2021-04-19

Other improvements:

- Renamed default branch to `main` from `master` (@thomashoneyman)
- Fix UnusedName warnings revealed by v0.14.1 PureScript release (#22 by @JordanMartinez)

Expand Down
32 changes: 0 additions & 32 deletions bower.json

This file was deleted.

16 changes: 9 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
{
"private": true,
"scripts": {
"clean": "rimraf output && rimraf .pulp-cache",
"build": "pulp build -- --censor-lib --strict",
"test": "pulp test",
"build:docs": "rimraf docs && pulp docs"
"build": "spago build",
"test": "spago test",
"build:docs": "spago docs",
"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",
"purescript": "^0.15.16",
"purs-tidy": "^0.11.1",
"spago": "^1.0.5"
}
}
34 changes: 34 additions & 0 deletions spago.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package:
name: filterable
description: Classes for filterable and witherable data structures
build:
strict: true
pedanticPackages: true
publish:
version: 5.0.1
license: MIT
location:
githubOwner: purescript
githubRepo: purescript-filterable
dependencies:
- arrays: ">=7.0.0 <8.0.0"
- control: ">=6.0.0 <7.0.0"
- either: ">=6.0.0 <7.0.0"
- foldable-traversable: ">=6.0.0 <7.0.0"
- identity: ">=6.0.0 <7.0.0"
- lists: ">=7.0.0 <8.0.0"
- maybe: ">=6.0.0 <7.0.0"
- newtype: ">=5.0.0 <6.0.0"
- ordered-collections: ">=3.0.0 <4.0.0"
- prelude: ">=6.0.0 <7.0.0"
- st: ">=6.0.0 <7.0.0"
- tuples: ">=7.0.0 <8.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: {}
140 changes: 90 additions & 50 deletions src/Data/Compactable.purs
Original file line number Diff line number Diff line change
Expand Up @@ -64,53 +64,69 @@ import Prelude (class Ord, const, discard, unit, void, (<<<))
-- | - `compact (const Nothing <$> xs) ≡ empty`

class Compactable f where
compact :: forall a.
f (Maybe a) -> f a

separate :: forall l r.
f (Either l r) -> { left :: f l, right :: f r }

compactDefault :: forall f a. Functor f => Compactable f =>
f (Maybe a) -> f a
compact
:: forall a
. f (Maybe a)
-> f a

separate
:: forall l r
. f (Either l r)
-> { left :: f l, right :: f r }

compactDefault
:: forall f a
. Functor f
=> Compactable f
=> f (Maybe a)
-> f a
compactDefault = _.right <<< separate <<< map (note unit)

separateDefault :: forall f l r. Functor f => Compactable f =>
f (Either l r) -> { left :: f l, right :: f r}
separateDefault xs = { left: compact $ (hush <<< swapEither) <$> xs
, right: compact $ hush <$> xs
}
separateDefault
:: forall f l r
. Functor f
=> Compactable f
=> f (Either l r)
-> { left :: f l, right :: f r }
separateDefault xs =
{ left: compact $ (hush <<< swapEither) <$> xs
, right: compact $ hush <$> xs
}
where
swapEither e = case e of
Left x -> Right x
Right y -> Left y
swapEither e = case e of
Left x -> Right x
Right y -> Left y

instance compactableMaybe :: Compactable Maybe where
compact = join

separate Nothing = { left: Nothing, right: Nothing }
separate (Just e) = case e of
Left l -> { left: Just l, right: Nothing }
Right r -> { left: Nothing, right: Just r }
separate = case _ of
Nothing -> { left: Nothing, right: Nothing }
Just e -> case e of
Left l -> { left: Just l, right: Nothing }
Right r -> { left: Nothing, right: Just r }

instance compactableEither :: Monoid m => Compactable (Either m) where
compact (Left m) = Left m
compact (Right m) = case m of
Just v -> Right v
Nothing -> Left mempty

separate (Left x) = { left: Left x, right: Left x }
separate (Right e) = case e of
Left l -> { left: Right l, right: Left mempty }
Right r -> { left: Left mempty, right: Right r }
compact = case _ of
Left m -> Left m
Right m -> case m of
Just v -> Right v
Nothing -> Left mempty

separate = case _ of
Left x -> { left: Left x, right: Left x }
Right e -> case e of
Left l -> { left: Right l, right: Left mempty }
Right r -> { left: Left mempty, right: Right r }

instance compactableArray :: Compactable Array where
compact xs = ST.run do
result <- STA.new
iter <- STAI.iterator (xs !! _)
iter <- STAI.iterator (xs !! _)

STAI.iterate iter $ void <<< case _ of
Nothing -> pure 0
Just j -> STA.push j result
Just j -> STA.push j result

STA.unsafeFreeze result

Expand All @@ -120,45 +136,69 @@ instance compactableArray :: Compactable Array where
iter <- STAI.iterator (xs !! _)

STAI.iterate iter $ void <<< case _ of
Left l -> STA.push l ls
Left l -> STA.push l ls
Right r -> STA.push r rs

{left: _, right: _} <$> STA.unsafeFreeze ls <*> STA.unsafeFreeze rs
{ left: _, right: _ } <$> STA.unsafeFreeze ls <*> STA.unsafeFreeze rs

instance compactableList :: Compactable List.List where
compact = List.catMaybes
separate = foldl go { left: empty, right: empty } where
separate = foldl go { left: empty, right: empty }
where
go acc = case _ of
Left l -> acc { left = acc.left <|> pure l }
Left l -> acc { left = acc.left <|> pure l }
Right r -> acc { right = acc.right <|> pure r }

instance compactableMap :: Ord k => Compactable (Map.Map k) where
compact = foldr select Map.empty <<< mapToList
where
select (Tuple k x) m = Map.alter (const x) k m
select (Tuple k x) m = Map.alter (const x) k m

separate = foldr select { left: Map.empty, right: Map.empty } <<< mapToList
where
select (Tuple k v) { left, right } = case v of
Left l -> { left: Map.insert k l left, right }
Right r -> { left: left, right: Map.insert k r right }

mapToList :: forall k v. Ord k =>
Map.Map k v -> List.List (Tuple k v)
select (Tuple k v) { left, right } = case v of
Left l -> { left: Map.insert k l left, right }
Right r -> { left: left, right: Map.insert k r right }

mapToList
:: forall k v
. Ord k
=> Map.Map k v
-> List.List (Tuple k v)
mapToList = Map.toUnfoldable

applyMaybe :: forall f a b. Apply f => Compactable f =>
f (a -> Maybe b) -> f a -> f b
applyMaybe
:: forall f a b
. Apply f
=> Compactable f
=> f (a -> Maybe b)
-> f a
-> f b
applyMaybe p = compact <<< apply p

applyEither :: forall f a l r. Apply f => Compactable f =>
f (a -> Either l r) -> f a -> { left :: f l, right :: f r }
applyEither
:: forall f a l r
. Apply f
=> Compactable f
=> f (a -> Either l r)
-> f a
-> { left :: f l, right :: f r }
applyEither p = separate <<< apply p

bindMaybe :: forall m a b. Bind m => Compactable m =>
m a -> (a -> m (Maybe b)) -> m b
bindMaybe
:: forall m a b
. Bind m
=> Compactable m
=> m a
-> (a -> m (Maybe b))
-> m b
bindMaybe x = compact <<< bind x

bindEither :: forall m a l r. Bind m => Compactable m =>
m a -> (a -> m (Either l r)) -> { left :: m l, right :: m r }
bindEither
:: forall m a l r
. Bind m
=> Compactable m
=> m a
-> (a -> m (Either l r))
-> { left :: m l, right :: m r }
bindEither x = separate <<< bind x
Loading
Loading