Способ мышления об этом, который я читал где-то, что действительно помогло мне в этом вопросе, состоит в том, чтобы посмотреть на это так:
- Каждое выражение производит thunk .
- Thunks будет принудительным , когда их значение «необходимо».
- Понятие «потребность» - это то, что вы можете назвать «условное принуждение»: «Предполагая, что переходник T принуждается, какие еще громовые толчки будут вызваны? "Функция является строгой в своем аргументе, если форсирование thunk, который применяет эту функцию, вызывает принудительный вызов ее аргумента.
Таким образом, значения выводятся на консоль путем вызова соответствующегоshow
метод на них;т. е. печать на консоль вызывает выражение вида show x
(для некоторых x
).Вынужденные show x
силы x
.Предположим, что x
равно negate $ 5 * sqrt 16
;поскольку negate
является строгим в своем аргументе, форсирование thunk также заставляет thunk для 5 * sqrt 16
.Аналогично, *
и sqrt
оба являются строгими в своих аргументах, поэтому также необходимо принудительно указывать на 5
, sqrt 16
и 16
.
Другая вещь, которую нужно понять, это то, как данныеконструкторы и сопоставление с образцом влияют на тункинг.По сути, если нет специальных аннотаций строгости, конструкторы похожи на нестрогие функции, в этом форсирование thunk не вызывает аргументы конструктора.Если не используется специальный синтаксис сопоставления с ленивым образцом, сопоставление с конструктором вызывает аргумент thunk.Итак имеем:
identity x = x -- irrefutable pattern; `x` is not forced
uncons (x:xs) = (x, xs) -- match against (:) constructor; argument
-- must be forced, but x and xs aren't forced
foo (x:x':xs) = (x, x', xs) -- two matches against (:) constructor;
-- the argument thunk is forced, as is its
-- tail thunk.