【问题标题】:Haskell: use last reference to a variable to efficiently create a new variableHaskell:使用对变量的最后引用来有效地创建新变量
【发布时间】:2019-12-23 20:53:24
【问题描述】:

这个 C 代码在概念上可以描述为创建一个与输入数组相同但第一个元素为 1 的新数组:

int* retire_and_update(int* arr) {
    arr[0] = 1;
    return arr;
}

这是一个纯函数(wink wink nudge nudge),只要不进一步引用输入数组及其元素。 C 类型系统不会为我们强制执行,但原则上似乎可以强制执行。

gcc生成的代码简单高效:

retire_and_update:
    movq    %rdi, %rax
    movl    $1, (%rdi)
    ret

我们的函数通过在恒定时间内创建一个全新的数组并且不使用额外的内存来实现看似不可能的事情。好的。可以编写一个具有类似数组输入和输出的 Haskell 函数,并且可以用类似的代码有效地实现吗?有没有办法表达“这是对这个变量的最后引用”,以便纯函数可以在幕后蚕食变量?

如果函数被内联,那么这里不需要发生任何有趣的事情,所以假设调用者和函数将分别编译。

【问题讨论】:

  • IIUC“唯一性类型”或类似的线性类型,这样做。不幸的是,这些不是 Haskell 类型系统的特性。 Haskell 中的常规方法是使用the ST monad 在概念上纯设置中实现突变(暂时进入具有可变状态的monad,但类型系统保证计算是确定性的并且状态不会泄漏)。不过,这与您所说的完全不同。
  • Clean 是一种使用唯一性类型的函数式语言,也受到 Haskell 的影响。
  • related:一个纯UArray Int Bool 正在循环中更新,没有任何对其先前值的引用。与您在此处表达的类似,它可以就地更新,但似乎不是。

标签: c haskell ghc in-place purely-functional


【解决方案1】:

虽然ST monad 不是您所描述的,但实际上您可以使用STUArray 来实现大部分功能。因此,您的代码模型可能类似于:

import Control.Monad (forM_)
import Control.Monad.ST (ST)
import Data.Array.Unboxed (UArray)
import Data.Array.ST (STUArray, newArray, readArray, writeArray, runSTUArray)

retire_and_update :: STUArray s Int Int -> ST s (STUArray s Int Int)
retire_and_update arr = do
    writeArray arr 0 1
    return arr

如果你有另一个函数可以就地改变数组,比如:

mutate_inplace :: STUArray s Int Int -> Int -> ST s ()
mutate_inplace arr size = do
    forM_ [2..size - 1] $ \i -> do
        a <- readArray arr (i - 2)
        b <- readArray arr (i - 1)
        writeArray arr i (a + b)

您可以将两个不纯函数绑定在一起,并在纯函数中调用它们使用runSTUArray

run :: Int -> UArray Int Int
run size = runSTUArray $ do
    arr <- newArray (0, size - 1) 0
    retire_and_update arr
    mutate_inplace arr size
    return arr

注意run 保持纯净,返回数组的早期版本不会泄露到任何地方

\> run 8
array (0,7) [(0,1),(1,0),(2,1),(3,1),(4,2),(5,3),(6,5),(7,8)]

【讨论】:

  • 已经一年了,但这个答案突然闪过我的脑海,我想检查一下我是否理解它,所以现在我有一个问题。为什么你说ST monad 不太适合这个问题?你只是说在单子中保持状态的额外打字和概念问题吗?还是强制在某处创建副本?谢谢。
  • @Praxeolitic 没有没有复制; ST monad(与State Monad 相比)实际上确实就地发生了变异。 ST Monad 的要点是突变在类型系统中变得显式。但它不提供uniqueness type 提供的保证。
猜你喜欢
  • 2015-09-22
  • 2021-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多