Подтвердить что ты не робот

Как действует функция seq force?

Фон

Этот вопрос возникает из-за того, что Брент Йорги поставил на OPLSS: напишите функцию f :: (Int -> Int) -> Bool, которая отличает f undefined от f (\x -> undefined). Все наши ответы либо использовали seq, либо что-то вроде шаблонов ударов, которые desugar в 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
4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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

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 и т.д. Весь полезный материал.