3

我有大量的 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,...]

但我无法让它工作。建议?

4

3 回答 3

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动作提供信息。final\_ -> return ()是确保commit在这一切结束时调用它。

于 2014-08-05T19:45:07.277 回答
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
于 2014-08-05T19:44:39.530 回答
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 (): an IO ()that's "missing" a ConnectionReaderT允许您不将commitsetupUtterancessetupSegments朋友视为函数,而是将其视为共享一个共同的、隐含的Connection. ReaderT Connection IO只是一个单子,所以你可以commit轻松地在每个动作之后添加一个。

于 2014-08-06T02:07:36.080 回答