Newest at the top
| 2026-06-28 13:42:18 +0000 | <fp> | Wild |
| 2026-06-28 13:42:10 +0000 | <tomsmeding> | and it uses unsafeInterleaveIO to achieve that |
| 2026-06-28 13:42:04 +0000 | <tomsmeding> | getContents returns a thunk that does IO when you look at it |
| 2026-06-28 13:41:41 +0000 | <tomsmeding> | fp: yes, with memoisation, that's the point |
| 2026-06-28 13:41:32 +0000 | <tomsmeding> | this means that what IO gets executed when depends on the evaluation order of your pure code, which normally is not allowed to happen in Haskell (because it makes reasoning extremely difficult) |
| 2026-06-28 13:41:30 +0000 | <fp> | perhaps with memoization as well |
| 2026-06-28 13:41:09 +0000 | <fp> | So in another language, lazy evaluation might look like `var foo = { get() { compute_foo() } }` |
| 2026-06-28 13:41:04 +0000 | <tomsmeding> | now if you do tricks to put a side effect inside a thunk, now suddenly you have pure code (that looks at the thunk and thus triggers its evaluation) that triggers IO |
| 2026-06-28 13:40:16 +0000 | <tomsmeding> | but that closure is a pure function, so you don't see it in the output (apart from being faster/slower/terminating) |
| 2026-06-28 13:39:56 +0000 | <fp> | Ok so getContents is magic in particular |
| 2026-06-28 13:39:54 +0000 | <tomsmeding> | lazy evaluation means that a part of a value may not actually be computed yet; it's a thunk, i.e. a closure, that gets evaluated whenever you try to look at it |
| 2026-06-28 13:39:28 +0000 | <fp> | That said, I did see RealWorld, which is cool. |
| 2026-06-28 13:39:06 +0000 | <tomsmeding> | which is not a REPL and not nearly as magic |
| 2026-06-28 13:39:00 +0000 | <tomsmeding> | if you have a simple implementation of getContents that just reads its input in IO as "normal", your REPL would be "read all input lines, then execute all of them" |
| 2026-06-28 13:38:36 +0000 | <fp> | Yeah I tried digging into getContents to see what it does. Suffice to say I didn't understand what was going on |
| 2026-06-28 13:37:53 +0000 | <tomsmeding> | that requires some unsafeInterleaveIO in getContents |
| 2026-06-28 13:37:37 +0000 | <tomsmeding> | """pure""" |
| 2026-06-28 13:37:25 +0000 | <tomsmeding> | fp: that example relies on 'contents' being a pure value that, when you look at it, does some IO to give you the thing you're trying to read |
| 2026-06-28 13:37:09 +0000 | <fp> | I guess I could simplify with map (show . eval) |
| 2026-06-28 13:36:29 +0000 | <tomsmeding> | RE(L)P |
| 2026-06-28 13:36:25 +0000 | <tomsmeding> | yeah but there's only one R and only one P, and the L is inside the E |
| 2026-06-28 13:36:08 +0000 | <mauke> | map is a loop |
| 2026-06-28 13:36:05 +0000 | <tomsmeding> | that's lazy IO, though, not just lazy evaluation |
| 2026-06-28 13:35:33 +0000 | <tomsmeding> | lol |
| 2026-06-28 13:35:25 +0000 | <fp> | Like there's no loop! my repl is a rep but it still works! |
| 2026-06-28 13:34:55 +0000 | <tomsmeding> | heh, yes that's fun |
| 2026-06-28 13:34:54 +0000 | <fp> | Maybe yeah |
| 2026-06-28 13:34:30 +0000 | <tomsmeding> | possibly with some serialised arguments |
| 2026-06-28 13:34:19 +0000 | <tomsmeding> | as in, instead of constructing an IO computation in the commanding process and sending it over to the fieldbus process, look at your application and write a normal `fn` that does the whole thing, put it in a list of functions (with a name for each), and have the commanding process tell the fieldbus process to "now execute function abc" |
| 2026-06-28 13:33:48 +0000 | emilym | (~Thunderbi@user/emilym) (Ping timeout: 256 seconds) |
| 2026-06-28 13:33:22 +0000 | <fp> | The magic is less now, though lazy evaluation still feels crazy to me. That you can make a repl with =getContents >>= \contents -> putStrLn $ (unlines . map show . map eval . lines) contents= is bonkers |
| 2026-06-28 13:33:10 +0000 | <tomsmeding> | if it's a different process on the same machine, I'd seriously consider if there is way to group your computations into "pre-made programs" that can be triggered by the commanding process as a whole |
| 2026-06-28 13:33:09 +0000 | chromoblob | (~chromoblo@user/chromob1ot1c) chromoblob\0 |
| 2026-06-28 13:31:53 +0000 | chromoblob | (~chromoblo@user/chromob1ot1c) (Read error: Connection reset by peer) |
| 2026-06-28 13:31:34 +0000 | <fp> | And also IO feels like magic sometimes and I wanted to understand it better |
| 2026-06-28 13:30:58 +0000 | <fp> | Yeah like I have some programs that are running with this fieldbus IO, but it's very timing sensitive, so I really need to move it to a different process (though same machine is probably fine). But then of course I have to develop a way to command IO actions of the other process, which is how I got here |
| 2026-06-28 13:30:01 +0000 | berke93___ | (~default@193.108.195.249) (Ping timeout: 266 seconds) |
| 2026-06-28 13:29:39 +0000 | <tomsmeding> | (I'm assuming "device" here is a separate piece of hardware that doesn't necessarily share a CPU architecture with the "main" computer) |
| 2026-06-28 13:29:05 +0000 | <tomsmeding> | which you can serde etc |
| 2026-06-28 13:28:55 +0000 | <tomsmeding> | that means you have to also write the stuff in the .bind() closures in your little language, but the payoff is that the thing you send to the device, and what you execute there, is just a regular old data type |
| 2026-06-28 13:28:42 +0000 | chromoblob | (~chromoblo@user/chromob1ot1c) chromoblob\0 |
| 2026-06-28 13:28:21 +0000 | <tomsmeding> | (I think you already suggested this) |
| 2026-06-28 13:28:10 +0000 | <tomsmeding> | an intermediate version that is much more feasible is defining a little language that you have an interpreter for on the device |
| 2026-06-28 13:27:57 +0000 | <fp> | That is a good question to ask, one that I should really consider |
| 2026-06-28 13:27:55 +0000 | chromoblob | (~chromoblo@user/chromob1ot1c) (Ping timeout: 276 seconds) |
| 2026-06-28 13:27:45 +0000 | <tomsmeding> | and what kind of computation do you actually want to run |
| 2026-06-28 13:27:18 +0000 | <tomsmeding> | because then the first thing I'd think about is "what kind of computation, aside from the precise representation of the IO operations, can I run on this device" |
| 2026-06-28 13:26:50 +0000 | <tomsmeding> | fp: can you just dispatch a single primitive IO action to the device, or do you really need to dispatch a larger program? |
| 2026-06-28 13:26:16 +0000 | <tomsmeding> | I feel like this is wrapping closures in IO instead of IO in closures |
| 2026-06-28 13:26:00 +0000 | <hc> | (Not that I'm saying I particularly like async rust) |