Newest at the top
| 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 +0000 | emilym | (~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 +0000 | emilym | (~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 +0000 | fp | (~Thunderbi@46-133-26-225.mobile.vf-ua.net) fp |
| 2026-06-28 12:54:47 +0000 | traxex | (traxex@user/traxex) traxex |
| 2026-06-28 12:53:05 +0000 | fp | (~Thunderbi@178-133-117-157.mobile.vf-ua.net) (Ping timeout: 256 seconds) |
| 2026-06-28 12:52:59 +0000 | bitdex | (~bitdex@gateway/tor-sasl/bitdex) bitdex |
| 2026-06-28 12:51:16 +0000 | Pozyomka | (~pyon@user/pyon) pyon |
| 2026-06-28 12:47:36 +0000 | Pozyomka | (~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 +0000 | weary-traveler | (~user@user/user363627) user363627 |
| 2026-06-28 12:35:12 +0000 | weary-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 +0000 | rensenwxre | (~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" |
| 2026-06-28 12:30:23 +0000 | <fp> | For the first one, it's "hi\n5hi\nhi" |
| 2026-06-28 12:30:02 +0000 | <mauke> | the correct output is "3\nhi\nhi\n" |
| 2026-06-28 12:29:22 +0000 | <mauke> | main = let { x :: IO (); x = putStrLn "hi" } in print (length [putStrLn "a", putStrLn "b", putStrLn "c"]) >> x >> x |
| 2026-06-28 12:28:48 +0000 | <mauke> | actually, we can do better |