Więc ja niedawno wpadł na ten zgrabny pomysł, w nadziei, że kod podziału między ścisłymi i leniwych modułów State
transformatorowych:obejmującego wszystkie przypadki promowanego typu danych
{-# 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,())
Widać, że get
i put
Oba działają bez żadnego duplikowania - bez instancji klasy typu, bez niczego - zarówno na typach ścisłych, jak i leniwych. Jednak, mimo że obejmuje zarówno ewentualne przypadki dla Strictness
, nie mam instancję monada dla State t s a
ogólnie:
-- 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
następujące prace w porządku, aczkolwiek wymagająca FlexibleContexts
:
pro :: (Monad (State t [Bool])) => State t [Bool]()
-- otherwise as before
Potem można utworzyć instancję t
pod numerem Lazy
lub Strict
i uruchomić wynik i uzyskać to, czego się spodziewam. Ale dlaczego muszę podać ten kontekst? Czy jest to ograniczenie koncepcyjne, czy praktyczne? Czy jest jakiś powód, dla którego brakuje mi tego, dlaczego Monad (State t s a)
właściwie się nie trzyma, lub czy nie ma jeszcze sposobu, aby przekonać GHC o tym jeszcze?
(Na marginesie: przy użyciu kontekstu Monad (State t s)
nie praca.
Could not deduce (Monad (State t [Bool])) arising from a do statement
from the context (Monad (State t s))
które po prostu myli mnie jeszcze bardziej pewnością były to wywnioskować z tego ostatniego?)
To rzeczywiście ograniczenie 'DataKinds'. Widziałem coś podobnego, w którym GHC nie mógł zrozumieć, że wzorce GADT z 'DataKinds' były wyczerpujące i generowały sugestie, które nie sprawdzałyby typu. –