/ / Haskellのフィボナッチを理解する-haskell、list-comprehension

ハスケルのフィボナッチ・ハスケル、リスト理解の理解

fibs :: [Int]
fibs = 0 : 1 : [ a + b | (a, b) <- zip fibs (tail fibs)]

これにより、フィボナッチ数列が生成されます。

警備員の行動を理解しています :, zip そして tail、でもわからない <-。ここで何をしているの?

回答:

回答№1の13

賛成のおかげで、私はコメントを答えにしました。

あなたが見るものは警備員ではありませんが、 リストの理解。まず第一に、それを表現する方法として考えてくださいA = {x | x要素N}は、次の行に沿ったものを意味します。セットAは、すべての自然数のセットです。リスト内包表記では [x | x <- [1..] ].

数値に制約を使用することもできます。 [x | x <- [1..], x `mod` 2 == 0 ] その他多くのこと。

リストの理解度、さらにはhaskellリソースに関するStackOverflowの質問までカバーする、たくさんの良いhaskell turorialsがあります。


回答№2の10

唯一のトリッキーなことは zip fibs (tail fibs). zip 引数ごとにペアごとのリストを作成します。したがって、次のような2つのリストがある場合:

[ 1, 2, 3, 4 ]
[ "a", "b", "c", "d" ]

それらを圧縮すると、次のようになります。

[ (1,"a"), (2,"b"), (3,"c"), (4,"d") ]

左矢印(破壊パターンへの割り当て)は、ペアになった要素を抽出するだけなので、それらを一緒に追加できます。圧縮される2つのリストは次のとおりです。 fibs そして (tail fibs) -言い換えれば、フィボナッチ数列1要素のフィボナッチ数列オフセット。 Haskellは遅延評価されるため、多くの要素が必要な場合でもリストを計算できます。これはzipにも当てはまります。


回答№3の場合は3

広げてみましょう。

zip 2つのリストの内容からペアを作成します。だから最初のペア zip fibs (tail fibs) 私たちに与えます (0, 1)、合計は1です。したがって、リストは [0,1,1]。これでリスト内の3つの要素がわかったので、リストの理解を続けて、リストから次のアイテムを取得し、テールから次のアイテムを取得できます。 (1,1) —一緒に追加して、2にします。次に、次のペアを取得します。 (1,2)、シーケンス3の次の番号を作成します。これは、理解が常に十分なアイテムを提供するため、無限に継続できます。


答え№4の2

関数型プログラミングの利点の1つは、数式を数学の問題のように手動で評価できることです。

fibs = 0 : 1 : [ a + b | (a, b) <- zip fibs (tail fibs)]
= 0 : 1 : [ a + b | (a, b) <- zip [0, 1, ??] (tail [0, 1, ??])]

ここに ?? まだ評価されていない部分です。続行するときに記入します。

     = 0 : 1 : [ a + b | (a, b) <- zip [0, 1, ??] [1, ??])]
= 0 : 1 : [ a + b | (a, b) <- (0, 1) : zip [1, ??] [??]]

私は評価を排除していることに注意してください zip その定義はここでは示されておらず、詳細は現在の質問と実際には密接な関係がないためです。これは、数字の各ペアが作成されることを示すために使用する表記法です zip リストの理解によって消費されます。

     = 0 : 1 : 0+1 : [ a + b | (a, b) <- zip [1, ??] [??]]
= 0 : 1 : 1 : [ a + b | (a, b) <- zip [1, ??] [??]]

これで、次の要素が ?? 〜です 1

     = 0 : 1 : 1 : [ a + b | (a, b) <- zip [1, 1, ??] [1, ??]]
= 0 : 1 : 1 : [ a + b | (a, b) <- (1, 1) : zip [1, ??] [??]]
= 0 : 1 : 1 : 1+1 : [ a + b | (a, b) <- zip [1, ??] [??]]
= 0 : 1 : 1 : 2 : [ a + b | (a, b) <- zip [1, ??] [??]]

そして次の要素は2です:

     = 0 : 1 : 1 : 2 : [ a + b | (a, b) <- zip [1, 2, ??] [2, ??]]

すすぎ、繰り返します。


回答№5の場合は1

括弧内のリストの理解:

[ a + b | (a, b) <- zip fibs (tail fibs)]

変数aとbの結果から得られる出力(a + b)を含むリストを返します

zip fibs (tail fibs)

答え№6の場合は1

価値があるものについては、次のバージョンの方がわかりやすいと思います。

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

回答№7は0

このストリーム図を定義します

           .----->>------->>----.
/                      
/                       /
                      /
<---- 0 <---- 1 ---<<--- (+)
/              
               
              /
*---->>------*

それはそれ自体から新しい入力を引き出します生成されますが、常に生成ポイントの前の1つと2つの位置によって、シーケンスへの2つの「バックポインター」をそのまま維持します。これは定義に反映されます fibs = 0:1:[ a+b | a <- fibs | b <- tail fibs]、並列リスト内包表記(:set -XParallelListComp 等。)。

最後のもののみを使用するため 要素、それは同等です

    map fst . iterate ((a, b) -> (b, a+b)) $ (0,1)

回答№8の場合は-1

そうでなければ、パーサーは(a、b)に何が入るかをどのようにして知るのでしょうか?

編集:ViralShahのおかげで、私はこれを少しグノミックにします。 「<-」は、右側の「zip fibs(テールfibs)」から左側の「(a、b)」にペアのリストを割り当てるようにパーサーに指示します。


答え№9の場合-1

私はまだ理解していません。この答えが好きです: https://stackoverflow.com/a/42183415/246387 (から コード見習い)。

しかし、私はこの行からどのように理解していない:

= 0 : 1 : 1 : [ a + b | (a, b) <- zip [1, ??] [??]]

これに移動します:

= 0 : 1 : 1 : [ a + b | (a, b) <- zip [1, 1, ??] [1, ??]]

そして、これに加えて、私は私を悩ます何かがあります:

どうやって使えますか fib 私が持っていない場合、リスト内包表記内 fib まったく(そうだと思われるが、確かに私は間違っている」 fib まだ計算されていません。 (等号の左側)で(等号の)右側で計算されるのを「待機」します。