Я играл с примерами из книги Симона Марлоу о параллельных и параллельных программирования в 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)
, но не при загрузке определения из файла. Мое подозрение в том, что
это как-то связано с привязкой к шаблону, но я не знаю, где искать это для разъяснения (возможно, я просто совершенно совершенно не прав). Я бы ожидал, что он каким-то образом будет вести себя как пример в файле.
Любые указатели или краткое объяснение, почему это происходит?