# ハスケル：状態を反復する、私が望む振る舞いを強制する方法？

これは私の最初の投稿であり、私は比較的新しいHaskellですので、間違いを犯したり、私のコードが慣用的でない場合はどうぞ！

a、f（a）、f（f（a））...の2つの直感的な説明を考えてみましょう。

A. a list containing: a, the application of f to a, the application of f to that, the application of f to that...

B. a list containing, in the ith position, i nested applications of f to a.

``````import Control.Monad.State

example :: State Int [[String]]

step :: [String] -> State Int [String]
step l = do
currentState <- get
let result = if (currentState == 1)
then "foo":l
else "bar":l
put (currentState + 1)
return result

example = do
sequence \$ take 3 . iterate (>>= step) \$ return []
``````

これらの定義により、

``````evalState example 1
``````

``````[[],["foo"],["bar","bar"]]
``````

それにもかかわらず、これを掲示する理由は2つある。

まず、` iterate `は初心者が実際に B A していると誤解する可能性がある方法でよく説明されています>。これには、 Learn You A Haskell （それ以外は信じられないほど役に立つと思う）が含まれますが、SO（ここここ）。実際、LYAHFGGの` iterate `の口頭での説明は、ほぼ正確には A の定義です。ですから、このためにバグを取得し、説明を探している他のHaskell初心者のためのリソースとして、これを投稿することは有益かもしれません（もっと正確で、技術的で、より良いフレーズを投稿します。以下の A B の違い）。

``````example2 = do
firstResult <- step []
secondResult <- step firstResult
return \$ [[], firstResult, secondResult]
``````

そのために

``````evalState example2 1
``````

``````[[],["foo"],["bar","foo"]]
``````

` iterate `を使用して` example2 `を書き直すにはどうすればよいですか？

``````iterate' f x = x : rest
where previous = f x
rest = previous `seq` iterate f previous
``````

これに関するすべての洞察は非常に高く評価されます。

4

## 2 答え

There is no difference between A. and B., they are the same thing by referential transparency.
The core of the problem seems to be that you're interpreting them in the context of execution of stateful computations. In that context, the analogue of A that you're expecting is
A': Produce a result list by 1. putting the result of the initial computation into the list, 2. determine the next computation from the previous result, execute it and append its result to the list, 3. goto 2.
The analogue of B is
B': Produce a list of computations (by iterating (>>= step)) and from that a result list by executing the computations one after the other.
For stateless computations, or when you pass the same initial state to all computations produced in B', the only difference is in efficiency, but if you're using `sequence`, each computation starts with a different state, so you get different results from A'. Breaking down your `example`, we have

``````actionList = take 3 \$ iterate (>>= step) (return [])
= [return [], return [] >>= step, return [] >>= step >>= step]
``````

` State Int [String] `のアクション（またはモナド値）のリスト。さて、` sequence `を適用すると、

``````example = sequence actionList
``````

Basically, a value of type `State s v` is a function of type `s -> (v, s)`. `iterate` creates a list of functions, and `sequence` applys these functions, supplying different `s` arguments to them (each gets the `s` produced by the previous).

``````iterateM :: Monad m => (a -> m a) -> m a -> m [a]
iterateM step start = do
first <- start
rest <- iterateM step (step first)
return (first:rest)
``````

それは生産する

``````Prelude Control.Monad Control.Monad.State> evalState (fmap (take 4) (iterateM step (return []))) 1
[[],["foo"],["bar","foo"],["bar","bar","foo"]]
``````

But it works only in monads with sufficiently lazy `(>>=)`, `Control.Monad.State.Lazy` is one of the few, `Control.Monad.State.Strict` is not. And even with `C.M.S.Lazy`, You cannot use the state after an `iterateM`, you have to `put` a new state before you can continue the computation. To get something usable with other monads, we could add a count parameter,

``````iterCountM :: (Monad m) => Int -> (a -> m a) -> m a -> m [a]
iterCountM 0 _ _ = return []
iterCountM k step start = do
first <- start
rest <- iterCountM (k-1) step (step fisrt)
return (first:rest)
``````

16

はい、それはまさに私が考えているパターンです。つまり、` example2 `（元の質問に編集）を参照すると、「あなたは` iterate `を使って書き直すことはできません！ ？それでは、コンパクトでエレガントな/慣用的なやり方は何でしょうか？私が言ったように、私は状態の中に結果を累積することなくこれを行う方法に興味があるでしょう。

ダニエル、別の答えに2番目のコメント（文脈で）を書いてもらうと、私はそれを投票することができます。（最初の答えは確かに` example `それが何をしているのか、私は代わりに何か他のことをする方法についてのガイダンスを探していただけです！）

それは信じられないほど助けになります、あなたの寛大な助けをありがとう！

@Carl参加してくれてありがとうございますが、ダニエルはすでに私のためにそれをすべてクリアしました。私が見逃していたパズルの部分は、あなたが思うものではありませんが、決して気にしません。申し訳ありませんが、SO初心者として：私はそれらの行に沿ってさらにコメントを募ることを避けるために元の質問を編集するはずですか？

あと、新しいタイプのラッパーを無視して、繰り返しのnewtypeとcurrying、`（>> = step）::（（[String]、Int） - >（[String]、Int） ） - >（（[String]、Int） - >（[String]、Int））`）。各関数は、この変換を前の関数に適用した結果です（完全に評価されているかどうかは、参照透過性のために重要ではありません）。前の関数のアプリケーションの結果を次の関数の判定に含めるには、それは反復ではなく別のパターンです。

@ビラル、私は元の答えにガイダンスを追加し、それが助けてくれることを願っています。

@BilalBarakat AとBは同じものです。最初にstepを呼び出すときの最初の状態は常に1であると仮定しています。シーケンスを使用しているため、そうではありません。状態のコンテキストでは、シーケンスとは、「現在の状態で最初のアクションを実行し、結果の状態を次のアクションに渡して実行し、最後のアクションの結果になるように現在の状態を更新する」という意味です。あなたはそれが「現在の状態で各行動を実行する」と仮定しているようです。

これは、あなたが提出した質問には答えられないかもしれませんが、あなたがしていることは` unfoldr `のように非常によく聞こえます。

``````step (seed, l) = Just (l', (seed', l'))
where seed' = succ seed
l' = (if seed == 1 then "foo" else "bar"):l
``````

``````ghci> take 3 \$ unfoldr step (1, [])
[["foo"], ["bar", "foo"], ["bar", "bar", "foo"]]
``````

モナドは必要ありません。あなたが実際に何をしようとしているのかを指定していないので、私は暗闇の中で刺すようですが、` step `を正しいかどうかにかかわらず、単純な状態のスレッディングにも使用できます。

``````unfoldr :: (seed -> Maybe (val, seed)) -> seed -> [val]
``````
3

ありがとう@ダン、素敵なtipp、と私はunfoldr（私はmapAccumLを使用して調べていたが）認識していませんでした。それを私のツールキットに追加するのは間違いありませんが、私の現在の目的では、それぞれの "ステップ"はかなり複雑であり、まだ拡張されるかもしれないので、モナールの一般性はおそらく有益でしょう。