fp-ts Functorの内容確認

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

# 参照元

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

## 一覧

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

### Functorの内容確認 

参考

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

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

  <tr>
    <td>Functor</td> 
    <td>
        <ul>
            <li>function</li>
            <li>HKT</li>
        </ul>
    </td>
    <td>interface, function のみ</td>
    <td>なし</td>
    <td>12</td>
  </tr>
  
</table>

https://ja.wikipedia.org/wiki/%E9%96%A2%E6%89%8B

https://qiita.com/ryokat3/items/5f67dda315ef485a4fae#functor

満たすべきもの

恒等射、単位元

```math
F.map(fa, x => x) = fa
```


```plantuml
card fa as c1
card fa as c2

c1 -> c2 : ""(x) => x ※identity""
```

射の合成、合成

```math
F.map(fa, x => f(g(x))) = F.map(F.map(fa, g), f)
```

```plantuml
card "fa ※Aの型の値" as c1
card "fb ※Bの型の値" as c2
card "fc ※Cの型の値" as c3
title F.map(fa, x => f(g(x)))

c1 --> c2 : ""g(fa) ※A=>Bへの型変換""
c2 --> c3 : ""f(fb) ※B=>Cへの型変換""
c1 -> c3 : ""x => f(g(x)) ※関数合成""
```

<br>

```plantuml
card "fa ※Aの型の値" as c1
card "fb ※Bの型の値" as c2
card "fc ※Cの型の値" as c3
title F.map(F.map(fa, g), f)

c1 --> c2 : ""F.map(fa, g) ※A=>Bへの型変換""
c2 --> c3 : ""F.map(fb, f) ※B=>Cへの型変換 ※fb=F.map(fa, g) ""
```

```ts
import { describe, it } from 'vitest'
import { type Functor1 } from 'fp-ts/lib/Functor'
import type { Kind, URIS } from 'fp-ts/lib/HKT'
import { pipe } from 'fp-ts/lib/function'
import * as f from 'fp-ts/function'

const URI = 'Test2'
type URI = typeof URI

declare module 'fp-ts/HKT' {
  interface URItoKind<A> {
    readonly Test2: Test2<A>
  }
}

const Test2Functor: Functor1<URI> = {
  URI,
  map: (ma, f) => ({ Test2: f(ma.Test2) })
}

const Functor1Id: <F extends URIS>(Functor: Functor1<F>) => <A>(fa: Kind<F, A>) => Kind<F, A> =
  (Functor) => (fa) =>
    Functor.map(fa, f.identity)

const Functor1Composition1: <F extends URIS>(
  Functor: Functor1<F>
) => <A, B>(g: (a: A) => B) => <C>(f: (a: B) => C) => (fa: Kind<F, A>) => Kind<F, C> =
  (Functor) => (g) => (f) => (fa) =>
    Functor.map(fa, (x) => f(g(x)))

const Functor1Composition2: <F extends URIS>(
  Functor: Functor1<F>
) => <A, B>(g: (a: A) => B) => <C>(f: (a: B) => C) => (fa: Kind<F, A>) => Kind<F, C> =
  (Functor) => (g) => (f) => (fa) =>
    Functor.map(Functor.map(fa, g), f)

type Test2<XXX> = {
  Test2: XXX
}

type A = number
type B = string
type C = boolean

type A2 = string
type B2 = boolean
type C2 = number

type A3 = boolean
type B3 = string
type C3 = number

type F<XXX> = Test2<XXX>

describe('fp-ts Tutorial', () => {
  it('Functor', () => {
    // object
    const a: A = 123
    const a2: A2 = 'abc'
    const a3: A3 = true

    const fa: F<A> = {
      Test2: a
    }
    const fa2: F<A2> = {
      Test2: a2
    }
    const fa3: F<A3> = {
      Test2: a3
    }

    const a_b_function: (a: A) => B = (a) => String(a)
    const b_c_function: (b: B) => C = (b) => Boolean(b)

    const a2_b2_function: (a: A2) => B2 = (a) => Boolean(a)
    const b2_c2_function: (b: B2) => C2 = (b) => (Number.isNaN(Number(b)) ? 0 : Number(b))

    const a3_b3_function: (a: A3) => B3 = (a) => String(a)
    const b3_c3_function: (b: B3) => C3 = (b) => (Number.isNaN(Number(b)) ? 0 : Number(b))

    console.log('A => B => C')
    console.log()
    console.log('F.map(fa, x => x) - ', pipe(fa, Functor1Id(Test2Functor)))
    console.log('fa - ', fa)
    console.log()
    console.log(
      'F.map(fa, x => f(g(x))) - ',
      pipe(fa, Functor1Composition1(Test2Functor)(a_b_function)(b_c_function))
    )
    console.log(
      'F.map(F.map(fa, g), f) - ',
      pipe(fa, Functor1Composition2(Test2Functor)(a_b_function)(b_c_function))
    )

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

    console.log('A2 => B2 => C2')
    console.log()
    console.log('F.map(fa, x => x) - ', pipe(fa2, Functor1Id(Test2Functor)))
    console.log('fa - ', fa2)
    console.log()
    console.log(
      'F.map(fa, x => f(g(x))) - ',
      pipe(fa2, Functor1Composition1(Test2Functor)(a2_b2_function)(b2_c2_function))
    )
    console.log(
      'F.map(F.map(fa, g), f) - ',
      pipe(fa2, Functor1Composition2(Test2Functor)(a2_b2_function)(b2_c2_function))
    )

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

    console.log('A3 => B3 => C3')
    console.log()
    console.log('F.map(fa, x => x) - ', pipe(fa3, Functor1Id(Test2Functor)))
    console.log('fa - ', fa3)
    console.log()
    console.log(
      'F.map(fa, x => f(g(x))) - ',
      pipe(fa3, Functor1Composition1(Test2Functor)(a3_b3_function)(b3_c3_function))
    )
    console.log(
      'F.map(F.map(fa, g), f) - ',
      pipe(fa3, Functor1Composition2(Test2Functor)(a3_b3_function)(b3_c3_function))
    )
  })
})
```

