Вопрос

Этот FAQ Говорит, что

Оператор seq

seq :: a -> b -> b

Икс seq Y оценит X, достаточно, чтобы проверить, что он не внизу, а затем отбросьте результат и оцените Y.Это может показаться не полезным, но это означает, что X гарантированно оценивается до рассмотрения Y.

Это очень мило со стороны Haskell, но значит ли это, что в

x `seq` f x

стоимость оценки x будет выплачена дважды («сбросить результат»)?

Это было полезно?

Решение

А seq функция отбросит значение x, но поскольку значение было вычислено, все ссылки на x «обновлены», чтобы больше не указывать на неоцененную версию x, а вместо этого указывать на оцененную версию.Итак, хотя seq оценивает и отбрасывает x, значение было оценено для других пользователей x а также, что приводит к отсутствию повторных оценок.

Другие советы

Нет, это не «вычислить и забыть», это «вычислить», что требует кэширования.

Например, рассмотрим этот код:

 let x = 1 + 1
 in x + 1

Поскольку Haskell ленив, это оценивается как ((1 + 1) + 1).Thunk, содержащий сумму thunk и единицы, причем внутренний thunk равен единице плюс один.

Давайте воспользуемся javascript, неленивым языком, чтобы показать, как это выглядит:

 function(){
   var x = function(){ return 1 + 1 };
   return x() + 1;
 }

Объединив такие мысли, можно вызвать переполнение стека, если это делается неоднократно, так seq в помощь.

let x = 1 + 1
in x `seq` (x + 1)

Я лгу, когда говорю вам, что это оценивается как (2 + 1), но это почти правда - просто вычисление 2 принудительно происходит до того, как произойдет остальное (но 2 все равно вычисляется лениво).

Возвращаясь к javascript:

 function(){
   var x = function(){ return 1 + 1 };
   return (function(x){
     return x + 1;
   })( x() );
 }

Я считаю x будет оценен только один раз (и результат сохранится для использования в будущем, что типично для ленивых операций).Именно такое поведение делает seq полезный.

Вы всегда можете уточнить у unsafePerformIO или trace

import System.IO.Unsafe (unsafePerformIO)

main = print (x `seq` f (x + x))
  where
    f = (+4)
    x = unsafePerformIO $ print "Batman!" >> return 3

Конечно seq само по себе делает нет «оценивать» что-либо.Он просто записывает зависимость порядка принудительного выполнения.Само принуждение инициируется сопоставлением с образцом.Когда seq x (f x) вынужден, x сначала будет принудительно выполнено (запоминание полученного значения), а затем f x будет вынужден.Ленивая оценка Haskell означает, что он запоминает результаты принудительного выполнения выражений, поэтому повторная «оценка» (здесь пугающие кавычки) выполняться не будет.

Я заключил слово «оценка» в пугающие кавычки, потому что оно подразумевает полный оценка.По словам Викибук по Хаскелю,

«Значения Haskell очень многоуровневы;«Оценка» значения Haskell может означать оценку любого из этих уровней».

Позвольте мне повторить: seq сам по себе ничего не оценивает. seq x x не оценивает x ни при каких обстоятельствах. seq x (f x) ничего не оценивает, когда f = id, вопреки чему Отчет кажется, говорил.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top