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

Понимание различного поведения thunks, когда GHCi допускает привязки

Я играл с примерами из книги Симона Марлоу о параллельных и параллельных программирования в Haskell и наткнулся на интересное поведение, которое я действительно не понимаю. Это действительно о том, что я пытаюсь понять некоторые из внутренних действий GHC.

Скажем, я делаю следующее в REPL:

λ» let x = 1 + 2 :: Int
λ» let z = (x,x)
λ» :sprint x
x = _
λ» :sprint z
z = (_,_)
λ» seq x ()
()
λ» :sprint z
z = (3,3)

Хорошо, это в значительной степени то, что я ожидал, за исключением того, что z уже оценивается WHNF. Позвольте написать аналогичную программу и поместить ее в файл:

module Thunk where

import Debug.Trace

x :: Int
x = trace "add" $ 1 + 2

z :: (Int,Int)
z = (x,x)

И играйте с ним в GHCi:

λ» :sprint x
x = _
λ» :sprint z
z = _
λ» seq x ()
add
()
λ» :sprint z
z = _
λ» seq z ()
()
λ» z
(3,3)

Итак, это немного отличается: z заранее не оценивается WHNF. Мой вопрос:

Почему z оценивается WHNF в REPL при выполнении let z = (x,x), но не при загрузке определения из файла. Мое подозрение в том, что это как-то связано с привязкой к шаблону, но я не знаю, где искать это для разъяснения (возможно, я просто совершенно совершенно не прав). Я бы ожидал, что он каким-то образом будет вести себя как пример в файле.

Любые указатели или краткое объяснение, почему это происходит?

4b9b3361

Ответ 1

Поскольку (,) является конструктором, разница не имеет никакого отношения к семантике Haskell (:sprint предоставляет доступ к внутренним деталям реализации thunk, поэтому не учитывается.) Таким образом, это вопрос, какие оптимизации и компромиссы GHC при компиляции (x,x) в разных положениях. Кто-то может знать точную причину в этих случаях.