Newest at the top
| 2026-07-04 20:35:30 +0000 | <tomsmeding> | yes, not separating the two makes it simpler in the sense that you don't have to think about the separation. ;) |
| 2026-07-04 20:35:06 +0000 | <tomsmeding> | if that would be the normal way of doing IO, why would we separate IO and non-IO? |
| 2026-07-04 20:34:39 +0000 | <EvanR> | do the IO and evaluate the result all at the same time |
| 2026-07-04 20:34:18 +0000 | <EvanR> | that account of IO makes unsafePerformIO sound simpler than normal IO (one kind of special event associated with an action not two) |
| 2026-07-04 20:32:51 +0000 | bitdex | (~bitdex@gateway/tor-sasl/bitdex) (Ping timeout: 252 seconds) |
| 2026-07-04 20:28:11 +0000 | bitdex | (~bitdex@gateway/tor-sasl/bitdex) bitdex |
| 2026-07-04 20:27:28 +0000 | merijn | (~merijn@host-cl.cgnat-g.v4.dfn.nl) (Ping timeout: 268 seconds) |
| 2026-07-04 20:27:23 +0000 | haritz | (~hrtz@user/haritz) haritz |
| 2026-07-04 20:27:23 +0000 | haritz | (~hrtz@2a01:4b00:bc2e:7000:d5af:a266:ca31:5ef8) (Changing host) |
| 2026-07-04 20:27:23 +0000 | haritz | (~hrtz@2a01:4b00:bc2e:7000:d5af:a266:ca31:5ef8) |
| 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 |