быть достаточно. В более конкретных сценариях, возможно, эти ограничения также имеют смысл.

буя разные подходы делать то, что иногда называют инъекцией зависимости. Для этого я разработал простой пример приложения погоды, где мы хотим получить данные о погоде (из веб-службы или с аппаратного устройства), сохранить данные о погоде (это может быть база данных или просто файл), и сообщить об этом (либо распечатать его на экран, или говорить погоду). Идея состоит в том, чтобы написать программу, которая использует некоторые, а такжеfetch, store функции, реализация которых может варьироваться.reportМне удалось отделить проблемы и абстрагироваться от реализации поиска, хранения и отчетности с помощью

функции а такжебесплатно-монадыОднако решение, которое я достиг с помощью стека монад, выглядит плохо:В приведенном выше коде оба

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module WeatherReporterMTL where

import           Control.Monad.IO.Class
import           Control.Monad.Trans.Class

type WeatherData = String

class Monad m => WeatherService m where
    fetch :: m WeatherData

class Monad m => Storage m where
    store :: WeatherData -> m ()

class Monad m => Reporter m where
    report :: WeatherData -> m ()

-- | A dummy implementation of the @WeatherService@
newtype DummyService m a = DummyService { runDummyService :: m a }
    deriving (Functor, Applicative, Monad, MonadIO)

instance MonadIO m => WeatherService (DummyService m) where
    fetch = return "won't get any warmer in December."

-- | A dummy implementation of the @Storage@
newtype DummyStorage m a = DummyStorage { runDummyStorage :: m a }
    deriving (Functor, Applicative, Monad, MonadIO, WeatherService)

-- It seems wrong that the storage has to be an instance the weather service
-- (@WeatherService@) ...

instance MonadIO m => Storage (DummyStorage m) where
    store d = liftIO $ putStrLn $ "No room left for this report: " ++ d

-- | A dummy implementation of the @Reporter@
newtype DummyReporter m a = DummyReporter { runDummyReporter :: m a }
    deriving (Functor, Applicative, Monad, MonadIO, WeatherService, Storage)

-- Ok, now this seems even worse: we're putting information about
-- how we're gonna stack our monads :/

instance MonadIO m => Reporter (DummyReporter m) where
    report d = liftIO $ putStrLn $ "Here at the MTL side " ++ d

reportWeather :: (WeatherService m, Storage m, Reporter m) => m ()
reportWeather = do
    w <- fetch
    store w
    report w

dummyWeatherReport :: IO ()
dummyWeatherReport = runDummyService $ runDummyStorage $ runDummyReporter reportWeather

 а такжеDummyStorage должны иметь тривиальные случаи дляDummyReporter, что, кажется, явно неправильно. Более того, эти случаи зависят от порядка монады, сложенного в конце. Есть ли способ избежать утечки информации между различными стеками?WeatherService«В приведенном выше коде и DummyStorage, и DummyReporter должны иметь тривиальные экземпляры для WeatherService, что кажется совершенно неверным». Нет, так работает MTL. У всех преобразователей есть экземпляры для всех классов типов (ну, в основном), чтобы вы могли сложить их в любом порядке.

Ответы на вопрос(1)

Ваш ответ на вопрос