fp-ts Monoidの内容確認

fp-tsの一覧ページがあまりにも重くなったので、分割

# 参照元

https://gcanti.github.io/fp-ts/modules/

## 一覧

https://qiita.com/kuangzhixitian3/items/3fc5d8abd6fe170d7489

### Monoidの内容確認 

参考

https://github.com/gcanti/fp-ts/blob/master/docs/modules/Monoid.ts.md

<table>
  <thead>
    <tr>
      <th>ファイル名</th> 
      <th>import先</th> 
      <th>ソースの中身</th>
      <th>declare module がある</th>
      <th>importでの参照される数</th>
    </tr>
  </thead>

  <!-- interface, const のみ -->
  <tr>
    <td>Monoid</td> 
    <td>
        <ul>
            <li>Bounded</li>
            <li>Endomorphism</li>
            <li>function</li>
            <li>internal</li>
            <li>ReadonlyRecord</li>
            <li>Semigroup</li>
        </ul>
    </td>
    <td>interface, const のみ</td>
    <td>なし</td>
    <td>16</td>
  </tr>
  
</table>

https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%8E%E3%82%A4%E3%83%89

満たすべきもの

結合律

```math
(a \cdot b) \cdot c = a \cdot (b \cdot c)
```

単位元の存在

```math
e \cdot a = a \cdot e = a
```

