Как работает seq force? - PullRequest
       40

Как работает seq force?

26 голосов
/ 22 июня 2011

Фон

Этот вопрос возникает из задачи, которую Брент Йорги поставил на OPLSS: напишите функцию f :: (Int -> Int) -> Bool, которая отличает f undefined от f (\x -> undefined).Во всех наших ответах использовались либо seq, либо что-то вроде паттернов взрыва, которые вводятся в seq.Например:

f :: (Int -> Int) -> Bool
f g = g `seq` True

*Main> f undefined
*** Exception: Prelude.undefined
*Main> f (\x -> undefined)
True

В комментарии GHC к seq говорится, что

e1 `seq` e2 

используется для десугарации в

case e1 of { _ -> e2 }

, поэтомуЯ попытался desugaring вручную.Это не сработало:

f' g = case g of { _ -> True }

*Main> f' undefined
True
*Main> f' (\x -> undefined)
True

Вопрос

Зависит ли это поведение от более сложного seq, описанного в конце комментария , и если да, то, как это работает?Может ли такой f быть написан без этих примитивов?

x  `seq` e2 ==> case seq# x RW of (# x, _ #) -> e2    -- Note shadowing!
e1 `seq` e2 ==> case seq# x RW of (# _, _ #) -> e2

Ответы [ 2 ]

23 голосов
/ 22 июня 2011

seq не может быть реализовано в Haskell. Вместо этого, это примитивный «крючок» в оценке к нормальной форме слабой головы в любой среде выполнения, на которой работает ваш Haskell. Например. в GHC он компилируется в case в GHC Core, который запускает оценку для самого внешнего конструктора.

Поскольку он не может быть реализован в чистом Haskell, он определен (в GHC) как прим:

pseudoop   "seq"
       a -> b -> b
       { Evaluates its first argument to head normal form, and then returns its second
         argument as the result. }

Поскольку функции не имеют нормальной формы, seq останавливает оценку, как только она достигает единицы.

Магически доступен для компилятора. То же самое касается других примитивов, таких как par или unsafeCoerce, токен RealWorld, forkOn и так далее. Все полезные вещи.

9 голосов
/ 30 июня 2011

Существует более высокоуровневое описание STG-машины в Как сделать быстрое карри: push / enter vs eval / apply

Рисунок 2 содержит правило CASEANY, которое работает дляфункции.В этой статье выражение «является значением» означает либо:

  • это приложение с насыщенным конструктором
  • это функция
  • это приложение с частичной функцией (это семантически функция, все еще являющаяся функцией)

Специально обрабатываются незарегистрированные значения, включая литералы, более подробную информацию можно найти в Записанные значения как граждане первого класса

Все это детали реализации и скрыты внутри компилятора (GHC).Выражение case в Haskell не требует его проверки, только сопоставление с образцом и seq do.

...