I have a feeling that I will be very unpopular to say what I am going to say, but I felt that I have to answer some of the (in my opinion, incorrect) information presented here.
Although it is true that unsafePerformIO was officially added to the language as a complement to FFI, the reasons for this are mostly historical rather than logical. It existed informally and was widely used long before Haskell ever had FFI. This was never officially part of the core Haskell standard because, as you noticed, it was just too embarrassing. Probably the hope was that at some point in the future it would simply disappear. Well, this did not happen, and will not, in my opinion.
The development of the FFI add-on served as a convenient pretext for the unsafe PerformanceIO to gain access to the official language standard, since, apparently, this is not too bad compared to the addition of the ability to call external (IE C) code (where all bets are disabled relative to static cleanliness and type safety anyway). It was also convenient to add it here for political reasons. This has fostered the myth that Haskell would be clean if it weren’t for all the dirty "poorly designed" C or "poorly designed" operating systems, or the "poorly designed" hardware or ... whatever. unsafePerformIO is regularly used with FFI-related code, but the reasons for this are often due to poor FFI design and even to Haskell itself, a good design for any foreign object that Haskell is also trying to use the interface.
So, according to Norman Ramsey, the official position was that it was normal to use unsafePerformIO if certain evidence was satisfied by those who used it (first of all, it invalidates important compiler transformations, such as inline and general subtitles, exception expression) . So far, so good, or so you might think. The real kicker is that these evidential obligations cannot be satisfied , which is probably the most common use of the unsafe PerformIO, which in my opinion makes up more than 50% of all unsafe PerformIOs in the wild, I'm talking about the terrifying idiom known as an “unsafe PerformanceIO hack,” which is provably (actually explicitly) completely unsafe (with inlining and cse).
Actually, I don’t have the time, space or inclination to understand what an “unsafe PerformIO hack is” or why it is needed in real IO libraries, but the point is that people who work with the IO Haskells infrastructure are usually “stuck” between a stone and a solid place. " They can either provide an inherent security API that does not have a secure implementation (in Haskell), or they can provide an inherently insecure API that can be implemented safely, but what they rarely can do is provide security in both the design of the API and and . Judging by the depressing regularity with which the "unsafe PerformIO hack" appears in real-world code (including the Haskell standard libraries), it seems that most choose the previous option as the lesser of two evils and just hope that the compiler will not guess things with inlays, cse or any other conversion.
I would like all this to be wrong. Unfortunately it is so.