在推广monad时,性能下降近50%

时间:2015-03-23 02:53:34

标签: performance haskell monad-transformers

我有代码根据指定的规则对文件进行一些解析。整个解析发生在monad中,它是ReaderT / STTrans / ErrorT的堆栈。

type RunningRule s a = ReaderT (STRef s LocalVarMap) (STT s (ErrorT String Identity)) a

因为在代码中运行一些IO会很方便(例如查询外部数据库),我想我会概括解析,这样它就可以在Identity或IO base monad中运行,具体取决于我的功能欲望。这将签名更改为:

type RunningRule s m a = ReaderT (STRef s LocalVarMap) (STT s (ErrorT String m)) a

在更改了适当的类型签名(并使用一些扩展来绕过类型)后,我再次在Identity monad中运行它,它的速度慢了约50%。虽然基本没什么变化,但速度要慢得多。这是正常的行为吗?有一些简单的方法可以让它更快吗? (例如,将ErrorT和ReaderT(以及可能的STT)堆栈组合成一个monad变换器?)

添加代码示例 - 基于解析的输入(以类C语言给出)构建解析器。代码如下所示:

compileRule :: forall m. (Monad m, Functor m) =>
        -> [Data -> m (Either String Data)] -- For tying the knot
        -> ParsedRule -- This is the rule we are compiling 
        -> Data -> m (Either String Data) -- The real parsing
compileRule compiled (ParsedRule name parsedlines) = 
    \input -> runRunningRule input $ do
         sequence_ compiledlines
   where
       compiledlines = map compile parsedlines
       compile (Expression expr) = compileEx expr >> return ()
       compile (Assignment var expr) = 
       ...
       compileEx (Function "check" expr) = do
           value <- expr
           case value of
               True -> return ()
               False -> fail "Check failed"
           where
                code = compileEx expr

1 个答案:

答案 0 :(得分:12)

这不是那么不寻常,不。您应该尝试使用SPECIALIZE pragma专门用于Identity,也可以使用IO。使用-ddump-simpl并注意有关规则左侧太复杂的警告。当专业化没有发生时,GHC最终会在运行时传递类词类字典。这本质上是效率低下的,但更重要的是它阻止了GHC内联类方法以进一步简化。