Utilice pipes
. Je ne dirai pas que c'est idiomatique car la bibliothèque est encore relativement nouvelle, mais je pense que cela résout exactement votre problème.
Par exemple, disons que vous voulez envelopper une interface avec une base de données :
import Control.Proxy
-- This is just some pseudo-code. I'm being lazy here
type QueryString = String
type Result = String
query :: QueryString -> IO Result
database :: (Proxy p) => QueryString -> Server p QueryString Result IO r
database = runIdentityK $ foreverK $ \queryString -> do
result <- lift $ query queryString
respond result
Nous pouvons alors modéliser une interface vers la base de données :
user :: (Proxy p) => () -> Client p QueryString Result IO r
user () = forever $ do
lift $ putStrLn "Enter a query"
queryString <- lift getLine
result <- request queryString
lift $ putStrLn $ "Result: " ++ result
Vous les connectez comme ça :
runProxy $ database >-> user
Cela permettra ensuite à l'utilisateur d'interagir avec la base de données à partir de l'invite.
Nous pouvons alors remplacer la base de données par une base de données factice :
mockDatabase :: (Proxy p) => QueryString -> Server p QueryString Result IO r
mockDatabase = runIdentityK $ foreverK $ \query -> respond "42"
Maintenant, nous pouvons remplacer la base de données par la base factice très facilement :
runProxy $ mockDatabase >-> user
Ou nous pouvons changer le client de la base de données. Par exemple, si nous avons remarqué qu'une session client particulière a déclenché un bogue bizarre, nous pouvons le reproduire comme suit :
reproduce :: (Proxy p) => () -> Client p QueryString Result IO ()
reproduce () = do
request "SELECT * FROM WHATEVER"
request "CREATE TABLE BUGGED"
request "I DON'T REALLY KNOW SQL"
... puis le brancher comme ça :
runProxy $ database >-> reproduce
pipes
vous permet de diviser les comportements de flux ou interactifs en composants modulaires afin de pouvoir les mélanger comme bon vous semble, ce qui est l'essence même de l'injection de dépendances.
Pour en savoir plus sur pipes
il suffit de lire le tutoriel à Control.Proxy.Tutorial .