设计 – Haskell中的依赖注入:习惯性地解决任务
依赖注入的习惯Haskell解决方案是什么?
例如,假设你有一个接口f??robby,你需要传递一个符合frobby的实例(可能有这些实例的多个变种,说,foo和bar)。 典型操作是: >取一些值X并返回一些值Y的函数。例如,这可能是一个数据库访问器,采用SQL查询&连接器并返回数据集。你可能需要实现postgres,mysql和一个模拟测试系统。 一个人解决了这个问题,如下: http://mikehadlow.blogspot.com/2011/05/dependency-injection-haskell-style.html 但我不知道这是否是管理这项任务的规范方式。
我认为这里的正确答案是,我可能会收到几个downvote只是这样说:忘记术语依赖注入。把它忘了吧。这是一个来自OO世界的时尚流行词,但没有更多。
让我们来解决真正的问题。请记住,你正在解决一个问题,这个问题是手头的特定编程任务。不要让你的问题“实现依赖注入”。 我们将以一个记录器为例,因为这是许多程序想要拥有的基本功能,并且有很多不同类型的记录器:一个记录到stderr,一个记录到一个文件,一个数据库,和一个根本不做任何事情。要统一它们所有你想要的类型: type Logger m = String -> m () 您还可以选择一个鸽友类型来保存一些击键: class PrettyPrint a where pretty :: a -> String type Logger m = forall a. (PrettyPrint a) => a -> m () 现在让我们使用后者的变体定义几个记录器: noLogger :: (Monad m) => Logger m noLogger _ = return () stderrLogger :: (MonadIO m) => Logger m stderrLogger x = liftIO . hPutStrLn stderr $ pretty x fileLogger :: (MonadIO m) => FilePath -> Logger m fileLogger logF x = liftIO . withFile logF AppendMode $ h -> hPutStrLn h (pretty x) acidLogger :: (MonadIO m) => AcidState MyDB -> Logger m acidLogger db x = update' db . AddLogLine $ pretty x 您可以看到这是如何构建依赖关系的图。 acidLogger依赖于MyDB数据库布局的数据库连接。将参数传递给函数是关于在程序中表达依赖性的最自然的方式。毕竟一个函数只是一个取决于另一个值的值。行动也是如此。如果你的行为取决于一个记录器,那么自然它是记录器的一个功能: printFile :: (MonadIO m) => Logger m -> FilePath -> m () printFile log fp = do log ("Printing file: " ++ fp) liftIO (readFile fp >>= putStr) log "Done printing." 看看这是多么容易?在某些时候,这让你意识到你的生活会多么容易,当你只是忘记了OO已经教给你的所有废话。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |