假设我正在编写一个函数来进行 HTTP 调用以获取数据。我已将 API 调用分解为我编写的更小的函数:
const buildPayload = (inputs:Inputs) => reader.of({...inputs, some:'bar'}) // (inputs:Inputs) => Reader<unknown, Payload>
const buildUrl = reader.of('path/to/call') // Reader<unknown, string> (will be Reader<BaseUrl, string>)
const options = reader.of({options:{headers: /*...*/ }}) //Reader<unknown, AxiosOptions>
// (inputs:Inputs) => reader<unknown, [string,AxiosOptions,Payload]>
const fetchDeps = flow(buildPayload, _ => sequenceT(reader)(buildUrl, options, _))
// (inputs:Inputs) => reader<unknown, ()=>AxiosResponse<any>>
const fetchThunk = flow(fetchDeps, reader.chain(deps => ()=>axios.post(...deps)))
// And so forth
export const apiCall = flow(fetchThunk, /*...*/) // (inputs:Inputs) => ReaderTaskEither<TokenAndBaseUrl, DomainError, RequestedApiData>
使用flow
我已经设法最小化定义输入参数的频率。它只是一个地方,在buildPayload
,我没有任何隐含的any
论点)。如果出现新需求,这使得更改参数变得容易:更新一个地方,更改会在其余代码中级联。我认为这被称为“无点编程”。
当每一步都依赖于前一步而不依赖于其他步骤时,这很容易。但是假设流程中const foo = (a:A)=>B
的第一步是,第二步是const bar = (a:A,b:B)=>C
这样,第一步取决于第一步的结果,但也需要与第一步相同的参数。
我怎样才能做到这一点并且仍然是免费的(假设我正确使用了该术语)?
flow(foo, bar)
不起作用,因为 thenbar
需要接受的返回值foo
作为其参数。
我可以将它们定义为foo = (a:A) => ...
然后bar = (a:A, b:B) => ...
export const apiCall = (inputs:A) => pipe(foo(inputs), _ => bar(inputs, _), /*...*/)
但现在我必须(inputs:A)
在三个地方定义:foo
、bar
和apiCall
. 如果我更改参数,我必须更新三个不同的函数参数列表。