3

次のHaskell関数を理解するのに助けが必要です。

split l = rr++[ll]
            where
              split = foldl
                        ( \ (c,a) e ->
                               case c of
                                [] -> ([e],a)  
                                _ -> if e*(head c) < 0
                                     then ([e],a++[c])
                                     else (c++[e],a))
                        ([],[])
              (ll,rr) = split l

> split [1,2,3,-1,-2,7,4,-3,-5,-6,2,3]
[[1,2,3],[-1,-2],[7,4],[-3,-5,-6],[2,3]]

上記のように、同じ符号の連続する番号を別々のリストに分割します。スキームでは、トレーサー関数は式を段階的に評価するのに非常に役立ちましたが、残念ながら、GHCiにはそのような機能がありません。コードをステップスルーするのを手伝ってください。ありがとう!

注:関数のfoldl部分を理解しています。本当に混乱するのはパターンマッチング部分(split l = rr++[ll]と)です!(ll,rr) = split l

4

2 に答える 2

8

ここで混乱するかもしれないsplitのは、実際には内部がトップレベルとはwhereまったく異なることです。ローカル変数がグローバル変数をオーバーライドするのと同じように、内部変数は外部変数を「シャドウ」します。split次のコードはまったく同じことをします:

split l = rr++[ll]
            where
              notSplit = foldl
                        ( \ (c,a) e ->
                               case c of
                                [] -> ([e],a)  
                                _ -> if e*(head c) < 0
                                     then ([e],a++[c])
                                     else (c++[e],a))
                        ([],[])
              (ll,rr) = notSplit l

したがってnotSplit、タプルを返す入力リストを呼び出し(ll,rr)、それを計算rr ++ [ll]して返します。

(私のコメントが上で述べたように、アルゴリズムは不必要に曖昧で、非効率的で、ゼロを含むリストでは正しくありません。しかし、それは完全に別の問題です)。

于 2012-12-14T03:47:08.603 に答える
4

foldl式が何を生み出すかを正確に考えてください。リストを通過するにつれて、タプルが蓄積され(c, a)ます。このタプルの最初の要素であるc、は、常に数値のリストです。a数字のリストのリストです---これはたまたまあなたが返したいものです。

新しい番号を取得したときに、の番号と同じ符号の場合はc、に追加しcます。現在の記号とは異なる記号がある場合は、cすべてを取得してにc入れaます。

c最後に、との最後の値のタプルを取得しますaa完全ではないことを除いて、ほぼ正確に希望する結果になります。追加する必要がありますc。つまり、表現の最後です

(ll, rr) = split l

splitcと)の結果を取得し、とにa割り当てます。最終的な答えは、最後に追加されます。cllarrrrll

于 2012-12-14T03:49:21.673 に答える