Any way to make a cleaner version of this Hocell IO feature?
I have a large number of IConnection functions conn => conn -> IO () that I need to execute in order to set up the database correctly. Now, it's not very pretty as it is, but I start too much in Haskell to make it better.
setup :: IConnection conn => conn -> IO ()
setup conn = do
setupUtterances conn
commit conn
setupSegments conn
commit conn
setupLevels conn
commit conn
setupLevelLevel conn
commit conn
setupTCLevelLevel conn
commit conn
setupPaths conn
commit conn
setupLabelTypes conn
commit conn
setupLegalLabels conn
commit conn
setupTracks conn
commit conn
setupVariables conn
commit conn
setupFeatures conn
commit conn
setupAssociations conn
commit conn
return ()
Anyway to cut it down? I played with
sequence $ map ($ conn) [func1, func2,...]
But I cannot get it to work. Suggestions?
source to share
Just put together a feature list, draw the feature app, and move commits. Then you just order your actions and manually call the final commit:
import Data.List (intersperse)
-- ... other things
setup :: IConnection => -> IO ()
setup conn =
let ops = [ setupUtterances
, setupSegments
, setupLevels
, setupLevelLevel
, setupTCLevelLevel
, setupPaths
, setupLabelTypes
, setupLegalLabels
, setupTracks
, setupVariables
, setupFeatures
, setupAssociations
]
acts = map ($ conn) $ intersperse commit ops
in sequence_ acts >> commit conn
source to share
How about just
setup conn = mapM_ ($ conn) $ intersperse commit
[ setupUtterances,
, setupSegments
, setupLevels
, setupLevelLevel
, setupTCLevelLevel
, setupPaths
, setupLabelTypes
, setupLegalLabels
, setupTracks
, setupVariables
, setupFeatures
, setupAssociations
, \_ -> return ()]
intersperse
stick commit
between all actions and mapM_ ($conn)
for filing conn
for all actions IO
. The final one \_ -> return ()
must ensure that it commit
is called at the end of everything.
source to share
I feel like I'm playing golf today. One-liner (well, it started out as one):
import Control.Monad.Trans.Reader
-- | Run a sequence of actions with the same connection, committing that
-- connection after each action.
runSetup :: IConnection conn => [conn -> IO ()] -> conn -> IO ()
runSetup = runReaderT . mapM_ withCommit
where withCommit action = ReaderT action >> ReaderT commit
setup = runSetup actions
where actions = [ setupUtterances
, setupSegments
, setupLevels
, setupLevelLevel
, setupTCLevelLevel
, setupPaths
, setupLabelTypes
, setupLegalLabels
, setupTracks
, setupVariables
, setupFeatures
, setupAssociations
]
The basic idea here is what is the Connection -> IO ()
same as ReaderT Connection IO ()
: a IO ()
, which is "missing" a Connection
. ReaderT
can handle commit
, setupUtterances
, setupSegments
and friends not as a function, and as the actions that have a common, implicit Connection
. ReaderT Connection IO
is just a monad, so you can just attack commit
after each action easily.
source to share