```ts
import { describe, it } from 'vitest'
import * as M from 'fp-ts/Monoid'
import { type Monoid } from 'fp-ts/lib/Monoid'
import type { Bounded } from 'fp-ts/lib/Bounded'

type Test2<XXX> = {
  Test2: XXX
}

type _a = number
type _b = string

type A = Test2<_a>
type B = Test2<_b>

const TestMonoidTest2a: Monoid<A> = {
  concat: (x, y) => ({
    Test2:
      x !== undefined && y !== undefined
        ? x.Test2 + y.Test2
        : x !== undefined
          ? x.Test2
          : y !== undefined
            ? y.Test2
            : 0
  }),
  empty: {
    Test2: 0
  }
}

const _compare_b = (x: B, y: B) => (x.Test2 > y.Test2 ? 1 : x.Test2 < y.Test2 ? -1 : 0)
const _concat_b = (x: B, y: B) => {
  // const array = [x, y].sort(_compare_b)
  const array = [x, y]
  return `${array[0].Test2} - ${array[1].Test2}`
}
const TestMonoidTest2b: Monoid<B> = {
  concat: (x, y) => ({
    Test2:
      x !== undefined && y !== undefined && x.Test2.length > 0 && y.Test2.length > 0
        ? _concat_b(x, y)
        : x !== undefined && x.Test2.length > 0
          ? x.Test2
          : y !== undefined && y.Test2.length > 0
            ? y.Test2
            : ''
  }),
  empty: {
    Test2: ''
  }
}

const TestBoundedTest2a: Bounded<A> = {
  top: {
    Test2: 600 // no particular meaning
  },
  bottom: {
    Test2: 200 // no particular meaning
  },
  compare: (first, second) =>
    first.Test2 > second.Test2 ? 1 : first.Test2 < second.Test2 ? -1 : 0,
  equals: (x, y) => x.Test2 === y.Test2
}

const TestBoundedTest2b: Bounded<B> = {
  top: {
    Test2: 'faa' // no particular meaning
  },
  bottom: {
    Test2: 'baa' // no particular meaning
  },
  compare: _compare_b,
  equals: (x, y) => x.Test2 === y.Test2
}

describe('fp-ts Tutorial', () => {
  it('Monoid', () => {
    // base
    const a1: A = { Test2: 123 }
    const a2: A = { Test2: 456 }
    const a3: A = { Test2: 789 }

    const b1: B = { Test2: 'abc' }
    const b2: B = { Test2: 'def' }
    const b3: B = { Test2: 'ghi' }

    // object
    const record_a12: Record<string, A> = {
      key1: a1,
      key2: a2
    }
    const record_a23: Record<string, A> = {
      key2: a2,
      key3: a3
    }

    const record_b12: Record<string, B> = {
      key1: b1,
      key2: b2
    }
    const record_b23: Record<string, B> = {
      key2: b2,
      key3: b3
    }

    const record_ab12: Record<string, A | B> = {
      key1: a1,
      key2: b2
    }
    const record_ab23: Record<string, A | B> = {
      key2: b2,
      key3: a3
    }

    const tuple_a123: [A, A, A] = [a1, a2, a3]
    const tuple_a231: [A, A, A] = [a2, a3, a1]
    const tuple_a12: [A, A, A] = [a1, a2] as any
    const tuple_a23: [A, A, A] = [a2, a3] as any

    const tuple_b123: [B, B, B] = [b1, b2, b3]
    const tuple_b231: [B, B, B] = [b2, b3, b1]
    const tuple_b12: [B, B, B] = [b1, b2] as any
    const tuple_b23: [B, B, B] = [b2, b3] as any

    const tuple_ab123: [A, B, A] = [a1, b2, a3]
    const tuple_ab231: [A, B, A] = [a2, b3, a1]
    const tuple_ab12: [A, B, A] = [a1, b2] as any
    const tuple_ab23: [A, B, A] = [a2, b3] as any

    const array_a123: A[] = [a1, a2, a3]

    const array_b123: B[] = [b1, b2, b3]

    // function object
    const record_ma123: Record<string, Monoid<A>> = {
      key1: TestMonoidTest2a,
      key2: TestMonoidTest2a,
      key3: TestMonoidTest2a
    }

    const record_mb123: Record<string, Monoid<B>> = {
      key1: TestMonoidTest2b,
      key2: TestMonoidTest2b,
      key3: TestMonoidTest2b
    }

    const record_mab123: Record<string, Monoid<A | B>> = {
      key1: TestMonoidTest2a as any,
      key2: TestMonoidTest2b as any,
      key3: TestMonoidTest2a as any
    }

    // check
    console.log('concat - empty - check - a1 - ', a1)
    console.log(
      'concat - empty - check - a1 - ',
      TestMonoidTest2a.concat(a1, TestMonoidTest2a.empty)
    )
    console.log(
      'concat - empty - check - a1 - ',
      TestMonoidTest2a.concat(TestMonoidTest2a.empty, a1)
    )
    console.log('concat - empty - check - b1 - ', b1)
    console.log(
      'concat - empty - check - b1 - ',
      TestMonoidTest2b.concat(b1, TestMonoidTest2b.empty)
    )
    console.log(
      'concat - empty - check - b1 - ',
      TestMonoidTest2b.concat(TestMonoidTest2b.empty, b1)
    )

    console.log('---------')

    console.log(
      'concat - check - a1, (a2, a3) - ',
      TestMonoidTest2a.concat(a1, TestMonoidTest2a.concat(a2, a3))
    )
    console.log(
      'concat - check - (a1, a2), a3 - ',
      TestMonoidTest2a.concat(TestMonoidTest2a.concat(a1, a2), a3)
    )

    console.log(
      'concat - check - b1, (b2, b3) - ',
      TestMonoidTest2b.concat(b1, TestMonoidTest2b.concat(b2, b3))
    )
    console.log(
      'concat - check - (b1, b2), b3 - ',
      TestMonoidTest2b.concat(TestMonoidTest2b.concat(b1, b2), b3)
    )

    console.log('---------')

    // test
    console.log('empty - A => ', TestMonoidTest2a.empty)
    console.log('empty - B => ', TestMonoidTest2b.empty)

    console.log('concat (a1,a2) - (', a1, ',', a2, ') => ', TestMonoidTest2a.concat(a1, a2))
    console.log('concat (b1,b2) - (', b1, ',', b2, ') => ', TestMonoidTest2b.concat(b1, b2))

    console.log('---------')

    console.log(
      'min - concat (a1,a2) - (',
      a1,
      ',',
      a2,
      ') => ',
      M.min(TestBoundedTest2a).concat(a1, a2)
    )
    console.log(
      'min - concat (b1,b2) - (',
      b1,
      ',',
      b2,
      ') => ',
      M.min(TestBoundedTest2b).concat(b1, b2)
    )

    console.log('---------')

    console.log(
      'max - concat (a1,a2) - (',
      a1,
      ',',
      a2,
      ') => ',
      M.max(TestBoundedTest2a).concat(a1, a2)
    )
    console.log(
      'max - concat (b1,b2) - (',
      b1,
      ',',
      b2,
      ') => ',
      M.max(TestBoundedTest2b).concat(b1, b2)
    )

    console.log('---------')

    console.log(
      'reverse - concat (a1,a2) - (',
      a1,
      ',',
      a2,
      ') => ',
      M.reverse(TestMonoidTest2a).concat(a1, a2)
    )
    console.log(
      'reverse - concat (b1,b2) - (',
      b1,
      ',',
      b2,
      ') => ',
      M.reverse(TestMonoidTest2b).concat(b1, b2)
    )

    console.log('---------')

    console.log(
      'struct - concat (record_ma123, record_a12, record_a23) - (',
      record_ma123,
      ',',
      record_a12,
      ',',
      record_a23,
      ') => ',
      M.struct(record_ma123).concat(record_a12, record_a23)
    )
    console.log(
      'struct - concat (record_ma123, record_a12, record_a12) - (',
      record_ma123,
      ',',
      record_a12,
      ',',
      record_a12,
      ') => ',
      M.struct(record_ma123).concat(record_a12, record_a12)
    )
    console.log(
      'struct - concat (record_mb123, record_b12, record_b23) - (',
      record_mb123,
      ',',
      record_b12,
      ',',
      record_b23,
      ') => ',
      M.struct(record_mb123).concat(record_b12, record_b23)
    )
    console.log(
      'struct - concat (record_mb123, record_b12, record_b12) - (',
      record_mb123,
      ',',
      record_b12,
      ',',
      record_b12,
      ') => ',
      M.struct(record_mb123).concat(record_b12, record_b12)
    )
    console.log(
      'struct - concat (record_mab123, record_ab12, record_ab23) - (',
      record_mab123,
      ',',
      record_ab12,
      ',',
      record_ab23,
      ') => ',
      M.struct(record_mab123).concat(record_ab12, record_ab23)
    )
    console.log(
      'struct - concat (record_mab123, record_ab12, record_ab12) - (',
      record_mab123,
      ',',
      record_ab12,
      ',',
      record_ab12,
      ') => ',
      M.struct(record_mab123).concat(record_ab12, record_ab12)
    )

    console.log('---------')

    console.log(
      'tuple - concat (tuple_a123, tuple_a231) - (',
      tuple_a123,
      ',',
      tuple_a231,
      ') => ',
      M.tuple(TestMonoidTest2a, TestMonoidTest2a, TestMonoidTest2a).concat(tuple_a123, tuple_a231)
    )
    console.log(
      'tuple - concat (record_a12, record_a23) - (',
      tuple_a12,
      ',',
      tuple_a23,
      ') => ',
      M.tuple(TestMonoidTest2a, TestMonoidTest2a, TestMonoidTest2a).concat(tuple_a12, tuple_a23)
    )
    console.log(
      'tuple - concat (tuple_b123, tuple_b231) - (',
      tuple_b123,
      ',',
      tuple_b231,
      ') => ',
      M.tuple(TestMonoidTest2b, TestMonoidTest2b, TestMonoidTest2b).concat(tuple_b123, tuple_b231)
    )
    console.log(
      'tuple - concat (record_b12, record_b23) - (',
      tuple_b12,
      ',',
      tuple_b23,
      ') => ',
      M.tuple(TestMonoidTest2b, TestMonoidTest2b, TestMonoidTest2b).concat(tuple_b12, tuple_b23)
    )
    console.log(
      'tuple - concat (tuple_ab123, tuple_ab231) - (',
      tuple_ab123,
      ',',
      tuple_ab231,
      ') => ',
      M.tuple(TestMonoidTest2a, TestMonoidTest2b, TestMonoidTest2a).concat(tuple_ab123, tuple_ab231)
    )
    console.log(
      'tuple - concat (record_ab12, record_ab23) - (',
      tuple_ab12,
      ',',
      tuple_ab23,
      ') => ',
      M.tuple(TestMonoidTest2a, TestMonoidTest2b, TestMonoidTest2a).concat(tuple_ab12, tuple_ab23)
    )

    console.log('---------')

    console.log(
      'concatAll - array_a123 - ',
      array_a123,
      ' => ',
      M.concatAll(TestMonoidTest2a)(array_a123)
    )
    console.log(
      'concatAll - tuple_a231 - ',
      tuple_a231,
      ' => ',
      M.concatAll(TestMonoidTest2a)(tuple_a231)
    )
    console.log(
      'concatAll - array_b123 - ',
      array_b123,
      ' => ',
      M.concatAll(TestMonoidTest2b)(array_b123)
    )
    console.log(
      'concatAll - tuple_b231 - ',
      tuple_b231,
      ' => ',
      M.concatAll(TestMonoidTest2b)(tuple_b231)
    )
  })
})
```

