У меня такое чувство, что я буду очень непопулярным из-за того, что говорю, что собираюсь сказать, но чувствовал, что должен был ответить на некоторую (на мой взгляд, неправильную) информацию, представленную здесь.
Хотя верно, что unsafePerformIO был официально добавлен в язык как часть приложения FFI, причины этого в значительной степени исторические, а не логические. Он существовал неофициально и широко использовался задолго до того, как Хаскелл когда-либо имел FFI. Официально он никогда не был частью основного стандарта Haskell, потому что, как вы заметили, это было слишком много смущения. Я предполагаю, что надежда была на то, что она когда-нибудь исчезнет в будущем. Ну, этого не произошло, и, по моему мнению, этого не произойдет.
Разработка приложения FFI предоставила удобный повод для unsafePerformIO, чтобы приспособиться к официальному языковому стандарту, поскольку здесь, вероятно, не так уж и плохо, по сравнению с добавлением возможности вызывать иностранный (IE C) код (где в любом случае все ставки на статическое обеспечение чистоты и безопасность типов не принимаются). Также было очень удобно разместить его здесь по политическим причинам. Это породило миф о том, что Haskell был бы чист, если бы не все эти грязные «плохо спроектированные» C, или «плохо спроектированные» операционные системы, или «плохо спроектированные» аппаратные средства или ... что угодно ... Это действительно так unsafePerformIO регулярно используется с кодом, связанным с FFI, но причины этого часто связаны с плохим дизайном FFI и самого Haskell, а не плохим дизайном того, что посторонний пользователь Haskell пытается использовать в интерфейсе.
Таким образом, как говорит Норман Рэмси, официальная позиция заключалась в том, что можно было использовать unsafePerformIO при условии, что кто-либо использовал его, если определенные обязательства по проверке были выполнены (прежде всего то, что это не делает недействительными важные преобразования компилятора, такие как встраивание и обычные подпрограммы) устранение выражения). Пока все хорошо, или так можно подумать. Настоящим фактом является то, что эти доказательные обязательства не могут быть выполнены тем, что, вероятно, является наиболее распространенным вариантом использования unsafePerformIO, который, по моим оценкам, составляет более 50% от всех unsafePerformIO в дикой природе. Я говорю об ужасающей идиоме, известной как "unsafePerformIO hack", которая доказуемо (на самом деле очевидно) совершенно небезопасна (при наличии inlining и cse).
У меня действительно нет времени, пространства или желания разбираться в том, что такое «взлом unsafePerformIO» или зачем он нужен в реальных библиотеках ввода-вывода, но суть в том, что люди, которые работают с инфраструктурой ввода-вывода Haskells, обычно " застрял между камнем и наковальней ". Они могут либо предоставить по своей сути безопасный API, который не имеет безопасной реализации (в Haskell), либо они могут предоставить по своей сути небезопасный API, который может быть безопасно реализован, но что они редко могут сделать, так это обеспечить безопасность как при разработке API , так и реализация. Судя по удручающей регулярности, с которой «взлом unsafePerformIO» появляется в коде реального мира (включая стандартные библиотеки Haskell), кажется, что большинство выбирает первый вариант как меньшее из двух зол, и просто надеются, что компилятор не испортит вещи с помощью inlining, cse или любого другого преобразования.
Хотел бы я, чтобы все это было не так. К сожалению, это так.