如何使用任务monad? (fp-ts)
How to use the Task monad? (fp-ts)
import * as T from 'fp-ts/lib/Task'
import { pipe, flow } from 'fp-ts/lib/function'
const getHello: T.Task<string> = () => new Promise((resolve) => {
resolve('hello')
})
我理解 Task
的目的及其重要性。问题是我真的不知道如何正确使用它或与它组合。
如果我只调用 getHello()
,它会给我 Promise<pending>
:
console.log(getHello()) // returns Promise<pending>
如果我这样做,但是:
const run = async () => {
const hello = await getHello()
console.log(hello) // prints 'hello'
}
有效。
但是这个:
const waitAndGet = async () => {
return await getHello()
}
console.log(waitAndGet()) // prints Promise<pending>
没有。
此外,我将如何与它作曲?像这样:
const getHelloAndAddWorld = flow(
getHello(),
addAtEnd('world')
)
首先,让我们了解一下 Task
到底是什么。
export interface Task<A> {
(): Promise<A>
}
// note that this could also be written as
export type Task<A> = () => Promise<A>
A Task
只是一个 return 是 Promise
的函数,因此在您的示例中调用 getHello
将 return 是 Promise<string>
.
console.log(getHello())
与 console.log(Promise.resolve('hello'))
相同,所以这就是为什么它会记录 Promise {<fulfilled>: "hello"}
、Promise<pending>
或其他内容而不是 hello
的原因]:
// Promise.resolve(foo) is the same as new Promise(resolve => resolve(foo))
const getHello = () => Promise.resolve('hello')
console.log(getHello())
有关 promises 的更多信息,我建议阅读 Using Promises on MDN。
至于如何合成,因为Task
是一个Monad
你可以用map
, ap
, chain
, apSecond
等等
例如,假设 addAtEnd
定义如下:
const addAtEnd = (b: string) => (a: string): string => a + b
您可以通过 Task.map
:
将其与 getHello()
一起使用
import * as T from 'fp-ts/Task'
import { pipe } from 'fp-ts/function'
// type of map:
// export declare const map: <A, B>(f: (a: A) => B) => (fa: Task<A>) => Task<B>
// Task<string> which, when called, would resolve to 'hello world'
const getHelloAndAddWorld = pipe(
getHello,
T.map(addAtEnd(' world'))
)
// same as
const getHelloAndAddWorld = T.map(addAtEnd(' world'))(getHello)
或者如果你想记录它的值,你可以使用 chainIOK
and Console.log
:
import * as Console from 'fp-ts/Console'
// type of T.chainIOK:
// export declare function chainIOK<A, B>(f: (a: A) => IO<B>): (ma: Task<A>) => Task<B>
// type of Console.log:
// export declare function log(s: unknown): IO<void>
// Note that IO<A> is a function that (usually) does a side-effect and returns A
// (() => A)
// Task<void>
const logHelloAndWorld = pipe(
getHelloAndAddWorld,
T.chainIOK(Console.log)
)
// same as
const logHelloAndWorld = pipe(
getHello,
T.map(addAtEnd(' world')),
T.chainIOK(Console.log)
)
要执行Task
s,只需调用它:
logHelloAndWorld() // logs 'hello world'
对于仿函数、应用程序和单子的简单介绍,Adit's 'Functors, Applicatives, And Monads In Pictures' or Tze-Hsiang Lin's JavaScript version of that 是一些很好的起点。
import * as T from 'fp-ts/lib/Task'
import { pipe, flow } from 'fp-ts/lib/function'
const getHello: T.Task<string> = () => new Promise((resolve) => {
resolve('hello')
})
我理解 Task
的目的及其重要性。问题是我真的不知道如何正确使用它或与它组合。
如果我只调用 getHello()
,它会给我 Promise<pending>
:
console.log(getHello()) // returns Promise<pending>
如果我这样做,但是:
const run = async () => {
const hello = await getHello()
console.log(hello) // prints 'hello'
}
有效。
但是这个:
const waitAndGet = async () => {
return await getHello()
}
console.log(waitAndGet()) // prints Promise<pending>
没有。
此外,我将如何与它作曲?像这样:
const getHelloAndAddWorld = flow(
getHello(),
addAtEnd('world')
)
首先,让我们了解一下 Task
到底是什么。
export interface Task<A> {
(): Promise<A>
}
// note that this could also be written as
export type Task<A> = () => Promise<A>
A Task
只是一个 return 是 Promise
的函数,因此在您的示例中调用 getHello
将 return 是 Promise<string>
.
console.log(getHello())
与 console.log(Promise.resolve('hello'))
相同,所以这就是为什么它会记录 Promise {<fulfilled>: "hello"}
、Promise<pending>
或其他内容而不是 hello
的原因]:
// Promise.resolve(foo) is the same as new Promise(resolve => resolve(foo))
const getHello = () => Promise.resolve('hello')
console.log(getHello())
有关 promises 的更多信息,我建议阅读 Using Promises on MDN。
至于如何合成,因为Task
是一个Monad
你可以用map
, ap
, chain
, apSecond
等等
例如,假设 addAtEnd
定义如下:
const addAtEnd = (b: string) => (a: string): string => a + b
您可以通过 Task.map
:
getHello()
一起使用
import * as T from 'fp-ts/Task'
import { pipe } from 'fp-ts/function'
// type of map:
// export declare const map: <A, B>(f: (a: A) => B) => (fa: Task<A>) => Task<B>
// Task<string> which, when called, would resolve to 'hello world'
const getHelloAndAddWorld = pipe(
getHello,
T.map(addAtEnd(' world'))
)
// same as
const getHelloAndAddWorld = T.map(addAtEnd(' world'))(getHello)
或者如果你想记录它的值,你可以使用 chainIOK
and Console.log
:
import * as Console from 'fp-ts/Console'
// type of T.chainIOK:
// export declare function chainIOK<A, B>(f: (a: A) => IO<B>): (ma: Task<A>) => Task<B>
// type of Console.log:
// export declare function log(s: unknown): IO<void>
// Note that IO<A> is a function that (usually) does a side-effect and returns A
// (() => A)
// Task<void>
const logHelloAndWorld = pipe(
getHelloAndAddWorld,
T.chainIOK(Console.log)
)
// same as
const logHelloAndWorld = pipe(
getHello,
T.map(addAtEnd(' world')),
T.chainIOK(Console.log)
)
要执行Task
s,只需调用它:
logHelloAndWorld() // logs 'hello world'
对于仿函数、应用程序和单子的简单介绍,Adit's 'Functors, Applicatives, And Monads In Pictures' or Tze-Hsiang Lin's JavaScript version of that 是一些很好的起点。