fp-ts 시작하기: 적용
f: (a: A) => F<B>
이 functor 인스턴스를 허용하는 경우 g: (b: B) => C
을 함수 g
으로 들어 올려 순수한 프로그램 lift(g): (fb: F<B>) => F<C>
으로 효과적인 프로그램 F
을 구성할 수 있음을 보았습니다.프로그램 f
프로그램 g
구성
순수한
순수한
g ∘ f
효과적인
순수(단항)
lift(g) ∘ f
그러나
g
은 단항이어야 합니다. 즉, 하나의 인수만 입력으로 받아들여야 합니다. g
이 두 개의 인수를 허용하면 어떻게 될까요? functor 인스턴스만 사용하여 여전히 g
을 들어올릴 수 있습니까? 자, 시도해보자!카레
먼저 B
및 C
(튜플을 사용할 수 있음) 유형의 두 인수를 받아들이고 D
유형의 값을 반환하는 함수를 모델링해야 합니다.
g: (args: [B, C]) => D
커링이라는 기술을 사용하여 g
을 다시 쓸 수 있습니다.
Currying is the technique of translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument. For example, a function that takes two arguments, one from B
and one from C
, and produces outputs in D
, by currying is translated into a function that takes a single argument from C
and produces as outputs functions from B
to C
.
(출처: currying on wikipedia.org )
따라서 g
을 다음과 같이 다시 쓸 수 있습니다.
g: (b: B) => (c: C) => D
우리가 원하는 것은 리프팅 작업입니다. 이전 liftA2
과 구별하기 위해 lift
이라고 부르겠습니다. 이 작업은 다음 서명이 있는 함수를 출력합니다.
liftA2(g): (fb: F<B>) => (fc: F<C>) => F<D>
우리 거기 어떻게가? g
은 이제 단항이므로 functor 인스턴스와 이전 lift
을 사용할 수 있습니다.
lift(g): (fb: F<B>) => F<(c: C) => D>
그러나 이제 우리는 막혔습니다. 함수 F<(c: C) => D>
에 값 (fc: F<C>) => F<D>
을 압축 해제할 수 있는 functor 인스턴스에 대한 합법적인 작업이 없습니다.
적용하다
따라서 이러한 압축 풀기 작업(이름: Apply
)을 소유하는 새로운 추상화 ap
을 소개하겠습니다.
interface Apply<F> extends Functor<F> {
ap: <C, D>(fcd: HKT<F, (c: C) => D>, fc: HKT<F, C>) => HKT<F, D>
}
ap
함수는 기본적으로 인수가 재정렬된 unpack
입니다.
unpack: <C, D>(fcd: HKT<F, (c: C) => D>) => ((fc: HKT<F, C>) => HKT<F, D>)
ap: <C, D>(fcd: HKT<F, (c: C) => D>, fc: HKT<F, C>) => HKT<F, D>
따라서 ap
은 unpack
에서 파생될 수 있으며 그 반대도 마찬가지입니다.
참고: HKT
유형은 제네릭 유형 생성자를 나타내는 fp-ts
방식입니다(Lightweight higher-kinded polymorphism 문서에서 제안된 기술). 따라서 HKT<F, X>
을 볼 때 유형 생성자 F
450을 생각할 수 있습니다.
적용
또한 X
유형의 값을 F<X>
유형의 값으로 올릴 수 있는 작업이 있으면 편리합니다. 이런 식으로 A
및 F<A>
유형의 인수를 제공하거나 liftA2(g)
및 F<B>
유형의 값을 들어 올려 F<C>
함수를 호출할 수 있습니다.
B
을 기반으로 하고 이러한 작업을 소유하는 C
추상화를 소개하겠습니다(이름: Applicative
).
interface Applicative<F> extends Apply<F> {
of: <A>(a: A) => HKT<F, A>
}
몇 가지 일반적인 데이터 유형에 대한 Apply
인스턴스를 살펴보겠습니다.
예( of
)
import { flatten } from 'fp-ts/Array'
const applicativeArray = {
map: <A, B>(fa: Array<A>, f: (a: A) => B): Array<B> => fa.map(f),
of: <A>(a: A): Array<A> => [a],
ap: <A, B>(fab: Array<(a: A) => B>, fa: Array<A>): Array<B> =>
flatten(fab.map(f => fa.map(f)))
}
예( Applicative
)
import { Option, some, none, isNone } from 'fp-ts/Option'
const applicativeOption = {
map: <A, B>(fa: Option<A>, f: (a: A) => B): Option<B> =>
isNone(fa) ? none : some(f(fa.value)),
of: <A>(a: A): Option<A> => some(a),
ap: <A, B>(fab: Option<(a: A) => B>, fa: Option<A>): Option<B> =>
isNone(fab) ? none : applicativeOption.map(fa, fab.value)
}
예( F = Array
)
import { Task } from 'fp-ts/Task'
const applicativeTask = {
map: <A, B>(fa: Task<A>, f: (a: A) => B): Task<B> => () => fa().then(f),
of: <A>(a: A): Task<A> => () => Promise.resolve(a),
ap: <A, B>(fab: Task<(a: A) => B>, fa: Task<A>): Task<B> => () =>
Promise.all([fab(), fa()]).then(([f, a]) => f(a))
}
리프팅
따라서 F = Option
에 대한 F = Task
의 인스턴스가 주어지면 이제 Apply
을 쓸 수 있습니까?
import { HKT } from 'fp-ts/HKT'
import { Apply } from 'fp-ts/Apply'
type Curried2<B, C, D> = (b: B) => (c: C) => D
function liftA2<F>(
F: Apply<F>
): <B, C, D>(g: Curried2<B, C, D>) => Curried2<HKT<F, B>, HKT<F, C>, HKT<F, D>> {
return g => fb => fc => F.ap(F.map(fb, g), fc)
}
멋진! 그러나 세 개의 인수가 있는 함수는 어떻습니까? 또 다른 추상화가 필요합니까?
좋은 소식은 대답은 아니오, F
이면 충분하다는 것입니다.
type Curried3<B, C, D, E> = (b: B) => (c: C) => (d: D) => E
function liftA3<F>(
F: Apply<F>
): <B, C, D, E>(
g: Curried3<B, C, D, E>
) => Curried3<HKT<F, B>, HKT<F, C>, HKT<F, D>, HKT<F, E>> {
return g => fb => fc => fd => F.ap(F.ap(F.map(fb, g), fc), fd)
}
실제로 liftA2
의 인스턴스가 주어지면 각 Apply
에 대해 Apply
함수를 작성할 수 있습니다.
메모. liftAn
은 n
, liftA1
연산입니다.
이제 "구성 테이블"을 업데이트할 수 있습니다.
프로그램 f
프로그램 g
구성
순수한
순수한lift
효과적인
순수한, Functor
-aryg ∘ f
어디 n
일반적인 문제가 해결되었습니까?
아직 아님. 여전히 중요한 경우가 빠져 있습니다. 두 프로그램이 모두 효과적이라면 어떻게 될까요?
다시 한 번 더 필요한 것이 있습니다. 이 게시물에서 함수형 프로그래밍의 가장 중요한 추상화 중 하나인 모나드에 대해 이야기하겠습니다.
TLDR: 함수형 프로그래밍은 구성에 관한 것입니다.
Reference
이 문제에 관하여(fp-ts 시작하기: 적용), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/gcanti/getting-started-with-fp-ts-applicative-1kb3
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
g: (args: [B, C]) => D
Currying is the technique of translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument. For example, a function that takes two arguments, one from B
and one from C
, and produces outputs in D
, by currying is translated into a function that takes a single argument from C
and produces as outputs functions from B
to C
.
g: (b: B) => (c: C) => D
liftA2(g): (fb: F<B>) => (fc: F<C>) => F<D>
lift(g): (fb: F<B>) => F<(c: C) => D>
따라서 이러한 압축 풀기 작업(이름:
Apply
)을 소유하는 새로운 추상화 ap
을 소개하겠습니다.interface Apply<F> extends Functor<F> {
ap: <C, D>(fcd: HKT<F, (c: C) => D>, fc: HKT<F, C>) => HKT<F, D>
}
ap
함수는 기본적으로 인수가 재정렬된 unpack
입니다.unpack: <C, D>(fcd: HKT<F, (c: C) => D>) => ((fc: HKT<F, C>) => HKT<F, D>)
ap: <C, D>(fcd: HKT<F, (c: C) => D>, fc: HKT<F, C>) => HKT<F, D>
따라서
ap
은 unpack
에서 파생될 수 있으며 그 반대도 마찬가지입니다.참고:
HKT
유형은 제네릭 유형 생성자를 나타내는 fp-ts
방식입니다(Lightweight higher-kinded polymorphism 문서에서 제안된 기술). 따라서 HKT<F, X>
을 볼 때 유형 생성자 F
450을 생각할 수 있습니다.적용
또한 X
유형의 값을 F<X>
유형의 값으로 올릴 수 있는 작업이 있으면 편리합니다. 이런 식으로 A
및 F<A>
유형의 인수를 제공하거나 liftA2(g)
및 F<B>
유형의 값을 들어 올려 F<C>
함수를 호출할 수 있습니다.
B
을 기반으로 하고 이러한 작업을 소유하는 C
추상화를 소개하겠습니다(이름: Applicative
).
interface Applicative<F> extends Apply<F> {
of: <A>(a: A) => HKT<F, A>
}
몇 가지 일반적인 데이터 유형에 대한 Apply
인스턴스를 살펴보겠습니다.
예( of
)
import { flatten } from 'fp-ts/Array'
const applicativeArray = {
map: <A, B>(fa: Array<A>, f: (a: A) => B): Array<B> => fa.map(f),
of: <A>(a: A): Array<A> => [a],
ap: <A, B>(fab: Array<(a: A) => B>, fa: Array<A>): Array<B> =>
flatten(fab.map(f => fa.map(f)))
}
예( Applicative
)
import { Option, some, none, isNone } from 'fp-ts/Option'
const applicativeOption = {
map: <A, B>(fa: Option<A>, f: (a: A) => B): Option<B> =>
isNone(fa) ? none : some(f(fa.value)),
of: <A>(a: A): Option<A> => some(a),
ap: <A, B>(fab: Option<(a: A) => B>, fa: Option<A>): Option<B> =>
isNone(fab) ? none : applicativeOption.map(fa, fab.value)
}
예( F = Array
)
import { Task } from 'fp-ts/Task'
const applicativeTask = {
map: <A, B>(fa: Task<A>, f: (a: A) => B): Task<B> => () => fa().then(f),
of: <A>(a: A): Task<A> => () => Promise.resolve(a),
ap: <A, B>(fab: Task<(a: A) => B>, fa: Task<A>): Task<B> => () =>
Promise.all([fab(), fa()]).then(([f, a]) => f(a))
}
리프팅
따라서 F = Option
에 대한 F = Task
의 인스턴스가 주어지면 이제 Apply
을 쓸 수 있습니까?
import { HKT } from 'fp-ts/HKT'
import { Apply } from 'fp-ts/Apply'
type Curried2<B, C, D> = (b: B) => (c: C) => D
function liftA2<F>(
F: Apply<F>
): <B, C, D>(g: Curried2<B, C, D>) => Curried2<HKT<F, B>, HKT<F, C>, HKT<F, D>> {
return g => fb => fc => F.ap(F.map(fb, g), fc)
}
멋진! 그러나 세 개의 인수가 있는 함수는 어떻습니까? 또 다른 추상화가 필요합니까?
좋은 소식은 대답은 아니오, F
이면 충분하다는 것입니다.
type Curried3<B, C, D, E> = (b: B) => (c: C) => (d: D) => E
function liftA3<F>(
F: Apply<F>
): <B, C, D, E>(
g: Curried3<B, C, D, E>
) => Curried3<HKT<F, B>, HKT<F, C>, HKT<F, D>, HKT<F, E>> {
return g => fb => fc => fd => F.ap(F.ap(F.map(fb, g), fc), fd)
}
실제로 liftA2
의 인스턴스가 주어지면 각 Apply
에 대해 Apply
함수를 작성할 수 있습니다.
메모. liftAn
은 n
, liftA1
연산입니다.
이제 "구성 테이블"을 업데이트할 수 있습니다.
프로그램 f
프로그램 g
구성
순수한
순수한lift
효과적인
순수한, Functor
-aryg ∘ f
어디 n
일반적인 문제가 해결되었습니까?
아직 아님. 여전히 중요한 경우가 빠져 있습니다. 두 프로그램이 모두 효과적이라면 어떻게 될까요?
다시 한 번 더 필요한 것이 있습니다. 이 게시물에서 함수형 프로그래밍의 가장 중요한 추상화 중 하나인 모나드에 대해 이야기하겠습니다.
TLDR: 함수형 프로그래밍은 구성에 관한 것입니다.
Reference
이 문제에 관하여(fp-ts 시작하기: 적용), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/gcanti/getting-started-with-fp-ts-applicative-1kb3
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
interface Applicative<F> extends Apply<F> {
of: <A>(a: A) => HKT<F, A>
}
import { flatten } from 'fp-ts/Array'
const applicativeArray = {
map: <A, B>(fa: Array<A>, f: (a: A) => B): Array<B> => fa.map(f),
of: <A>(a: A): Array<A> => [a],
ap: <A, B>(fab: Array<(a: A) => B>, fa: Array<A>): Array<B> =>
flatten(fab.map(f => fa.map(f)))
}
import { Option, some, none, isNone } from 'fp-ts/Option'
const applicativeOption = {
map: <A, B>(fa: Option<A>, f: (a: A) => B): Option<B> =>
isNone(fa) ? none : some(f(fa.value)),
of: <A>(a: A): Option<A> => some(a),
ap: <A, B>(fab: Option<(a: A) => B>, fa: Option<A>): Option<B> =>
isNone(fab) ? none : applicativeOption.map(fa, fab.value)
}
import { Task } from 'fp-ts/Task'
const applicativeTask = {
map: <A, B>(fa: Task<A>, f: (a: A) => B): Task<B> => () => fa().then(f),
of: <A>(a: A): Task<A> => () => Promise.resolve(a),
ap: <A, B>(fab: Task<(a: A) => B>, fa: Task<A>): Task<B> => () =>
Promise.all([fab(), fa()]).then(([f, a]) => f(a))
}
따라서
F = Option
에 대한 F = Task
의 인스턴스가 주어지면 이제 Apply
을 쓸 수 있습니까?import { HKT } from 'fp-ts/HKT'
import { Apply } from 'fp-ts/Apply'
type Curried2<B, C, D> = (b: B) => (c: C) => D
function liftA2<F>(
F: Apply<F>
): <B, C, D>(g: Curried2<B, C, D>) => Curried2<HKT<F, B>, HKT<F, C>, HKT<F, D>> {
return g => fb => fc => F.ap(F.map(fb, g), fc)
}
멋진! 그러나 세 개의 인수가 있는 함수는 어떻습니까? 또 다른 추상화가 필요합니까?
좋은 소식은 대답은 아니오,
F
이면 충분하다는 것입니다.type Curried3<B, C, D, E> = (b: B) => (c: C) => (d: D) => E
function liftA3<F>(
F: Apply<F>
): <B, C, D, E>(
g: Curried3<B, C, D, E>
) => Curried3<HKT<F, B>, HKT<F, C>, HKT<F, D>, HKT<F, E>> {
return g => fb => fc => fd => F.ap(F.ap(F.map(fb, g), fc), fd)
}
실제로
liftA2
의 인스턴스가 주어지면 각 Apply
에 대해 Apply
함수를 작성할 수 있습니다.메모.
liftAn
은 n
, liftA1
연산입니다.이제 "구성 테이블"을 업데이트할 수 있습니다.
프로그램 f
프로그램 g
구성
순수한
순수한
lift
효과적인
순수한,
Functor
-aryg ∘ f
어디
n
일반적인 문제가 해결되었습니까?
아직 아님. 여전히 중요한 경우가 빠져 있습니다. 두 프로그램이 모두 효과적이라면 어떻게 될까요?
다시 한 번 더 필요한 것이 있습니다. 이 게시물에서 함수형 프로그래밍의 가장 중요한 추상화 중 하나인 모나드에 대해 이야기하겠습니다.
TLDR: 함수형 프로그래밍은 구성에 관한 것입니다.
Reference
이 문제에 관하여(fp-ts 시작하기: 적용), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/gcanti/getting-started-with-fp-ts-applicative-1kb3
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여(fp-ts 시작하기: 적용), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/gcanti/getting-started-with-fp-ts-applicative-1kb3텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)