実行結果
```ts
concat - empty - check - a1 -  { Test2: 123 }
concat - empty - check - a1 -  { Test2: 123 }
concat - empty - check - a1 -  { Test2: 123 }
concat - empty - check - b1 -  { Test2: 'abc' }
concat - empty - check - b1 -  { Test2: 'abc' }
concat - empty - check - b1 -  { Test2: 'abc' }
---------
concat - check - a1, (a2, a3) -  { Test2: 1368 }
concat - check - (a1, a2), a3 -  { Test2: 1368 }
concat - check - b1, (b2, b3) -  { Test2: 'abc - def - ghi' }
concat - check - (b1, b2), b3 -  { Test2: 'abc - def - ghi' }
---------
empty - A =>  { Test2: 0 }
empty - B =>  { Test2: '' }
concat (a1,a2) - ( { Test2: 123 } , { Test2: 456 } ) =>  { Test2: 579 }
concat (b1,b2) - ( { Test2: 'abc' } , { Test2: 'def' } ) =>  { Test2: 'abc - def' }
---------
min - concat (a1,a2) - ( { Test2: 123 } , { Test2: 456 } ) =>  { Test2: 123 }
min - concat (b1,b2) - ( { Test2: 'abc' } , { Test2: 'def' } ) =>  { Test2: 'abc' }
---------
max - concat (a1,a2) - ( { Test2: 123 } , { Test2: 456 } ) =>  { Test2: 456 }
max - concat (b1,b2) - ( { Test2: 'abc' } , { Test2: 'def' } ) =>  { Test2: 'def' }
---------
reverse - concat (a1,a2) - ( { Test2: 123 } , { Test2: 456 } ) =>  { Test2: 579 }
reverse - concat (b1,b2) - ( { Test2: 'abc' } , { Test2: 'def' } ) =>  { Test2: 'def - abc' }
---------
struct - concat (record_ma123, record_a12, record_a23) - ( {
  key1: { concat: [Function: concat], empty: { Test2: 0 } },
  key2: { concat: [Function: concat], empty: { Test2: 0 } },
  key3: { concat: [Function: concat], empty: { Test2: 0 } }
} , { key1: { Test2: 123 }, key2: { Test2: 456 } } , { key2: { Test2: 456 }, key3: { Test2: 789 } } ) =>  { key1: { Test2: 123 }, key2: { Test2: 912 }, key3: { Test2: 789 } }
struct - concat (record_ma123, record_a12, record_a12) - ( {
  key1: { concat: [Function: concat], empty: { Test2: 0 } },
  key2: { concat: [Function: concat], empty: { Test2: 0 } },
  key3: { concat: [Function: concat], empty: { Test2: 0 } }
} , { key1: { Test2: 123 }, key2: { Test2: 456 } } , { key1: { Test2: 123 }, key2: { Test2: 456 } } ) =>  { key1: { Test2: 246 }, key2: { Test2: 912 }, key3: { Test2: 0 } }
struct - concat (record_mb123, record_b12, record_b23) - ( {
  key1: { concat: [Function: concat], empty: { Test2: '' } },
  key2: { concat: [Function: concat], empty: { Test2: '' } },
  key3: { concat: [Function: concat], empty: { Test2: '' } }
} , { key1: { Test2: 'abc' }, key2: { Test2: 'def' } } , { key2: { Test2: 'def' }, key3: { Test2: 'ghi' } } ) =>  {
  key1: { Test2: 'abc' },
  key2: { Test2: 'def - def' },
  key3: { Test2: 'ghi' }
}
struct - concat (record_mb123, record_b12, record_b12) - ( {
  key1: { concat: [Function: concat], empty: { Test2: '' } },
  key2: { concat: [Function: concat], empty: { Test2: '' } },
  key3: { concat: [Function: concat], empty: { Test2: '' } }
} , { key1: { Test2: 'abc' }, key2: { Test2: 'def' } } , { key1: { Test2: 'abc' }, key2: { Test2: 'def' } } ) =>  {
  key1: { Test2: 'abc - abc' },
  key2: { Test2: 'def - def' },
  key3: { Test2: '' }
}
struct - concat (record_mab123, record_ab12, record_ab23) - ( {
  key1: { concat: [Function: concat], empty: { Test2: 0 } },
  key2: { concat: [Function: concat], empty: { Test2: '' } },
  key3: { concat: [Function: concat], empty: { Test2: 0 } }
} , { key1: { Test2: 123 }, key2: { Test2: 'def' } } , { key2: { Test2: 'def' }, key3: { Test2: 789 } } ) =>  {
  key1: { Test2: 123 },
  key2: { Test2: 'def - def' },
  key3: { Test2: 789 }
}
struct - concat (record_mab123, record_ab12, record_ab12) - ( {
  key1: { concat: [Function: concat], empty: { Test2: 0 } },
  key2: { concat: [Function: concat], empty: { Test2: '' } },
  key3: { concat: [Function: concat], empty: { Test2: 0 } }
} , { key1: { Test2: 123 }, key2: { Test2: 'def' } } , { key1: { Test2: 123 }, key2: { Test2: 'def' } } ) =>  {
  key1: { Test2: 246 },
  key2: { Test2: 'def - def' },
  key3: { Test2: 0 }
}
---------
tuple - concat (tuple_a123, tuple_a231) - ( [ { Test2: 123 }, { Test2: 456 }, { Test2: 789 } ] , [ { Test2: 456 }, { Test2: 789 }, { Test2: 123 } ] ) =>  [ { Test2: 579 }, { Test2: 1245 }, { Test2: 912 } ]
tuple - concat (record_a12, record_a23) - ( [ { Test2: 123 }, { Test2: 456 } ] , [ { Test2: 456 }, { Test2: 789 } ] ) =>  [ { Test2: 579 }, { Test2: 1245 }, { Test2: 0 } ]
tuple - concat (tuple_b123, tuple_b231) - ( [ { Test2: 'abc' }, { Test2: 'def' }, { Test2: 'ghi' } ] , [ { Test2: 'def' }, { Test2: 'ghi' }, { Test2: 'abc' } ] ) =>  [
  { Test2: 'abc - def' },
  { Test2: 'def - ghi' },
  { Test2: 'ghi - abc' }
]
tuple - concat (record_b12, record_b23) - ( [ { Test2: 'abc' }, { Test2: 'def' } ] , [ { Test2: 'def' }, { Test2: 'ghi' } ] ) =>  [ { Test2: 'abc - def' }, { Test2: 'def - ghi' }, { Test2: '' } ]
tuple - concat (tuple_ab123, tuple_ab231) - ( [ { Test2: 123 }, { Test2: 'def' }, { Test2: 789 } ] , [ { Test2: 456 }, { Test2: 'ghi' }, { Test2: 123 } ] ) =>  [ { Test2: 579 }, { Test2: 'def - ghi' }, { Test2: 912 } ]
tuple - concat (record_ab12, record_ab23) - ( [ { Test2: 123 }, { Test2: 'def' } ] , [ { Test2: 456 }, { Test2: 'ghi' } ] ) =>  [ { Test2: 579 }, { Test2: 'def - ghi' }, { Test2: 0 } ]
---------
concatAll - array_a123 -  [ { Test2: 123 }, { Test2: 456 }, { Test2: 789 } ]  =>  { Test2: 1368 }
concatAll - tuple_a231 -  [ { Test2: 456 }, { Test2: 789 }, { Test2: 123 } ]  =>  { Test2: 1368 }
concatAll - array_b123 -  [ { Test2: 'abc' }, { Test2: 'def' }, { Test2: 'ghi' } ]  =>  { Test2: 'abc - def - ghi' }
concatAll - tuple_b231 -  [ { Test2: 'def' }, { Test2: 'ghi' }, { Test2: 'abc' } ]  =>  { Test2: 'def - ghi - abc' }
```