Что означает Нормальная Форма Слабой Головы (WHNF)? Что означают нормальная форма головы (HNF) и нормальная форма (NF)?
Реальный мир Haskell утверждает:
Привычная функция seq вычисляет выражение к тому, что мы называем нормальной головой (сокращенно HNF). Он останавливается, как только достигает самого внешнего конструктора ("головы"). Это отличается от нормальной формы (NF), в которой выражение полностью оценивается.
Вы также услышите, что программисты на Haskell ссылаются на нормальную форму слабой головы (WHNF). Для нормальных данных слабая нормальная форма головы такая же, как нормальная форма головы. Разница возникает только для функций, и она слишком сложна, чтобы беспокоить нас здесь.
Я прочитал несколько ресурсов и определений (Haskell Wiki и Список рассылки Haskell и Бесплатный словарь), но не понимаю. Может ли кто-нибудь привести пример или дать определение непрофессионала?
Я предполагаю, что это будет похоже на:
WHNF = thunk : thunk
HNF = 0 : thunk
NF = 0 : 1 : 2 : 3 : []
Как seq
и ($!)
Связаны с WHNF и HNF?
Обновить
Я все еще в замешательстве. Я знаю, что некоторые ответы говорят, чтобы игнорировать HNF. Из прочтения различных определений кажется, что нет никакой разницы между обычными данными в WHNF и HNF. Тем не менее, кажется, что есть разница, когда дело доходит до функции. Если не было никакой разницы, почему seq
необходим для foldl'
?
Еще одна путаница связана с тем, что Haskell Wiki утверждает, что seq
сводится к WHNF, и ничего не будет делать в следующем примере. Затем они говорят, что им нужно использовать seq
для форсирования оценки. Разве это не принуждает его к HNF?
Общий код новичков:
myAverage = uncurry (/) . foldl' (\(acc, len) x -> (acc+x, len+1)) (0,0)
Люди, которые понимают seq и нормальную форму слабой головы (whnf), могут сразу понять, что здесь не так. (acc + x, len + 1) уже находится в whnf, поэтому seq, который уменьшает значение до whnf, ничего не делает для этого. Этот код будет создавать thunks точно так же, как и оригинальный пример foldl, они просто будут внутри кортежа. Решение состоит в том, чтобы просто заставить компоненты кортежа, например,
myAverage = uncurry (/) . foldl' (\(acc, len) x -> acc 'seq' len 'seq' (acc+x, len+1)) (0,0)