Skip to content

Commit

Permalink
feat(semigroup): add partial semigroup
Browse files Browse the repository at this point in the history
  • Loading branch information
JalilArfaoui committed Feb 14, 2023
1 parent 2e8ebc9 commit 4b4881a
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 0 deletions.
34 changes: 34 additions & 0 deletions docs/modules/Semigroup.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Added in v2.0.0
- [concatAll](#concatall)
- [intercalate](#intercalate)
- [reverse](#reverse)
- [partial](#partial)
- [struct](#struct)
- [tuple](#tuple)
- [zone of death](#zone-of-death)
Expand Down Expand Up @@ -246,6 +247,39 @@ const S1 = pipe(S.Semigroup, intercalate(' + '))
assert.strictEqual(S1.concat('a', 'b'), 'a + b')
```

Added in v2.14.0

## partial

Given a struct of semigroups returns a semigroup for the struct, that can have optional keys.

**Signature**

```ts
export declare const partial: <A>(
semigroups: { [K in keyof A]: Semigroup<A[K]> }
) => Semigroup<{ readonly [K in keyof Partial<A>]: A[K] }>
```
**Example**
```ts
import { partial, last } from 'fp-ts/Semigroup'
import * as S from 'fp-ts/string'

interface Person {
readonly name: string
readonly age: number
}

const S1 = partial<Person>({
name: S.Semigroup,
age: last(),
})

assert.deepStrictEqual(S1.concat({ name: 'first', age: 42 }, { name: 'second' }), { name: 'firstsecond', age: 42 })
```

Added in v2.10.0

## reverse
Expand Down
40 changes: 40 additions & 0 deletions src/Semigroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,46 @@ export const struct = <A>(semigroups: { [K in keyof A]: Semigroup<A[K]> }): Semi
}
})

/**
* Given a struct of semigroups returns a semigroup for the struct, that can have optional keys.
*
* @example
* import { partial, last } from 'fp-ts/Semigroup'
* import * as S from 'fp-ts/string'
*
* interface Person {
* readonly name: string
* readonly age: number
* }
*
* const S1 = partial<Person>({
* name: S.Semigroup,
* age: last()
* })
*
* assert.deepStrictEqual(S1.concat({ name: "first", age: 42 }, { name: "second" }), { name: "firstsecond", age: 42 })
*
* @category combinators
* @since 2.10.0
*/
export const partial = <A>(
semigroups: { [K in keyof A]: Semigroup<A[K]> }
): Semigroup<{ readonly [K in keyof Partial<A>]: A[K] }> => ({
concat: (first, second) => {
const r: A = {} as any
for (const k in semigroups) {
if (_.has.call(semigroups, k)) {
if (_.has.call(first, k) && _.has.call(second, k)) {
r[k] = semigroups[k].concat(first[k], second[k])
} else if (_.has.call(first, k) || _.has.call(second, k)) {
r[k] = second[k] || first[k]
}
}
}
return r
}
})

/**
* Given a tuple of semigroups returns a semigroup for the tuple.
*
Expand Down
9 changes: 9 additions & 0 deletions test/Semigroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ describe('Semigroup', () => {
U.deepStrictEqual(S.concat({}, {}), {})
})

it('partial', () => {
// should ignore non own properties
const S1 = _.partial(Object.create({ a: 1 }))
U.deepStrictEqual(S1.concat({}, {}), {})

const S2 = _.partial({ a: S.Semigroup, b: N.SemigroupSum, c: B.SemigroupAll, d: S.Semigroup })
U.deepStrictEqual(S2.concat({ a: 'first', b: 12 }, { b: 2, c: true }), { a: 'first', b: 14, c: true })
})

it('semigroupAll', () => {
const S = _.semigroupAll
U.deepStrictEqual(S.concat(true, true), true)
Expand Down

0 comments on commit 4b4881a

Please sign in to comment.