wyjątki od Edwarda Kmetta biblioteka nie zapewnia instancji MonadMask dla ExceptT.Dlaczego nie ma instancji MonadMask dla narzędzia ExceptT?
Ben Gamari once asked about this a następnie doszedł do wniosku, że wyjaśniono to w dokumentacji. Jest to najbliżej istotne wyglądające przejście mogę znaleźć:
Zauważ, że ten pakiet ma zapewnić wystąpienie
MonadMask
dlaCatchT
. Ta instancja jest ważna tylko wtedy, gdy podstawowa monada nie zapewnia możliwości dostarczenia wielu wyjść. Na przykład:IO
lubEither
byłyby nieprawidłowymi monadami podstawowymi, ale akceptowalne byłybyReader
lubState
.
Ale jego znaczenie nie jest dla mnie oczywiste. Co oznacza "wiele wyjść" i dlaczego blokuje instancję MonadMask
?
[...] 'MonadMask', co pozwala na zagwarantowanie prowadzony jest to, że niektóre działania, nawet w obecności wyjątkami (zarówno synchronicznych i asynchronicznych). Aby zapewnić tę gwarancję, monada stack musi być w stanie kontrolować swój przepływ wykonania. W szczególności wyklucza to wystąpienia dla [...] Monad z wieloma punktami wyjścia, takimi jak
ErrorT
przezIO
.
Być może byłoby bardziej jasne zadać to alternatywny pytanie: Jeśli uchylenie transformatory i rozważyć nieco prostszy typ:
data IOEither a = IOEither { unIOEither :: IO (Either String a) }
deriving Functor
To wydaje że możemy rzeczywiście napisać instancji MonadMask
:
instance Applicative IOEither where
pure = IOEither . return . Right
IOEither fIO <*> IOEither xIO = IOEither $
fIO >>= either (return . Left) (\f -> (fmap . fmap) f xIO)
instance Monad IOEither where
IOEither xIO >>= f = IOEither $
xIO >>= either (return . Left) (\x -> unIOEither (f x))
instance MonadThrow IOEither where
throwM e = IOEither (throwM @IO e)
instance MonadCatch IOEither where
catch (IOEither aIO) f = IOEither $ catch @IO aIO (unIOEither . f)
instance MonadMask IOEither where
mask f = IOEither $ mask @IO $ \restore ->
unIOEither $ f (IOEither . restore . unIOEither)
uninterruptibleMask f = IOEither $ uninterruptibleMask @IO $ \restore ->
unIOEither $ f (IOEither . restore . unIOEither)
Czy ta instancja, którą napisałem, nie działa poprawnie?
Czytelnicy zainteresowani w tej kwestii powinny również rozważyć Snoyman z [* Wyjątki Dobrych Praktyk w Haskell *] (https://www.fpcomplete.com/blog/2016/11/exceptions-best-practices-haskell) dla opinia, dlaczego 'IO (albo String a)' po prostu nie jest typem, którego powinno się używać. –