Haskell - 如何将具有不同依赖子集的组件连接在一起?

时间:2014-09-21 20:00:28

标签: haskell dependency-injection

如何从需要各种基础设施功能子集的组件中集成应用程序?

有些将非常简单,只需要一个配置阅读器(我想只公开每个业务功能的相关子集),也可能需要一个记录器。有些还需要连接到外部服务(带缓存),我还希望与外部世界进行有限范围的可能交互。

我不想处理明确地将多个参数传递给这些函数或将它们包装在能够执行所有操作的某些MonadIO中。

在Java应用程序容器中注入多个依赖项最接近的是什么?

1 个答案:

答案 0 :(得分:5)

mtl库具有类型类,用于表示从环境MonadReader读取配置的计算,并将数据写入记录器MonadWriter之类的内容。我们将这些用于我们的示例。

我们将使用的MonadReader部分是

class Monad m => MonadReader r m | m -> r where
    ask :: m r

我们将使用的MonadWriter部分是

class (Monoid w, Monad m) => MonadWriter w m | m -> w where Source  
    tell :: w -> m ()

要求" 多个依赖关系",我们需要一个m来为多个类型类提供实例。

样板

最终,我们将使用ReaderT中的WriterTIdentity以及{-# LANGUAGE FlexibleContexts #-} --mtl import Control.Monad.Reader.Class import Control.Monad.Writer.Class --transformers import Control.Monad.Trans.Reader hiding (ask) import Control.Monad.Trans.Writer.Strict hiding (tell) import Data.Functor.Identity 来运行我们的示例。

MonadReader Configuration

使用多个依赖项:读取配置和记录

我们的读者将阅读以下环境;它将提供data Configuration = Config { site :: String } deriving Show

MonadWriter [String]

我们的记录器将累积一个消息列表,每个消息都是一个字符串。它将提供m

您可以通过要求多个类型类的实例来要求多种功能。为此,您可以要求一个MonadReader具有MonadWriterlogConfig :: (MonadWriter String m, MonadReader Configuration m) => m () logConfig = do config <- ask tell [show config] 的实例。这是一个需要环境来读取配置的组件以及编写日志消息的方法。

m

为变换器提供多个依赖项

我们可以在不触及IO的情况下提供必要的ReaderT。来自变形金刚的Monad添加了从环境读取MonadReader Configuration的能力;我们将使用它来提供WriterT。来自变形金刚的Monad增加了将输出累积到MonadWriter [String]的能力;我们将使用它来提供Monad。对于基础Identity,我们只是使用IO来炫耀我们不会弄乱MonadReader Configuration。以下内容同时提供MonadWriter [String]IO,并在不使用type DepsIdentity = ReaderT Configuration (WriterT [String] Identity) runDepsIdentity :: DepsIdentity a -> Configuration -> (a, [String]) runDepsIdentity ma = runIdentity . runWriterT . runReaderT ma 的情况下运行计算。

logConfig

运行示例

我们会在另一个更大的例子中使用我们之前的example :: (MonadWriter [String] m, MonadReader Configuration m) => m () example = do tell ["Starting", "Logging Config"] logConfig tell ["Done Logging Config", "Done"]

example

最后,我们将使用Configuration运行IO并查看其功能。请注意,main :: IO () main = print . runDepsIdentity example $ Config {site = "StackOverflow"} 此处仅用于输出最终结果以运行示例。

((),["Starting","Logging Config","Config {site = \"StackOverflow\"}","Done Logging Config","Done"])

这会产生以下输出

{{1}}