明示的共有と暗黙的共有についてです。ものに明示的に名前を付けると、自然に共有できます。つまり、メモリ内に個別のエンティティとして存在し、再利用できます。(もちろん、共有は言語自体の一部ではありません。特定のものを共有するようにコンパイラーを微調整することしかできません)。
しかし、同じ式を 2 回または 3 回記述すると、コンパイラに依存して、共通のサブ式を 1 つの明示的に共有されたエンティティに置き換えます。それは起こるかもしれないし、起こらないかもしれません。
最初のバリアントは次と同等です
memoized_fib :: Int -> Integer
memoized_fib = (map fib [0 ..] !!) where
fib 0 = 0
fib 1 = 1
fib n = memoized_fib (n-2) + memoized_fib (n-1)
ここでは、エンティティに具体的な名前を付けて、その名前で参照します。しかし、それは機能です。再利用をさらに確実にするために、ここで共有される実際の値のリストに明示的に名前を付けることができます。
memoized_fib :: Int -> Integer
memoized_fib = (fibs !!) where
fibs = map fib [0 ..]
fib 0 = 0
fib 1 = 1
fib n = memoized_fib (n-2) + memoized_fib (n-1)
最後の行は、ここで共有されている実際のエンティティ (上記の手順で名前を付けたリスト) を明示的に参照することで、さらに視覚的にわかりやすくすることができます。fibs
fib n = fibs !! (n-2) + fibs !! (n-1)
2番目のバリアントはこれと同等です:
memoized_fib :: Int -> Integer
memoized_fib = (map fib [0 ..] !!) where
fib 0 = 0
fib 1 = 1
fib n = (map fib [0 ..] !!) (n-2) + (map fib [0 ..] !!) (n-1)
ここには、一見独立しているように見える 3 つのmap
式があり、コンパイラによって共有される場合と共有されない場合があります。でコンパイルするとghc -O2
、共有が再導入され、速度が向上するようです。