2013-01-11 6 views
5

yüzden son zamanlarda bu düzgün fikir geldi bir terfi veri türü bütün davaları kapsayan:sıkı ve tembel <code>State</code> trafo modülleri arasında paylaşım kod umuduyla,

{-# 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,()) 

görebilirsiniz get ve put o Her ikisi de herhangi bir çoğaltma olmaksızın çalışır - hem katı hem de tembel türlerde hiçbir tip sınıf örneği, hiçbir şey yoktur. Ancak, ben Strictness hem olası örneğini kapsar rağmen ben genel olarak State t s a bir Monad örneği yok:

-- 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 

aşağıdaki eserlerini ince FlexibleContexts gerektiren olsa:

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

Sonra Lazy veya Strict numaralı telefondan t'u çalıştırabilir ve sonucu çalıştırabilir ve beklediğim şeyi alabilir. Ama neden bu bağlamı vermek zorundayım? Bu kavramsal bir sınırlama mı yoksa pratik bir mi? Monad (State t s a)'un neden tutulmadığına dair bir nedenim var mı, yoksa GHC'yi henüz ikna etmenin bir yolu yok mu?

(Kenara: bağlamını Monad (State t s)kullanarak yapar değil eser.

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

sadece beni daha Şüphesiz eski karıştırır ikincisi bir sonucu değildir nedir?)

+0

Bu gerçekten 'DataKinds' sınırlamasıdır. GHC'nin "DataKinds" ile bir GADT modelinin kapsamlı olduğunu ve yazım denetimi yapmayan öneriler oluşturduğunu anlatan bir şey gördüm. –

cevap

5

Bu bir sınırlamadır, ancak iyi bir nedene sahiptir: eğer bu şekilde çalışmadıysa ne olurdu? iyi

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

example :: s -> a 
example = snd $ runState ((State undefined) >> return 1)() 

beklenen semantik, o

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 

olabilir veya bu aynı değildir

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 

olabilir. Sonra

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

tanımlamak ve yerine IsStrictness parçası olarak bindState tanımlama, sen a tek kullanabilirsiniz Seçeneklerden biri daha sonra

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

ve benzeri bir fonksiyonu ekstra sınıfını tanımlamak olacaktır

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 = ... 
Özel sınıf ve tekil tip yerine GHC 7.6'dan singelton altyapıları kullanılarak daha da geliştirilebilen

. Gerçekten bu kadar korkutucu olmayan

ile sonlanacaksınız. Kısıtlama kümelerinizde SingI _'a sahip olun. En azından bir süre böyle çalışacak, ve o kadar da çirkin değil.Sorun State t ss dış düzeyde ölçülür diğer bir deyişle, üst düzey bağlamında, olmasıdır: State t [Bool]State t s bir sonucu değildir değildir neden olarak

. “Herhangi bir t ve s için Monad (State t s) 'nin size vereceği gibi) söyleyen bir fonksiyon tanımlıyorsunuz. Ama bu, "Monad (Devlet t [Bool]) 'un size vereceği gibi ..." demez. Ne yazık ki, bu evrensel ölçülü kısıtlamalar Haskell'de o kadar kolay değildir.

+0

Şu anda olduğu gibi tepki vermek için "örnek" in içeriğindeyim, belirsiz bir tür hatayla - bu belirsizliğin çözülmesine rağmen, bir "Monad" örneğinin ortaya çıktığını kabul ediyorum. –

+0

Bir tür değişkeni gibi görünüyor t: Strictness, 'Strict', 'Lazy' ve ne-in-her iki değerlerini tutabilir. Yine de, 'Devlet t s' hakkındaki noktanızı görüyorum, teşekkürler. Evrensel kısıtlamayı ifade etmenin bir yolu olmalı. –