2026/06/28

Newest at the top

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 +0000chromoblob(~chromoblo@user/chromob1ot1c) chromoblob\0
2026-06-28 13:31:53 +0000chromoblob(~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 +0000berke93___(~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 +0000chromoblob(~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 +0000chromoblob(~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)
2026-06-28 13:25:44 +0000 <hc> Hmm, not having read the backlog thoroughly, but isn't that pretty much what rust's async/"Futures" do? Wrap IO in closures?
2026-06-28 13:25:26 +0000 <tomsmeding> because an arbitrary IO action contains calls to primitive IO operations as well as "pure" glue code that decides what next action to take
2026-06-28 13:25:23 +0000 <fp> Sure
2026-06-28 13:24:52 +0000 <tomsmeding> and serialise, transfer and deserialise the closures
2026-06-28 13:24:42 +0000 <tomsmeding> if you want to dispatch the IO computation to a device, and you describe IO like Haskell does, you'll need to also run arbitrary Rust code on the device
2026-06-28 13:23:33 +0000 <fp> What I'm imagining is that a user can describe a complex IO action and that can be dispatched to the IO device or to a server that does the IO and they get back either the expected data or a rich error
2026-06-28 13:18:57 +0000 <fp> Or generally like an interpreter
2026-06-28 13:18:56 +0000 <tomsmeding> is that what you need?
2026-06-28 13:18:54 +0000 <tomsmeding> what Haskell's "IO" gives you is a data type for describing arbitrary side-effectful computations in a non-side-effectful language
2026-06-28 13:18:34 +0000 <fp> I guess building a stack machine might be more reasonable
2026-06-28 13:18:06 +0000 <tomsmeding> hm, no that still has closures everywhere
2026-06-28 13:17:46 +0000 <tomsmeding> you might have more luck with the free monad encoding
2026-06-28 13:17:38 +0000 <fp> Yeah I'm seeing that
2026-06-28 13:17:27 +0000 <tomsmeding> I think this experience is enough to show that Haskell's way of representing an IO computation -- using closures -- is not usable in Rust :p
2026-06-28 13:16:34 +0000 <fp> "T may not live long enough"
2026-06-28 13:16:23 +0000 <fp> Ultimately, my goal isn't to emulate Haskell per se, but to have a composable Io interface in Rust. For context, I'm testing this out to see if I could make an API for an industrial fieldbus this way
2026-06-28 13:15:28 +0000 <tomsmeding> what precisely is the error? ret() owns t, right, so it should be able to move it into the closure
2026-06-28 13:14:42 +0000 <fp> No, move doesn't work
2026-06-28 13:14:23 +0000 <tomsmeding> and yes my rust is rusty, add Box<> as necessary
2026-06-28 13:13:54 +0000 <tomsmeding> also not if you `move || t`?
2026-06-28 13:12:51 +0000emilym(~Thunderbi@user/emilym) emilym
2026-06-28 13:11:45 +0000 <fp> like in `fn ret(t: Rc<T>) -> Io<T> { Io(Rc::new(|| t.clone())) }`, t doesn't have a long enough lifetime
2026-06-28 13:10:34 +0000 <fp> That actually doesn't work because Fn() -> T is a DST, so you need to Box (or just &, but I won't) it and use dyn, or use a function pointer (but that means capturing closures aren't allowed). And even with Rc and clone, you still run into lifetime issues
2026-06-28 13:09:09 +0000 <tomsmeding> lifetimes are 100% distracting from the mechanics of IO :p
2026-06-28 13:08:51 +0000 <tomsmeding> add .clone() and Rc<> until it works
2026-06-28 13:08:41 +0000 <tomsmeding> because of lifetimes?
2026-06-28 13:08:25 +0000 <fp> Yes and that is the root of all evil
2026-06-28 13:08:10 +0000 <tomsmeding> try `struct Io<T>(Fn() -> T);`
2026-06-28 13:07:23 +0000 <tomsmeding> where's the computation? This is just a T
2026-06-28 13:07:19 +0000 <tomsmeding> fp: "struct Io<T>(T);" "/// A computation that, when performed, does some I/O before returning a value of type `T`."