针对 unsafePerformIO 的部门限制

发布于 2024-09-26 20:53:51 字数 243 浏览 14 评论 0原文

工作中有人讨论将其制定为部门范围的政策,禁止使用 unsafePerformIO 及其同类产品。就我个人而言,我并不介意,因为我一直认为,如果我发现自己想要使用它,通常意味着我需要重新考虑我的方法。

这个限制听起来合理吗?我似乎记得在某处读到它主要是为 FFI 提供的,但我现在不记得在哪里读到过。

编辑: 好吧,那是我的错。它不会在合理需要的地方受到限制,即。 FFI。该政策的目的更多是为了阻止懒惰和代码异味。

There has been some talk at work about making it a department-wide policy of prohibiting the use of unsafePerformIO and its ilk. Personally, I don't really mind as I've always maintained that if I found myself wanting to use it, it usually meant that I need to rethink my approach.

Does this restriction sound reasonable? I seem to remember reading somewhere that it was included mainly for FFI, but I can't remember where I read that at the moment.

edit:
Ok, that's my fault. It wouldn't be restricted where it's reasonably needed, ie. FFI. The point of the policy is more to discourage laziness and code smells.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

沉溺在你眼里的海 2024-10-03 20:53:51

许多核心库(例如 ByteString)在底层使用了 unsafePerformIO,例如自定义内存分配。

当您使用这样的库时,您相信库作者已经证明了其导出的 API 的引用透明度,并且记录了用户的任何必要先决条件。您的部门应该制定政策和审查流程,以便在内部做出类似的保证,而不是全面禁止。

A lot of core libraries like ByteString use unsafePerformIO under the hood, for example to customize memory allocation.

When you use such a library, you're trusting that the library author has proven the referential transparency of their exported API, and that any necessary preconditions for the user are documented. Rather than a blanket ban, your department should establish a policy and a review process for making similar assurances internally.

我乃一代侩神 2024-10-03 20:53:51

好吧,unsafePerformIO 的有效用途。它不只是为了装饰,或者作为考验你美德的诱惑。然而,这些用途都不涉及向日常代码添加有意义的副作用。以下是一些可能可能合理的使用示例,但存在不同程度的怀疑:

  • 包装一个内部不纯的函数,但没有外部可观察到的副作用。这与 ST monad 的基本思想相同,只​​是程序员有责任证明不纯性不会“泄漏”。

  • 以某种受限方式故意伪装不纯粹的函数。例如,只写杂质看起来与“从内部”的总纯度相同,因为无法观察所产生的输出。这对于某些类型的日志记录或调试很有用,在这些情况下,您明确想要 IO monad 所需的一致性和明确定义的顺序。一个例子是Debug.Trace.trace,我有时将其称为unsafePerformPrintfDebugging

  • 对纯计算的内省,产生纯结果。一个典型的例子是明确的选择运算符,它可以并行运行两个等效的纯函数为了更快地得到答案。

  • 内部不可观察地破坏引用透明度,例如在初始化数据时引入不确定性。只要每个不纯函数仅计算一次,在程序的任何单次运行期间都会有效地保留引用透明度,即使使用相同参数调用的同一伪纯函数在不同的运行中给出不同的结果。

关于上述所有内容,需要注意的重要一点是,所产生的杂质受到仔细控制并限制其范围。给定比通用 IO monad 更细粒度的控制副作用的系统,这些都将是切掉半纯度位的明显候选者,就像前面提到的ST monad。


Post scriptum:如果正在考虑对任何非必需使用 unsafePerformIO 采取强硬立场,我强烈鼓励
将禁止范围扩大到包括 unsafeInterleaveIO 以及任何允许观察其行为的函数。如果你问我的话,它至少和我上面列出的一些 unsafePerformIO 示例一样粗略。

