解決策があり、解決策があります。最初に解決策から始めて、解決策に向かって進みましょう。
最初に観察することは、あなたが主張した結果が必要な場合は、型を変更し、もう少しラッピングを行う必要があるということです:
-- was pascal :: Integer -> [Integer]
pascal :: Integer -> [[Integer]]
pascal 0 = [[1]]
pascal m = [x | x <- pascal (m-1)] ++ [[choose m k | k <- [0,1..m]]]
さて、いくつかの[x | x <- foo]
構文ポインタ:foo
[0,1..m]
[0..m]
pascal m = pascal (m-1) ++ [[choose m k | k <- [0..m]]]
これにより、再帰呼び出しごとに別のリストの末尾にシングルトン リストが追加されていることがわかります。これは非効率的です。前からリストを作成する方がよいでしょう。したがって、一般的なリファクタリングを使用します。アキュムレータを使用してヘルパーを作成します。
pascal = go [] where
go 0 acc = [1] : acc
go m acc = go (m-1) ([choose m k | k <- [0..m]] : acc)
次の観察は、毎回再計算するよりも少し効率的に物事を行うことができるということですchoose m k
: 前の行といくつかの加算のみを使用して、パスカルの三角形の次の行を計算できます。これは、パスカルの三角形のすべての行の遅延 (無限) リストを作成できることを意味します。
nextRow vs = [1] ++ zipWith (+) vs (tail vs) ++ [1]
allPascals = iterate nextRow [1]
最後に、パスカルの三角形のすべての行はその中点に対して対称であるため、各行の前半だけの無限リストを作成しようとする場合があります。これには、残りの「リストの最後に追加」操作を排除するという利点があります。これは演習として残します。行は偶数の要素と奇数の要素の間で交互に配置されることに注意してください。これにより、この部分が少しトリッキー (かつ醜い) になります。