2014-12-02 2 views

답변

4

당신이 소스 파일의 최상위에 좋아 달성 할 [0] 방법은 없습니다 : 단순히 그런 전역의 "실행"의 순서에 보장이 없다가. 실제로, 전혀 실행이 없습니다 (그러므로 이전의 겁나는 따옴표). 이어야합니다. runST 아래의 실행으로 함께 ST 액션을 작성해야합니다.

즉, 전역 변수의 이름을 처음 선언 할 때와 같이 불순한 바인딩은 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)이 될 수 있습니다. 이것은 이미 하스켈이 부서 졌다는 아주 나쁜 징후입니다. 요점을 더욱 명확하게하기 위해 test2은 참조 투명성으로 인해 test1과 분명히 동일해야합니다. 여전히 test2은 내부에 다른 값을 가진 쌍을 생성 할 수 없습니다.

따라서 최상위 레벨 STRef을 가질 수 없습니다. 최대 수준의 IO 참조를 가질 수 있습니다 (예 :

x :: IORef Int 
x = unsafePerformIO (newIORef 0) 

는만큼 위의 참조가 단형이며,이 즉 안전 및 참조 투명성을 입력 하스켈의 주요 기능을 중단하지 않습니다 (IORef IntIORef [Int]IORef [a]이 아닌, 확인하다). 그것은 금지 된 기능 unsafePerformIO을 사용하기 때문에 여전히 약간 해킹으로 여겨지지만, 적어도 이것은 잘 알려진 안전한 사용법입니다.

왜 IO 참조가 허용되고 ST 참조가 아닌가? ST 모나드에는 순수한 코드 (예 : test1test2)에서 모나드 값을 사용할 수있는 이스케이프 기능 runST이 있기 때문에 대신 IO에는 유사한 runIO 이스케이프 기능이 없습니다.

관련 문제