splitAt
関数は(https://wiki.haskell.org/Lazy_pattern_match)以下のように実施することができる。なぜ遅延パターンがsplitAt関数のバージョンにマッチするのですか?
import Prelude hiding (splitAt)
splitAt :: Int -> [a] -> ([a], [a])
splitAt n xs =
if n<=0
then ([], xs)
else
case xs of
[] -> ([], [])
y:ys ->
case splitAt (n-1) ys of
~(prefix, suffix) -> (y : prefix, suffix) -- Here using lazy pattern match
main :: IO()
main = do
let r = splitAt 1000000 $ repeat 'a'
print $ length $ fst r
と厳格なパターンマッチを使用しては非常に速度を遅くすることができます。
time ./lazy -- 0.04s user 0.00s system 90% cpu 0.047 total
time ./strict -- 0.12s user 0.02s system 96% cpu 0.147 total
理由がわかりません。この記事によると、厳密なバージョンでは、パターンが適合するかどうかを確認するために、より多くのメモリとすべての再帰呼び出しが必要になる場合があります。しかし、私は怠惰なバージョンもすべての再帰呼び出しを必要とし、再帰関数呼び出しの結果を格納するメモリが必要だと思います。その違いは何ですか?