任何方法都可以使这个Haskell IO函数的版本更简洁



我已经得到了大量的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,...]

但是我不能让它工作。建议吗?

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

interspersecommit置于所有动作之间,mapM_ ($conn)conn馈送至所有IO动作。最后的_ -> return ()是为了确保在最后调用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

我今天想打代码高尔夫。一行代码(好吧,它开始是这样的):

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只是一个单子,所以你可以很容易地在每个动作之后添加一个commit

最新更新