2012-09-25 4 views
5

私はシード値xで始まり、各ステップで新しいシード値と出力値を生成するパターンを見つけました。私の望む最終結果は、出力値のリストです。これは次の関数で表すことができる。「出力」の値が反復されている値と同じでない場合、プレリュードの反復の代替手段は何ですか?

my_iter :: (a -> (a, b)) -> a -> [b] 
my_iter f x = y : my_iter f x' 
    where (x',y) = f x 

そして、フィボナッチ数列を生成することになる、これを使用しての不自然な例:

fibs:: [Integer] 
fibs = my_iter (\(a,b) -> let c = a+b in ((b, c), c)) (0,1) 
-- [1, 2, 3, 5, 8... 

私の問題は、私は非常にがあることをこの気持ちを持っているということですおそらくこの種のものをするもっと慣用的な方法です。私の機能の慣用的な選択肢は何ですか?

私が今考えている唯一のものは、プレリュードのiterateですが、いくつかの欠点があります。

一つの方法別のf1とf2関数にfを分割する全く自然な方法が存在しない場合は、これは醜い見ることができる最初の反復と

my_iter f x = map f2 $ iterate f1 x 
    where f1 = fst . f 
      f2 = snd . f 

後にマップすることです。 (実際のフィボナッチの場合、これは簡単ですが、生成された値が種の「独立」関数ではないので、事を分割するのが簡単ではない場合があります)

もう1つの方法は、一緒種と「出力」の値、および(種類のものをソートするための「シュワルツ変換」のように)それらを分離するために、別のステップを使用します。

my_iter f x = map snd . tail $ iterate (f.fst) (x, undefined) 

しかし、これは奇妙なようで、私たちは忘れてはいけないので、シード(f.fst)ビットに到達するために生成された値を無視し、最初に生成されたダミー値に "未定義"値が必要です。

答えて

11

すでに述べたように、必要な機能はunfoldrです。名前が示すように、それはfoldrの反対ですが、それが本当に正しい理由を知ることは有益かもしれません。

(a -> b -> b) -> b -> [a] -> b 

最初の2つの引数がタイプbの何かを得るための方法であり、リストの二つのデータコンストラクタに対応:

[] :: [a] 
(:) :: a -> [a] -> [a] 

...の各発生ここでfoldrのタイプがあります[a]bに置き換えられます。 []ケースでは入力がないbが生成されることに注意して、入力としてMaybe (a, b)を取る関数として2つを統合することができます。

(Maybe (a, b) -> b) -> ([a] -> b) 

余分な括弧は、これが本質的に1つの種類の変換を別の種類に変換する関数であることを示しています。

今、単に両方の変換の方向を逆:

(b -> Maybe (a, b)) -> (b -> [a]) 

結果はunfoldrの正確タイプです。

これが示す根本的な考え方は、他の再帰的なデータ型にも同様に適用できます。

iterateM :: Monad m => m a -> m [a] 
iterateM = sequence . repeat 

それは標準ライブラリではありませんが、構築するのは簡単です:

+4

興味深いのは、「おそらく(a、b)」の部分は '(a、')の基礎となる '展開するための)固定小数点。 @missingnoが要求したバージョンは 'Stream a'の' unfoldr'です。その基礎となるファンクタは '(a、_)'です。 Prelude 'unfoldr'の追加の' Nothing'は、あなたのリストの生成を止めたいところをカバーしますが、ここでは決して起こらないでしょう。 – copumpkin

+3

@copumpkin: '[a]'はよく知られている有限で有限で潜在的に無限のリストの3つすべてが永続的なペットのかわいこの1つです。 >:[ –

6

お探しの標準機能はunfoldrです。

2

もう一つの可能​​性はStateモナドでiterateMです。

だからあなたmy_iter

evalState . sequence . repeat :: State s a -> s -> [a] 
+2

または、[monad-loops'パッケージ](http://hackage.haskell.org/packages/archive/monad-loops/0.3.3.0/doc/html/Control-Monad-Loops.html)を使用してください。 )あなたが今までに望んでいたよりも、アイデアのバリエーションが増えます。 :] –

+0

モナドループはすべての可能なループのランダムなコレクションのようです。それは良いですが、私はよく考えられたコンビネータの小さなセットを好むでしょう。それは、標準ライブラリに 'iterateUntil'のようなものがないことは残念です。 – nponeccop

5

Hoogleであることが唯一の名前ではなく、タイプ別に検索機能をサポートしていないため、この場合には非常に便利なツールです。

あなたの場合、希望するタイプは(a -> (a, b)) -> a -> [b]です。それを入力すると結果は得られません。

まあ、わずかに異なる構文の標準機能があるかもしれません。たとえば、標準関数の引数を反転させることができます。どこかの型署名に(a -> (a, b))というものを探してみましょう。今回はたくさんの結果があるので運が良かったですが、それらのすべてがエキゾチックなパッケージになっていて、どれも非常に役に立つとは思われません。

あなたの関数の2番目の部分がより良い一致になっている可能性があります。結局のところ、いくつかの初期要素からリストを生成したいので、a -> [b]とヒットします。最初の結果:unfoldr - ビンゴ!

+0

ハハハ、私はもともと最初の検索を試みたが、それをあきらめた。誰かが常にHoogleを使用するように言っている人として、病気はこれを学んだレッスンにしなければなりません:) – hugomg

関連する問題