Newest at the top
2025-01-20 03:49:49 +0100 | <monochrom> | But here is also a low-level reason. |
2025-01-20 03:49:40 +0100 | <monochrom> | Anyway, that's a high-level reason why I don't make a distinction between "call stack like in C" and "eval stack like in Haskell". (I'm also mocking the irony there too because neither ISO C nor Haskell 2010 require a stack.) They are all continuation stacks, and once you know the evaluation order you know what continuation means. |
2025-01-20 03:46:02 +0100 | <monochrom> | Yeah you're just trading heap for stack. It's why I was so worked up about limited stack and unlimited heap. |
2025-01-20 03:45:47 +0100 | <geekosaur> | that's what I said, wall-o-wtf 🙂 |
2025-01-20 03:45:39 +0100 | hgolden | (~hgolden@2603:8000:9d00:3ed1:6ff3:8389:b901:6363) hgolden |
2025-01-20 03:45:29 +0100 | <albet70> | I like this talks even I don't understand now, it's very inspired :) |
2025-01-20 03:45:00 +0100 | <int-e> | monochrom: Heh. So if you use Cont or other (a -> r) -> (b -> r) -> r Haskell-level continuations, then at runtime, you have thunk-level CPS (continuations are stored in thunks until needed) |
2025-01-20 03:43:58 +0100 | hgolden | (~hgolden@2603:8000:9d00:3ed1:6ff3:8389:b901:6363) (Remote host closed the connection) |
2025-01-20 03:43:29 +0100 | Adran | (~adran@botters/adran) Adran |
2025-01-20 03:42:44 +0100 | merijn | (~merijn@128-137-045-062.dynamic.caiway.nl) (Ping timeout: 265 seconds) |
2025-01-20 03:41:25 +0100 | <monochrom> | Ooops, s/small// |
2025-01-20 03:40:07 +0100 | <monochrom> | In this case, context is synonym for continuation. |
2025-01-20 03:39:55 +0100 | <geekosaur> | unless they drowned in the wall-o-wtf |
2025-01-20 03:39:47 +0100 | <monochrom> | If you then try to go a bit lower level, you say: push the context (or representation of) on the stack, bring the redex to the front and work on it, afterwards pop the context and look for the next redex, etc. |
2025-01-20 03:39:26 +0100 | <int-e> | geekosaur: *surely* one of the many answers we've come up with was satisfactory |
2025-01-20 03:38:15 +0100 | <monochrom> | At a high level, it goes like this. Given an evaluation order, you can factor each to-be-evaluated expression into redex and context. Redex means the small subexpression to evaluate right now, context is the rest. |
2025-01-20 03:38:05 +0100 | merijn | (~merijn@128-137-045-062.dynamic.caiway.nl) merijn |
2025-01-20 03:37:50 +0100 | <geekosaur> | you know we probably lost albet70 long ago… |
2025-01-20 03:37:31 +0100 | peterbecich | (~Thunderbi@syn-047-229-123-186.res.spectrum.com) peterbecich |
2025-01-20 03:33:51 +0100 | <monochrom> | Fortunately! PLT people have noticed a commonality over all evaluation orders. The "some things" is called... continuations. You can always say "continuation stack" and it will be always right. |
2025-01-20 03:32:42 +0100 | <monochrom> | Once you fix an evaluation order, you will realize you need a stack for some things. Eager and lazy have opposite "some things", but both will need a stack. |
2025-01-20 03:30:07 +0100 | <int-e> | Well, not sure. But the chances are good. |
2025-01-20 03:29:28 +0100 | <int-e> | Anyway. Understanding Haskell low-level execution is quite difficult. I'm sure I'm getting it subtly wrong. |
2025-01-20 03:28:13 +0100 | <int-e> | (the strictness analyser can spoil the fun of course) |
2025-01-20 03:27:42 +0100 | <int-e> | because that *tail-recusively* builds a huge thunk that is then entered, entering a chain of subthunks all at once |
2025-01-20 03:27:21 +0100 | merijn | (~merijn@128-137-045-062.dynamic.caiway.nl) (Ping timeout: 244 seconds) |
2025-01-20 03:26:58 +0100 | <int-e> | But the thunk thing explains why `foldl (+) 1 [1..1000000]` used to overflow the stack (before stacks were made extensible) |
2025-01-20 03:26:17 +0100 | <geekosaur> | (in a profiling report, you do get an indication of call stacks of some flavor) |
2025-01-20 03:26:01 +0100 | <int-e> | (GHC does way too much inlining, for starters. And you'd need to anticipate strictness analysis too.) |
2025-01-20 03:25:28 +0100 | <int-e> | Details get murky quickly. You won't be able to discern most of these things at the source code level. |
2025-01-20 03:24:01 +0100 | <geekosaur> | I know you can piggyback on the mechanism to get a "stack trace" (with +RTS -xc) *but* profiling must be enabled for it to work; I presume that provides something resembling a call stack |
2025-01-20 03:23:59 +0100 | <int-e> | AIUI, fundamentally, entering a thunk allocates a stack frame. This extends to strict functions (which can be thought of as a thunk that is entered immediately, but GHC won't allocate the thunk) |
2025-01-20 03:23:32 +0100 | <c_wraith> | ghc uses the stack for nested evaluation of thunks. That often corresponds with nested function calls, but not always. |
2025-01-20 03:22:43 +0100 | merijn | (~merijn@128-137-045-062.dynamic.caiway.nl) merijn |
2025-01-20 03:22:28 +0100 | <geekosaur> | (possibly it's all exception frames. note that in Haskell you must be in IO to handle an exception, so things are a bit different than they are for pure code anyway) |
2025-01-20 03:21:33 +0100 | <geekosaur> | in GHC Haskell these frames don't correspond to calls the way they do in more procedural languages; but I don't recall what they do correspond to. |
2025-01-20 03:20:36 +0100 | <probie> | "true" CPS codeâ„¢ (with TCO) doesn't allocate stack frames |
2025-01-20 03:18:38 +0100 | <geekosaur> | in all cases it works backwards up stack frames until it finds one with an exception handler |
2025-01-20 03:17:42 +0100 | <monochrom> | THANK YOU! |
2025-01-20 03:17:22 +0100 | <int-e> | The game we're playing could be called "pick your favorite abstraction to think about your code". |
2025-01-20 03:17:18 +0100 | <geekosaur> | exceptions pretty much require it |
2025-01-20 03:17:02 +0100 | <geekosaur> | so does GHC for that matter |
2025-01-20 03:16:54 +0100 | <geekosaur> | so does C++ |
2025-01-20 03:16:51 +0100 | <geekosaur> | it does stack unwinding |
2025-01-20 03:16:43 +0100 | <int-e> | On a different level, the answer is no; you can't have a pure function with an early return. Obviously not; that wouldn't be pure. |
2025-01-20 03:16:36 +0100 | <monochrom> | I'm going to go out on a limb that Python achieves that by compiling an exception language to CPS low level code. |
2025-01-20 03:15:58 +0100 | <int-e> | Which you can read as ParsecT wrapping a function that takes *four* continuations |
2025-01-20 03:15:39 +0100 | <c_wraith> | You need to make significant changes, because the whole point is that you're replacing nested function calls with continuations |
2025-01-20 03:15:38 +0100 | <int-e> | For example, look at this https://hackage.haskell.org/package/parsec-3.1.18.0/docs/src/Text.Parsec.Prim.html#ParsecT |
2025-01-20 03:15:23 +0100 | <int-e> | The answer is yes but you have to change all your functions to take continuations as arguments. (Whether you do that using Cont or not is up to you.) |