我有代码根据指定的规则对文件进行一些解析。整个解析发生在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
答案 0 :(得分:12)
这不是那么不寻常,不。您应该尝试使用SPECIALIZE
pragma专门用于Identity
,也可以使用IO
。使用-ddump-simpl
并注意有关规则左侧太复杂的警告。当专业化没有发生时,GHC最终会在运行时传递类词类字典。这本质上是效率低下的,但更重要的是它阻止了GHC内联类方法以进一步简化。