実行結果
```ts
A => B => C

F.map(fa, x => x) -  { Test2: 123 }
fa -  { Test2: 123 }

F.map(fa, x => f(g(x))) -  { Test2: true }
F.map(F.map(fa, g), f) -  { Test2: true }
---------
A2 => B2 => C2

F.map(fa, x => x) -  { Test2: 'abc' }
fa -  { Test2: 'abc' }

F.map(fa, x => f(g(x))) -  { Test2: 1 }
F.map(F.map(fa, g), f) -  { Test2: 1 }
---------
A3 => B3 => C3

F.map(fa, x => x) -  { Test2: true }
fa -  { Test2: true }

F.map(fa, x => f(g(x))) -  { Test2: 0 }
F.map(F.map(fa, g), f) -  { Test2: 0 }
```

### Functorの法則を満たさないもの 

不完全なFunctorを作成できてしまう

```ts
import { describe, it } from 'vitest'
import { type Functor1 } from 'fp-ts/lib/Functor'
import type { Kind, URIS } from 'fp-ts/lib/HKT'
import { pipe } from 'fp-ts/lib/function'
import * as f from 'fp-ts/function'

const URI = 'Test2'
type URI = typeof URI

declare module 'fp-ts/HKT' {
  interface URItoKind<A> {
    readonly Test2: Test2<A>
  }
}

const Test2Functor: Functor1<URI> = {
  URI,
  map: <A, B>(ma: Kind<URI, A>, f: (a: A) => B) => {
    const test: A =
      typeof ma.Test2 === 'number'
        ? ((ma.Test2 + 1) as A)
        : typeof ma.Test2 === 'string'
          ? ((ma.Test2 + 'a') as A)
          : typeof ma.Test2 === 'boolean'
            ? (!ma.Test2 as A)
            : ma.Test2
    return { Test2: f(test) }
  }
}

const Functor1Id: <F extends URIS>(Functor: Functor1<F>) => <A>(fa: Kind<F, A>) => Kind<F, A> =
  (Functor) => (fa) =>
    Functor.map(fa, f.identity)

const Functor1Composition1: <F extends URIS>(
  Functor: Functor1<F>
) => <A, B>(g: (a: A) => B) => <C>(f: (a: B) => C) => (fa: Kind<F, A>) => Kind<F, C> =
  (Functor) => (g) => (f) => (fa) =>
    Functor.map(fa, (x) => f(g(x)))

const Functor1Composition2: <F extends URIS>(
  Functor: Functor1<F>
) => <A, B>(g: (a: A) => B) => <C>(f: (a: B) => C) => (fa: Kind<F, A>) => Kind<F, C> =
  (Functor) => (g) => (f) => (fa) =>
    Functor.map(Functor.map(fa, g), f)

type Test2<XXX> = {
  Test2: XXX
}

type A = number
type B = string
type C = boolean

type A2 = string
type B2 = boolean
type C2 = number

type A3 = boolean
type B3 = string
type C3 = number

type F<XXX> = Test2<XXX>

describe('fp-ts Tutorial', () => {
  it('Functor', () => {
    // object
    const a: A = 123
    const a2: A2 = 'abc'
    const a3: A3 = true

    const fa: F<A> = {
      Test2: a
    }
    const fa2: F<A2> = {
      Test2: a2
    }
    const fa3: F<A3> = {
      Test2: a3
    }

    const a_b_function: (a: A) => B = (a) => String(a)
    const b_c_function: (b: B) => C = (b) => Boolean(b)

    const a2_b2_function: (a: A2) => B2 = (a) => Boolean(a)
    const b2_c2_function: (b: B2) => C2 = (b) => (Number.isNaN(Number(b)) ? 0 : Number(b))

    const a3_b3_function: (a: A3) => B3 = (a) => String(a)
    const b3_c3_function: (b: B3) => C3 = (b) => (Number.isNaN(Number(b)) ? 0 : Number(b))

    console.log('A => B => C')
    console.log()
    console.log('F.map(fa, x => x) - ', pipe(fa, Functor1Id(Test2Functor)))
    console.log('fa - ', fa)
    console.log()
    console.log(
      'F.map(fa, x => f(g(x))) - ',
      pipe(fa, Functor1Composition1(Test2Functor)(a_b_function)(b_c_function))
    )
    console.log(
      'F.map(F.map(fa, g), f) - ',
      pipe(fa, Functor1Composition2(Test2Functor)(a_b_function)(b_c_function))
    )

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

    console.log('A2 => B2 => C2')
    console.log()
    console.log('F.map(fa, x => x) - ', pipe(fa2, Functor1Id(Test2Functor)))
    console.log('fa - ', fa2)
    console.log()
    console.log(
      'F.map(fa, x => f(g(x))) - ',
      pipe(fa2, Functor1Composition1(Test2Functor)(a2_b2_function)(b2_c2_function))
    )
    console.log(
      'F.map(F.map(fa, g), f) - ',
      pipe(fa2, Functor1Composition2(Test2Functor)(a2_b2_function)(b2_c2_function))
    )

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

    console.log('A3 => B3 => C3')
    console.log()
    console.log('F.map(fa, x => x) - ', pipe(fa3, Functor1Id(Test2Functor)))
    console.log('fa - ', fa3)
    console.log()
    console.log(
      'F.map(fa, x => f(g(x))) - ',
      pipe(fa3, Functor1Composition1(Test2Functor)(a3_b3_function)(b3_c3_function))
    )
    console.log(
      'F.map(F.map(fa, g), f) - ',
      pipe(fa3, Functor1Composition2(Test2Functor)(a3_b3_function)(b3_c3_function))
    )
  })
})
```

