2014-12-02 56 views
1

是有可能改寫這個源在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

你應該告訴我們你想寫什麼樣的代碼。 – ErikR 2014-12-02 21:19:59

回答

4

在源文件的頂層沒有[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]好了,不需要打破哈斯克爾沒有語義上的猶太方式。有時候人們仍然在作弊,但我不能以任何誠意推薦它。

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 IntIORef [Int]和是好的,IORef [a]不是),這不破Haskell的主要特點,即鍵入安全和引用透明。它仍然以某種方式被認爲是一個小黑客,因爲它使用禁止功能unsafePerformIO,但至少這是一個衆所周知的安全使用。

爲什麼IO引用被允許並且ST引用不是?由於ST monad具有轉義函數runST,因此可以在純代碼中使用monadic值(例如,在test1test2中)。相反,IO沒有類似的runIO轉義函數。