Logs: liberachat/#haskell
| 2025-08-29 17:32:22 | → | cherryramatisdev joins (~cherryram@user/cherryramatisdev) |
| 2025-08-29 17:34:45 | → | jmcantrell_ joins (~weechat@user/jmcantrell) |
| 2025-08-29 17:37:02 | → | hjj123 joins (~hjj123@178.155.116.235) |
| 2025-08-29 17:38:39 | × | cherryramatisdev quits (~cherryram@user/cherryramatisdev) (Ping timeout: 260 seconds) |
| 2025-08-29 17:39:45 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-29 17:44:46 | → | cherryramatisdev joins (~cherryram@user/cherryramatisdev) |
| 2025-08-29 17:45:03 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 260 seconds) |
| 2025-08-29 17:45:15 | → | target_i joins (~target_i@user/target-i/x-6023099) |
| 2025-08-29 17:51:06 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-29 17:56:09 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 260 seconds) |
| 2025-08-29 17:56:46 | → | segfaultfizzbuzz joins (~segfaultf@23-93-74-222.fiber.dynamic.sonic.net) |
| 2025-08-29 18:02:33 | × | hjj123 quits (~hjj123@178.155.116.235) (Quit: Client closed) |
| 2025-08-29 18:03:37 | × | jmcantrell_ quits (~weechat@user/jmcantrell) (Quit: WeeChat 4.7.1) |
| 2025-08-29 18:05:41 | → | jmcantrell_ joins (~weechat@user/jmcantrell) |
| 2025-08-29 18:05:41 | jmcantrell_ | is now known as jmcantrell |
| 2025-08-29 18:06:55 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-29 18:12:05 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 258 seconds) |
| 2025-08-29 18:15:51 | × | ouilemur quits (~jgmerritt@user/ouilemur) (Quit: WeeChat 4.7.1) |
| 2025-08-29 18:17:10 | → | tzh joins (~tzh@c-76-115-131-146.hsd1.or.comcast.net) |
| 2025-08-29 18:17:24 | <lightspell> | I was on here yesterday asking about getting a StateT wrapped around a StatefulGen working. I've fixed my connection issues and I've tried to understand the suggestion from @absence. I think I need to declare my GameState type something like this: `type GameState a = (StatefulGen g m) => StateT Game (m g) a`. However, that and a number of other variations I've tried all lead to different errors. |
| 2025-08-29 18:17:37 | <lightspell> | Here's the updated code: https://play.haskell.org/saved/bhdquoHn |
| 2025-08-29 18:19:33 | <lightspell> | `g` and `m` are not in scope, so I tried `type GameState g m a = (StatefulGen g m) => StateT Game (m g) a` and `type GameState g m a = (StatefulGen g m) => StateT Game m a` but neither of them worked either. I'd like to actually understand what I'm doing wrong, instead of just randomly trying different variations to see if it works. |
| 2025-08-29 18:22:42 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-29 18:23:03 | → | ouilemur joins (~jgmerritt@user/ouilemur) |
| 2025-08-29 18:25:59 | <lightspell> | I thought I could make it more concrete with `type GameState a = StateT Game (State StdGen) a`, but then I get "Couldn't match type ‘m’ with ‘State StdGen’" |
| 2025-08-29 18:27:29 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 248 seconds) |
| 2025-08-29 18:31:32 | <lightspell> | Hm, this seems the closest to working: `type GameState g m a = (StatefulGen g m) => StateT Game (State g) a`. Here's what that looks like: https://play.haskell.org/saved/JPa8opVe |
| 2025-08-29 18:33:00 | <lightspell> | But that still doesn't work, and then every function has to have a type signature like `getPlayer :: (StatefulGen g m) => PlayerId -> GameState g m Player`, which seems like it's not right. |
| 2025-08-29 18:34:18 | → | zarakshR joins (~Thunderbi@0542a05a.skybroadband.com) |
| 2025-08-29 18:38:29 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-29 18:41:38 | × | cherryramatisdev quits (~cherryram@user/cherryramatisdev) (Ping timeout: 260 seconds) |
| 2025-08-29 18:43:31 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 258 seconds) |
| 2025-08-29 18:44:52 | × | trickard_ quits (~trickard@cpe-53-98-47-163.wireline.com.au) (Read error: Connection reset by peer) |
| 2025-08-29 18:44:55 | × | ames quits (~amelia@offtopia/offtopian/amelia) (Server closed connection) |
| 2025-08-29 18:45:05 | → | ames joins (~amelia@offtopia/offtopian/amelia) |
| 2025-08-29 18:45:06 | → | trickard_ joins (~trickard@cpe-53-98-47-163.wireline.com.au) |
| 2025-08-29 18:45:23 | → | sprotte24 joins (~sprotte24@p200300d16f05a9000cb0d4b3f4edd851.dip0.t-ipconnect.de) |
| 2025-08-29 18:45:52 | × | vetkat quits (~vetkat@user/vetkat) (Read error: Connection reset by peer) |
| 2025-08-29 18:46:12 | → | vetkat joins (~vetkat@user/vetkat) |
| 2025-08-29 18:50:51 | → | sw4n joins (~sw4n@2605:59c0:413f:3110:e59f:e0ff:6b6e:883b) |
| 2025-08-29 18:52:09 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-29 18:54:31 | → | emperori joins (~emperori@223.187.118.137) |
| 2025-08-29 18:58:57 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 248 seconds) |
| 2025-08-29 19:00:03 | × | caconym747 quits (~caconym@user/caconym) (Quit: bye) |
| 2025-08-29 19:00:43 | → | caconym747 joins (~caconym@user/caconym) |
| 2025-08-29 19:02:00 | × | sw4n quits (~sw4n@2605:59c0:413f:3110:e59f:e0ff:6b6e:883b) (Quit: sw4n) |
| 2025-08-29 19:02:16 | → | sw4n joins (~sw4n@2605:59c0:413f:3110:e59f:e0ff:6b6e:883b) |
| 2025-08-29 19:03:04 | × | segfaultfizzbuzz quits (~segfaultf@23-93-74-222.fiber.dynamic.sonic.net) (Ping timeout: 258 seconds) |
| 2025-08-29 19:03:44 | × | emperori quits (~emperori@223.187.118.137) (Read error: Connection reset by peer) |
| 2025-08-29 19:07:50 | → | Tuplanolla joins (~Tuplanoll@91-159-69-59.elisa-laajakaista.fi) |
| 2025-08-29 19:10:12 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-29 19:14:44 | <tomsmeding> | lightspell: is there a reason you don't want the random state in your Game state? |
| 2025-08-29 19:15:20 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 258 seconds) |
| 2025-08-29 19:17:30 | <tomsmeding> | lightspell: isn't your problem that neither StateT nor State is an instance of StatefulGen |
| 2025-08-29 19:17:44 | <tomsmeding> | then you can declare constraints as much as you like, but if the instance isn't there, it isn't there |
| 2025-08-29 19:20:42 | × | tjbc quits (~tjbc@user/fliife) (Server closed connection) |
| 2025-08-29 19:21:00 | → | tjbc joins (~tjbc@user/fliife) |
| 2025-08-29 19:21:23 | <tomsmeding> | lightspell: do you need the monad to be polymorphic in the generator type? |
| 2025-08-29 19:24:55 | <EvanR> | explicitly including RNG state in the game state lets you replay a game without recording every step |
| 2025-08-29 19:25:13 | <EvanR> | the history of the game is generated from the game state and the user's inputs |
| 2025-08-29 19:25:59 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-29 19:26:31 | → | segfaultfizzbuzz joins (~segfaultf@23-93-74-222.fiber.dynamic.sonic.net) |
| 2025-08-29 19:28:19 | × | arandombit quits (~arandombi@user/arandombit) (Ping timeout: 260 seconds) |
| 2025-08-29 19:30:57 | × | merijn quits (~merijn@host-vr.cgnat-g.v4.dfn.nl) (Ping timeout: 248 seconds) |
| 2025-08-29 19:33:41 | <tomsmeding> | lightspell: okay the StatefulGen API works like this: there is a monad (m) and a handle type (g); the functions for generating random values take a handle and run in the monad, and the monad (m) is responsible for storing the actual random generator data |
| 2025-08-29 19:34:07 | <tomsmeding> | if you want to make your game monad polymorphic over both g and m, you're making your life difficult |
| 2025-08-29 19:34:22 | <lightspell> | There's no particular reason not to include the random state in the game state. I just didn't know how to do that. I'm struggling to understand the System.Random docks. |
| 2025-08-29 19:34:43 | <lightspell> | *docs |
| 2025-08-29 19:34:45 | <tomsmeding> | are you fine with a non-polymorphic solution? |
| 2025-08-29 19:36:36 | <lightspell> | Yes, non-polymorphic would be fine. I'm just trying to figure out how all this fits together. I thought from reading the docs that I could use StatefulGen in such a way to make the random number generator update itself in a State monad as it's used, so I wouldn't have to do it manually. Everything else is just my failing to understand how to do that. |
| 2025-08-29 19:37:25 | <EvanR> | just using the stdlib RNG normally would be a good starting point |
| 2025-08-29 19:37:32 | <EvanR> | before using some weird library |
| 2025-08-29 19:37:37 | <tomsmeding> | EvanR: this _is_ the stdlib rng |
| 2025-08-29 19:37:42 | <tomsmeding> | it's System.Random.Stateful |
| 2025-08-29 19:37:43 | <EvanR> | StatefulGen ? |
| 2025-08-29 19:37:45 | <tomsmeding> | I've never liked the API |
| 2025-08-29 19:37:49 | <lightspell> | yeah, fair enough |
| 2025-08-29 19:37:54 | <EvanR> | never heard of it |
| 2025-08-29 19:37:58 | <tomsmeding> | https://hackage-content.haskell.org/package/random-1.3.1/docs/System-Random-Stateful.html#t:StatefulGen |
| 2025-08-29 19:38:45 | <tomsmeding> | the requirement for the MonadState constraint on the `StatefulGen (StateGenM g) m` instance is a bother |
| 2025-08-29 19:38:50 | <EvanR> | random :: RandomGen g => g -> (a, g) |
| 2025-08-29 19:39:01 | <EvanR> | I guess this is "non-stateful" xD |
| 2025-08-29 19:39:14 | <tomsmeding> | yes, the idea of the stateful API is that the random generator is stored in a state monad |
| 2025-08-29 19:39:14 | → | fp joins (~Thunderbi@89-27-10-140.bb.dnainternet.fi) |
| 2025-08-29 19:39:17 | <tomsmeding> | and that handling is done for you |
| 2025-08-29 19:39:36 | <tomsmeding> | but the API is polymorphic over various kinds of state monads; it also allows an IORef in IO, for example |
| 2025-08-29 19:39:40 | <tomsmeding> | and that makes it cumbersome to work with |
| 2025-08-29 19:41:08 | <lightspell> | Yeah, that's exactly what I'm struggling with. I have no idea how to make it non-polymorphic, or how to store its state inside the Game type alongside the rest of the game state. Either approach would be fine. |
| 2025-08-29 19:41:12 | <tomsmeding> | damn and they don't even export all methods of StatefulGen from the public module so you can't make an optimally performing manual instance without importing Internal |
| 2025-08-29 19:41:15 | <tomsmeding> | that feels like a bug |
| 2025-08-29 19:41:48 | → | merijn joins (~merijn@host-vr.cgnat-g.v4.dfn.nl) |
| 2025-08-29 19:42:07 | <EvanR> | smh |
| 2025-08-29 19:42:32 | → | weary-traveler joins (~user@user/user363627) |
| 2025-08-29 19:43:44 | <lightspell> | If I just cared about getting the game working I'd just store a regular rng in the game state and manage it manually. But I'd like to figure out how to do it with monads because the whole point is to teach myself how all this works. |
| 2025-08-29 19:43:54 | <lightspell> | Everything you guys have said is already really helpful, thank you. |
| 2025-08-29 19:44:02 | <tomsmeding> | this StatefulGen API is kind of crappy |
| 2025-08-29 19:44:06 | <tomsmeding> | not a good example to learn from :p |
| 2025-08-29 19:44:18 | × | amadaluzia quits (~amadaluzi@user/amadaluzia) (Quit: ZNC 1.9.1 - https://znc.in) |
| 2025-08-29 19:44:18 | <lightspell> | Yeah I've been bouncing off it pretty hard. |
| 2025-08-29 19:44:40 | <tomsmeding> | I'll hack up what feels to me like the neatest way to use this API |
All times are in UTC.