fp-ts 시작하기: Monoid

20547 단어 functionaltypescript
마지막에서 우리는 Semigroup 값을 "병합"하는 개념을 포착하는 것을 보았습니다( concat를 통해). A MonoidSemigroup 에 대해 "중립"인 특별한 값을 갖게 된 모든 concat입니다.

유형 클래스 정의


fp-ts에서 평소와 같이 Monoid 모듈에 포함된 유형 클래스fp-ts/Monoid는 TypeScriptinterface로 구현되며, 여기서 중립 값은 empty로 명명됩니다.

import { Semigroup } from 'fp-ts/Semigroup'

interface Monoid<A> extends Semigroup<A> {
  readonly empty: A
}


다음 법률을 준수해야 합니다.

  • 오른쪽 ID: concat(x, empty) = x , 모두를 위한 x in A

  • 왼쪽 ID: concat(empty, x) = x , 모두x in A
  • concat 어느 쪽이든 값 empty 을 입력하면 값에 차이가 없어야 합니다.

    메모. empty 값이 있으면 고유합니다.

    인스턴스



    우리가 이전 게시물에서 본 대부분의 semigroups는 실제로 monoids입니다.

    /** number `Monoid` under addition */
    const monoidSum: Monoid<number> = {
      concat: (x, y) => x + y,
      empty: 0
    }
    
    /** number `Monoid` under multiplication */
    const monoidProduct: Monoid<number> = {
      concat: (x, y) => x * y,
      empty: 1
    }
    
    const monoidString: Monoid<string> = {
      concat: (x, y) => x + y,
      empty: ''
    }
    
    /** boolean monoid under conjunction */
    const monoidAll: Monoid<boolean> = {
      concat: (x, y) => x && y,
      empty: true
    }
    
    /** boolean monoid under disjunction */
    const monoidAny: Monoid<boolean> = {
      concat: (x, y) => x || y,
      empty: false
    }
    


    모든 반군도 모노이드인지 궁금할 것입니다. 그렇지 않습니다. 반례로 다음 반그룹을 고려하십시오.

    const semigroupSpace: Semigroup<string> = {
      concat: (x, y) => x + ' ' + y
    }
    

    empty 와 같은 concat(x, empty) = x 값을 찾을 수 없습니다.

    좀 더 복잡한 유형에 대한 몇 가지Monoid 인스턴스를 작성해 보겠습니다. Monoid와 같은 구조체에 대해 Point 인스턴스를 만들 수 있습니다.

    type Point = {
      x: number
      y: number
    }
    


    각 필드에 대해 Monoid 인스턴스를 제공할 수 있다면

    import { getStructMonoid } from 'fp-ts/Monoid'
    
    const monoidPoint: Monoid<Point> = getStructMonoid({
      x: monoidSum,
      y: monoidSum
    })
    


    방금 정의한 인스턴스로 계속해서 피드getStructMonoid할 수 있습니다.

    type Vector = {
      from: Point
      to: Point
    }
    
    const monoidVector: Monoid<Vector> = getStructMonoid({
      from: monoidPoint,
      to: monoidPoint
    })
    


    접는



    semigroup 대신 monoid를 사용하면 접기가 훨씬 더 간단합니다. 초기 값을 명시적으로 제공할 필요가 없습니다(구현에서는 이에 대해 monoid의 empty 값을 사용할 수 있음).

    import { fold } from 'fp-ts/Monoid'
    
    fold(monoidSum)([1, 2, 3, 4]) // 10
    fold(monoidProduct)([1, 2, 3, 4]) // 24
    fold(monoidString)(['a', 'b', 'c']) // 'abc'
    fold(monoidAll)([true, false, true]) // false
    fold(monoidAny)([true, false, true]) // true
    


    유형 생성자를 위한 모노이드


    A 에 대한 semigroup 인스턴스가 주어지면 Option<A> 에 대한 semigroup 인스턴스를 파생할 수 있다는 것을 이미 알고 있습니다.
    A에 대한 모노이드 인스턴스를 찾을 수 있다면 다음과 같이 작동하는 Option<A> (getApplyMonoid를 통해)에 대한 모노이드 인스턴스를 파생할 수 있습니다.


    엑스
    와이
    연결(x, y)


    없음
    없음
    없음

    일부(a)
    없음
    없음

    없음
    일부(a)
    없음

    일부(a)
    일부(ㄴ)
    일부(concat(a, b))



    import { getApplyMonoid, some, none } from 'fp-ts/Option'
    
    const M = getApplyMonoid(monoidSum)
    
    M.concat(some(1), none) // none
    M.concat(some(1), some(2)) // some(3)
    M.concat(some(1), M.empty) // some(1)
    

    Option<A> (for all A )에 대해 두 개의 다른 모노이드를 유도할 수 있습니다.

    1) getFirstMonoid ...

    가장 왼쪽의 비None 값을 반환하는 모노이드


    엑스
    와이
    연결(x, y)


    없음
    없음
    없음

    일부(a)
    없음
    일부(a)

    없음
    일부(a)
    일부(a)

    일부(a)
    일부(ㄴ)
    일부(a)



    import { getFirstMonoid, some, none } from 'fp-ts/Option'
    
    const M = getFirstMonoid<number>()
    
    M.concat(some(1), none) // some(1)
    M.concat(some(1), some(2)) // some(1)
    


    2) ...및 이중: getLastMonoid
    가장 오른쪽의 비None 값을 반환하는 모노이드


    엑스
    와이
    연결(x, y)


    없음
    없음
    없음

    일부(a)
    없음
    일부(a)

    없음
    일부(a)
    일부(a)

    일부(a)
    일부(ㄴ)
    일부(ㄴ)



    import { getLastMonoid, some, none } from 'fp-ts/Option'
    
    const M = getLastMonoid<number>()
    
    M.concat(some(1), none) // some(1)
    M.concat(some(1), some(2)) // some(2)
    


    예를 들어 getLastMonoid는 선택적 값을 관리하는 데 유용할 수 있습니다.

    import { Monoid, getStructMonoid } from 'fp-ts/Monoid'
    import { Option, some, none, getLastMonoid } from 'fp-ts/Option'
    
    /** VSCode settings */
    interface Settings {
      /** Controls the font family */
      fontFamily: Option<string>
      /** Controls the font size in pixels */
      fontSize: Option<number>
      /** Limit the width of the minimap to render at most a certain number of columns. */
      maxColumn: Option<number>
    }
    
    const monoidSettings: Monoid<Settings> = getStructMonoid({
      fontFamily: getLastMonoid<string>(),
      fontSize: getLastMonoid<number>(),
      maxColumn: getLastMonoid<number>()
    })
    
    const workspaceSettings: Settings = {
      fontFamily: some('Courier'),
      fontSize: none,
      maxColumn: some(80)
    }
    
    const userSettings: Settings = {
      fontFamily: some('Fira Code'),
      fontSize: some(12),
      maxColumn: none
    }
    
    /** userSettings overrides workspaceSettings */
    monoidSettings.concat(workspaceSettings, userSettings)
    /*
    { fontFamily: some("Fira Code"),
      fontSize: some(12),
      maxColumn: some(80) }
    */
    


    다음 게시물

    좋은 웹페이지 즐겨찾기