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
にはMonadインスタンスがありません。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
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))
それは私をさらに混乱させます。確かに前者は後者から推論可能ですか?)