Fp ts P5 유틸리티: 적용, 시퀀스 및 반복
22946 단어 fptsfunctionaltypescript
소개하다.
본 시리즈의 5부에 오신 것을 환영하며 실용적인 방식으로 fpts를 배웁니다.
지금까지 당신은
of
, map
, chain
, flatten
, ap
에 소개되었지만 우리는 아직 ap
또는 apply에 대해 토론한 적이 없습니다.ap
연산자는 이른바 응용 프로그램의 큰 부분이다.응용 프로그램은 서열과 반복의 기초를 구성한다.이 글에서, 나는
ap
의 기본 원리, 그것의 용례, 그리고 우리가 실제로 그것을 필요로 하지 않는 이유를 설명할 것이다. 왜냐하면 우리는 서열과 반복이 있기 때문이다.신청하다.
신비로운
map
연산자는 무엇입니까? 애플이라고도 부릅니까?여러모로
write
의 반대편과 같다.값 파이프를 함수로 만드는 것이 아니라 함수 파이프를 값으로 만드는 것이다.이 점을 보여주기 위해 currying에 대해 알아보겠습니다.Currying은 매개 변수가 여러 개인 함수를 고급 함수로 변환하여 매개 변수를 반복적으로 사용합니다.
예를 들어 우리는 3개의 매개 변수를 받아들이는
true
함수를 가지고 있다.declare function write(key: string, value: string, flush: boolean): unknown
다음과 같이 카레 함수로 변환할 수 있습니다.const writeC = (key: string) => (value: string) => (flush: boolean) =>
write(key, value, flush)
우리는 이렇게 간단하게 함수를 호출할 수 있다.writeC('key')('value')(true)
만약 우리가 파이프 문법으로 같은 일을 하고 싶다면, 우리는 이런 방법을 시도해 볼 수 있다.// ❌ Wrong
pipe(true, 'value', 'key', writeC)
그러나 불행하게도 파이프는 왼쪽에서 오른쪽으로 평가되기 때문에 효과가 없다.컴파일러는 value
이 파이프를 통해 value
key
으로 전송할 수 없다고 불평할 것이다.이 점을 실현하기 위해서 우리는 더 많은 파이프를 사용하여 조작 순서를 집행해야 한다(수학에서처럼)!// ✅ Correct
pipe(true, pipe('value', pipe('key', writeC)))
이제 컴파일러는 우리가 오른쪽에서 먼저 값을 구하도록 강요했기 때문에 알았다.그러나 이런 문법은 이상적이지 않다. 왜냐하면 주문을 위해 추가 파이프를 추가하는 것은 매우 짜증나기 때문이다.솔루션은
ap
입니다.import { ap } from 'fp-ts/lib/Identity'
pipe(writeC, ap('key'), ap('value'), ap(true))
내가 ap
은 단지 하나의 함수를 하나의 값으로 변환한다고 말한 것을 기억하십니까?이것이 바로 네가 여기서 본 것이다.writeC
은 파이프를 통해 key
에 연결되어 함수 (value: string) => (flush: boolean) => write(key, value, flush)
을 형성한다.이 함수는 파이프를 통해 value
에 연결되고 후자는 함수 (flush: boolean) => write(key, value, flush)
을 구성한다.마지막으로 마지막 함수는 파이프를 통해 true
으로 전송되며, 우리의 3개 파라미터를 호출하여 함수를 기록합니다: write(key, value, flush)
.본질적으로
ap
은 정확한 조작 순서를 유지하는 동시에 함수 값의 전환을 더욱 쉽게 실현할 수 있다.ap
의 또 다른 용례는 함수와 값이 잘 협동하지 못할 때 그 중 하나가 Option
또는 Either
에 갇혀 있기 때문이다.ap
은 이 상황에서 매우 유용하다. 왜냐하면 값이나 함수를 특정 분류로 끌어올릴 수 있기 때문이다.시범을 보이기 위해서 예를 하나 봅시다.
import * as O from 'fp-ts/lib/Option'
import { Option } from 'fp-ts/lib/Option'
declare const a: Option<number>
declare const b: Option<string>
declare function foo(a: number, b: string): boolean
보시다시피 우리는 변수 foo
과 a
을 사용하여 b
을 호출하고자 합니다. 그러나 문제는 a
과 b
은 옵션 클래스에 있고 foo
은 옵션 클래스에 있습니다.간단한 값을 사용합니다.
foo
을 실행하는 간단한 방법은 chain
과 map
을 사용하는 것이다.// Option<boolean>
O.option.chain(a, (a1) => O.option.map(b, (b1) => foo(a1, b1)))
그러나 이것은 매우 무섭다. 왜냐하면:우선, 우리는
foo
을 하나의 통용 함수인 fooC
으로 바꾸어야 한다.const fooC = (a: number) => (b: string) => foo(a, b)
그리고 이것은 우리가 이전에 한 것과 같지만 fooC
을 사용하여 Option
을 of
종류로 끌어올려야 한다. 왜냐하면 Option
의 ap
버전은 두 가지 옵션에서 실행되어야 하기 때문이다.// Option<boolean>
pipe(O.of(fooC), O.ap(a), O.ap(b))
이 예를 한층 더 확장합시다.만약 우리가 또 다른 함수 bar
을 가지고 있다면, 그것은 브리 값 (반환값 foo
) 을 받아들이고, object
을 되돌려준다.물론 우리는 foo
을 호출한 다음에 bar
을 호출하고 반환치는 foo
이다.우리는 이미
foo
을 Option<boolean>
으로 계산했기 때문에 이것은 단지 ap
으로 간단하게 향상시키는 과정일 뿐이다declare function bar(a: boolean): object
const fooOption = pipe(O.of(fooC), O.ap(a), O.ap(b))
// Option<object>
pipe(O.of(bar), O.ap(fooOption))
멋있다. ap
은 분명히 강하다.그런데 ap
에 무슨 문제가 있습니까?우선, fp를 사용하기 위해서는 기존의 모든 함수를 사용해야 하기 때문에 심심하다.
그 다음에 파이프 내 함수의 입력 값을 왼쪽에서 오른쪽에서 오른쪽에서 왼쪽으로 전도하면 조작의 자연 순서
flow
을 파괴할 수 있다.현실 세계에서
ap
은 서열을 이용할 수 있기 때문에 거의 쓸모가 없다.1순서
그럼 서열은 뭘까요?
수학에서 우리는 하나의 서열을 하나의 숫자 서열로 본다.이와 유사하게 우리는 이를 일련의 옵션, 일련의 Eithers 등에 응용할 수 있다...
서열에서 가장 흔히 볼 수 있는 용례는say 옵션의 그룹을 그룹으로 바꾸는 옵션입니다.
// How?
Array<Option<A>> => Option<A[]>
이를 위해서는 Applicative
의 실례를 제공해야 합니다.응용 프로그램에는 3가지 방법이 있는데 그것이 바로 of
, map
, ap
이다.이 응용 프로그램은 컬렉션의 객체 유형을 정의합니다.Options
의 목록에 대해 O.option
을 제공합니다.import * as A from 'fp-ts/lib/Array'
import * as O from 'fp-ts/lib/Option'
const arr = [1, 2, 3].map(O.of)
A.array.sequence(O.option)(arr) // Option<number[]>
이제 우리는 문제로 돌아간다. 우리는 sequence를 어떻게 사용합니까? 그러면 우리는curried 함수를 작성하고 ap
을 사용할 필요가 없습니다.sequenceT
을 입력합니다.SequenceT
sequenceT
은 일반적인 sequence
과 같지만 rest parameter(vararg)을 전달했습니다.반환 값은 응용 프로그램이 제공하는 모듈을 형식 매개 변수로 합니다.예를 들면 다음과 같습니다.
// Option<[number, string]>
sequenceT(O.option)(O.of(123), O.of('asdf'))
이제 이게 어떻게 된 일인지 알겠네.우리는 파이프를 통해 그것을 최초의 foo
과 bar
함수로 가져올 수 있다.declare function foo(a: number, b: string): boolean
declare function bar(a: boolean): object
// Option<object>
pipe(
sequenceT(O.option)(O.of(123), O.of('asdf')),
O.map((args) => foo(...args)),
O.map(bar),
)
...
확장 문법을 사용하여 원조를 매개 변수 형식으로 변환해야 합니다.순서
때때로, 우리의 함수는 여러 개의 매개 변수가 아니라 하나의 대상 매개 변수만 받아들인다.이 문제를 해결하기 위해 우리는
sequenceS
을 이용할 수 있다.import * as E from 'fp-ts/lib/Either'
type RegisterInput = {
email: string
password: string
}
declare function validateEmail(email: string): E.Either<Error, string>
declare function validatePassword(password: string): E.Either<Error, string>
declare function register(input: RegisterInput): unknown
declare const input: RegisterInput
pipe(
input,
({ email, password }) =>
sequenceS(E.either)({
email: validateEmail(email),
password: validatePassword(password),
}),
E.map(register),
)
통과
때때로 입력이 잘 맞지 않을 때가 있습니다.
sequence
을 적용하기 전에 추가 계산을 실행해야 합니다.두루 돌아다니는 것이 답이다.그것은 같은 일의 서열을 실행하지만, 우리는 중간 값을 바꾸게 한다.하나의 좋은 예는 파일 부분을 검색하는 네트워크 요청이다.너는 모든 부품을 원하든지, 아니면 하나도 원하지 않는다.
import * as TE from 'fp-ts/lib/TaskEither'
import { TaskEither } from 'fp-ts/lib/TaskEither'
import * as A from 'fp-ts/lib/Array'
declare const getPartIds: () => TaskEither<Error, string[]>
declare const getPart: (partId: string) => TaskEither<Error, Blob>
// ✅ TE.TaskEither<Error, Blob[]>
pipe(getPartIds(), TE.chain(A.traverse(TE.taskEither)(getPart)))
결론
이 글에서 우리는 애플과 그 용례, 그리고 그것을 어떻게 서열과 반복을 통해 우리의 생활에 응용하는지 이해했다.
읽어주셔서 감사합니다. 만약에 이 내용을 좋아하신다면 저에게 후속을 주십시오. 문제가 있으면 저에게 DM을 주세요!
시퀀스와 스트리밍은 내부에서
ap
을 사용합니다. ↩ Reference
이 문제에 관하여(Fp ts P5 유틸리티: 적용, 시퀀스 및 반복), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ryanleecode/practical-guide-to-fp-ts-p5-apply-sequences-and-traversals-1bdm텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)