解決すべき問題は、入力と一連の関数があり、関数を順番に入力に適用することです。
関数が純粋に状態を変更する関数でs -> s
あり、 type の入力に対して、それらを使用する必要s
はありません。Haskell は、これらのような関数を連鎖させるのが非常に得意です。 State
.
foldr (.) id
foldr id
ただし、関数が両方とも状態を変更し、その結果を報告する場合は、それらに type を与えることができるため、s -> (s,a)
それらをすべてくっつけるのは少し面倒です。結果のタプルをアンパックし、新しい状態値を次の関数に渡し、報告された値を別の場所で使用してから、その結果をアンパックする必要があります。アンパックを行うには、各結果に名前を付けて明示的に入力する必要があるため、間違った状態を入力関数に渡すのは簡単です。次のような結果になります。
let
(res1, s1) = fun1 s0
(res2, s2) = fun2 s1
(res3, s3) = fun3 res1 res2 s1
...
in resN
後で 2 行目を追加し、3 行目を変更する必要があることに気づかなかったために、誤っs1
て の代わりにパスしてしまいました。s2
関数を構成するとき、s -> s
正しい名前がないため、この問題はおそらく発生しません。
let
resN = fun1 . fun2 . fun3 . -- etc.
だから私たちState
は同じトリックをするために発明しました。基本的には、適切な状態が常に適切な関数に渡されるように、State
関数のようなものを接着する方法にすぎません。s -> (s,a)
だから、「 を使いたい、使おう」というよりは、「 のような関数を書いている、それを簡単にするために発明しよう」という人が多かっState
たs -> (s,a)
のですs -> (s,a)
。State
functionss -> s
を使用すると、すでに簡単であり、何も発明する必要はありません。
が自然に発生する例として、s -> (s,a)
構文解析を考えてみましょう。パーサーは何らかの入力を受け取り、入力の一部を消費して値を返します。Haskell では、これは自然に入力リストを取得し、値と残りの入力のペア、つまり[Input] -> ([Input], a)
orを返すものとしてモデル化されState [Input]
ます。