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?

+3


source to share


3 answers


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

      

+4


source


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.

+8


source


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.

0


source







All Articles