Newest at the top
| 2026-07-04 20:20:24 +0000 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-07-04 20:16:09 +0000 | <tomsmeding> | that crazy thunk-inspecting unsafeUnperformIO would have a really amusing failure case though: if it's not a state token application, "Cannot unperformIO: already performed" |
| 2026-07-04 20:15:41 +0000 | bdkl | (~bdkl@user/bdkl) (Quit: bdkl) |
| 2026-07-04 20:14:42 +0000 | tromp | (~textual@2001:1c00:340e:2700:ec0e:2a6c:3177:923e) |
| 2026-07-04 20:14:30 +0000 | <int-e> | etc. |
| 2026-07-04 20:14:28 +0000 | <int-e> | You can't have unsafeUnperformIO; |
| 2026-07-04 20:14:14 +0000 | <int-e> | You can't have unsafePerformIO; the way I'd describe the reason is that IO actions have a "lever" that triggers the underlying IO operations independently of forcing the action's result; unsafePerformIO inextricably ties these two things together. Unless you go crazy and write code that inspects thunks and code to find pending applications of state tokens I suppose. |
| 2026-07-04 20:11:41 +0000 | <int-e> | (that's also wrong of course) |
| 2026-07-04 20:11:29 +0000 | <lambdabot> | a -> IO a |
| 2026-07-04 20:11:28 +0000 | <int-e> | :t Control.Exception.evaluate |
| 2026-07-04 20:11:17 +0000 | <monochrom> | I don't actually know. Maybe it works out of the box. |
| 2026-07-04 20:09:36 +0000 | <EvanR> | aw |
| 2026-07-04 20:09:20 +0000 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 245 seconds) |
| 2026-07-04 20:08:46 +0000 | <yahb2> | <no output> |
| 2026-07-04 20:08:45 +0000 | <tomsmeding> | % :unset +s |
| 2026-07-04 20:08:35 +0000 | <monochrom> | The way GHC encodes IO, it may be impossible. |
| 2026-07-04 20:08:32 +0000 | <yahb2> | (0.01 secs, 0 bytes) |
| 2026-07-04 20:08:31 +0000 | <tomsmeding> | % unsafe²id :: a -> a ; unsafe²id = System.IO.Unsafe.unsafePerformIO . unsafeUnperformIO where unsafeUnperformIO = return |
| 2026-07-04 20:07:36 +0000 | <EvanR> | unsafeSquaredId |
| 2026-07-04 20:07:10 +0000 | <EvanR> | it gives you id :: IO a -> IO a but pick up an unsafe squared |
| 2026-07-04 20:06:57 +0000 | <tomsmeding> | well, unsafePerformIO . unsafeUnperformIO = id :: a -> a just fine. :) |
| 2026-07-04 20:06:36 +0000 | <monochrom> | I was hoping unsafeUnperformIO . unsafePerformIO = id :: IO a -> IO a |
| 2026-07-04 20:06:23 +0000 | haritz | (~hrtz@user/haritz) (Quit: ZNC 1.8.2+deb3.1+deb12u1 - https://znc.in) |
| 2026-07-04 20:06:06 +0000 | tomsmeding | . o O ( return? ) |
| 2026-07-04 20:05:54 +0000 | <monochrom> | Consider unsafeUnperformIO :: a -> IO a >:) |
| 2026-07-04 20:05:26 +0000 | <tomsmeding> | yeah good point |
| 2026-07-04 20:05:24 +0000 | <tomsmeding> | uh, oh right, the point was that this is in pure code |
| 2026-07-04 20:05:12 +0000 | <EvanR> | that's an external shenanigan xD |
| 2026-07-04 20:05:00 +0000 | <tomsmeding> | EvanR: watch out, you're in IO so you can `catch` |
| 2026-07-04 20:04:44 +0000 | <EvanR> | whoever gets there when it's a bottom can't observe a difference, without external shenanignas |
| 2026-07-04 20:04:28 +0000 | Lord_of_Life | (~Lord@user/lord-of-life/x-2819915) Lord_of_Life |
| 2026-07-04 20:04:16 +0000 | <EvanR> | i.e. poor man's IVar |
| 2026-07-04 20:04:02 +0000 | <EvanR> | if you update an IORef containing a bottom so it doesn't contain a bottom, and it's never updated again / updated with that same value only, then you might make an argument that it's still right |
| 2026-07-04 20:03:24 +0000 | <tomsmeding> | ah yes, common subexpression elimination :) |
| 2026-07-04 20:02:41 +0000 | <monochrom> | Usually the surprise is the converse. You run "unsafePerformIO (print "hello" >> return 10) 3 times expecting to print hello 3 times, but clearly GHC is right to let it happen just once (and cache the 10). |
| 2026-07-04 20:02:40 +0000 | <brooke2k> | woah I hadn't thought of that either, good point... if the internal IORef gets copied to another thread that could get dangerous |
| 2026-07-04 20:02:37 +0000 | <tomsmeding> | so that's a realistic situation where a pure computation may be evaluated more than once |
| 2026-07-04 20:02:26 +0000 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) merijn |
| 2026-07-04 20:02:18 +0000 | <tomsmeding> | (the locking-like technique that prevents this from happening, called "blackholing", is disabled by default because it turned out that enabling it cost more in the vast majority of cases than it won) |
| 2026-07-04 20:01:38 +0000 | <tomsmeding> | also, if a thread encounters a thunk while another thread has already started evaluating it, the second thread may also start evaluating the thunk in parallel |
| 2026-07-04 20:01:07 +0000 | <tomsmeding> | GHC does not duplicate computation willy-nilly (because that would be a pessimisation!), but yes it can happen |
| 2026-07-04 20:00:40 +0000 | <brooke2k> | the idempotency thing helps though, thanks. I guess GHC optimizes under the assumption that a thunk can get run multiple times with no issues |
| 2026-07-04 19:59:40 +0000 | <brooke2k> | which is how they implement Effectful.Error.Static already, I'm just trying to make sure that my version is safe |
| 2026-07-04 19:58:52 +0000 | <brooke2k> | I don't think I can use ST in this instance... I'm trying to write an effectful static effect that internally uses IO, but gets wrapped in a pure interface |
| 2026-07-04 19:58:18 +0000 | s00pcan | (~s00pcan@71.214.104.207) s00pcan |
| 2026-07-04 19:58:14 +0000 | <brooke2k> | damn actually that's helpful I'm not sure the function in question is idempotent |
| 2026-07-04 19:58:07 +0000 | <tomsmeding> | if you just want some mutable references inside your function that aren't visible outside, then you may be able to write your function using ST, in which case you do retain purity (because you can runST safely) |
| 2026-07-04 19:56:52 +0000 | <brooke2k> | hmm that makes sense |
| 2026-07-04 19:56:18 +0000 | <tomsmeding> | if you modify IORefs that are also visible outside the function, then such things matter very much |
| 2026-07-04 19:56:01 +0000 | <tomsmeding> | brooke2k: being a pure function also means that evaluating it twice, or evaluating it later, doesn't matter semantically |