diff --git a/CHANGELOG.md b/CHANGELOG.md index 019e5f8..03b1c14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,22 +15,27 @@ Other improvements: ## [v7.2.0](https://github.com/purescript/purescript-arrays/releases/tag/v7.2.0) - 2023-01-17 New features: + - Add `prependArray` (#224 by @JordanMartinez) - Add `Data.Array.ST.length` (#239 by @Blugatroff) Other improvements: + - Use more efficient implementation for `mapWithIndex` (#233 by @JordanMartinez) +- Updates non-`ST` FFI to use uncurried functions via `Fn` types (#235 by @JordanMartinez) - Updates `ST` FFI to use uncurried functions via `STFnX` types (#234 by @JordanMartinez) ## [v7.1.0](https://github.com/purescript/purescript-arrays/releases/tag/v7.1.0) - 2022-08-06 New features: + - Added `transpose` to `Array` (#225 by @newlandsvalley and @JordanMartinez) - Added `transpose` and `transpose' `to `Array.NonEmpty` (#227 by @newlandsvalley and @JordanMartinez) ## [v7.0.0](https://github.com/purescript/purescript-arrays/releases/tag/v7.0.0) - 2022-04-27 Breaking changes: + - Migrate FFI to ES modules (#218 by @kl0tl and @JordanMartinez) - Drop deprecated `group'` and `empty` (#219 by @JordanMartinez) @@ -39,21 +44,25 @@ New features: Bugfixes: Other improvements: + - Fixed minor documentation issue with `find` (#216 by @JamieBallingall) ## [v6.0.1](https://github.com/purescript/purescript-arrays/releases/tag/v6.0.1) - 2021-04-19 Other improvements: + - Fixed warnings revealed by `v0.14.1` PS release (#213 by @JordanMartinez) ## [v6.0.0](https://github.com/purescript/purescript-arrays/releases/tag/v6.0.0) - 2021-02-26 Breaking changes: + - Added support for PureScript 0.14 and dropped support for all previous versions (#181) - Renamed `Data.Array.ST.empty` to `Data.Array.ST.new` (#191, #198) - Renamed `group'` to `groupAll` (#194, #200) New features: + - Added specialized versions of the functions from `Data.Foldable` (#201): - Added `foldl`, `foldr`, `foldMap`, `fold`, `intercalate` to `Array` - Added `foldl1`, `foldr1`, `foldMap1`, `foldl1`, `intercalate` to `Array.NonEmpty` @@ -62,9 +71,11 @@ New features: - Added `mapWithIndex`, `groupBy` to `Array.NonEmpty` (#201, #164) Bugfixes: + - Fixed `sort`, so `undefined` is sorted by comparison function and not simply moved to the end of the array (#195, #197) Other improvements: + - Generated changelog and added PR template (#208, #209) - Added benchmarking (#178) - Migrated to GitHub Actions for CI (#187, #169) @@ -98,7 +109,7 @@ Fixed issue with `fill` polyfill not being included in the bundle by `purs bundl ## [v5.1.0](https://github.com/purescript/purescript-arrays/releases/tag/v5.1.0) - 2018-09-25 -* Make `groupBy` stable https://github.com/purescript/purescript-arrays/pull/148 (@LiamGoodacre) +- Make `groupBy` stable https://github.com/purescript/purescript-arrays/pull/148 (@LiamGoodacre) ## [v5.0.0](https://github.com/purescript/purescript-arrays/releases/tag/v5.0.0) - 2018-05-23 @@ -119,8 +130,8 @@ Fixed issue with `fill` polyfill not being included in the bundle by `purs bundl ## [v4.2.2](https://github.com/purescript/purescript-arrays/releases/tag/v4.2.2) - 2017-12-16 -* Add examples to the docs for most functions in `Data.Array` (@csicar) -* Remove some redundant parentheses (@matthewleon) +- Add examples to the docs for most functions in `Data.Array` (@csicar) +- Remove some redundant parentheses (@matthewleon) ## [v4.2.1](https://github.com/purescript/purescript-arrays/releases/tag/v4.2.1) - 2017-10-01 @@ -136,8 +147,8 @@ Fix some bugs in `Data.Array.ST.Partial` (@mhuisi) ## [v4.1.1](https://github.com/purescript/purescript-arrays/releases/tag/v4.1.1) - 2017-06-20 -* Improve performance of `unzip`; this function is now O(n) instead of O(n^2) -* Various documentation improvements +- Improve performance of `unzip`; this function is now O(n) instead of O(n^2) +- Various documentation improvements ## [v4.1.0](https://github.com/purescript/purescript-arrays/releases/tag/v4.1.0) - 2017-05-28 @@ -259,6 +270,7 @@ This release works with versions 0.7.\* of the PureScript compiler. It will not ## [v0.4.0-rc.2](https://github.com/purescript/purescript-arrays/releases/tag/v0.4.0-rc.2) - 2015-06-07 Updates for parity with `purescript-lists`: + - Added `insert`, `insertBy`, `alterAt`, `union`, `unionBy` - The `insertAt`, `modifyAt`, `deleteAt`... functions now return `Nothing` when given an out of range index @@ -288,8 +300,6 @@ Add `modifyAt`. ## [v0.3.2](https://github.com/purescript/purescript-arrays/releases/tag/v0.3.2) - 2015-02-18 - - ## [v0.3.1](https://github.com/purescript/purescript-arrays/releases/tag/v0.3.1) - 2015-01-24 Add `take` and `drop`. @@ -308,12 +318,8 @@ Include `(..)` operator. ## [v0.1.8](https://github.com/purescript/purescript-arrays/releases/tag/v0.1.8) - 2014-05-30 - - ## [v0.1.7](https://github.com/purescript/purescript-arrays/releases/tag/v0.1.7) - 2014-05-29 - - ## [v0.1.6](https://github.com/purescript/purescript-arrays/releases/tag/v0.1.6) - 2014-05-22 - Added `delete`, `deleteBy`, `(\\)` (garyb) diff --git a/bower.json b/bower.json index f1ec083..19b1992 100644 --- a/bower.json +++ b/bower.json @@ -18,6 +18,7 @@ "purescript-bifunctors": "^6.0.0", "purescript-control": "^6.0.0", "purescript-foldable-traversable": "^6.0.0", + "purescript-functions": "^6.0.0", "purescript-maybe": "^6.0.0", "purescript-nonempty": "^7.0.0", "purescript-partial": "^4.0.0", diff --git a/src/Data/Array.js b/src/Data/Array.js index 490c53f..aa36c4d 100644 --- a/src/Data/Array.js +++ b/src/Data/Array.js @@ -2,43 +2,37 @@ // Array creation -------------------------------------------------------------- //------------------------------------------------------------------------------ -export const range = function (start) { - return function (end) { - var step = start > end ? -1 : 1; - var result = new Array(step * (end - start) + 1); - var i = start, n = 0; - while (i !== end) { - result[n++] = i; - i += step; - } - result[n] = i; - return result; - }; +export const rangeImpl = function (start, end) { + var step = start > end ? -1 : 1; + var result = new Array(step * (end - start) + 1); + var i = start, n = 0; + while (i !== end) { + result[n++] = i; + i += step; + } + result[n] = i; + return result; }; -var replicateFill = function (count) { - return function (value) { - if (count < 1) { - return []; - } - var result = new Array(count); - return result.fill(value); - }; +var replicateFill = function (count, value) { + if (count < 1) { + return []; + } + var result = new Array(count); + return result.fill(value); }; -var replicatePolyfill = function (count) { - return function (value) { - var result = []; - var n = 0; - for (var i = 0; i < count; i++) { - result[n++] = value; - } - return result; - }; +var replicatePolyfill = function (count, value) { + var result = []; + var n = 0; + for (var i = 0; i < count; i++) { + result[n++] = value; + } + return result; }; // In browsers that have Array.prototype.fill we use it, as it's faster. -export const replicate = typeof Array.prototype.fill === "function" ? replicateFill : replicatePolyfill; +export const replicateImpl = typeof Array.prototype.fill === "function" ? replicateFill : replicatePolyfill; export const fromFoldableImpl = (function () { function Cons(head, tail) { @@ -64,10 +58,8 @@ export const fromFoldableImpl = (function () { return result; } - return function (foldr) { - return function (xs) { - return listToArray(foldr(curryCons)(emptyList)(xs)); - }; + return function (foldr, xs) { + return listToArray(foldr(curryCons)(emptyList)(xs)); }; })(); @@ -83,109 +75,59 @@ export const length = function (xs) { // Non-indexed reads ----------------------------------------------------------- //------------------------------------------------------------------------------ -export const unconsImpl = function (empty) { - return function (next) { - return function (xs) { - return xs.length === 0 ? empty({}) : next(xs[0])(xs.slice(1)); - }; - }; +export const unconsImpl = function (empty, next, xs) { + return xs.length === 0 ? empty({}) : next(xs[0])(xs.slice(1)); }; //------------------------------------------------------------------------------ // Indexed operations ---------------------------------------------------------- //------------------------------------------------------------------------------ -export const indexImpl = function (just) { - return function (nothing) { - return function (xs) { - return function (i) { - return i < 0 || i >= xs.length ? nothing : just(xs[i]); - }; - }; - }; +export const indexImpl = function (just, nothing, xs, i) { + return i < 0 || i >= xs.length ? nothing : just(xs[i]); }; -export const findMapImpl = function (nothing) { - return function (isJust) { - return function (f) { - return function (xs) { - for (var i = 0; i < xs.length; i++) { - var result = f(xs[i]); - if (isJust(result)) return result; - } - return nothing; - }; - }; - }; +export const findMapImpl = function (nothing, isJust, f, xs) { + for (var i = 0; i < xs.length; i++) { + var result = f(xs[i]); + if (isJust(result)) return result; + } + return nothing; }; -export const findIndexImpl = function (just) { - return function (nothing) { - return function (f) { - return function (xs) { - for (var i = 0, l = xs.length; i < l; i++) { - if (f(xs[i])) return just(i); - } - return nothing; - }; - }; - }; +export const findIndexImpl = function (just, nothing, f, xs) { + for (var i = 0, l = xs.length; i < l; i++) { + if (f(xs[i])) return just(i); + } + return nothing; }; -export const findLastIndexImpl = function (just) { - return function (nothing) { - return function (f) { - return function (xs) { - for (var i = xs.length - 1; i >= 0; i--) { - if (f(xs[i])) return just(i); - } - return nothing; - }; - }; - }; +export const findLastIndexImpl = function (just, nothing, f, xs) { + for (var i = xs.length - 1; i >= 0; i--) { + if (f(xs[i])) return just(i); + } + return nothing; }; -export const _insertAt = function (just) { - return function (nothing) { - return function (i) { - return function (a) { - return function (l) { - if (i < 0 || i > l.length) return nothing; - var l1 = l.slice(); - l1.splice(i, 0, a); - return just(l1); - }; - }; - }; - }; +export const _insertAt = function (just, nothing, i, a, l) { + if (i < 0 || i > l.length) return nothing; + var l1 = l.slice(); + l1.splice(i, 0, a); + return just(l1); }; -export const _deleteAt = function (just) { - return function (nothing) { - return function (i) { - return function (l) { - if (i < 0 || i >= l.length) return nothing; - var l1 = l.slice(); - l1.splice(i, 1); - return just(l1); - }; - }; - }; +export const _deleteAt = function (just, nothing, i, l) { + if (i < 0 || i >= l.length) return nothing; + var l1 = l.slice(); + l1.splice(i, 1); + return just(l1); }; -export const _updateAt = function (just) { - return function (nothing) { - return function (i) { - return function (a) { - return function (l) { - if (i < 0 || i >= l.length) return nothing; - var l1 = l.slice(); - l1[i] = a; - return just(l1); - }; - }; - }; - }; +export const _updateAt = function (just, nothing, i, a, l) { + if (i < 0 || i >= l.length) return nothing; + var l1 = l.slice(); + l1[i] = a; + return just(l1); }; //------------------------------------------------------------------------------ @@ -213,55 +155,43 @@ export const concat = function (xss) { return result; }; -export const filter = function (f) { - return function (xs) { - return xs.filter(f); - }; +export const filterImpl = function (f, xs) { + return xs.filter(f); }; -export const partition = function (f) { - return function (xs) { - var yes = []; - var no = []; - for (var i = 0; i < xs.length; i++) { - var x = xs[i]; - if (f(x)) - yes.push(x); - else - no.push(x); - } - return { yes: yes, no: no }; - }; +export const partitionImpl = function (f, xs) { + var yes = []; + var no = []; + for (var i = 0; i < xs.length; i++) { + var x = xs[i]; + if (f(x)) + yes.push(x); + else + no.push(x); + } + return { yes: yes, no: no }; }; -export const scanl = function (f) { - return function (b) { - return function (xs) { - var len = xs.length; - var acc = b; - var out = new Array(len); - for (var i = 0; i < len; i++) { - acc = f(acc)(xs[i]); - out[i] = acc; - } - return out; - }; - }; +export const scanlImpl = function (f, b, xs) { + var len = xs.length; + var acc = b; + var out = new Array(len); + for (var i = 0; i < len; i++) { + acc = f(acc)(xs[i]); + out[i] = acc; + } + return out; }; -export const scanr = function (f) { - return function (b) { - return function (xs) { - var len = xs.length; - var acc = b; - var out = new Array(len); - for (var i = len - 1; i >= 0; i--) { - acc = f(xs[i])(acc); - out[i] = acc; - } - return out; - }; - }; +export const scanrImpl = function (f, b, xs) { + var len = xs.length; + var acc = b; + var out = new Array(len); + for (var i = len - 1; i >= 0; i--) { + acc = f(xs[i])(acc); + out[i] = acc; + } + return out; }; //------------------------------------------------------------------------------ @@ -306,19 +236,15 @@ export const sortByImpl = (function () { } } - return function (compare) { - return function (fromOrdering) { - return function (xs) { - var out; + return function (compare, fromOrdering, xs) { + var out; - if (xs.length < 2) return xs; + if (xs.length < 2) return xs; - out = xs.slice(0); - mergeFromTo(compare, fromOrdering, out, xs.slice(0), 0, xs.length); + out = xs.slice(0); + mergeFromTo(compare, fromOrdering, out, xs.slice(0), 0, xs.length); - return out; - }; - }; + return out; }; })(); @@ -326,61 +252,47 @@ export const sortByImpl = (function () { // Subarrays ------------------------------------------------------------------- //------------------------------------------------------------------------------ -export const slice = function (s) { - return function (e) { - return function (l) { - return l.slice(s, e); - }; - }; +export const sliceImpl = function (s, e, l) { + return l.slice(s, e); }; //------------------------------------------------------------------------------ // Zipping --------------------------------------------------------------------- //------------------------------------------------------------------------------ -export const zipWith = function (f) { - return function (xs) { - return function (ys) { - var l = xs.length < ys.length ? xs.length : ys.length; - var result = new Array(l); - for (var i = 0; i < l; i++) { - result[i] = f(xs[i])(ys[i]); - } - return result; - }; - }; +export const zipWithImpl = function (f, xs, ys) { + var l = xs.length < ys.length ? xs.length : ys.length; + var result = new Array(l); + for (var i = 0; i < l; i++) { + result[i] = f(xs[i])(ys[i]); + } + return result; }; //------------------------------------------------------------------------------ // Folding --------------------------------------------------------------------- //------------------------------------------------------------------------------ -export const any = function (p) { - return function (xs) { - var len = xs.length; - for (var i = 0; i < len; i++) { - if (p(xs[i])) return true; - } - return false; - }; +export const anyImpl = function (p, xs) { + var len = xs.length; + for (var i = 0; i < len; i++) { + if (p(xs[i])) return true; + } + return false; }; -export const all = function (p) { - return function (xs) { - var len = xs.length; - for (var i = 0; i < len; i++) { - if (!p(xs[i])) return false; - } - return true; - }; +export const allImpl = function (p, xs) { + var len = xs.length; + for (var i = 0; i < len; i++) { + if (!p(xs[i])) return false; + } + return true; }; //------------------------------------------------------------------------------ // Partial --------------------------------------------------------------------- //------------------------------------------------------------------------------ -export const unsafeIndexImpl = function (xs) { - return function (n) { - return xs[n]; - }; +export const unsafeIndexImpl = function (xs, n) { + return xs[n]; }; diff --git a/src/Data/Array.purs b/src/Data/Array.purs index fdd3223..431f942 100644 --- a/src/Data/Array.purs +++ b/src/Data/Array.purs @@ -31,7 +31,8 @@ module Data.Array ( fromFoldable , toUnfoldable , singleton - , (..), range + , (..) + , range , replicate , some , many @@ -39,7 +40,8 @@ module Data.Array , null , length - , (:), cons + , (:) + , cons , snoc , insert , insertBy @@ -51,7 +53,8 @@ module Data.Array , uncons , unsnoc - , (!!), index + , (!!) + , index , elem , notElem , elemIndex @@ -113,7 +116,8 @@ module Data.Array , delete , deleteBy - , (\\), difference + , (\\) + , difference , intersect , intersectBy @@ -143,6 +147,7 @@ import Data.Array.ST as STA import Data.Array.ST.Iterator as STAI import Data.Foldable (class Foldable, traverse_) import Data.Foldable as F +import Data.Function.Uncurried (Fn2, Fn3, Fn4, Fn5, runFn2, runFn3, runFn4, runFn5) import Data.FunctorWithIndex as FWI import Data.Maybe (Maybe(..), maybe, isJust, fromJust, isNothing) import Data.Traversable (sequence, traverse) @@ -156,7 +161,7 @@ toUnfoldable xs = unfoldr f 0 where len = length xs f i - | i < len = Just (Tuple (unsafePartial (unsafeIndex xs i)) (i+1)) + | i < len = Just (Tuple (unsafePartial (unsafeIndex xs i)) (i + 1)) | otherwise = Nothing -- | Convert a `Foldable` structure into an `Array`. @@ -167,32 +172,36 @@ toUnfoldable xs = unfoldr f 0 -- | ``` -- | fromFoldable :: forall f. Foldable f => f ~> Array -fromFoldable = fromFoldableImpl F.foldr +fromFoldable = runFn2 fromFoldableImpl F.foldr foreign import fromFoldableImpl :: forall f a - . (forall b. (a -> b -> b) -> b -> f a -> b) - -> f a - -> Array a + . Fn2 (forall b. (a -> b -> b) -> b -> f a -> b) (f a) (Array a) -- | Create an array of one element -- | ```purescript -- | singleton 2 = [2] -- | ``` singleton :: forall a. a -> Array a -singleton a = [a] +singleton a = [ a ] -- | Create an array containing a range of integers, including both endpoints. -- | ```purescript -- | range 2 5 = [2, 3, 4, 5] -- | ``` -foreign import range :: Int -> Int -> Array Int +range :: Int -> Int -> Array Int +range = runFn2 rangeImpl + +foreign import rangeImpl :: Fn2 Int Int (Array Int) -- | Create an array containing a value repeated the specified number of times. -- | ```purescript -- | replicate 2 "Hi" = ["Hi", "Hi"] -- | ``` -foreign import replicate :: forall a. Int -> a -> Array a +replicate :: forall a. Int -> a -> Array a +replicate = runFn2 replicateImpl + +foreign import replicateImpl :: forall a. Fn2 Int a (Array a) -- | An infix synonym for `range`. -- | ```purescript @@ -245,7 +254,7 @@ foreign import length :: forall a. Array a -> Int -- | -- | Note, the running time of this function is `O(n)`. cons :: forall a. a -> Array a -> Array a -cons x xs = [x] <> xs +cons x xs = [ x ] <> xs -- | An infix alias for `cons`. -- | @@ -285,8 +294,10 @@ insert = insertBy compare -- | insertBy :: forall a. (a -> a -> Ordering) -> a -> Array a -> Array a insertBy cmp x ys = - let i = maybe 0 (_ + 1) (findLastIndex (\y -> cmp x y == GT) ys) - in unsafePartial (fromJust (insertAt i x ys)) + let + i = maybe 0 (_ + 1) (findLastIndex (\y -> cmp x y == GT) ys) + in + unsafePartial (fromJust (insertAt i x ys)) -------------------------------------------------------------------------------- -- Non-indexed reads ----------------------------------------------------------- @@ -326,7 +337,7 @@ last xs = xs !! (length xs - 1) -- | -- | Running time: `O(n)` where `n` is the length of the array tail :: forall a. Array a -> Maybe (Array a) -tail = unconsImpl (const Nothing) (\_ xs -> Just xs) +tail = runFn3 unconsImpl (const Nothing) (\_ xs -> Just xs) -- | Get all but the last element of an array, creating a new array, or -- | `Nothing` if the array is empty. @@ -357,14 +368,11 @@ init xs -- | Nothing -> somethingElse -- | ``` uncons :: forall a. Array a -> Maybe { head :: a, tail :: Array a } -uncons = unconsImpl (const Nothing) \x xs -> Just { head: x, tail: xs } +uncons = runFn3 unconsImpl (const Nothing) \x xs -> Just { head: x, tail: xs } foreign import unconsImpl :: forall a b - . (Unit -> b) - -> (a -> Array a -> b) - -> Array a - -> b + . Fn3 (Unit -> b) (a -> Array a -> b) (Array a) b -- | Break an array into its last element and all preceding elements. -- | @@ -392,15 +400,11 @@ unsnoc xs = { init: _, last: _ } <$> init xs <*> last xs -- | ``` -- | index :: forall a. Array a -> Int -> Maybe a -index = indexImpl Just Nothing +index = runFn4 indexImpl Just Nothing foreign import indexImpl :: forall a - . (forall r. r -> Maybe r) - -> (forall r. Maybe r) - -> Array a - -> Int - -> Maybe a + . Fn4 (forall r. r -> Maybe r) (forall r. Maybe r) (Array a) Int (Maybe a) -- | An infix version of `index`. -- | @@ -453,15 +457,16 @@ find f xs = unsafePartial (unsafeIndex xs) <$> findIndex f xs -- | Find the first element in a data structure which satisfies -- | a predicate mapping. findMap :: forall a b. (a -> Maybe b) -> Array a -> Maybe b -findMap = findMapImpl Nothing isJust +findMap = runFn4 findMapImpl Nothing isJust foreign import findMapImpl :: forall a b - . (forall c. Maybe c) - -> (forall c. Maybe c -> Boolean) - -> (a -> Maybe b) - -> Array a - -> Maybe b + . Fn4 + (forall c. Maybe c) + (forall c. Maybe c -> Boolean) + (a -> Maybe b) + (Array a) + (Maybe b) -- | Find the first index for which a predicate holds. -- | @@ -471,15 +476,16 @@ foreign import findMapImpl -- | ``` -- | findIndex :: forall a. (a -> Boolean) -> Array a -> Maybe Int -findIndex = findIndexImpl Just Nothing +findIndex = runFn4 findIndexImpl Just Nothing foreign import findIndexImpl :: forall a - . (forall b. b -> Maybe b) - -> (forall b. Maybe b) - -> (a -> Boolean) - -> Array a - -> Maybe Int + . Fn4 + (forall b. b -> Maybe b) + (forall b. Maybe b) + (a -> Boolean) + (Array a) + (Maybe Int) -- | Find the last index for which a predicate holds. -- | @@ -489,15 +495,16 @@ foreign import findIndexImpl -- | ``` -- | findLastIndex :: forall a. (a -> Boolean) -> Array a -> Maybe Int -findLastIndex = findLastIndexImpl Just Nothing +findLastIndex = runFn4 findLastIndexImpl Just Nothing foreign import findLastIndexImpl :: forall a - . (forall b. b -> Maybe b) - -> (forall b. Maybe b) - -> (a -> Boolean) - -> Array a - -> Maybe Int + . Fn4 + (forall b. b -> Maybe b) + (forall b. Maybe b) + (a -> Boolean) + (Array a) + (Maybe Int) -- | Insert an element at the specified index, creating a new array, or -- | returning `Nothing` if the index is out of bounds. @@ -508,16 +515,17 @@ foreign import findLastIndexImpl -- | ``` -- | insertAt :: forall a. Int -> a -> Array a -> Maybe (Array a) -insertAt = _insertAt Just Nothing +insertAt = runFn5 _insertAt Just Nothing foreign import _insertAt :: forall a - . (forall b. b -> Maybe b) - -> (forall b. Maybe b) - -> Int - -> a - -> Array a - -> Maybe (Array a) + . Fn5 + (forall b. b -> Maybe b) + (forall b. Maybe b) + Int + a + (Array a) + (Maybe (Array a)) -- | Delete the element at the specified index, creating a new array, or -- | returning `Nothing` if the index is out of bounds. @@ -528,15 +536,16 @@ foreign import _insertAt -- | ``` -- | deleteAt :: forall a. Int -> Array a -> Maybe (Array a) -deleteAt = _deleteAt Just Nothing +deleteAt = runFn4 _deleteAt Just Nothing foreign import _deleteAt :: forall a - . (forall b. b -> Maybe b) - -> (forall b. Maybe b) - -> Int - -> Array a - -> Maybe (Array a) + . Fn4 + (forall b. b -> Maybe b) + (forall b. Maybe b) + Int + (Array a) + (Maybe (Array a)) -- | Change the element at the specified index, creating a new array, or -- | returning `Nothing` if the index is out of bounds. @@ -547,16 +556,17 @@ foreign import _deleteAt -- | ``` -- | updateAt :: forall a. Int -> a -> Array a -> Maybe (Array a) -updateAt = _updateAt Just Nothing +updateAt = runFn5 _updateAt Just Nothing foreign import _updateAt :: forall a - . (forall b. b -> Maybe b) - -> (forall b. Maybe b) - -> Int - -> a - -> Array a - -> Maybe (Array a) + . Fn5 + (forall b. b -> Maybe b) + (forall b. Maybe b) + Int + a + (Array a) + (Maybe (Array a)) -- | Apply a function to the element at the specified index, creating a new -- | array, or returning `Nothing` if the index is out of bounds. @@ -611,15 +621,16 @@ alterAt i f xs = maybe Nothing go (xs !! i) -- | ``` intersperse :: forall a. a -> Array a -> Array a intersperse a arr = case length arr of - len | len < 2 -> arr - | otherwise -> STA.run do - let unsafeGetElem idx = unsafePartial (unsafeIndex arr idx) - out <- STA.new - _ <- STA.push (unsafeGetElem 0) out - ST.for 1 len \idx -> do - _ <- STA.push a out - void (STA.push (unsafeGetElem idx) out) - pure out + len + | len < 2 -> arr + | otherwise -> STA.run do + let unsafeGetElem idx = unsafePartial (unsafeIndex arr idx) + out <- STA.new + _ <- STA.push (unsafeGetElem 0) out + ST.for 1 len \idx -> do + _ <- STA.push a out + void (STA.push (unsafeGetElem idx) out) + pure out -- | Reverse an array, creating a new array. -- | @@ -656,7 +667,12 @@ concatMap = flip bind -- | filter (_ > 0) [-1, 4, -5, 7] = [4, 7] -- | ``` -- | -foreign import filter :: forall a. (a -> Boolean) -> Array a -> Array a +filter :: forall a. (a -> Boolean) -> Array a -> Array a +filter = runFn2 filterImpl + +foreign import filterImpl + :: forall a + . Fn2 (a -> Boolean) (Array a) (Array a) -- | Partition an array using a predicate function, creating a set of -- | new arrays. One for the values satisfying the predicate function @@ -666,11 +682,16 @@ foreign import filter :: forall a. (a -> Boolean) -> Array a -> Array a -- | partition (_ > 0) [-1, 4, -5, 7] = { yes: [4, 7], no: [-1, -5] } -- | ``` -- | -foreign import partition +partition :: forall a . (a -> Boolean) -> Array a -> { yes :: Array a, no :: Array a } +partition = runFn2 partitionImpl + +foreign import partitionImpl + :: forall a + . Fn2 (a -> Boolean) (Array a) { yes :: Array a, no :: Array a } -- | Splits an array into two subarrays, where `before` contains the elements -- | up to (but not including) the given index, and `after` contains the rest @@ -702,7 +723,7 @@ splitAt i xs = { before: slice 0 i xs, after: slice i (length xs) xs } filterA :: forall a f. Applicative f => (a -> f Boolean) -> Array a -> f (Array a) filterA p = traverse (\x -> Tuple x <$> p x) - >>> map (mapMaybe (\(Tuple x b) -> if b then Just x else Nothing)) + >>> map (mapMaybe (\(Tuple x b) -> if b then Just x else Nothing)) -- | Apply a function to each element in an array, keeping only the results -- | which contain a value, creating a new array. @@ -815,12 +836,12 @@ transpose xs = go 0 [] go :: Int -> Array (Array a) -> Array (Array a) go idx allArrays = case buildNext idx of Nothing -> allArrays - Just next -> go (idx + 1) (snoc allArrays next) - + Just next -> go (idx + 1) (snoc allArrays next) + buildNext :: Int -> Maybe (Array a) buildNext idx = do xs # flip foldl Nothing \acc nextArr -> do - maybe acc (\el -> Just $ maybe [el] (flip snoc el) acc) $ index nextArr idx + maybe acc (\el -> Just $ maybe [ el ] (flip snoc el) acc) $ index nextArr idx -- | Fold a data structure from the left, keeping all intermediate results -- | instead of only the final result. Note that the initial value does not @@ -830,7 +851,10 @@ transpose xs = go 0 [] -- | scanl (+) 0 [1,2,3] = [1,3,6] -- | scanl (-) 10 [1,2,3] = [9,7,4] -- | ``` -foreign import scanl :: forall a b. (b -> a -> b) -> b -> Array a -> Array b +scanl :: forall a b. (b -> a -> b) -> b -> Array a -> Array b +scanl = runFn3 scanlImpl + +foreign import scanlImpl :: forall a b. Fn3 (b -> a -> b) b (Array a) (Array b) -- | Fold a data structure from the right, keeping all intermediate results -- | instead of only the final result. Note that the initial value does not @@ -840,7 +864,10 @@ foreign import scanl :: forall a b. (b -> a -> b) -> b -> Array a -> Array b -- | scanr (+) 0 [1,2,3] = [6,5,3] -- | scanr (flip (-)) 10 [1,2,3] = [4,5,7] -- | ``` -foreign import scanr :: forall a b. (a -> b -> b) -> b -> Array a -> Array b +scanr :: forall a b. (a -> b -> b) -> b -> Array a -> Array b +scanr = runFn3 scanrImpl + +foreign import scanrImpl :: forall a b. Fn3 (a -> b -> b) b (Array a) (Array b) -------------------------------------------------------------------------------- -- Sorting --------------------------------------------------------------------- @@ -867,7 +894,7 @@ sort xs = sortBy compare xs -- | ``` -- | sortBy :: forall a. (a -> a -> Ordering) -> Array a -> Array a -sortBy comp = sortByImpl comp case _ of +sortBy comp = runFn3 sortByImpl comp case _ of GT -> 1 EQ -> 0 LT -> -1 @@ -884,7 +911,7 @@ sortBy comp = sortByImpl comp case _ of sortWith :: forall a b. Ord b => (a -> b) -> Array a -> Array a sortWith f = sortBy (comparing f) -foreign import sortByImpl :: forall a. (a -> a -> Ordering) -> (Ordering -> Int) -> Array a -> Array a +foreign import sortByImpl :: forall a. Fn3 (a -> a -> Ordering) (Ordering -> Int) (Array a) (Array a) -------------------------------------------------------------------------------- -- Subarrays ------------------------------------------------------------------- @@ -899,7 +926,10 @@ foreign import sortByImpl :: forall a. (a -> a -> Ordering) -> (Ordering -> Int) -- | slice 4 1 letters = [] -- | ``` -- | -foreign import slice :: forall a. Int -> Int -> Array a -> Array a +slice :: forall a. Int -> Int -> Array a -> Array a +slice = runFn3 sliceImpl + +foreign import sliceImpl :: forall a. Fn3 Int Int (Array a) (Array a) -- | Keep only a number of elements from the start of an array, creating a new -- | array. @@ -1085,16 +1115,16 @@ nubBy :: forall a. (a -> a -> Ordering) -> Array a -> Array a nubBy comp xs = case head indexedAndSorted of Nothing -> [] Just x -> map snd $ sortWith fst $ ST.run do - -- TODO: use NonEmptyArrays here to avoid partial functions - result <- STA.unsafeThaw $ singleton x - ST.foreach indexedAndSorted \pair@(Tuple _ x') -> do - lst <- snd <<< unsafePartial (fromJust <<< last) <$> STA.unsafeFreeze result - when (comp lst x' /= EQ) $ void $ STA.push pair result - STA.unsafeFreeze result + -- TODO: use NonEmptyArrays here to avoid partial functions + result <- STA.unsafeThaw $ singleton x + ST.foreach indexedAndSorted \pair@(Tuple _ x') -> do + lst <- snd <<< unsafePartial (fromJust <<< last) <$> STA.unsafeFreeze result + when (comp lst x' /= EQ) $ void $ STA.push pair result + STA.unsafeFreeze result where indexedAndSorted :: Array (Tuple Int a) indexedAndSorted = sortBy (\x y -> comp (snd x) (snd y)) - (mapWithIndex Tuple xs) + (mapWithIndex Tuple xs) -- | Remove the duplicates from an array, where element equality is determined -- | by the specified equivalence relation, creating a new array. @@ -1161,7 +1191,7 @@ delete = deleteBy eq -- | ``` -- | deleteBy :: forall a. (a -> a -> Boolean) -> a -> Array a -> Array a -deleteBy _ _ [] = [] +deleteBy _ _ [] = [] deleteBy eq x ys = maybe ys (\i -> unsafePartial $ fromJust (deleteAt i ys)) (findIndex (eq x) ys) -- | Delete the first occurrence of each element in the second array from the @@ -1212,12 +1242,21 @@ intersectBy eq xs ys = filter (\x -> isJust (findIndex (eq x) ys)) xs -- | ```purescript -- | zipWith (*) [1, 2, 3] [4, 5, 6, 7] == [4, 10, 18] -- | ``` -foreign import zipWith +zipWith :: forall a b c . (a -> b -> c) -> Array a -> Array b -> Array c +zipWith = runFn3 zipWithImpl + +foreign import zipWithImpl + :: forall a b c + . Fn3 + (a -> b -> c) + (Array a) + (Array b) + (Array c) -- | A generalization of `zipWith` which accumulates results in some -- | `Applicative` functor. @@ -1277,7 +1316,10 @@ unzip xs = -- | any (_ > 0) [-1, 0, 1] = True -- | any (_ > 0) [-1, -2, -3] = False -- | ``` -foreign import any :: forall a. (a -> Boolean) -> Array a -> Boolean +any :: forall a. (a -> Boolean) -> Array a -> Boolean +any = runFn2 anyImpl + +foreign import anyImpl :: forall a. Fn2 (a -> Boolean) (Array a) Boolean -- | Returns true if all the array elements satisfy the given predicate. -- | iterating the array only as necessary and stopping as soon as the predicate @@ -1288,7 +1330,10 @@ foreign import any :: forall a. (a -> Boolean) -> Array a -> Boolean -- | all (_ > 0) [1, 2, 3] = True -- | all (_ > 0) [-1, -2, -3] = False -- | ``` -foreign import all :: forall a. (a -> Boolean) -> Array a -> Boolean +all :: forall a. (a -> Boolean) -> Array a -> Boolean +all = runFn2 allImpl + +foreign import allImpl :: forall a. Fn2 (a -> Boolean) (Array a) Boolean -- | Perform a fold using a monadic step function. -- | @@ -1296,7 +1341,7 @@ foreign import all :: forall a. (a -> Boolean) -> Array a -> Boolean -- | foldM (\x y -> Just (x + y)) 0 [1, 4] = Just 5 -- | ``` foldM :: forall m a b. Monad m => (b -> a -> m b) -> b -> Array a -> m b -foldM f b = unconsImpl (\_ -> pure b) (\a as -> f b a >>= \b' -> foldM f b' as) +foldM f b = runFn3 unconsImpl (\_ -> pure b) (\a as -> f b a >>= \b' -> foldM f b' as) foldRecM :: forall m a b. MonadRec m => (b -> a -> m b) -> b -> Array a -> m b foldRecM f b array = tailRecM2 go b 0 @@ -1321,6 +1366,6 @@ foldRecM f b array = tailRecM2 go b 0 -- | since this expression evaluates to `undefined`, attempting to use it in an `if` statement will cause -- | the else branch to be taken. unsafeIndex :: forall a. Partial => Array a -> Int -> a -unsafeIndex = unsafeIndexImpl +unsafeIndex = runFn2 unsafeIndexImpl -foreign import unsafeIndexImpl :: forall a. Array a -> Int -> a +foreign import unsafeIndexImpl :: forall a. Fn2 (Array a) Int a diff --git a/src/Data/Array/NonEmpty/Internal.js b/src/Data/Array/NonEmpty/Internal.js index 97b620e..dc06c32 100644 --- a/src/Data/Array/NonEmpty/Internal.js +++ b/src/Data/Array/NonEmpty/Internal.js @@ -1,22 +1,18 @@ -export const foldr1Impl = function (f) { - return function (xs) { - var acc = xs[xs.length - 1]; - for (var i = xs.length - 2; i >= 0; i--) { - acc = f(xs[i])(acc); - } - return acc; - }; +export const foldr1Impl = function (f, xs) { + var acc = xs[xs.length - 1]; + for (var i = xs.length - 2; i >= 0; i--) { + acc = f(xs[i])(acc); + } + return acc; }; -export const foldl1Impl = function (f) { - return function (xs) { - var acc = xs[0]; - var len = xs.length; - for (var i = 1; i < len; i++) { - acc = f(acc)(xs[i]); - } - return acc; - }; +export const foldl1Impl = function (f, xs) { + var acc = xs[0]; + var len = xs.length; + for (var i = 1; i < len; i++) { + acc = f(acc)(xs[i]); + } + return acc; }; export const traverse1Impl = function () { @@ -51,35 +47,31 @@ export const traverse1Impl = function () { return arr; } - return function (apply) { - return function (map) { - return function (f) { - var buildFrom = function (x, ys) { - return apply(map(consList)(f(x)))(ys); - }; + return function (apply, map, f) { + var buildFrom = function (x, ys) { + return apply(map(consList)(f(x)))(ys); + }; - var go = function (acc, currentLen, xs) { - if (currentLen === 0) { - return acc; - } else { - var last = xs[currentLen - 1]; - return new Cont(function () { - var built = go(buildFrom(last, acc), currentLen - 1, xs); - return built; - }); - } - }; + var go = function (acc, currentLen, xs) { + if (currentLen === 0) { + return acc; + } else { + var last = xs[currentLen - 1]; + return new Cont(function () { + var built = go(buildFrom(last, acc), currentLen - 1, xs); + return built; + }); + } + }; - return function (array) { - var acc = map(finalCell)(f(array[array.length - 1])); - var result = go(acc, array.length - 1, array); - while (result instanceof Cont) { - result = result.fn(); - } + return function (array) { + var acc = map(finalCell)(f(array[array.length - 1])); + var result = go(acc, array.length - 1, array); + while (result instanceof Cont) { + result = result.fn(); + } - return map(listToArray)(result); - }; - }; + return map(listToArray)(result); }; }; }(); diff --git a/src/Data/Array/NonEmpty/Internal.purs b/src/Data/Array/NonEmpty/Internal.purs index 1dcd1bf..752ada6 100644 --- a/src/Data/Array/NonEmpty/Internal.purs +++ b/src/Data/Array/NonEmpty/Internal.purs @@ -13,6 +13,7 @@ import Control.Alt (class Alt) import Data.Eq (class Eq1) import Data.Foldable (class Foldable) import Data.FoldableWithIndex (class FoldableWithIndex) +import Data.Function.Uncurried (Fn2, Fn3, runFn2, runFn3) import Data.FunctorWithIndex (class FunctorWithIndex) import Data.Ord (class Ord1) import Data.Semigroup.Foldable (class Foldable1, foldMap1DefaultL) @@ -49,15 +50,15 @@ derive newtype instance foldableWithIndexNonEmptyArray :: FoldableWithIndex Int instance foldable1NonEmptyArray :: Foldable1 NonEmptyArray where foldMap1 = foldMap1DefaultL - foldr1 = foldr1Impl - foldl1 = foldl1Impl + foldr1 = runFn2 foldr1Impl + foldl1 = runFn2 foldl1Impl derive newtype instance unfoldable1NonEmptyArray :: Unfoldable1 NonEmptyArray derive newtype instance traversableNonEmptyArray :: Traversable NonEmptyArray derive newtype instance traversableWithIndexNonEmptyArray :: TraversableWithIndex Int NonEmptyArray instance traversable1NonEmptyArray :: Traversable1 NonEmptyArray where - traverse1 = traverse1Impl apply map + traverse1 f = runFn3 traverse1Impl apply map f sequence1 = sequence1Default derive newtype instance applyNonEmptyArray :: Apply NonEmptyArray @@ -71,13 +72,13 @@ derive newtype instance monadNonEmptyArray :: Monad NonEmptyArray derive newtype instance altNonEmptyArray :: Alt NonEmptyArray -- we use FFI here to avoid the unncessary copy created by `tail` -foreign import foldr1Impl :: forall a. (a -> a -> a) -> NonEmptyArray a -> a -foreign import foldl1Impl :: forall a. (a -> a -> a) -> NonEmptyArray a -> a +foreign import foldr1Impl :: forall a. Fn2 (a -> a -> a) (NonEmptyArray a) a +foreign import foldl1Impl :: forall a. Fn2 (a -> a -> a) (NonEmptyArray a) a foreign import traverse1Impl :: forall m a b - . (forall a' b'. (m (a' -> b') -> m a' -> m b')) - -> (forall a' b'. (a' -> b') -> m a' -> m b') - -> (a -> m b) - -> NonEmptyArray a - -> m (NonEmptyArray b) + . Fn3 + (forall a' b'. (m (a' -> b') -> m a' -> m b')) + (forall a' b'. (a' -> b') -> m a' -> m b') + (a -> m b) + (NonEmptyArray a -> m (NonEmptyArray b))