dependency injection - Haskell - how to wire together components that have different subsets of dependencies? -


how can integrate application components require various subsets of infrastructure functionality?

some simple , require configuration reader (i want expose relevant subset each business function) , maybe logger. require connectivity external services (with cache) want expose limited scope of possible interactions outside world.

i don't want deal passing multiple arguments such functions explicitly or wrapping them in monadio capable of doing everything.

what closest thing injecting multiple dependencies in java application containers?

the mtl library has type classes represent computations read configuration environment, monadreader, , write data logger, monadwriter. we'll use these our examples.

the portion of monadreader use

class monad m => monadreader r m | m -> r     ask :: m r 

the portion of monadwriter use is

class (monoid w, monad m) => monadwriter w m | m -> w source       tell :: w -> m () 

to require "multiple dependencies", require single m provides instances multiple type classes.

boilerplate

ultimately, we'll use readert , writert , identity transformers run our example.

{-# 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 

using multiple dependencies: reading configuration , logging

our reader read following environment; provide monadreader configuration.

data configuration = config { site :: string }     deriving show 

our logger accumulate list of messages, each of string. provide monadwriter [string].

you can require multiple capabilities requiring instances of multiple type classes. so, can require single m has instances both monadreader , monadwriter. here's component requires environment read configuration , way write log messages.

logconfig :: (monadwriter string m, monadreader configuration m) => m () logconfig =      config <- ask     tell [show config] 

providing multiple dependencies transformers

we can provide necessary m without touching io. readert transformers adds ability read environment monad; we'll use provide monadreader configuration. writert transformers adds ability accumulate output monad; we'll use provide monadwriter [string]. underlying monad, we'll use identity show off aren't messing io. following provides both monadreader configuration , monadwriter [string], , runs computation without using io.

type depsidentity =  readert configuration (writert [string] identity)  rundepsidentity :: depsidentity -> configuration -> (a, [string]) rundepsidentity ma = runidentity . runwritert . runreadert ma 

running example

we'll use our earlier logconfig in another, larger example:

example :: (monadwriter [string] m, monadreader configuration m) => m () example =     tell ["starting", "logging config"]     logconfig     tell ["done logging config", "done"] 

finally, we'll run example configuration , see does. note io here used output final result purpose of running example.

main :: io () main = print . rundepsidentity example $ config {site = "stackoverflow"} 

this produces following output

((),["starting","logging config","config {site = \"stackoverflow\"}","done logging config","done"]) 

Comments

Popular posts from this blog

php - Submit Form Data without Reloading page -

linux - Rails running on virtual machine in Windows -