haskell中最快的错误monad是什么?

Pau*_*ner 11 monads haskell

Maybe/Either monad显着降低了速度.使用一些延续monad来处理错误会加快速度吗?有没有"内置延续monad"或"buitin error monad"这样的东西?内置我的意思是ST.

基准测试:

import Criterion.Main                                          

unsafeDiv x 0 = error "division by zero"                       
unsafeDiv x y = x `div` y                                      

safeDiv x 0 = Nothing                                          
safeDiv x y = Just (x `div` y)                                 

test1 :: Int -> [Int]                                          
test1 n = map (n `unsafeDiv`) [n,n-1..1]                       

test2 :: Int -> Maybe [Int]                                    
test2 n = mapM (n `safeDiv`) [n-1,n-2..0]                      

test3 :: Int -> Maybe [Int]                                    
test3 n = test3' Just [n-1,n-2..0]                             
  where test3' k []     = k []                                 
        test3' k (0:ns) = Nothing                              
        test3' k (n:ns) = test3' (k . (n:)) ns                 

main = defaultMain                                             
  [ bench "test1" (nf test1 100000)                            
  , bench "test2" (nf test2 100000)                            
  , bench "test3" (nf test3 100000)                            
  ] 
Run Code Online (Sandbox Code Playgroud)

小智 12

通常使用Maybe/Either不应该减慢速度.但是,如果Maybe/Either确实是你的瓶颈,你可以尝试在contstuff包中使用基于CPS的Maybe monad .另一种可能性是使用具有逃生路线的Cont monad.

无论如何,我不相信Maybe和Either都是瓶颈.你可能会错误地使用它们,例如强迫太多.所有性能问题都可以通过使用来解决,这是一种常见的误解seq.


Edw*_*ETT 11

我用一个相当可怕的手写monad取得了一些成功

newtype M r a = M { runM :: r -> (# Bool, a #) }
Run Code Online (Sandbox Code Playgroud)

我将Bool视为Maybe构造函数,并且在Nothing案例中为'a'添加了错误.当我有更多的结构(环境e,状态,日志等)时,我通常会使用它,所以我不确定当它如此简单时会有多好,但monad看起来像:

instance Monad (M r) where
  return a = M (\_ -> (# True, a #))
  M f >>= k = M (\r -> case f r of
    (# True, a #) -> runM (k a) r
    (# False, _ #) -> (# False, undefined #))
  fail _ = M (\_ -> (# False, undefined #))
Run Code Online (Sandbox Code Playgroud)

这样做的好处是我们不会在堆上构造任何东西,只是堆栈.

但是,你需要小心在所有正确的地方严格要求.很容易意外地在你的州建立一个可以扼杀你的表现的thunk.

如果你感觉大胆,你可以unsafeCoerce在失败的'a'插槽中走私d错误并在最后提取它,或者你可以将其翻译Bool成a Maybe e但你需要小心,因为你不想要建立一个不安全的塔楼,击败你所经历的所有工作,以实现这一目标.

这种方法的有效性取决于构建和拆除Maybe框架的开销与分配代码以处理代码中许多不同位置的故障的代码的精神和执行时间成本相比.注意>> =必须手动有效地展开Failure案例.


Cor*_*nor 5

Control.Exception在IO monad中提供try/catch/finally.这使得它们也可以在ST monad中使用(假设你很小心.)throw方程可用于纯代码.我怀疑(虽然我还没有验证)异常机制是有效的.虽然与使用monad变换器提供故障控制流程不同,但有时异常是正确的解决方案.