Skip to content

Commit

Permalink
add modifyF, closes #149
Browse files Browse the repository at this point in the history
  • Loading branch information
gcanti committed Jan 22, 2021
1 parent 2cbd238 commit 5c9d692
Show file tree
Hide file tree
Showing 14 changed files with 245 additions and 6 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
**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.3.5

- **Experimental**
- add `modifyF`, closes #149 (@gcanti)
- `Iso`
- `Lens`
- `Prism`
- `Optional`

# 2.3.4

- **Experimental**
Expand Down
22 changes: 22 additions & 0 deletions docs/modules/Iso.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Added in v2.3.0
- [imap](#imap)
- [combinators](#combinators)
- [modify](#modify)
- [modifyF](#modifyf)
- [compositions](#compositions)
- [compose](#compose)
- [constructors](#constructors)
Expand Down Expand Up @@ -73,6 +74,27 @@ export declare const modify: <A>(f: (a: A) => A) => <S>(sa: Iso<S, A>) => (s: S)

Added in v2.3.0

## modifyF

**Signature**

```ts
export declare function modifyF<F extends URIS3>(
F: Functor3<F>
): <A, R, E>(f: (a: A) => Kind3<F, R, E, A>) => <S>(sa: Iso<S, A>) => (s: S) => Kind3<F, R, E, S>
export declare function modifyF<F extends URIS2>(
F: Functor2<F>
): <A, E>(f: (a: A) => Kind2<F, E, A>) => <S>(sa: Iso<S, A>) => (s: S) => Kind2<F, E, S>
export declare function modifyF<F extends URIS>(
F: Functor1<F>
): <A>(f: (a: A) => Kind<F, A>) => <S>(sa: Iso<S, A>) => (s: S) => Kind<F, S>
export declare function modifyF<F>(
F: Functor<F>
): <A>(f: (a: A) => HKT<F, A>) => <S>(sa: Iso<S, A>) => (s: S) => HKT<F, S>
```

Added in v2.3.5

# compositions

## compose
Expand Down
22 changes: 22 additions & 0 deletions docs/modules/Lens.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Added in v2.3.0
- [key](#key)
- [left](#left)
- [modify](#modify)
- [modifyF](#modifyf)
- [prop](#prop)
- [props](#props)
- [right](#right)
Expand Down Expand Up @@ -187,6 +188,27 @@ export declare const modify: <A>(f: (a: A) => A) => <S>(sa: Lens<S, A>) => (s: S

Added in v2.3.0

## modifyF

**Signature**

```ts
export declare function modifyF<F extends URIS3>(
F: Functor3<F>
): <A, R, E>(f: (a: A) => Kind3<F, R, E, A>) => <S>(sa: Lens<S, A>) => (s: S) => Kind3<F, R, E, S>
export declare function modifyF<F extends URIS2>(
F: Functor2<F>
): <A, E>(f: (a: A) => Kind2<F, E, A>) => <S>(sa: Lens<S, A>) => (s: S) => Kind2<F, E, S>
export declare function modifyF<F extends URIS>(
F: Functor1<F>
): <A>(f: (a: A) => Kind<F, A>) => <S>(sa: Lens<S, A>) => (s: S) => Kind<F, S>
export declare function modifyF<F>(
F: Functor<F>
): <A>(f: (a: A) => HKT<F, A>) => <S>(sa: Lens<S, A>) => (s: S) => HKT<F, S>
```

Added in v2.3.5

## prop

Return a `Lens` from a `Lens` and a prop
Expand Down
22 changes: 22 additions & 0 deletions docs/modules/Optional.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Added in v2.3.0
- [key](#key)
- [left](#left)
- [modify](#modify)
- [modifyF](#modifyf)
- [modifyOption](#modifyoption)
- [prop](#prop)
- [props](#props)
Expand Down Expand Up @@ -188,6 +189,27 @@ export declare const modify: <A>(f: (a: A) => A) => <S>(optional: Optional<S, A>

Added in v2.3.0

## modifyF

**Signature**

```ts
export declare function modifyF<F extends URIS3>(
F: Applicative3<F>
): <A, R, E>(f: (a: A) => Kind3<F, R, E, A>) => <S>(sa: Optional<S, A>) => (s: S) => Kind3<F, R, E, S>
export declare function modifyF<F extends URIS2>(
F: Applicative2<F>
): <A, E>(f: (a: A) => Kind2<F, E, A>) => <S>(sa: Optional<S, A>) => (s: S) => Kind2<F, E, S>
export declare function modifyF<F extends URIS>(
F: Applicative1<F>
): <A>(f: (a: A) => Kind<F, A>) => <S>(sa: Optional<S, A>) => (s: S) => Kind<F, S>
export declare function modifyF<F>(
F: Applicative<F>
): <A>(f: (a: A) => HKT<F, A>) => <S>(sa: Optional<S, A>) => (s: S) => HKT<F, S>
```

Added in v2.3.5

## modifyOption

**Signature**
Expand Down
22 changes: 22 additions & 0 deletions docs/modules/Prism.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Added in v2.3.0
- [key](#key)
- [left](#left)
- [modify](#modify)
- [modifyF](#modifyf)
- [modifyOption](#modifyoption)
- [prop](#prop)
- [props](#props)
Expand Down Expand Up @@ -188,6 +189,27 @@ export declare const modify: <A>(f: (a: A) => A) => <S>(sa: Prism<S, A>) => (s:

Added in v2.3.0

## modifyF

**Signature**

```ts
export declare function modifyF<F extends URIS3>(
F: Applicative3<F>
): <A, R, E>(f: (a: A) => Kind3<F, R, E, A>) => <S>(sa: Prism<S, A>) => (s: S) => Kind3<F, R, E, S>
export declare function modifyF<F extends URIS2>(
F: Applicative2<F>
): <A, E>(f: (a: A) => Kind2<F, E, A>) => <S>(sa: Prism<S, A>) => (s: S) => Kind2<F, E, S>
export declare function modifyF<F extends URIS>(
F: Applicative1<F>
): <A>(f: (a: A) => Kind<F, A>) => <S>(sa: Prism<S, A>) => (s: S) => Kind<F, S>
export declare function modifyF<F>(
F: Applicative<F>
): <A>(f: (a: A) => HKT<F, A>) => <S>(sa: Prism<S, A>) => (s: S) => HKT<F, S>
```

Added in v2.3.5

## modifyOption

**Signature**
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "monocle-ts",
"version": "2.3.4",
"version": "2.3.5",
"description": "A porting of scala monocle library to TypeScript",
"files": [
"lib",
Expand Down
23 changes: 21 additions & 2 deletions src/Iso.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
*/
import { Applicative } from 'fp-ts/lib/Applicative'
import { Category2 } from 'fp-ts/lib/Category'
import { flow, identity } from 'fp-ts/lib/function'
import { HKT } from 'fp-ts/lib/HKT'
import { flow, identity, pipe } from 'fp-ts/lib/function'
import { Functor, Functor1, Functor2, Functor3 } from 'fp-ts/lib/Functor'
import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from 'fp-ts/lib/HKT'
import { Invariant2 } from 'fp-ts/lib/Invariant'
import * as O from 'fp-ts/lib/Option'
import * as _ from './internal'
Expand Down Expand Up @@ -127,6 +128,24 @@ export const reverse = <S, A>(sa: Iso<S, A>): Iso<A, S> => ({
*/
export const modify = <A>(f: (a: A) => A) => <S>(sa: Iso<S, A>) => (s: S): S => sa.reverseGet(f(sa.get(s)))

/**
* @category combinators
* @since 2.3.5
*/
export function modifyF<F extends URIS3>(
F: Functor3<F>
): <A, R, E>(f: (a: A) => Kind3<F, R, E, A>) => <S>(sa: Iso<S, A>) => (s: S) => Kind3<F, R, E, S>
export function modifyF<F extends URIS2>(
F: Functor2<F>
): <A, E>(f: (a: A) => Kind2<F, E, A>) => <S>(sa: Iso<S, A>) => (s: S) => Kind2<F, E, S>
export function modifyF<F extends URIS>(
F: Functor1<F>
): <A>(f: (a: A) => Kind<F, A>) => <S>(sa: Iso<S, A>) => (s: S) => Kind<F, S>
export function modifyF<F>(F: Functor<F>): <A>(f: (a: A) => HKT<F, A>) => <S>(sa: Iso<S, A>) => (s: S) => HKT<F, S>
export function modifyF<F>(F: Functor<F>): <A>(f: (a: A) => HKT<F, A>) => <S>(sa: Iso<S, A>) => (s: S) => HKT<F, S> {
return (f) => (sa) => (s) => pipe(sa.get(s), f, (fa) => F.map(fa, sa.reverseGet))
}

// -------------------------------------------------------------------------------------
// pipeables
// -------------------------------------------------------------------------------------
Expand Down
21 changes: 20 additions & 1 deletion src/Lens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
import { Category2 } from 'fp-ts/lib/Category'
import { Either } from 'fp-ts/lib/Either'
import { flow, Predicate, Refinement } from 'fp-ts/lib/function'
import { Kind, URIS } from 'fp-ts/lib/HKT'
import { Functor, Functor1, Functor2, Functor3 } from 'fp-ts/lib/Functor'
import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from 'fp-ts/lib/HKT'
import { Invariant2 } from 'fp-ts/lib/Invariant'
import { Option } from 'fp-ts/lib/Option'
import { pipe } from 'fp-ts/lib/pipeable'
Expand Down Expand Up @@ -117,6 +118,24 @@ export const modify = <A>(f: (a: A) => A) => <S>(sa: Lens<S, A>) => (s: S): S =>
return o === n ? s : sa.set(n)(s)
}

/**
* @category combinators
* @since 2.3.5
*/
export function modifyF<F extends URIS3>(
F: Functor3<F>
): <A, R, E>(f: (a: A) => Kind3<F, R, E, A>) => <S>(sa: Lens<S, A>) => (s: S) => Kind3<F, R, E, S>
export function modifyF<F extends URIS2>(
F: Functor2<F>
): <A, E>(f: (a: A) => Kind2<F, E, A>) => <S>(sa: Lens<S, A>) => (s: S) => Kind2<F, E, S>
export function modifyF<F extends URIS>(
F: Functor1<F>
): <A>(f: (a: A) => Kind<F, A>) => <S>(sa: Lens<S, A>) => (s: S) => Kind<F, S>
export function modifyF<F>(F: Functor<F>): <A>(f: (a: A) => HKT<F, A>) => <S>(sa: Lens<S, A>) => (s: S) => HKT<F, S>
export function modifyF<F>(F: Functor<F>): <A>(f: (a: A) => HKT<F, A>) => <S>(sa: Lens<S, A>) => (s: S) => HKT<F, S> {
return (f) => (sa) => (s) => pipe(sa.get(s), f, (fa) => F.map(fa, (a) => sa.set(a)(s)))
}

/**
* Return a `Optional` from a `Lens` focused on a nullable value
*
Expand Down
32 changes: 31 additions & 1 deletion src/Optional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
*
* @since 2.3.0
*/
import { Applicative, Applicative1, Applicative2, Applicative3 } from 'fp-ts/lib/Applicative'
import { Category2 } from 'fp-ts/lib/Category'
import { Either } from 'fp-ts/lib/Either'
import { constant, flow, Predicate, Refinement } from 'fp-ts/lib/function'
import { Kind, URIS } from 'fp-ts/lib/HKT'
import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from 'fp-ts/lib/HKT'
import { Invariant2 } from 'fp-ts/lib/Invariant'
import * as O from 'fp-ts/lib/Option'
import { pipe } from 'fp-ts/lib/pipeable'
Expand Down Expand Up @@ -100,6 +101,35 @@ export const modifyOption: <A>(f: (a: A) => A) => <S>(optional: Optional<S, A>)
*/
export const modify: <A>(f: (a: A) => A) => <S>(optional: Optional<S, A>) => (s: S) => S = _.optionalModify

/**
* @category combinators
* @since 2.3.5
*/
export function modifyF<F extends URIS3>(
F: Applicative3<F>
): <A, R, E>(f: (a: A) => Kind3<F, R, E, A>) => <S>(sa: Optional<S, A>) => (s: S) => Kind3<F, R, E, S>
export function modifyF<F extends URIS2>(
F: Applicative2<F>
): <A, E>(f: (a: A) => Kind2<F, E, A>) => <S>(sa: Optional<S, A>) => (s: S) => Kind2<F, E, S>
export function modifyF<F extends URIS>(
F: Applicative1<F>
): <A>(f: (a: A) => Kind<F, A>) => <S>(sa: Optional<S, A>) => (s: S) => Kind<F, S>
export function modifyF<F>(
F: Applicative<F>
): <A>(f: (a: A) => HKT<F, A>) => <S>(sa: Optional<S, A>) => (s: S) => HKT<F, S>
export function modifyF<F>(
F: Applicative<F>
): <A>(f: (a: A) => HKT<F, A>) => <S>(sa: Optional<S, A>) => (s: S) => HKT<F, S> {
return (f) => (sa) => (s) =>
pipe(
sa.getOption(s),
O.fold(
() => F.of(s),
(a) => F.map(f(a), (a) => sa.set(a)(s))
)
)
}

/**
* Return an `Optional` from a `Optional` focused on a nullable value
*
Expand Down
32 changes: 31 additions & 1 deletion src/Prism.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
*
* @since 2.3.0
*/
import { Applicative, Applicative1, Applicative2, Applicative3 } from 'fp-ts/lib/Applicative'
import { Category2 } from 'fp-ts/lib/Category'
import { Either } from 'fp-ts/lib/Either'
import { flow, identity, Predicate, Refinement } from 'fp-ts/lib/function'
import { Kind, URIS } from 'fp-ts/lib/HKT'
import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from 'fp-ts/lib/HKT'
import { Invariant2 } from 'fp-ts/lib/Invariant'
import * as O from 'fp-ts/lib/Option'
import { pipe } from 'fp-ts/lib/pipeable'
Expand Down Expand Up @@ -138,6 +139,35 @@ export const modifyOption: <A>(f: (a: A) => A) => <S>(sa: Prism<S, A>) => (s: S)
*/
export const modify: <A>(f: (a: A) => A) => <S>(sa: Prism<S, A>) => (s: S) => S = _.prismModify

/**
* @category combinators
* @since 2.3.5
*/
export function modifyF<F extends URIS3>(
F: Applicative3<F>
): <A, R, E>(f: (a: A) => Kind3<F, R, E, A>) => <S>(sa: Prism<S, A>) => (s: S) => Kind3<F, R, E, S>
export function modifyF<F extends URIS2>(
F: Applicative2<F>
): <A, E>(f: (a: A) => Kind2<F, E, A>) => <S>(sa: Prism<S, A>) => (s: S) => Kind2<F, E, S>
export function modifyF<F extends URIS>(
F: Applicative1<F>
): <A>(f: (a: A) => Kind<F, A>) => <S>(sa: Prism<S, A>) => (s: S) => Kind<F, S>
export function modifyF<F>(
F: Applicative<F>
): <A>(f: (a: A) => HKT<F, A>) => <S>(sa: Prism<S, A>) => (s: S) => HKT<F, S>
export function modifyF<F>(
F: Applicative<F>
): <A>(f: (a: A) => HKT<F, A>) => <S>(sa: Prism<S, A>) => (s: S) => HKT<F, S> {
return (f) => (sa) => (s) =>
pipe(
sa.getOption(s),
O.fold(
() => F.of(s),
(a) => F.map(f(a), sa.reverseGet)
)
)
}

/**
* Return a `Prism` from a `Prism` focused on a nullable value
*
Expand Down
10 changes: 10 additions & 0 deletions test/Iso.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as assert from 'assert'
import { pipe } from 'fp-ts/lib/function'
import * as _ from '../src/Iso'
import * as Id from 'fp-ts/lib/Identity'
import * as O from 'fp-ts/lib/Option'

const numberFromString: _.Iso<number, string> = {
get: String,
Expand Down Expand Up @@ -58,4 +59,13 @@ describe('Iso', () => {
const sa = pipe(double, _.asTraversal)
assert.deepStrictEqual(sa.modifyF(Id.identity)((n) => n - 1)(3), 2.5)
})

it('modifyF', () => {
const f = pipe(
double,
_.modifyF(O.Functor)((n) => (n > 0 ? O.some(n * 2) : O.none))
)
assert.deepStrictEqual(f(1), O.some(2))
assert.deepStrictEqual(f(-1), O.none)
})
})
13 changes: 13 additions & 0 deletions test/Lens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,4 +224,17 @@ describe('Lens', () => {
assert.deepStrictEqual(sa.set(3)([-1, 2, -3]), [-1, 3, -3])
assert.deepStrictEqual(sa.set(4)([-1, -2, 3]), [-1, -2, 4])
})

it('modifyF', () => {
interface S {
readonly a: number
}
const sa: _.Lens<S, number> = pipe(_.id<S>(), _.prop('a'))
const f = pipe(
sa,
_.modifyF(O.Functor)((n) => (n > 0 ? O.some(n * 2) : O.none))
)
assert.deepStrictEqual(f({ a: 1 }), O.some({ a: 2 }))
assert.deepStrictEqual(f({ a: -1 }), O.none)
})
})
11 changes: 11 additions & 0 deletions test/Optional.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,15 @@ describe('Optional', () => {
assert.deepStrictEqual(sa.set(2)({ a: undefined }), { a: undefined })
assert.deepStrictEqual(sa.set(2)({ a: 1 }), { a: 2 })
})

it('modifyF', () => {
const sa = pipe(_.id<ReadonlyArray<number>>(), _.index(0))
const f = pipe(
sa,
_.modifyF(O.Applicative)((n) => (n > 0 ? O.some(n * 2) : O.none))
)
assert.deepStrictEqual(f([]), O.some([]))
assert.deepStrictEqual(f([1, 2, 3]), O.some([2, 2, 3]))
assert.deepStrictEqual(f([-1, 2, 3]), O.none)
})
})
Loading

0 comments on commit 5c9d692

Please sign in to comment.