如何使用Task monad?(fp-ts)

pad*_*wbr 2 functional-programming typescript 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')
})
Run Code Online (Sandbox Code Playgroud)

我理解它的目的Task以及为什么它很重要。问题是我真的不知道如何正确使用它或用它进行创作。

如果我只是打电话getHello(),它会给我Promise<pending>

console.log(getHello()) // returns Promise<pending>
Run Code Online (Sandbox Code Playgroud)

但是,如果我这样做:

const run = async () => {
  const hello = await getHello()
  console.log(hello) // prints 'hello'
}
Run Code Online (Sandbox Code Playgroud)

有用。

但是这个:

const waitAndGet = async () => {
  return await getHello()
}

console.log(waitAndGet()) // prints Promise<pending>
Run Code Online (Sandbox Code Playgroud)

没有。

而且,我怎样才能用它来作曲呢?就像这样:

const waitAndGet = async () => {
  return await getHello()
}

console.log(waitAndGet()) // prints Promise<pending>
Run Code Online (Sandbox Code Playgroud)

che*_*som 9

首先,让\xe2\x80\x99s了解一下Task到底什么是。

\n
export interface Task<A> {\n  (): Promise<A>\n}\n\n// note that this could also be written as\nexport type Task<A> = () => Promise<A>\n
Run Code Online (Sandbox Code Playgroud)\n

ATask只是一个返回 a 的函数Promise,因此在您的示例中调用getHello将返回 a Promise<string>

\n

console.log(getHello())与 相同console.log(Promise.resolve(\'hello\')),因此这就是为什么它会记录诸如Promise {<fulfilled>: "hello"}Promise<pending>或其他内容而不是hello

\n

\r\n
\r\n
// Promise.resolve(foo) is the same as new Promise(resolve => resolve(foo))\nconst getHello = () => Promise.resolve(\'hello\')\nconsole.log(getHello())
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

有关 Promise 的更多信息,我建议阅读MDN 上的 \xe2\x80\x98Using Promises\xe2\x80\x99

\n
\n

至于如何组合它,sinceTask是 aMonad你可以使用map, ap,chainapSecond

\n

例如,let\xe2\x80\x99s say 的addAtEnd定义如下:

\n
const addAtEnd = (b: string) => (a: string): string => a + b\n
Run Code Online (Sandbox Code Playgroud)\n

您可以getHello()通过以下方式使用它Task.map

\n
import * as T from \'fp-ts/Task\'\nimport { pipe } from \'fp-ts/function\'\n\n// type of map:\n// export declare const map: <A, B>(f: (a: A) => B) => (fa: Task<A>) => Task<B>\n\n// Task<string> which, when called, would resolve to \'hello world\'\nconst getHelloAndAddWorld = pipe(\n  getHello,\n  T.map(addAtEnd(\' world\'))\n)\n\n// same as\nconst getHelloAndAddWorld = T.map(addAtEnd(\' world\'))(getHello)\n
Run Code Online (Sandbox Code Playgroud)\n

或者,如果您想记录其值,您可以使用chainIOKand Console.log

\n
import * as Console from \'fp-ts/Console\'\n\n// type of T.chainIOK:\n// export declare function chainIOK<A, B>(f: (a: A) => IO<B>): (ma: Task<A>) => Task<B>\n\n// type of Console.log:\n// export declare function log(s: unknown): IO<void>\n\n// Note that IO<A> is a function that (usually) does a side-effect and returns A\n// (() => A)\n\n// Task<void>\nconst logHelloAndWorld = pipe(\n  getHelloAndAddWorld,\n  T.chainIOK(Console.log)\n)\n\n// same as\nconst logHelloAndWorld = pipe(\n  getHello,\n  T.map(addAtEnd(\' world\')),\n  T.chainIOK(Console.log)\n)\n
Run Code Online (Sandbox Code Playgroud)\n

要执行Tasks,只需调用它:

\n
logHelloAndWorld() // logs \'hello world\'\n
Run Code Online (Sandbox Code Playgroud)\n

有关函子、应用程序和单子的简单介绍,Adit\xe2\x80\x99s \xe2\x80\x98Functors, Applicatives, And Monads In Pictures\xe2\x80\x99Tze-Hsiang Lin\xe2\x80\x99s JavaScript的版本是一些很好的起点。

\n