有什么方法可以使这个Haskell IO功能更清晰?

时间:2014-08-05 19:38:53

标签: haskell io-monad

我有大量的IConnection conn => conn - >我需要执行IO()函数来正确设置数据库。现在,它并不是很漂亮,但是我在Haskell中太过初衷,无法让它变得更好。

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 ()

无论如何缩短它?我正在玩

sequence $ map ($ conn) [func1, func2,...]

但我无法让它发挥作用。建议?

3 个答案:

答案 0 :(得分:8)

如何

setup conn = mapM_ ($ conn) $ intersperse commit
             [ setupUtterances,
             , setupSegments
             , setupLevels
             , setupLevelLevel
             , setupTCLevelLevel
             , setupPaths
             , setupLabelTypes
             , setupLegalLabels
             , setupTracks 
             , setupVariables 
             , setupFeatures 
             , setupAssociations
             , \_ -> return ()]

intersperse在所有操作之间加上commit,并mapM_ ($conn)向所有conn行动提供IO。最后的\_ -> return ()是为了确保在所有内容的最后调用commit

答案 1 :(得分:4)

只需收集函数列表,映射函数应用程序并散布提交。然后,您只需对操作进行排序并手动调用最终提交:

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

答案 2 :(得分:0)

我觉得今天要打高尔夫球。单线(嗯,它开始像一个):

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
                    ]

这里的核心思想是Connection -> IO ()ReaderT Connection IO ()相同:IO ()“缺少”ConnectionReaderT允许您将commitsetupUtterancessetupSegments和朋友视为功能,而将其视为共享共同隐含Connection的操作。 ReaderT Connection IO只是一个monad,因此您可以轻松地在每个操作后点击commit