以前は状態遷移のシーケンスとして作成したプログラムを再編成する方法を理解しようとしています。
私はいくつかのビジネスロジックを持っています:
type In = Long
type Count = Int
type Out = Count
type S = Map[Int, Count]
val inputToIn: String => Option[In]
= s => try Some(s.toLong) catch { case _ : Throwable => None }
def transition(in: In): S => (S, Out)
= s => { val n = s.getOrElse(in, 0); (s + (in -> n+1), n+1) }
val ZeroOut: Out = 0
val InitialState: S = Map.empty
これらを使用して、初期状態(空のマップ)を渡し、stdinから入力を読み取り、に変換しIn
、状態遷移を実行して現在の状態S
と出力Out
をstdoutに出力するプログラムを作成したいと思います。
以前は、次のようなことをしていました。
val runOnce = StateT[IO, S, Out](s => IO.readLn.map(inputToIn) flatMap {
case None => IO((s, ZeroOut))
case Some(in) => val (t, o) = transition(in)(s)
IO.putStrLn(t.toString) |+| IO.putStrLn(o.toString) >| IO((t, o))
})
Stream.continually(runOnce).sequenceU.eval(InitialState)
ただし、このアプローチ(状態遷移のストリーム)をscalaz-streamに接続する方法を見つけるのに本当に苦労しています。私はこれから始めました:
type Transition = S => (S, Out)
val NoTransition: Transition = s => (s, 0)
io.stdInLines.map(inputToIn).map(_.fold(NoTransition)(transition))
これはタイプです:Process[Task, Transition]
。そこからどこへ行けばいいのかよくわかりません。
- 自分を「パスイン」して
InitialState
プログラムを実行し、S
各ステップの出力をS
次のステップへの入力としてスレッド化するにはどうすればよいですか? - 各ステップで
S
との値を取得し、Out
それらをstdoutに出力するにはどうすればよいですか(文字列に変換できると仮定)?
単一の理解のために使用しようとすると、私は同様に行き詰まります:
for {
i <- Process.eval(Task.now(InitialState))
l <- io.stdInLines.map(inputToIn)
...
どんな助けでも大歓迎です!
もう少し先になりました。
type In_ = (S, Option[In])
type Out_ = (S, Out)
val input: Process[Task, In_]
= for {
i <- Process.emit(InitialState)
o <- io.stdInLines.map(inputToIn)
} yield (i, o)
val prog =
input.pipe(process1.collect[In_, Out_]) {
case (s, Some(in)) => transition(in)(s)
}).to(io.stdOutLines.contramap[Out_](_.toString))
次に
prog.run.run
動作しません:状態がストリームにスレッド化されていないようです。むしろ、各段階で、初期状態が渡されます。
ポール・チウサノは、のアプローチを使用することを提案しましたprocess1.scan
。だから今私はこれを行います:
type In_ = In
type Out_ = (S, Out)
val InitialOut_ = (InitialState, ZeroOut)
val program =
io.stdInLines.collect(Function.unlift(inputToIn)).pipe(
process1.scan[In_, Out_](InitialOut_) {
case ((s, _), in) => transition(in)(s)
}).to(io.stdOutLines.contramap[Out_](_.shows))
ここに問題があります。この特定の例では、私のOut
タイプはモノイドであるため、そのIDを使用して初期状態を作成できますが、通常はそうではない可能性があります。それなら私は何をしますか?(私は使用できると思いますOption
が、これは不要のようです。)