How does Haskell (GHC) runtime know what code should be executed next after evaluation of a thunk?
On a conceptual level, how is that different from call stack in other programming languages (other than storing closed variables on heap and having tail recursion)?
GHC (or rather, the GHC RTS) has a normal call stack, like most things.
What's different is the contents of this stack. It doesn't match what you might expect.
Suppose that function
foo
calls functionbar
which calls functionbaz
. You might be expecting the call stack to look likeat some point. But actually, when
foo
callsbar
, all the "call" really does is create a thunk and return instantly. Sobar
doesn't appear on that stack at that point. But whenfoo
returns some data to the caller, and the caller decides to do something with it, at that pointbar
may appear on the call stack, even thoughfoo
is nowhere to be seen.In short, the order of stuff on the call stack is unrelated to who calls who. It's determined by who looks at what.