2013-08-20 13 views
6

List.concat/1に似た関数を書くと、リストの列挙が可能で、連結リストは連続ストリームとして出力されます。リストの列挙可能を束縛する

それはこのように動作します:

iex> 1..3 |> Stream.map(&([&1])) |> Enum.to_list 
[[1], [2], [3]] 
iex> 1..3 |> Stream.map(&([&1])) |> MyStream.concat |> Enum.to_list 
[1, 2, 3] 

を私はこれまでのところが出ていることはこれです:

defmodule MyStream do 
    def concat(lists) do 
    Enumerable.reduce(lists, [], fn(x, acc) -> acC++ x end) 
    end 
end 

これは正しい結果を生成するが、明らかに怠け者ではありません。

Stream.Lazyを使用してみましたが、実際にはその内部の仕組みを理解できていません。 Stream.Lazyの説明は非常に高く評価されます!

答えて

8

エリクシールの列挙型は、還元関数によって表されます。それを減らす方法を教えてくれれば、どのような構造もマップできます。

ストリームのアイデアは、あなたがそれらの還元機能を構成できるということです。のは、一例として、マップを見てみましょう:

def map(enumerable, f) do 
    Lazy[enumerable: enumerable, 
     fun: fn(f1) -> 
     fn(entry, acc) -> 
      f1.(f.(entry), acc) 
     end 
     end] 
end 

あなたが列挙を受け取り、あなたが機能fと各要素の上にマッピングします。怠惰なバージョンは、実際の還元作用f1を受け取り、entryacc(同じ引数がf1受け取ることになる)、その後、あなたがf1(還元作用)を呼び出す前に、効果的要素をマッピングf.(entry)を呼び出しを受けて、新たな機能を、返します。要素を1つずつマッピングする方法に注目してください。

本のフラットマップ変異体は、おそらくのようになります。さて、ではなく、あなたがf.(entry)を呼び出すたびに、あなたが戻ってリストを取得し、この新しいリストの各要素を反復処理したい

def flat_map(enumerable, f) do 
    Lazy[enumerable: enumerable, 
     fun: fn(f1) -> 
     fn(entry, acc) -> 
      Enumerable.reduce(f.(entry), acc, f1) 
     end 
     end] 
end 

リスト全体を反復処理します。

私は上記のコードを試していません(そして、私はいくつかの詳細を見逃しているかもしれませんが)。それはStreamsが一般的にどのように機能するかです。

5

the help of José Valimとは、コードから私が探していたものまで非常に小さなステップでした。私はおそらくこの質問をひどくひどく提起しましたが、私が本当に探していたのは、Pythonのitertools.chain関数と同等でした。

def chain(enumerable) do 
    Stream.Lazy[enumerable: enumerable, 
       fun: fn(f1) -> 
       fn(entry, acc) -> 
        Enumerable.reduce(entry, acc, f1) 
       end 
       end] 
end 

これにより、ストリームまたはリストの潜在的に無限の列挙型を連鎖させることができます。

iex> 1..1000000 |> Stream.map(&(1..(&1))) |> MyModule.chain |> Enum.take(20) 
[1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5] 
関連する問題