2013-01-11 21 views
5

तो मैं हाल ही में इस स्वच्छ विचार आया के सभी मामलों को कवर, सख्त और आलसी State ट्रांसफार्मर मॉड्यूल के बीच साझा करने कोड की आशा में:एक पदोन्नत डेटाप्रकार

{-# LANGUAGE FlexibleInstances, DataKinds, KindSignatures #-} 
module State where 

data Strictness = Strict | Lazy 
newtype State (t :: Strictness) s a = State (s -> (s, a)) 

returnState :: a -> State t s a 
returnState x = State $ \s -> (s, x) 

instance Monad (State Lazy s) where 
    return = returnState 
    State ma >>= amb = State $ \s -> case ma s of 
    ~(s', x) -> runState (amb x) s' 

instance Monad (State Strict s) where 
    return = returnState 
    State ma >>= amb = State $ \s -> case ma s of 
    (s', x) -> runState (amb x) s' 

get :: State t s s 
get = State $ \s -> (s, s) 

put :: s -> State t s() 
put s = State $ \_ -> (s,()) 

आप देख सकते हैं कि get और put बिना किसी नकल के दोनों काम - कोई प्रकार के वर्ग के उदाहरण, कुछ भी नहीं - दोनों सख्त और आलसी प्रकारों पर। FlexibleContexts की आवश्यकता होती है यद्यपि

-- from http://blog.melding-monads.com/2009/12/30/fun-with-the-lazy-state-monad/ 
pro :: State t [Bool]() 
pro = do 
    pro 
    s <- get 
    put (True : s) 

-- No instance for (Monad (State t [Bool])) arising from a do statement 

निम्नलिखित काम करता है ठीक,:: फिर

pro :: (Monad (State t [Bool])) => State t [Bool]() 
-- otherwise as before 

मैं हालांकि, भले ही मैं Strictness के लिए दोनों संभव मामलों को कवर किया, मैं एक इकाई उदाहरण State t s a के लिए सामान्य रूप में नहीं है tLazy या Strict पर तुरंत चालू कर सकते हैं और परिणाम चला सकते हैं और मुझे उम्मीद है कि मैं क्या उम्मीद कर सकता हूं। लेकिन मुझे यह संदर्भ क्यों देना है? क्या यह एक वैचारिक सीमा है, या एक व्यावहारिक है? क्या मुझे कोई कारण नहीं है कि Monad (State t s a) वास्तव में क्यों नहीं पकड़ता है, या फिर अभी तक जीएचसी को मनाने के लिए कोई रास्ता नहीं है?

(एक तरफ: संदर्भ Monad (State t s)का उपयोग कर नहीं काम:।

Could not deduce (Monad (State t [Bool])) arising from a do statement from the context (Monad (State t s))

जो सिर्फ मुझे और भी अधिक निश्चित रूप से पूर्व confuses बाद से निगम्य है?)

+0

यह वास्तव में 'डेटाकिंड्स 'की सीमा है। मैंने कुछ संबंधित घटना देखी है, जहां जीएचसी यह नहीं समझ सका कि 'डेटाकिंड्स' के साथ जीएडीटी के पैटर्न संपूर्ण थे, और इससे ऐसे सुझाव उत्पन्न हुए जो टाइप-चेक नहीं करेंगे। –

उत्तर

5

यह एक सीमा है, लेकिन अच्छे कारण के साथ एक है: अगर यह उस तरह से क्या होगा काम नहीं किया

runState :: State t s a -> s -> (s,a) 
runState (State f) s = f s 

example :: s -> a 
example = snd $ runState ((State undefined) >> return 1)() 
अच्छी तरह से

की उम्मीद अर्थ विज्ञान, यह

example = snd $ runState ((State undefined) >>= \_ -> return 1)() 
     = snd $ runState (State $ \s -> case undefined s of (s',_) -> (s',1))() 
     = snd $ case undefined() of (s',_) -> (s',1) 
     = snd $ case undefined of (s',_) -> (s',1) 
     = snd undefined 
     = undefined 

हो सकता है या यह हो सकता है

example = snd $ runState ((State undefined) >>= \_ -> return 1)() 
     = snd $ runState (State $ \s -> case undefined s of ~(s',_) -> (s',1))() 
     = snd $ case undefined() of ~(s',_) -> (s',1) 
     = snd $ (undefined,1) 
     = 1 

इन ही नहीं हैं। एक विकल्प, एक समारोह में एक अतिरिक्त वर्ग को परिभाषित करने के लिए की तरह

class IsStrictness t where 
    bindState :: State t s a -> (a -> State t s b) -> State t s b 

और फिर होगा तो

instance IsStrictness t => Monad (State t s) where 
    return = returnState 
    (>>=) = bindState 

को परिभाषित करने और IsStrictness के हिस्से के रूप bindState को परिभाषित करने के बजाय, आप एक सिंगलटन का उपयोग कर सकते

data SingStrictness (t :: Strictness) where 
    SingStrict :: SingStrictness Strict 
    SingLazy :: SingStrictness Lazy 

class IsStrictness t where 
    singStrictness :: SingStrictness t 

bindState :: IsStrictness t => State t s a -> (a -> State t s b) -> State t s b 
bindState ma' amb' = go singStrictness ma' amb' where 
    go :: SingStrictness t -> State t s a -> (a -> State t s b) -> State t s b 
    go SingStrict ma amb = ... 
    go SingLazy ma amb = ... 

जिसे कस्टम क्लास और सिंगलटन प्रकार के बजाय जीएचसी 7.6 से सिंगलटन इंफ्रास्ट्रक्चर का उपयोग करके आगे बढ़ाया जा सकता है। आप

instance SingI t => Monad (State t s) 

जो वास्तव में इतना डरावना नहीं है के साथ खत्म हो जाएगा। अपने बाधा सेट में SingI _ के बहुत सारे होने के लिए उपयोग करें। इस तरह यह कम से कम थोड़ी देर के लिए काम करने जा रहा है, और वह बदसूरत नहीं है।

क्यों State t [Bool]State t s से निगम्य नहीं है के रूप में: समस्या यह है कि State t s अपने शीर्ष स्तर के संदर्भ में, जिसका अर्थ है कि s सबसे बाहरी स्तर पर मात्रा निर्धारित है में है। आप एक समारोह को परिभाषित कर रहे हैं जो कहता है "किसी भी टी और एस के लिए जैसे कि मोनाद (राज्य टी) मैं आपको दूंगा ..."। लेकिन, यह नहीं कहता है "किसी भी टी के लिए मोनाद (राज्य टी [बूल]) मैं आपको दूंगा ..."। अफसोस की बात है, इन सार्वभौमिक रूप से मात्राबद्ध बाधाएं हास्केल में इतनी आसान नहीं हैं।

+0

मैं प्रतिक्रिया के लिए 'उदाहरण' के लिए सामग्री हूं क्योंकि फिलहाल यह एक अस्पष्ट प्रकार की त्रुटि के साथ प्रतिक्रिया करता है - यह स्वीकार करते हुए कि अस्पष्टता का समाधान हो गया है, एक 'मोनाद' उदाहरण उत्पन्न होता है। –

+0

ऐसा लगता है कि एक प्रकार परिवर्तनीय 'टी :: सख्तता' मूल्यों को 'सख्त', 'आलसी', और क्रमबद्ध नहीं कर सकता है। मैं 'स्टेट टी एस' के बारे में आपका बिंदु देखता हूं, हालांकि, धन्यवाद। ऐसा लगता है कि सार्वभौमिक बाधा व्यक्त करने का एक तरीका होना चाहिए। –