実行結果
```ts
A => B => C

F.map(fa, x => x) -  { Test2: 124 }
fa -  { Test2: 123 }

F.map(fa, x => f(g(x))) -  { Test2: true }
F.map(F.map(fa, g), f) -  { Test2: true }
---------
A2 => B2 => C2

F.map(fa, x => x) -  { Test2: 'abca' }
fa -  { Test2: 'abc' }

F.map(fa, x => f(g(x))) -  { Test2: 1 }
F.map(F.map(fa, g), f) -  { Test2: 0 }
---------
A3 => B3 => C3

F.map(fa, x => x) -  { Test2: false }
fa -  { Test2: true }

F.map(fa, x => f(g(x))) -  { Test2: 0 }
F.map(F.map(fa, g), f) -  { Test2: 0 }
```

### Functorの利用 

```ts
import { describe, it } from 'vitest'
import { type Functor1 } from 'fp-ts/lib/Functor'
// import type { Kind, URIS } from 'fp-ts/lib/HKT'
import { pipe } from 'fp-ts/lib/function'
// import * as f from 'fp-ts/function'
import * as F from 'fp-ts/Functor'

const URI2 = 'Test2'
type URI2 = typeof URI2

const URI3 = 'Test3'
type URI3 = typeof URI3

type Test2<XXX> = {
  Test2: XXX
}

type Test3<XXX> = {
  Test3: XXX[]
}

declare module 'fp-ts/HKT' {
  interface URItoKind<A> {
    readonly Test2: Test2<A>
    readonly Test3: Test3<A>
  }
}

const Test2Functor: Functor1<URI2> = {
  URI: URI2,
  map: (ma, f) => ({ Test2: f(ma.Test2) })
}

const Test3Functor: Functor1<URI3> = {
  URI: URI3,
  map: (ma, f) => ({ Test3: ma.Test3.map(f) })
}

// const Functor1Id: <FFF extends URIS>(
//   Functor: Functor1<FFF>
// ) => <XXX>(fa: Kind<FFF, XXX>) => Kind<FFF, XXX> = (Functor) => (fa) => Functor.map(fa, f.identity)

// const Functor1Composition1: <FFF extends URIS>(
//   Functor: Functor1<FFF>
// ) => <XXX, YYY>(
//   g: (x: XXX) => YYY
// ) => <ZZZ>(f: (y: YYY) => ZZZ) => (fx: Kind<FFF, XXX>) => Kind<FFF, ZZZ> =
//   (Functor) => (g) => (f) => (fa) =>
//     Functor.map(fa, (x) => f(g(x)))

// const Functor1Composition2: <FFF extends URIS>(
//   Functor: Functor1<FFF>
// ) => <XXX, YYY>(
//   g: (x: XXX) => YYY
// ) => <ZZZ>(f: (y: YYY) => ZZZ) => (fx: Kind<FFF, XXX>) => Kind<FFF, ZZZ> =
//   (Functor) => (g) => (f) => (fa) =>
//     Functor.map(Functor.map(fa, g), f)

type A = number
type B = string
// type C = boolean

type F2<XXX> = Test2<XXX>
type F3<XXX> = Test3<XXX>
type F<XXX> = Test3<Test2<XXX>>

describe('fp-ts Tutorial', () => {
  it('Functor', () => {
    // object
    const a123: A = 123
    const a456: A = 456
    const a789: A = 789

    const fa2_123: F2<A> = {
      Test2: a123
    }
    const fa2_456: F2<A> = {
      Test2: a456
    }
    const fa2_789: F2<A> = {
      Test2: a789
    }

    const fa3: F3<A> = {
      Test3: [a123, a456, a789]
    }

    const fa: F<A> = {
      Test3: [fa2_123, fa2_456, fa2_789]
    }

    const a_b_function: (a: A) => B = (a) => String(a)
    // const b_c_function: (b: B) => C = (b) => Boolean(b)

    const fa2_function_object: F2<(a: A) => B> = {
      Test2: a_b_function
    }
    const fa3_function_object: F3<(a: A) => B> = {
      Test3: [a_b_function, (a) => a_b_function(2 * a), (a) => a_b_function(3 * a)]
    }

    // // check
    // console.log('---- check -----')

    // console.log('Test2Functor')
    // console.log()
    // console.log('A => B => C')
    // console.log()
    // console.log('F.map(fa, x => x) - ', pipe(fa2, Functor1Id(Test2Functor)))
    // console.log('fa - ', fa2)
    // console.log()
    // console.log(
    //   'F.map(fa, x => f(g(x))) - ',
    //   pipe(fa2, Functor1Composition1(Test2Functor)(a_b_function)(b_c_function))
    // )
    // console.log(
    //   'F.map(F.map(fa, g), f) - ',
    //   pipe(fa2, Functor1Composition2(Test2Functor)(a_b_function)(b_c_function))
    // )

    // console.log('---------')
    // console.log()
    // console.log('Test2Functor')
    // console.log()
    // console.log('A => B => C')
    // console.log()
    // console.log('F.map(fa, x => x) - ', pipe(fa3, Functor1Id(Test3Functor)))
    // console.log('fa - ', fa3)
    // console.log()
    // console.log(
    //   'F.map(fa, x => f(g(x))) - ',
    //   pipe(fa3, Functor1Composition1(Test3Functor)(a_b_function)(b_c_function))
    // )
    // console.log(
    //   'F.map(F.map(fa, g), f) - ',
    //   pipe(fa3, Functor1Composition2(Test3Functor)(a_b_function)(b_c_function))
    // )

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

    // test
    console.log('map - ', pipe(fa, F.map(Test3Functor, Test2Functor)(a_b_function)))

    console.log('flap - Test2Functor - ', F.flap(Test2Functor)(a123)(fa2_function_object))
    console.log('flap - Test3Functor - ', F.flap(Test3Functor)(a123)(fa3_function_object))

    console.log('bindTo - Test2Functor - ', pipe(fa2_123, F.bindTo(Test2Functor)('Test BindTo')))
    console.log('bindTo - Test3Functor - ', pipe(fa3, F.bindTo(Test3Functor)('Test BindTo')))

    console.log(
      'let - Test2Functor - ',
      pipe(fa2_123, F.let(Test2Functor)('Test Let', a_b_function))
    )
    console.log('let - Test3Functor - ', pipe(fa3, F.let(Test3Functor)('Test Let', a_b_function)))
  })
})
```

実行結果
```ts
map -  { Test3: [ { Test2: '123' }, { Test2: '456' }, { Test2: '789' } ] }
flap - Test2Functor -  { Test2: '123' }
flap - Test3Functor -  { Test3: [ '123', '246', '369' ] }
bindTo - Test2Functor -  { Test2: { 'Test BindTo': 123 } }
bindTo - Test3Functor -  {
  Test3: [
    { 'Test BindTo': 123 },
    { 'Test BindTo': 456 },
    { 'Test BindTo': 789 }
  ]
}
let - Test2Functor -  { Test2: { 'Test Let': '123' } }
let - Test3Functor -  {
  Test3: [
    { 'Test Let': '123' },
    { 'Test Let': '456' },
    { 'Test Let': '789' }
  ]
}
```