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

ond*_*dra 10 performance haskell monad-transformers

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

type RunningRule s a = ReaderT (STRef s LocalVarMap) (STT s (ErrorT String Identity)) a
Run Code Online (Sandbox Code Playgroud)

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

type RunningRule s m a = ReaderT (STRef s LocalVarMap) (STT s (ErrorT String m)) a
Run Code Online (Sandbox Code Playgroud)

在更改了适当的类型签名(并使用一些扩展来绕过类型)之后,我再次在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
Run Code Online (Sandbox Code Playgroud)

dfe*_*uer 12

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