Haskell では、リストには特別な操作上の取り扱いはありません。それらは次のように定義されます。
data List a = Nil | Cons a (List a)
[a]
for List a
、[]
for Nil
、および(:)
forという特別な表記法がありCons
ます。同じものを定義し、すべての操作を再定義すると、まったく同じパフォーマンスが得られます。
したがって、Haskell のリストは単一リンクです。怠惰なため、イテレータとしてよく使用されます。 sum [1..n]
このリストの未使用のプレフィックスは、合計が進むにつれてガベージ コレクションされ、テールは必要になるまで生成されないため、定数空間で実行されます。
#4 について: Haskellのすべての値はメモ化されていますが、関数は引数のメモ テーブルを保持していません。したがって、あなたが行ったように定義するfib
と、結果がキャッシュされ、n 番目のフィボナッチ数が O(n) 時間でアクセスされます。ただし、この明らかに同等の方法で定義した場合:
-- Simulate infinite lists as functions from Integer
type List a = Int -> a
cons :: a -> List a -> List a
cons x xs n | n == 0 = x
| otherwise = xs (n-1)
tailF :: List a -> List a
tailF xs n = xs (n+1)
fib :: List Integer
fib = 1 `cons` (1 `cons` (\n -> fib n + tailF fib n))
(あなたの定義との類似性に注意してください)
その後、結果は共有されず、n 番目のフィボナッチ数は O(fib n) (指数関数的) 時間でアクセスされます。関数をdata-memocombinators のようなメモ化ライブラリと共有するように説得できます。