haskell lazy-evaluation ghci thunk weak-head-normal-form

haskell - Comprender el comportamiento diferente de los thunks cuando GHCi permite enlaces implicados



lazy-evaluation weak-head-normal-form (1)

Debido a que (,) es un constructor, la diferencia no hace ninguna diferencia en la semántica de Haskell ( :sprint da acceso a los detalles internos de la implementación de thunk para que no cuente). Así que esta es una cuestión de qué optimizaciones y compensaciones hace GHC al compilar (x,x) en diferentes posiciones. Alguien más puede saber la razón precisa en estos casos.

He estado jugando con algunos ejemplos del libro de Simon Marlow sobre programación paralela y concurrente en Haskell y tropecé con un comportamiento interesante que realmente no entiendo. Esto es realmente acerca de mí tratando de entender algunos de los mecanismos internos de GHC.

Digamos que hago lo siguiente en REPL:

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

Ok, esto es más o menos lo que esperaba, excepto que z ya es evaluado por WHNF. Vamos a escribir un programa similar y ponerlo en un archivo:

module Thunk where import Debug.Trace x :: Int x = trace "add" $ 1 + 2 z :: (Int,Int) z = (x,x)

Y jugar con él en GHCi:

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

Entonces esto se comporta un poco diferente: z no se evalúa a WHNF de antemano. Mi pregunta es:

¿Por qué se evalúa z a WHNF en REPL cuando se hace let z = (x,x) pero no al cargar la definición desde un archivo? Mi sospecha es que tiene algo que ver con el enlace de patrones, pero no sé dónde buscar eso para aclararlo (tal vez estoy totalmente equivocado). Hubiera esperado que se comportara de alguna manera como el ejemplo en el archivo.

¿Alguna sugerencia o una breve explicación de por qué sucede esto?