Когда полезно использовать "строгий шаблон" в Haskell и что он делает?
Я смотрел на некоторый исходный код Haskell и наткнулся на совпадение с шаблоном !_
, код здесь: http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.List.html#unsafeTake
take n xs | 0 < n = unsafeTake n xs
| otherwise = []
-- A version of take that takes the whole list if it given an argument less
-- than 1.
{-# NOINLINE [1] unsafeTake #-}
unsafeTake :: Int -> [a] -> [a]
unsafeTake !_ [] = []
unsafeTake 1 (x: _) = [x]
unsafeTake m (x:xs) = x : unsafeTake (m - 1) xs
Я действительно не понимаю, как работает "строгий шаблон" и почему он полезен для этой функции (или любой другой функции).
Ответы
Ответ 1
Идея состоит в том, что unsafeTake
(и take
, если на то пошло), когда его попросят вернуть первые m
элементы пустого списка, он должен вернуть пустой список, независимо от того, что значение m
есть. Но что, если m
- выражение, которое выдает исключение? Например, для unsafeTake undefined []
было бы странно возвращать []
. Поэтому нам нужно убедиться, что m
оценивается как целое, даже если нам все равно, что его точное значение (для случая с пустым списком, конечно). Это заставляет unsafeTake
вести себя одинаково, когда дело доходит до его первого аргумента, неважно, является ли второй аргумент (список) пустым или нет.