機能設計:「時間」コンビナータをより一般的にする方法
16969 ワード
私が書いたのは
すなわち、消費者は経過時間と何をすべきかを選択できない 作品 この記事では、最初の問題に取り組む.
経過時間を返すことによる柔軟性の追加
常にログの代わりに、計算された値と一緒に経過時間を返すことができます
我々はまだコンソールにログオンすることができます.
付録
の実装
1 )署名は、空のアクションリストを提供します
ヒア
time
類似のUNIXコマンドを模倣するコンバイナレータIO<A>
, 我々は行動を得ることができるIO<A>
これは、経過時間import { IO, io } from 'fp-ts/IO'
import { now } from 'fp-ts/Date'
import { log } from 'fp-ts/Console'
export function time<A>(ma: IO<A>): IO<A> {
return io.chain(now, start =>
io.chain(ma, a => io.chain(now, end => io.map(log(`Elapsed: ${end - start}`), () => a)))
)
}
この組み合わせには2つの問題があります.IO
のみ経過時間を返すことによる柔軟性の追加
常にログの代わりに、計算された値と一緒に経過時間を返すことができます
export function time<A>(ma: IO<A>): IO<[A, number]> {
return io.chain(now, start => io.chain(ma, a => io.map(now, end => [a, end - start])))
}
今、ユーザーは、それ自身の組み合わせを定義することによって経過時間と何をすべきかを選択することができます.我々はまだコンソールにログオンすることができます.
export function withLogging<A>(ma: IO<A>): IO<A> {
return io.chain(time(ma), ([a, millis]) =>
io.map(log(`Result: ${a}, Elapsed: ${millis}`), () => a)
)
}
用途import { randomInt } from 'fp-ts/Random'
function fib(n: number): number {
return n <= 1 ? 1 : fib(n - 1) + fib(n - 2)
}
const program = withLogging(io.map(randomInt(30, 35), fib))
program()
/*
Result: 14930352, Elapsed: 127
*/
...またはちょうど経過時間を無視する.export function ignoreSnd<A>(ma: IO<[A, unknown]>): IO<A> {
return io.map(ma, ([a]) => a)
}
...または、例えば、アクションの非空のリストの最速を維持するimport { fold, getMeetSemigroup } from 'fp-ts/Semigroup'
import { contramap, ordNumber } from 'fp-ts/Ord'
import { getSemigroup } from 'fp-ts/IO'
export function fastest<A>(head: IO<A>, tail: Array<IO<A>>): IO<A> {
const ordTuple = contramap(([_, elapsed]: [A, number]) => elapsed)(ordNumber)
const semigroupTuple = getMeetSemigroup(ordTuple)
const semigroupIO = getSemigroup(semigroupTuple)
const fastest = fold(semigroupIO)(time(head), tail.map(time))
return ignoreSnd(fastest)
}
用途io.chain(fastest(program, [program, program]), a => log(`Fastest result is: ${a}`))()
/*
Result: 5702887, Elapsed: 49
Result: 2178309, Elapsed: 20
Result: 5702887, Elapsed: 57
Fastest result is: 2178309
*/
我々はプログラミングの強力なスタイルを導入することによって、第2の問題に取り組むでしょう:タグのない決勝.付録
の実装
fastest
かなり密です.関連するビットを見てみましょう.1 )署名は、空のアクションリストを提供します
// at least one action --v v--- possibly other actions
function fastest<A>(head: IO<A>, tail: Array<IO<A>>): IO<A>
2).contramap
はOrd
の組み合わせを指定しますOrd
for T
からの関数U
to T
, のインスタンスを得ることができますOrd
for U
.ヒア
T = number
and U = [A, number]
// from `Ord<number>` to `Ord<[A, number]>`
const ordTuple = contramap(([_, elapsed]: [A, number]) => elapsed)(ordNumber)
3).getMeetSemigroup
インスタンスを変換するOrd<T>
のインスタンスにSemigroup<T>
これは、2つの値を組み合わせた場合、// from `Ord<[A, number]>` to `Semigroup<[A, number]>`
const semigroupTuple = getMeetSemigroup(ordTuple)
4).getSemigroup
はSemigroup
の組み合わせを指定しますSemigroup
for T
, のインスタンスを得ることができますSemigroup
for IO<T>
// from `Semigroup<[A, number]>` to `Semigroup<IO<[A, number]>>`
const semigroupIO = getSemigroup(semigroupTuple)
5)fold
指定したアクションの空のリストを減らすSemigroup
// from a non empty list of `IO<[A, number]>` to `IO<[A, number]>`
const fastest = fold(semigroupIO)(time(head), tail.map(time))
6 )最終的に経過時間を無視して値を返す// from `IO<[A, number]>` to `IO<A>`
return ignoreSnd(fastest)
Reference
この問題について(機能設計:「時間」コンビナータをより一般的にする方法), 我々は、より多くの情報をここで見つけました https://dev.to/gcanti/functional-design-how-to-make-the-time-combinator-more-general-3fgeテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol