2026/06/28

Newest at the top

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`."
2026-06-28 13:06:59 +0000emilym(~Thunderbi@user/emilym) (Ping timeout: 245 seconds)
2026-06-28 13:04:26 +0000 <tomsmeding> you're trying to simulate a language that's maximally-YOLO with memory management (pure Haskell) in one that's unusually precise about memory management
2026-06-28 13:03:25 +0000 <fp> I guess if I force users to put everything they want returned into an Rc first, that could work
2026-06-28 13:01:33 +0000 <tomsmeding> then as long as you don't create cycles, you get a "GC" like Haskell has
2026-06-28 13:01:15 +0000 <tomsmeding> fp: wrap everything everywhere in Rc<>?
2026-06-28 13:00:57 +0000 <fp> Maybe if I bring in a garbage collector it'll be easier, but I'm not sure it's possible to implement this otherwise
2026-06-28 13:00:03 +0000 <fp> mauke: Ok yeah that's basically what I tried at first. Unfortunately, Rust makes extending the lifetime of a capturing closure a major PITA
2026-06-28 12:58:26 +0000fp(~Thunderbi@46-133-26-225.mobile.vf-ua.net) fp
2026-06-28 12:54:47 +0000traxex(traxex@user/traxex) traxex
2026-06-28 12:53:05 +0000fp(~Thunderbi@178-133-117-157.mobile.vf-ua.net) (Ping timeout: 256 seconds)
2026-06-28 12:52:59 +0000bitdex(~bitdex@gateway/tor-sasl/bitdex) bitdex
2026-06-28 12:51:16 +0000Pozyomka(~pyon@user/pyon) pyon
2026-06-28 12:47:36 +0000Pozyomka(~pyon@user/pyon) (Quit: test)
2026-06-28 12:46:08 +0000 <mauke> (no 'print' because we're taking advantage of perl's implicit 'show')
2026-06-28 12:45:32 +0000 <mauke> I don't know rust, but I just prototyped it in perl: https://pt.gayr.at/p/akEXWseeFyQMI20qKUFlL479SHI
2026-06-28 12:43:30 +0000 <fp> So I guess I need to make a structure of closures and run it with an explicit command, like Io::ret(...).bind(...).run(). But Rust doesn't make that easy...
2026-06-28 12:39:35 +0000 <lambdabot> I :: t0 -> t1 -> t2 -> t3 -> String -> tVariable not in scope: suspectVari...
2026-06-28 12:39:35 +0000 <lambdabot> Data constructor not in scope:
2026-06-28 12:39:34 +0000 <fp> Yeah, or "hi\na\nb\nc3", but close enough
2026-06-28 12:39:34 +0000 <fp> > I suspect yours would give "hi\na\nb\nc\n"
2026-06-28 12:35:48 +0000weary-traveler(~user@user/user363627) user363627
2026-06-28 12:35:12 +0000weary-traveler(~user@user/user363627) (Quit: Konversation terminated!)
2026-06-28 12:33:03 +0000 <fp> So without the cheat, it would've said "hi\n5\n"
2026-06-28 12:32:31 +0000rensenwxre(~fwam@user/fwam) fwam
2026-06-28 12:31:33 +0000 <fp> But actually I had to cheat with the first one. I couldn't reuse the x variable for the two >>s, so I rewrote put_str_ln("hi")
2026-06-28 12:30:24 +0000 <mauke> I suspect yours would give "hi\na\nb\nc\n"