2017-02-17 5 views
3

Haskellの機能的な考察(p 213)では、サイクリックリストの2つのバージョンが示されています。一つは、二次の時間に評価されます。サイクリックリストのWHERE句の評価

iterate3 f x = x:map f (iterate3 f x) 

iterate3 (2*) 1 
= 1:map (2*) (iterate3 (2*) 1) 
= 1:2:map (2*) (map (2*) (iterate3 (2*) 1)) 
= 1:2:4:map (2*) (map (2*) (map (2*) (iterate3 (2*) 1))) 

whereを使用する、他の、線形時間で評価されます。

iterate2 f x = xs where xs = x:map f xs 

iterate2 (2*) 1  
xs   where xs = 1:map (2*) xs 
= 1:ys  where ys = map (2*) (1:ys) 
= 1:2:zs where zs = map (2*) (2:zs) 
= 1:2:4:ts where ts = map (2*) (4:ts) 

私はかなりこの評価を理解していません。 xは(最初のバージョンのように)1ではなく各連続するリスト要素にどのように再割り当てされるのですか?

答えて

4

重要な詳細は、iterate2xsがそれ自体で定義され、循環構造を作成することです。

グラフとして視覚化すると、評価は次のようになります(警告:ASCIIアート)。

xs where xs = 1 : map (2*) xs

 : <----------+ 
/ \   | applies to 
    1 map (2*) --+ 

-->

 : 
/ \ 
    1  : <--------+ 
    / \   | applies to 
    2 map (2*) --+ 

-->

 : 
/ \ 
    1  : 
    / \ 
    2  : <---------+ 
     / \   | applies to 
     4 map (2*) --+ 

のように。

+0

ありがとう!私にとって、適切な視覚化を見つけることは、多くの場合、再帰を理解する上での最大の障害です。 – planarian

+0

フォローアップ質問:iterate3は循環リストを生成しますか?この点で、テキストはやや曖昧です。 – planarian

+1

@planarian私は、リストそのものにサイクルがないと言っています。どれだけ評価しても、前の要素に戻ってくることはありませんが、定義にはその定義があると主張できます。 (つまり、それは「循環リストの定義」ではなく、「循環リストの定義」ではない)。 – molbdnilo

1

はのはiterate2で再帰をアンロールしてみましょう:

xs = x : map f xs 
    = x : map f (x : map f xs)       -- Inline xs 
    = x : (f x) : map f (map f xs)      -- Definition of map 
    = x : (f x) : map f (map f (x : map f xs))   -- Inline xs 
    = x : (f x) : map f ((f x) : map f (map f xs))  -- Definition of map 
    = x : (f x) : (f (f x)) : map f (map f (map f xs))) -- Definition of map 
    ... 

ですからように、iterate2 f xによって返されたリストには、最初の要素としてxを持っていることを第二としてf xを見て、することができます。

+1

この削減は意味的には正しいですが、これが線形時間で計算されていることを示していません - この削減ではまだ2次の複雑さがあります。これはOPを混乱させる可能性があります。 – chi

+0

そうですが、私はどのように「x」が「更新」されているかについての元の質問に答えながら、どのように表示するのか分かりません。 – Cactus