diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ce393c51..7344174f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,14 @@ **Note**: Gaps between patch versions are faulty/broken releases. **Note**: A feature tagged as Experimental is in a high state of flux, you're at risk of it changing without notice. +# 2.6.4 + +- **Bug Fix** + - `ReadonlyMap` + - `traverseWithIndex` should sort the keys (@gcanti) + - `ReadonlyRecord` + - `traverseWithIndex` should sort the keys (@gcanti) + # 2.6.3 - **Polish** diff --git a/package.json b/package.json index 3dec0c3f9..b16f3641b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fp-ts", - "version": "2.6.3", + "version": "2.6.4", "description": "Functional programming in TypeScript", "files": [ "lib", diff --git a/src/ReadonlyMap.ts b/src/ReadonlyMap.ts index fbcb3c6ed..56ebb1d95 100644 --- a/src/ReadonlyMap.ts +++ b/src/ReadonlyMap.ts @@ -720,14 +720,14 @@ export function getWitherable(O: Ord): Witherable2C & TraversableW const traverseWithIndex = ( F: Applicative - ): ((ta: ReadonlyMap, f: (k: K, a: A) => HKT) => HKT>) => { - return (ta: ReadonlyMap, f: (k: K, a: A) => HKT) => { + ): ((ta: ReadonlyMap, f: (k: K, a: A) => HKT) => HKT>) => { + return (ta: ReadonlyMap, f: (k: K, a: A) => HKT) => { let fm: HKT> = F.of(empty) - const entries = ta.entries() - let e: Next - // tslint:disable-next-line: strict-boolean-expressions - while (!(e = entries.next()).done) { - const [key, a] = e.value + const ks = keysO(ta) + const len = ks.length + for (let i = 0; i < len; i++) { + const key = ks[i] + const a = ta.get(key)! fm = F.ap( F.map(fm, (m) => (b: B) => new Map(m).set(key, b)), f(key, a) @@ -739,12 +739,12 @@ export function getWitherable(O: Ord): Witherable2C & TraversableW const traverse = ( F: Applicative - ): ((ta: ReadonlyMap, f: (a: A) => HKT) => HKT>) => { + ): ((ta: ReadonlyMap, f: (a: A) => HKT) => HKT>) => { const traverseWithIndexF = traverseWithIndex(F) return (ta, f) => traverseWithIndexF(ta, (_, a) => f(a)) } - const sequence = (F: Applicative): ((ta: ReadonlyMap>) => HKT>) => { + const sequence = (F: Applicative): ((ta: ReadonlyMap>) => HKT>) => { const traverseWithIndexF = traverseWithIndex(F) return (ta) => traverseWithIndexF(ta, (_, a) => a) } @@ -774,7 +774,7 @@ export function getWitherable(O: Ord): Witherable2C & TraversableW traverseWithIndex, wilt: ( F: Applicative - ): (( + ): (( wa: ReadonlyMap, f: (a: A) => HKT> ) => HKT, ReadonlyMap>>) => { @@ -783,7 +783,7 @@ export function getWitherable(O: Ord): Witherable2C & TraversableW }, wither: ( F: Applicative - ): ((wa: ReadonlyMap, f: (a: A) => HKT>) => HKT>) => { + ): ((wa: ReadonlyMap, f: (a: A) => HKT>) => HKT>) => { const traverseF = traverse(F) return (wa, f) => F.map(traverseF(wa, f), compact) } diff --git a/src/ReadonlyRecord.ts b/src/ReadonlyRecord.ts index 79fa4e7b5..583abc0e0 100644 --- a/src/ReadonlyRecord.ts +++ b/src/ReadonlyRecord.ts @@ -765,10 +765,10 @@ const reduceWithIndex_: (fa: Readonly>, b: B, f: (i: str f ) => { let out = b - const keys = Object.keys(fa).sort() - const len = keys.length + const ks = keys(fa) + const len = ks.length for (let i = 0; i < len; i++) { - const k = keys[i] + const k = ks[i] out = f(k, out, fa[k]) } return out @@ -778,10 +778,10 @@ const foldMapWithIndex_: (M: Monoid) => (fa: Readonly M ) => (fa, f) => { let out = M.empty - const keys = Object.keys(fa).sort() - const len = keys.length + const ks = keys(fa) + const len = ks.length for (let i = 0; i < len; i++) { - const k = keys[i] + const k = ks[i] out = M.concat(out, f(k, fa[k])) } return out @@ -793,10 +793,10 @@ const reduceRightWithIndex_: (fa: Readonly>, b: B, f: (i f ) => { let out = b - const keys = Object.keys(fa).sort() - const len = keys.length + const ks = keys(fa) + const len = ks.length for (let i = len - 1; i >= 0; i--) { - const k = keys[i] + const k = ks[i] out = f(k, fa[k], out) } return out @@ -879,12 +879,12 @@ const traverseWithIndex_ = (F: Applicative) => ( ta: ReadonlyRecord, f: (k: string, a: A) => HKT ) => { - const keys = Object.keys(ta) - if (keys.length === 0) { + const ks = keys(ta) + if (ks.length === 0) { return F.of(empty) } let fr: HKT> = F.of({}) - for (const key of keys) { + for (const key of ks) { fr = F.ap( F.map(fr, (r) => (b: B) => { r[key] = b diff --git a/test/ReadonlyMap.ts b/test/ReadonlyMap.ts index af3c7a3a9..a8a50f428 100644 --- a/test/ReadonlyMap.ts +++ b/test/ReadonlyMap.ts @@ -4,6 +4,7 @@ import { Either, left, right } from '../src/Either' import { Eq, eqNumber, fromEquals } from '../src/Eq' import { identity, pipe, Refinement } from '../src/function' import * as I from '../src/Identity' +import * as IO from '../src/IO' import { monoidString } from '../src/Monoid' import { none, option, Option, some } from '../src/Option' import { fromCompare, ord, ordNumber, ordString } from '../src/Ord' @@ -742,6 +743,24 @@ describe('ReadonlyMap', () => { describe('getWitherable', () => { const W = _.getWitherable(ordUser) + it('traverseWithIndex should sort the keys', () => { + const W = _.getWitherable(ordString) + // tslint:disable-next-line: readonly-array + const log: Array = [] + const append = (message: string): IO.IO => () => { + log.push(message) + } + + W.traverseWithIndex(IO.io)( + new Map([ + ['b', append('b')], + ['a', append('a')] + ]), + (_, io) => io + )() + assert.deepStrictEqual(log, ['a', 'b']) + }) + it('mapWithIndex', () => { const mapWithIndex = W.mapWithIndex const aa1 = new Map([[{ id: 'aa' }, 1]]) diff --git a/test/ReadonlyRecord.ts b/test/ReadonlyRecord.ts index 3e3db6dfa..0e09f3749 100644 --- a/test/ReadonlyRecord.ts +++ b/test/ReadonlyRecord.ts @@ -3,6 +3,7 @@ import { left, right } from '../src/Either' import { eqNumber } from '../src/Eq' import { identity, pipe } from '../src/function' import * as I from '../src/Identity' +import * as IO from '../src/IO' import { monoidString } from '../src/Monoid' import { getOrElse, isSome, none, option, Option, some } from '../src/Option' import { readonlyArray, zip } from '../src/ReadonlyArray' @@ -272,6 +273,20 @@ describe('ReadonlyRecord', () => { assert.deepStrictEqual(_.toUnfoldable(readonlyArray)({ a: 1 }), [['a', 1]]) }) + it('traverseWithIndex should sort the keys', () => { + // tslint:disable-next-line: readonly-array + const log: Array = [] + const append = (message: string): IO.IO => () => { + log.push(message) + } + + pipe( + { b: append('b'), a: append('a') }, + _.traverseWithIndex(IO.io)((_, io) => io) + )() + assert.deepStrictEqual(log, ['a', 'b']) + }) + it('traverseWithIndex', () => { const d1 = { k1: 1, k2: 2 } const t1 = _.traverseWithIndex(option)((k, n: number): Option => (k !== 'k1' ? some(n) : none))(d1)