Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding the different behavior of thunks when GHCi let bindings are involved

I've been playing with some examples from Simon Marlow's book about parallel and concurrent programming in Haskell and stumbled across an interesting behavior that I don't really understand. This is really about me trying to understand some of the inner workings of GHC.

Let's say I do the following in the REPL:

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

Ok, this is pretty much what I expected except that z gets evaluated to WHNF already. Let's write a similar program and put it in a file:

module Thunk where

import Debug.Trace

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

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

And fiddle around with it in GHCi:

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

So this behaves a little different: z is not evaluated to WHNF in advance. My question is:

Why is z evaluated to WHNF in the REPL when doing let z = (x,x) but not when loading the definition from a file. My suspicion is that it has something to do with pattern binding but I don't know where to look that up for clarification (maybe I'm just completely utterly wrong). I would have expected it to somehow behave like the example in the file.

Any pointers or a brief explanation why this happens?

like image 326
raichoo Avatar asked Jul 15 '14 10:07

raichoo


1 Answers

Because (,) is a constructor, the difference makes no difference to Haskell's semantics (:sprint gives access to internal thunk implementation details so doesn't count.) So this is a question of which optimizations and trade-offs GHC does when compiling (x,x) in different positions. Someone else may know the precise reason in these cases.

like image 64
Ørjan Johansen Avatar answered Oct 15 '22 09:10

Ørjan Johansen