fp-ts 시작하기: IO
19833 단어 functionaltypescript
fp-ts
에서 동기식 유효 계산은 기본적으로 썽크인 IO
유형, 즉 다음 서명이 있는 함수로 표시됩니다. () => A
interface IO<A> {
(): A
}
IO
는 절대 실패하지 않는 계산을 나타냅니다.이러한 계산의 예는 다음과 같습니다.
localStorage
console
에 쓰기예(
localStorage
에 읽기/쓰기)import { fromNullable, Option } from 'fp-ts/Option'
const getItem = (key: string): IO<Option<string>> => () =>
fromNullable(localStorage.getItem(key))
const setItem = (key: string, value: string): IO<void> => () =>
localStorage.setItem(key, value)
예(현재 시간 가져오기)
const now: IO<number> = () => new Date().getTime()
예(
console
에 작성)const log = (s: unknown): IO<void> => () => console.log(s)
예(난수 가져오기)
const random: IO<number> = () => Math.random()
IO
유형은 인스턴스를 허용하므로 map
...import { io } from 'fp-ts/IO'
/** get a random boolean */
const randomBool: IO<boolean> = io.map(random, n => n < 0.5)
...또는
chain
계산/** write to the `console` a random boolean */
const program: IO<void> = io.chain(randomBool, log)
program()
program()
를 호출할 때까지 아무 일도 일어나지 않습니다.program
는 효과적인 계산을 나타내는 값이므로 부작용을 실행하려면 "IO
작업을 실행"해야 합니다.IO
작업은 값일 뿐이므로 이를 처리하는 것과 같은 유용한 추상화를 사용할 수 있습니다.예(던전 앤 드래곤)
import { log } from 'fp-ts/Console'
import { getMonoid, IO, io } from 'fp-ts/IO'
import { fold, Monoid, monoidSum } from 'fp-ts/Monoid'
import { randomInt } from 'fp-ts/Random'
type Die = IO<number>
const monoidDie: Monoid<Die> = getMonoid(monoidSum)
/** returns the sum of the roll of the dice */
const roll: (dice: Array<Die>) => IO<number> = fold(monoidDie)
const D4: Die = randomInt(1, 4)
const D10: Die = randomInt(1, 10)
const D20: Die = randomInt(1, 20)
const dice = [D4, D10, D20]
io.chain(roll(dice), result => log(`Result is: ${result}`))()
/*
Result is: 11
*/
..또는 유용한 정의
/** Log any value to the console for debugging purposes */
const withLogging = <A>(action: IO<A>): IO<A> =>
io.chain(action, a => io.map(log(`Value is: ${a}`), () => a))
io.chain(roll(dice.map(withLogging)), result => log(`Result is: ${result}`))()
/*
Value is: 4
Value is: 2
Value is: 13
Result is: 19
*/
오류 처리
실패할 수 있는 효과적인 동기식 계산을 나타내려면 어떻게 해야 합니까?
두 가지 효과가 필요합니다.
유형 생성자
효과(해석)
IO<A>
동기식 유효 계산
Either<E, A>
실패할 수 있는 계산
해결책은 Either
안에 IO
를 넣으면 IOEither
유형이 됩니다.
interface IOEither<E, A> extends IO<Either<E, A>> {}
IOEither<E, A>
유형의 값을 "실행"하면 Left
유형의 오류로 계산이 실패했음을 의미하고 E
그렇지 않으면 Right
를 얻습니다. 유형의 값A
.
예(파일 읽기)
fs.readFileSync
가 던질 수 있으므로 tryCatch
도우미를 사용하겠습니다.
tryCatch: <E, A>(f: () => A) => IOEither<E, A>
여기서 f
는 오류( tryCatch
에 의해 자동으로 포착됨)를 발생시키거나 A
유형의 값을 반환하는 썽크입니다.
import { toError } from 'fp-ts/Either'
import { IOEither, tryCatch } from 'fp-ts/IOEither'
import * as fs from 'fs'
const readFileSync = (path: string): IOEither<Error, string> =>
tryCatch(() => fs.readFileSync(path, 'utf8'), toError)
readFileSync('foo')() // => left(Error: ENOENT: no such file or directory, open 'foo')
readFileSync(__filename)() // => right(...)
리프팅
fp-ts/IOEither
모듈은 IOEither
유형의 값을 생성할 수 있는 다른 도우미를 제공하며, 이를 집합적으로 리프팅 함수라고 합니다.
다음은 요약입니다.
시작 값
리프팅 기능
IO<E>
leftIO: <E, A>(ml: IO<E>) => IOEither<E, A>
E
left: <E, A>(e: E) => IOEither<E, A>
Either<E, A>
fromEither: <E, A>(ma: Either<E, A>) => IOEither<E, A>
A
right: <E, A>(a: A) => IOEither<E, A>
IO<A>
rightIO: <E, A>(ma: IO<A>) => IOEither<E, A>
예(임의 파일 로드)
세 파일( 1.txt
, 2.txt
, 3.txt
) 중 하나의 내용을 무작위로 로드한다고 가정해 보겠습니다.
randomInt: (low: number, high: number) => IO<number>
함수는 닫힌 간격에 균일하게 분포된 임의의 정수를 반환합니다[low, high]
.
import { randomInt } from 'fp-ts/Random'
위에서 정의한 randomInt
함수와 readFileSync
를 연결할 수 있습니다.
import { ioEither } from 'fp-ts/IOEither'
const randomFile = ioEither.chain(
randomInt(1, 3), // static error
n => readFileSync(`${__dirname}/${n}.txt`)
)
그러나 이것은 유형 검사가 아닙니다!
유형이 정렬되지 않음: randomInt
는 IO
컨텍스트에서 실행되고 readFileSync
는 IOEither
컨텍스트에서 실행됩니다.
그러나 randomInt
를 사용하여 IOEither
를 rightIO
컨텍스트로 들어올릴 수 있습니다(위의 요약 참조).
import { ioEither, rightIO } from 'fp-ts/IOEither'
const randomFile = ioEither.chain(rightIO(randomInt(1, 3)), n =>
readFileSync(`${__dirname}/${n}.txt`)
)
Reference
이 문제에 관하여(fp-ts 시작하기: IO), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/gcanti/getting-started-with-fp-ts-io-36p6
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
interface IOEither<E, A> extends IO<Either<E, A>> {}
tryCatch: <E, A>(f: () => A) => IOEither<E, A>
import { toError } from 'fp-ts/Either'
import { IOEither, tryCatch } from 'fp-ts/IOEither'
import * as fs from 'fs'
const readFileSync = (path: string): IOEither<Error, string> =>
tryCatch(() => fs.readFileSync(path, 'utf8'), toError)
readFileSync('foo')() // => left(Error: ENOENT: no such file or directory, open 'foo')
readFileSync(__filename)() // => right(...)
fp-ts/IOEither
모듈은 IOEither
유형의 값을 생성할 수 있는 다른 도우미를 제공하며, 이를 집합적으로 리프팅 함수라고 합니다.다음은 요약입니다.
시작 값
리프팅 기능
IO<E>
leftIO: <E, A>(ml: IO<E>) => IOEither<E, A>
E
left: <E, A>(e: E) => IOEither<E, A>
Either<E, A>
fromEither: <E, A>(ma: Either<E, A>) => IOEither<E, A>
A
right: <E, A>(a: A) => IOEither<E, A>
IO<A>
rightIO: <E, A>(ma: IO<A>) => IOEither<E, A>
예(임의 파일 로드)
세 파일(
1.txt
, 2.txt
, 3.txt
) 중 하나의 내용을 무작위로 로드한다고 가정해 보겠습니다.randomInt: (low: number, high: number) => IO<number>
함수는 닫힌 간격에 균일하게 분포된 임의의 정수를 반환합니다[low, high]
.import { randomInt } from 'fp-ts/Random'
위에서 정의한
randomInt
함수와 readFileSync
를 연결할 수 있습니다.import { ioEither } from 'fp-ts/IOEither'
const randomFile = ioEither.chain(
randomInt(1, 3), // static error
n => readFileSync(`${__dirname}/${n}.txt`)
)
그러나 이것은 유형 검사가 아닙니다!
유형이 정렬되지 않음:
randomInt
는 IO
컨텍스트에서 실행되고 readFileSync
는 IOEither
컨텍스트에서 실행됩니다.그러나
randomInt
를 사용하여 IOEither
를 rightIO
컨텍스트로 들어올릴 수 있습니다(위의 요약 참조).import { ioEither, rightIO } from 'fp-ts/IOEither'
const randomFile = ioEither.chain(rightIO(randomInt(1, 3)), n =>
readFileSync(`${__dirname}/${n}.txt`)
)
Reference
이 문제에 관하여(fp-ts 시작하기: IO), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/gcanti/getting-started-with-fp-ts-io-36p6텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)