のすべてのケースをカバーだから私は最近、厳しいと怠惰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
を見ることができますどちらも重複なしに動作します。厳密な型と遅延型の両方で、型クラスインスタンスはなく、何もありません。しかし、私はStrictness
のための可能なケースの両方をカバーするにもかかわらず、私は一般的にState t s a
ためモナドのインスタンスを持っていない:
-- 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
次はFlexibleContexts
を必要とするにもかかわらず、正常に動作します:
pro :: (Monad (State t [Bool])) => State t [Bool]()
-- otherwise as before
次にI t
をLazy
またはStrict
にインスタンス化して結果を実行し、私が期待するものを得ることができます。しかし、なぜ私はそのコンテキストを与えなければならないのですか?これは概念的な限界か、それとも実用的なものですか? Monad (State t s a)
が実際に保持しない理由が何か不足していますか、それともGHCをまだ納得させる方法がありませんか?
(脇:コンテキストにMonad (State t s)
を使用して仕事しません:。
Could not deduce (Monad (State t [Bool])) arising from a do statement
from the context (Monad (State t s))
だけでも、より多くの私を混乱させる確かに前者が後者から演繹あります?)
これは本当に 'DataKinds'の制限です。私はGHCが「DataKinds」を持つGADTのパターンが網羅的であることを把握できず、型チェックしない提案を生成したことが何らかの関連したことを見てきました。 –