Rozważmy następujący przykład program:Haskell: Nakładające się przypadki
next :: Int -> Int
next i
| 0 == m2 = d2
| otherwise = 3 * i + 1
where
(d2, m2) = i `divMod` 2
loopIteration :: MaybeT (StateT Int IO)()
loopIteration = do
i <- get
guard $ i > 1
liftIO $ print i
modify next
main :: IO()
main = do
(`runStateT` 31) . runMaybeT . forever $ loopIteration
return()
Można używać tylko get
zamiast lift get
ponieważ instance MonadState s m => MonadState s (MaybeT m)
jest zdefiniowana w module MaybeT.
Wiele takich przypadków definiuje się w sposób kombinatoryczny.
To byłoby miłe (choć możliwe, dlaczego?), Jeżeli mieliśmy następujące typu Klasa:
{-# LANGUAGE MultiParamTypeClasses #-}
class SuperMonad m s where
lifts :: m a -> s a
Spróbujmy zdefiniować go jako takie:
{-# LANGUAGE FlexibleInstances, ... #-}
instance SuperMonad a a where
lifts = id
instance (SuperMonad a b, MonadTrans t, Monad b) => SuperMonad a (t b) where
lifts = lift . lifts
Korzystanie lifts $ print i
zamiast z liftIO $ print i
działa, co jest miłe.
Ale używanie lifts (get :: StateT Int IO Int)
zamiast (get :: MaybeT (StateT Int IO) Int)
nie działa.
GHC (6.10.3) daje następujący błąd:
Overlapping instances for SuperMonad
(StateT Int IO) (StateT Int IO)
arising from a use of `lifts'
Matching instances:
instance SuperMonad a a
instance (SuperMonad a b, MonadTrans t, Monad b) =>
SuperMonad a (t b)
In a stmt of a 'do' expression:
i <- lifts (get :: StateT Int IO Int)
widzę, dlaczego stosuje "instance SuperMonad a a
". Ale dlaczego GHC sądzi, że ten drugi też tak robi?
+1 za doskonałe brzmienie. –
dzięki! podążając za twoimi danymi, udało mi się to zrobić! – yairchu
OverlappingInstances znajdują się daleko na mojej liście rozszerzeń (nawet bardziej niż UndecidableInstances, co jedynie utrudnia pracę kompilatora) do użycia - nie tylko nieprzenośne, ale także łamiące gwarancje bezpieczeństwa, które zwykle zapewnia Haskell. Radziłbym OP, żeby to wyssał i poradził sobie z "windowaniem", czy nie "podnoszeniem ręki", zamiast dodawać ten hack w ... ale to jest moja opinia. – ephemient