मैं runST
के प्रकार के लिए तर्क समझाने की कोशिश करेंगे:
runST :: (forall s. ST s a) -> a
और क्यों यह पसंद नहीं है यह सरल एक:
alternativeRunST :: ST s a -> a
ध्यान दें कि यह alternativeRunST
काम किया था होगा आपके कार्यक्रम के लिए
alternativeRunST
भी हमें ST
इकाई से बाहर चर लीक करने के लिए अनुमति होगी था:
leakyVar :: STRef s Int
leakyVar = alternativeRunST (newSTRef 0)
evilFunction :: Int -> Int
evilFunction x =
alternativeRunST $ do
val <- readSTRef leakyVar
writeSTRef leakyVar (val+1)
return (val + x)
तो फिर तुम GHCi में जा सकते हैं और कार्य करें:
>>> map evilFunction [7,7,7]
[7,8,9]
evilFunction
referentially पारदर्शी नहीं है!
Btw, यह अपने आप को बाहर की कोशिश करने के लिए यहाँ "बुरा अनुसूचित जनजाति" ढांचे ऊपर कोड चलाने के लिए आवश्यक है:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
import Control.Monad
import Data.IORef
import System.IO.Unsafe
newtype ST s a = ST { unST :: IO a } deriving Monad
newtype STRef s a = STRef { unSTRef :: IORef a }
alternativeRunST :: ST s a -> a
alternativeRunST = unsafePerformIO . unST
newSTRef :: a -> ST s (STRef s a)
newSTRef = ST . liftM STRef . newIORef
readSTRef :: STRef s a -> ST s a
readSTRef = ST . readIORef . unSTRef
writeSTRef :: STRef s a -> a -> ST s()
writeSTRef ref = ST . writeIORef (unSTRef ref)
असली runST
हमें इस तरह के "" बुराई कार्यों के निर्माण के लिए अनुमति नहीं है। इसे यह कैसे करना है? यह थोड़े मुश्किल है, नीचे देखें:
को चलाने के लिए कोशिश कर रहा है:
>>> runST (newSTRef "Hi")
error:
Couldn't match type `a' with `STRef s [Char]'
...
>>> :t runST
runST :: (forall s. ST s a) -> a
>>> :t newSTRef "Hi"
newSTRef "Hi" :: ST s (STRef s [Char])
newSTRef "Hi"
(forall s. ST s a)
फिट नहीं करता है। यह भी एक भी सरल उदाहरण का उपयोग देखा जा सकता है, जहां GHC हमें एक बहुत अच्छा त्रुटि देता है:
dontEvenRunST :: (forall s. ST s a) -> Int
dontEvenRunST = const 0
>>> dontEvenRunST (newSTRef "Hi")
<interactive>:14:1:
Couldn't match type `a0' with `STRef s [Char]'
because type variable `s' would escape its scope
ध्यान दें कि हम भी
dontEvenRunST :: forall a. (forall s. ST s a) -> Int
लिख सकते हैं और यह हम के रूप में forall a.
को छोड़ते हुए के बराबर है पहले किया था
ध्यान दें कि a
के दायरे s
की तुलना में बड़ा है, लेकिन newSTRef "Hi"
के मामले में अपने मूल्य s
पर निर्भर होना चाहिए। प्रकार प्रणाली इस अनुमति नहीं देता है।
वाह, यह अद्भुत है! विस्तृत स्पष्टीकरण के लिए धन्यवाद। –