【问题标题】:Does it break composition to modify input in Haskell?修改 Haskell 中的输入是否会破坏组合?
【发布时间】:2016-01-02 17:23:25
【问题描述】:

当我在haskell中阅读SDL的文档时,我发现一些函数不可避免地会修改它的输入。例如,blitSurface 将目标表面作为输入,但它在函数内更新。现在,概括问题,如果我有一个函数f :: a -> IO a,如果我在函数内部修改a,它会破坏组合吗? f :: IO a -> IO a 呢? a -> IO () 呢?那么IO a -> IO ()呢?

考虑到blitSurface实际上是一个外来函数,并且每帧制作一个新表面听起来效率不高,这些函数很难避免。这样的功能会导致更大范围的问题吗?例如,使用进行破坏性更新的fModifySurface :: Surface -> IO () 为例:

main = do
    w <- ... -- The window surface
    -- Do something here
    s <- someFuncGetSurface -- We get a surface here
    fModifySurface s -- Destructively update s
    blitSurface ...... -- Ignore the actual API, but destructively updates w

上面的代码中是否有任何意想不到的语义?如果是这样,利用改变输入的外部函数的最佳方法是什么?

【问题讨论】:

  • 严格来说,这些都不是“功能”。
  • 好的,命令意义上的“函数”。
  • 只要所有外部函数都返回IO SomeType,就不会破坏任何基本属性。你的情况与打电话有很大不同吗? writeIORef 更新可变变量?后者是“安全的”,即使它可以被滥用来编写单一的代码。
  • 问题是,外部函数就像f (type* src, type* dest),而dest的内容明显改变了。所以如果我调用f a,它只会返回a 被修改
  • Haskell 中的所有值都是不可变的,因此没有函数修改其输入。但是,某些值是(或包含)对内容可能更改的单元格的引用。但是更改这些单元格的内容并不会修改引用,就像更改文件的内容会修改其文件名一样。所以从语言的角度来看是没有问题的。当然,有时对涉及可变状态的系统进行推理可能会更加困难。

标签: haskell functional-programming sdl monads purely-functional


【解决方案1】:

我观察到 f a bflip f b a 是 beta 等效项。另一方面,直接的IO 版本,即f &lt;$&gt; a &lt;*&gt; bflip f &lt;$&gt; b &lt;*&gt; a,肯定不是beta 等价的;甚至使用来自"Tackling the Awkward Squad" 的等价,这使得更多IO 动作等价,这两个术语并不等价。

从高层次上讲,这意味着如果您证明了有关纯项行为的某些内容,那么即使将纯计算用作更大程序的一部分,您也可以重复使用该证明。另一方面,没有相应的方法将关于IO 术语的本地证明统一提升为关于更大的基于IO 的程序的证明;如果您希望这样做,您必须调用一些关于您计划一起使用的特定 IO 操作的 全局 属性。

这是将尽可能多的计算从 IO 提升到纯粹世界的常见建议背后的推动力——事实上,这是首先进行纯函数式编程的主要动机之一,即命令式程序的组合不好。

但是,这些讨论都不是特定于 FFI 或 IO 操作更新其输入之一引用的值的函数。 blitSurface 在这方面基本上不比我们扔进IO 的任何“罪恶箱”更差或更好。命令式程序根本不像纯程序那样具有组合性。

【讨论】:

  • 所以现在我只保留一层极薄的IO,方便手动管理。
  • 提及索引单子和效果系统可能是合适的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-27
  • 1970-01-01
  • 1970-01-01
  • 2014-12-19
  • 1970-01-01
  • 1970-01-01
  • 2011-01-09
相关资源
最近更新 更多