2011-11-19 102 views
37

我很難從Google發現的文檔和其他howtos /討論中瞭解STArray。下面有更多相關的問題。關於新手和State/ST相關問題的STArray文檔

根據文檔,STArray s爲在ST單子

易變盒裝和裝箱陣列。

這給我的印象,是STArray是爲了用作狀態被函數之間傳來傳去(想象你有一個必須經常更新,載體)。

顯然,這是用來區別,但:

ST s (STArray s a e) 

什麼狀態s這裏?如果它在內部使用,那麼爲什麼這不會被用戶隱藏?

這也意味着,如果我們想用一個STArray s Int Int正在傳遞的狀態,人會定義

type StateArray a = Control.Monad.State (ST s (STArray s Int Int)) a 

這似乎是相當麻煩的。

最後,

  • 是什麼STState之間的區別?
  • 如果STIO是用於「內部」使用,那麼STArrayIOArray之間的區別是什麼?

謝謝!

+1

如果你想看看這些,通常比數組更容易使用矢量。 – alternative

回答

64

ST是monad中允許有限類型的副作用,即可變引用和可變數組。因此,它允許您實現從外部世界看到的純粹功能,但內部使用突變。

這與State不同,它只通過將計算中的狀態作爲額外的輸入和輸出進行線程化來消除突變。當實施一些強制性算法時,差異很重要,因爲它們有時需要突變纔能有效實施。例如,在State monad中使用常規數組,您只能通過複製來修改它,而使用ST則可以在原地進行真正的變異。

爲什麼我們有兩個STIO的原因是ST提供了更強的保障比IO,即:

  1. ST不允許任意副作用,例如像訪問文件系統。
  2. 我們可以保證副作用ST確實允許不能越過runST的範圍,所以它可以被看作是從外界純粹的。

我們可以保證副作用無法逃避的原因與類型變量s有關。因爲在s中任何ST動作必須是多態的,所以您不能編寫允許任何可變引用進入或離開runST範圍的代碼,因爲類型檢查器會抱怨它不能保證您的動作的s和參考或陣列是相同的除非他們來自相同的runST範圍。

作爲使用ST單子與可變陣列的一個例子,這裏是Erathostenes的篩的實施方案:

import Control.Monad 
import Control.Monad.ST 
import Data.Array.ST 
import Data.Array.Unboxed 

primesUpto :: Int -> [Int] 
primesUpto n = [p | (p, True) <- assocs $ sieve n] 

sieve :: Int -> UArray Int Bool 
sieve n = runSTUArray $ do 
    sieve <- newArray (2, n) True 
    forM_ [2..n] $ \p -> do 
     isPrime <- readArray sieve p 
     when isPrime $ do 
      forM_ [p*2, p*3 .. n] $ \k -> do 
       writeArray sieve k False 
    return sieve 

runSTUArrayrunST一種特殊形式,其允許用戶使用突變構建的陣列在凍結之前,將它作爲一個不可變的數組返回。 newArrayreadArraywriteArray做你所期望的。

正如你所看到的,sieve的類型簽名表明它是一個純函數,它是。然而,它會在內部大量使用變異來有效地實現它。

+1

謝謝你這個偉大的解釋! – bbtrb

+1

是否有一個等同於'runSTUarray'的向量? –