是有可能改寫這個源在Haskell使用功能增加無參考X作爲參數?在Haskell的函數使用全局變量而不是作爲參考
increase 0 _ = return()
increase n x = do
modifySTRef x (+n)
increase (n - 1) x
calculation n = runST $ do
x <- newSTRef 0
increase n x
readSTRef x
是有可能改寫這個源在Haskell使用功能增加無參考X作爲參數?在Haskell的函數使用全局變量而不是作爲參考
increase 0 _ = return()
increase n x = do
modifySTRef x (+n)
increase (n - 1) x
calculation n = runST $ do
x <- newSTRef 0
increase n x
readSTRef x
在源文件的頂層沒有[0]方法來實現你喜歡的東西:對於像這樣的全局變量的「執行」的排序根本沒有保證。事實上,根本沒有執行(因此之前的恐慌報價)。你必須必須撰寫ST
一起行動到runST
下的執行,以使它們中的任何一個都發生。
這意味着不純的綁定 - 比如當你第一次聲明你的全局變量的名字時 - 必須在你的runST
塊中完成,因此它們的生命級別低於模塊中頂級綁定的級別。
但是,除了它們被導出之外,沒有什麼特別的關於這些頂級綁定。你可以建立一個新的「頂級」的runST
內:
stThread :: ST s Int
stThread = do
x <- newSTRef
let increase :: Int -> ST s()
increase 0 = return()
increase n = do
modifySTRef x (+n)
increase (n - 1) x
increase 10
increase 20
readSTRef x
calculation :: Int
calculation = runST stThread
[0]好了,不需要打破哈斯克爾沒有語義上的猶太方式。有時候人們仍然在作弊,但我不能以任何誠意推薦它。
您不能擁有頂級ST
參考。這會破壞參考透明度。考慮一下:
x :: STRef s Int
x = magicallyCreateSTRef 0
test1 :: (Int, Int)
test1 = (runST (modifySTRef x (+1) >> readSTRef x)
, runST (modifySTRef x (+1) >> readSTRef x))
test2 :: (Int, Int)
test2 = (y, y)
where y = runST (modifySTRef x (+1) >> readSTRef x)
現在test1
的值是多少?根據評估順序,它可能是(0,1)
或(1,0)
。這已經是一個非常糟糕的信號,Haskell被打破了。爲了使這一點更清楚,test2
應該明確等同於test1
,這要歸功於參照透明度。但是,test2
不能生成一個內部具有不同值的對。
因此,您不能擁有頂級STRef
s。最多可以有頂級的IO引用,例如
x :: IORef Int
x = unsafePerformIO (newIORef 0)
只要上述參考文獻是單態(IORef Int
IORef [Int]
和是好的,IORef [a]
不是),這不破Haskell的主要特點,即鍵入安全和引用透明。它仍然以某種方式被認爲是一個小黑客,因爲它使用禁止功能unsafePerformIO
,但至少這是一個衆所周知的安全使用。
爲什麼IO引用被允許並且ST引用不是?由於ST
monad具有轉義函數runST
,因此可以在純代碼中使用monadic值(例如,在test1
和test2
中)。相反,IO
沒有類似的runIO
轉義函數。
你應該告訴我們你想寫什麼樣的代碼。 – ErikR 2014-12-02 21:19:59