Well, there are valid uses for unsafePerformIO. It's not there just to be decorative, or as a temptation to test your virtue. None of those uses, however, involve adding meaningful side effects to everyday code. Here's a few examples of uses that can potentially be justified, with various degrees of suspicion:

  • Wrapping a function that's impure internally, but has no externally observable side effects. This is the same basic idea as the ST monad, except that here the burden is on the programmer to show that the impurity doesn't "leak".

  • Disguising a function that's deliberately impure in some restricted way. For instance, write-only impurity looks the same as total purity "from the inside", since there's no way to observe the output that's produced. This can be useful for some kinds of logging or debugging, where you explicitly don't want the consistency and well-defined ordering required by the IO monad. An example of this is Debug.Trace.trace, which I sometimes refer to as unsafePerformPrintfDebugging.

  • Introspection on pure computations, producing a pure result. A classic example is something like the unambiguous choice operator, which can run two equivalent pure functions in parallel in order to get an answer quicker.

  • Internally unobservable breaking of referential transparency, such as introducing nondeterminism when initializing data. As long as each impure function is evaluated only once, referential transparency will be effectively preserved during any single run of the program, even if the same faux-pure function called with the same arguments gives different results on different runs.

The important thing to note about all of the above is that the resulting impurity is carefully controlled and limited in scope. Given a more fine-grained system of controlling side-effects than the all-purpose IO monad, these would all be obvious candidates for slicing off bits of semi-purity, much like the controlled mutable state in the aforementioned ST monad.


Post scriptum: If a hard-line stance against any non-required use of unsafePerformIO is being considered, I strongly encourage
extending the prohibition to include unsafeInterleaveIO and any functions that allow observation of its behavior. It's at least as sketchy as some of the unsafePerformIO examples I listed above, if you ask me.

老子叫无熙 2024-10-03 20:53:51

unsafePerformIO 是 IO monad 的 runST。有时这是必要的。但是,与 runST 不同,编译器无法检查您是否保留了引用透明度。

所以如果你使用它,程序员就有负担解释为什么使用是安全的。不应该禁止,应该有证据。

unsafePerformIO is the runST of the IO monad. It is sometimes essential. However, unlike runST, the compiler cannot check that you are preserving referential transparency.

So if you use it, the programmer has a burden to explain why the use is safe. It shouldn't be banned, it should be accompanied with evidence.

Bonjour°[大白 2024-10-03 20:53:51

在“应用程序”代码中禁止 unsafePerformIO 是一个好主意。在我看来,在正常代码中没有理由使用 unsafePerformIO,并且根据我的经验,它是不需要的。它实际上不是该语言的一部分,因此如果您使用它,您就不再是真正的 Haskell 编程了。你怎么知道它到底意味着什么?

另一方面,如果您知道自己在做什么,则在 FFI 绑定中使用 unsafePerformIO 是合理的。

Outlawing unsafePerformIO in "application" code is an excellent idea. In my opinion there is no excuse for unsafePerformIO in normal code and in my experience it is not needed. It is really not part of the language so you are not really programming in Haskell any more if you use it. How do you know what it even means?

On the other hand, using unsafePerformIO in an FFI binding is reasonable if you know what you are doing.

暮光沉寂 2024-10-03 20:53:51

禁止 unsafePerformIO 是一个糟糕的主意,因为它有效地将代码锁定到 IO monad 中:例如,ac 库绑定几乎总是在 IO monad 中 - 然而,使用 unsafePerformIO 可以在其之上构建更高级别的纯功能库。

可以说,unsafePerformIO反映了个人计算机的高状态模型和haskell的纯粹无状态模型之间的折衷;从计算机的角度来看,即使函数调用也是有状态的,因为它需要将参数推入堆栈、弄乱寄存器等,但其用法是基于这些操作实际上在功能上组合的知识。

Outlawing unsafePerformIO is a terrible idea, because it effectively locks code into the IO monad: for example, a c library binding will almost always be in the IO monad - however, using unsafePerformIO a higher-level purely functional library can be built on top of it.

Arguably, unsafePerformIO reflects the compromise between the highly stateful model of the personal computer and the pure, stateless model of haskell; even a function call is a stateful from the computer's point of view since it requires pushing arguments onto a stack, messing with registers, etc., but the usage is based on the knowledge that these operations do in fact compose functionally.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文