fp-ts 시작하기: Eq

13087 단어 functionaltypescript
이 블로그 시리즈에서 나는 종종 "유형 클래스"와 "인스턴스"에 대해 이야기할 것입니다. 그것들이 무엇이며 어떻게 인코딩되는지 봅시다. fp-ts .

"type class" on wikipedia

The programmer defines a type class by specifying a set of functions or constant names, together with their respective types, that must exist for every type that belongs to the class.


fp-ts에서 유형 클래스는 TypeScriptinterface로 인코딩됩니다.

동일성을 인정하는 유형을 포함하기 위한 유형 클래스Eq는 다음과 같이 선언됩니다.

interface Eq<A> {
  /** returns `true` if `x` is equal to `y` */
  readonly equals: (x: A, y: A) => boolean
}


선언은 다음과 같이 읽을 수 있습니다.

a type A belongs to type class Eq if there is a function named equal of the appropriate type, defined on it



인스턴스는 어떻습니까?

A programmer can make any type A a member of a given type class C by using an instance declaration that defines implementations of all of C's members for the particular type A.


fp-ts에서 인스턴스는 정적 사전으로 인코딩됩니다.

예를 들어 다음은 Eq 유형에 대한 number 인스턴스입니다.

const eqNumber: Eq<number> = {
  equals: (x, y) => x === y
}


인스턴스는 다음 법률을 충족해야 합니다.

  • 반사성: equals(x, x) === true , 모두를 위해 x A

  • 대칭: equals(x, y) === equals(y, x) , 모두를 위한 x , y A

  • 전이성: if equals(x, y) === true and equals(y, z) === true , then equals(x, z) === true , for all x , y , z in A

  • 그런 다음 프로그래머는 다음과 같은 방식으로 함수elem(요소가 배열에 있는지 확인)를 정의할 수 있습니다.

    function elem<A>(E: Eq<A>): (a: A, as: Array<A>) => boolean {
      return (a, as) => as.some(item => E.equals(item, a))
    }
    
    elem(eqNumber)(1, [1, 2, 3]) // true
    elem(eqNumber)(4, [1, 2, 3]) // false
    


    더 복잡한 유형에 대한 몇 가지Eq 인스턴스를 작성해 보겠습니다.

    type Point = {
      x: number
      y: number
    }
    
    const eqPoint: Eq<Point> = {
      equals: (p1, p2) => p1.x === p2.x && p1.y === p2.y
    }
    


    먼저 참조 동등성을 확인하여 최적화equals를 시도할 수도 있습니다.

    const eqPoint: Eq<Point> = {
      equals: (p1, p2) => p1 === p2 || (p1.x === p2.x && p1.y === p2.y)
    }
    


    이것은 대부분 상용구입니다. 좋은 소식은 각 필드에 대해 Eq 인스턴스를 제공할 수 있다면 Point와 같은 구조체에 대해 Eq 인스턴스를 빌드할 수 있다는 것입니다.

    실제로 fp-ts/Eq 모듈은 getStructEq를 내보냅니다.

    import { getStructEq } from 'fp-ts/Eq'
    
    const eqPoint: Eq<Point> = getStructEq({
      x: eqNumber,
      y: eqNumber
    })
    


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

    type Vector = {
      from: Point
      to: Point
    }
    
    const eqVector: Eq<Vector> = getStructEq({
      from: eqPoint,
      to: eqPoint
    })
    

    getStructEqfp-ts 에서 제공하는 유일한 결합자가 아닙니다. 여기에 배열에 대한 Eq 인스턴스를 파생시킬 수 있는 결합자가 있습니다.

    import { getEq } from 'fp-ts/Array'
    
    const eqArrayOfPoints: Eq<Array<Point>> = getEq(eqPoint)
    


    마지막으로 Eq 인스턴스를 빌드하는 또 다른 유용한 방법은 contramap 결합기입니다. Eq
    import { contramap } from 'fp-ts/Eq'
    
    type User = {
      userId: number
      name: string
    }
    
    /** two users are equal if their `userId` field is equal */
    const eqUser = contramap((user: User) => user.userId)(eqNumber)
    
    eqUser.equals({ userId: 1, name: 'Giulio' }, { userId: 1, name: 'Giulio Canti' }) // true
    eqUser.equals({ userId: 1, name: 'Giulio' }, { userId: 2, name: 'Giulio' }) // false
    


    다음 게시물

    좋은 웹페이지 즐겨찾기