2016-09-05 22 views
3

Iはruler functionは無限ストリーム

ストリーム内のn番目の要素(第1要素を仮定が n = 1に相当)

0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,...

が定義しようと、UPENN Haskell Homework 6 Exercise 5に取り組んでいを定義するために失敗します最大power of 2は、nを均等に割ります。

は、私はただの整除テストなしでそれを構築するためのアイデアを思い付いた:

[0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2]

明らか

data Stream x = Cons x (Stream x) deriving (Eq) 

streamRepeat x = Cons x (streamRepeat x) 

interleaveStreams (Cons x xs) (Cons y ys) = 
    Cons x (Cons y (interleaveStreams xs ys)) 

ruler = 
    interleaveStreams (streamRepeat 0) 
     (interleaveStreams (streamRepeat 1) 
      (interleaveStreams (streamRepeat 2) 
       (interleaveStreams (streamRepeat 3) (...)) 

ruler = 
    interleaveStreams (streamRepeat 0) 
     (interleaveStreams (streamRepeat 1) 
      (interleaveStreams (streamRepeat 2) 
       (interleaveStreams (streamRepeat 3) (streamRepeat 4)))) 

の最初の20要素であるIそれを手動で無限に定義することはできませんでしたので、私はを定義しましたそのような無限再帰定義を支援する:

infInterStream n = interleaveStreams (streamRepeat n) (infInterStream (n+1)) 

ruler = infInterStream 0 

しかし、今ghcirulerに入力するとき、私は動けなくなる、それはおそらく無限ループに陥ります。

遅延評価が機能しているとは限りません。私はここで怠惰な評価が失敗する理由を知りたい。

streamToList (Cons x xs) = x : streamToList xs 

instance Show a => Show (Stream a) where 
    show = show . take 20 . streamToList 

答えて

7

あなたのインターリーブ機能が厳しすぎる:Streamを観察する


ヘルパー関数。以下の作品:

interleaveStreams (Cons x xs) ys = Cons x (interleaveStreams ys xs) 

また、これは動作します:

interleaveStreams (Cons x xs) ~(Cons y ys) = 
    Cons x (Cons y (interleaveStreams xs ys)) 

元の定義は、両方の引数がCons形式でなければなりませんinterleaveStreams需要ので、無限ループに入ります。 infInterStream nは2つのストリームのインターリーブに評価され、最初のものはConsにすぐに評価されますが、最初にConsに減らされなければならないので、再帰的にinfInterStream (n + 1)を呼び出します。

interleaveStreamsは、最初に第2引数を強制しなくてもCons a _を返すことができます。infInterStreamは、結果を段階的に構築することもできます。

+1

あなたの最初の定義は、私が以前に見たことがあることに非常によく似ています。私はそれがSICPにあったと思います – Wentao

1

ストリームの新しいタイプは必要ありません。代わりに、Haskellのレイジーリストを使用することができます。他の人が指摘したように、インタリーブの定義は、第2引数が空でないかどうかをテストする前に、出力の最初の要素を生成できるほど十分に怠惰でなければなりません。この定義は行います:

interleave (x:xs) ys = x : interleave ys xs 

をあなたはinterleaveが有限のリストにも仕事をしたい場合は、標準のプレリュードから関数を使用して、ということも方程式

interleave [] ys = ys 

ノートを追加することができ、

ruler = interleave (repeat 0) (map (+1) ruler) 

ここでrepeat 0はリスト[0, 0, 0, ...]です。

+0

別のストリームタイプを使用すると、パターンマッチが完全にローカルであることが明らかになります。 – dfeuer

+0

はい、あなたが好きならそれを行うことができます:しかし、あなたは、ストリームのすべての標準関数(上記の 'repeat'や' map'など)を再定義する必要があります。妥協はエンジニアリングの本質です。 –

+0

だから我々はHackageを持っているのです!コードはすでに書かれています。 – dfeuer

関連する問題