避免常见使用 unsafePerformIO 的方法

发布于 2024-11-08 13:48:23 字数 687 浏览 0 评论 0原文

我经常在 Haskell 代码中发现这种模式:

options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar

...

doSomething :: Foo -> Bar
doSomething = unsafePerformIO $ do
  opt <- readMVar options
  doSomething' where ...

基本上,一个人有一个选项记录或类似的东西,它最初是在程序开始时设置的。由于程序员很懒,他不想在整个程序中携带 options 记录。他定义了一个 MVar 来保存它 - 通过使用 unsafePerformIO 来定义。程序员确保状态仅在发生任何操作之前设置一次。现在程序的每个部分都必须再次使用unsafePerformIO,只是为了提取选项。

在我看来,这样的变量被认为是务实纯粹的(别打败我)。是否有一个库可以抽象这个概念并确保该变量仅设置一次,即在初始化之前不进行任何调用,并且不必编写 unsafeFireZeMissilesAndMakeYourCodeUglyAnd DisgustingBecauseOfThisLongFunctionName< /代码>

I often find this pattern in Haskell code:

options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar

...

doSomething :: Foo -> Bar
doSomething = unsafePerformIO $ do
  opt <- readMVar options
  doSomething' where ...

Basically, one has a record of options or something similar, that is initially set at the program's beginning. As the programmer is lazy, he doesn't want to carry the options record all over the program. He defines an MVar to keep it - defined by an ugly use of unsafePerformIO. The programmer ensures, that the state is set only once and before any operation has taken place. Now each part of the program has to use unsafePerformIO again, just to extract the options.

In my opinion, such a variable is considered pragmatically pure (don't beat me). Is there a library that abstracts this concept away and ensures that the variable is set only once, i.e. that no call is done before that initialization and that one doesn't have to write unsafeFireZeMissilesAndMakeYourCodeUglyAnd DisgustingBecauseOfThisLongFunctionName

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

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

发布评论

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

评论(5

对你而言 2024-11-15 13:48:23

那些愿意用基本的参考透明度来换取一点点的人
暂时的便利不值得
纯粹性和便利性。

这是一个坏主意。您发现的代码是错误的代码。*

无法安全地完全封装此模式,因为它不是安全模式。不要在您的代码中执行此操作。不要寻找安全的方法来执行此操作。没有安全的方法可以做到这一点。将 unsafePerformIO 慢慢地放在地板上,然后远离控制台...

*人们使用顶级 MVar 有正当理由,但这些原因与与外部代码的绑定有关在大多数情况下,或者其他一些事情,替代方案非常混乱。然而,据我所知,在这些情况下,顶级 MVar 无法从 unsafePerformIO 后面访问。

Those who would trade essential referential transparency for a little
temporary convenience deserve neither
purity nor convenience.

This is a bad idea. The code that you're finding this in is bad code.*

There's no way to fully wrap this pattern up safely, because it is not a safe pattern. Do not do this in your code. Do not look for a safe way to do this. There is not a safe way to do this. Put the unsafePerformIO down on the floor, slowly, and back away from the console...

*There are legitimate reasons that people do use top level MVars, but those reasons have to do with bindings to foreign code for the most part, or a few other things where the alternative is very messy. In those instances, as far as I know, however, the top level MVars are not accessed from behind unsafePerformIO.

落在眉间の轻吻 2024-11-15 13:48:23

如果您使用 MVar 来保存设置或类似的东西,为什么不尝试 reader monad?

foo :: ReaderT OptionRecord IO ()
foo = do
    options <- ask
    fireMissiles

main = runReaderT foo (OptionRecord "foo")

(如果你不需要 IO,也可以使用常规 Reader :P)

If you are using MVar for holding settings or something similar, why don't you try reader monad?

foo :: ReaderT OptionRecord IO ()
foo = do
    options <- ask
    fireMissiles

main = runReaderT foo (OptionRecord "foo")

(And regular Reader if you don't require IO :P)

风流物 2024-11-15 13:48:23

使用隐式参数。与让每个函数在其类型中都具有 ReaderReaderT 相比,它们的重量稍微轻一些。您确实必须更改函数的类型签名,但我认为可以编写这样的更改脚本。 (这对于 Haskell IDE 来说是一个很好的功能。)

Use implicit parameters. They're slightly less heavyweight than making every function have Reader or ReaderT in its type. You do have to change the type signatures of your functions, but I think such a change can be scripted. (Would make a nice feature for a Haskell IDE.)

悸初 2024-11-15 13:48:23

不使用这种模式有一个重要原因。据我所知,

options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar

Haskell 不保证 options 只会被评估一次。由于 option 的结果是一个纯值,它可以被记忆和重用,但它也可以为每次调用重新计算(即内联),并且程序的含义不得改变(与您的相反)案件)。

如果您仍然决定使用此模式,请务必添加 {-# NOINLINE options #-},否则它可能会被内联,并且您的程序将失败! (这样我们就摆脱了语言和类型系统给出的保证,而仅仅依赖于特定编译器的实现。)

这个主题已经被广泛讨论,并且在 Haskell Wiki 上很好地总结了可能的解决方案顶级可变状态。目前,如果没有一些额外的编译器支持,就不可能安全地抽象此模式。

There is an important reason for not using this pattern. As far as I know, in

options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar

Haskell gives no guarantees that options will be evaluated only once. Since the result of option is a pure value, it can be memoized and reused, but it can also be recomputed for every call (i.e. inlined) and the meaning of the program must not change (contrary to your case).

If you still decide to use this pattern, be sure to add {-# NOINLINE options #-}, otherwise it might get inlined and your program will fail! (And by this we're getting out of the guarantees given by the language and the type system and relying solely on the implementation of a particular compiler.)

This topic has been widely discussed and possible solutions are nicely summarized on Haskell Wiki in Top level mutable state. Currently it's not possible to safely abstract this pattern without some additional compiler support.

情愿 2024-11-15 13:48:23

我经常在 Haskell 代码中发现这种模式:

阅读不同的代码。

由于程序员很懒,他不想在程序中到处携带选项记录。他定义了一个 MVar 来保存它——通过 unsafePerformIO 的丑陋使用来定义。程序员确保状态仅在发生任何操作之前设置一次。现在程序的每个部分都必须再次使用 unsafePerformIO,只是为了提取选项。

听起来确实是 reader monad 完成的事情,只不过 reader monad 以安全的方式完成了它。不要迁就自己的懒惰,而应该编写实际的好代码。

I often find this pattern in Haskell code:

Read different code.

As the programmer is lazy, he doesn't want to carry the options record all over the program. He defines an MVar to keep it - defined by an ugly use of unsafePerformIO. The programmer ensures, that the state is set only once and before any operation has taken place. Now each part of the program has to use unsafePerformIO again, just to extract the options.

Sounds like literally exactly what the reader monad accomplishes, except that the reader monad does it in a safe way. Instead of accommodating your own laziness, just write actual good code.

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