Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
haskell中最快的错误monad是什么?_Haskell_Monads - Fatal编程技术网

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

haskell中最快的错误monad是什么?,haskell,monads,Haskell,Monads,Maybe/any单子显著减慢了速度。使用一些延续单子处理错误会加快速度吗?有“内置延续单子”或“内置错误单子”这样的东西吗?我指的是像圣 基准测试: import Criterion.Main unsafeDiv x 0 = error "division by zero" unsafeDiv x y = x `div` y

Maybe/any单子显著减慢了速度。使用一些延续单子处理错误会加快速度吗?有“内置延续单子”或“内置错误单子”这样的东西吗?我指的是像圣

基准测试:

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)                            
  ] 

通常情况下,使用Maybe/other不应减慢速度。但是,如果Maybe/other确实是您的瓶颈,您可以尝试在包中使用基于CPS的Maybe monad-like。另一种可能是使用带有逃生路线的Cont monad

在任何情况下,我都不认为这是瓶颈。你可能用错了,比如强迫太多。人们普遍错误地认为,所有性能问题都可以通过使用
seq
解决

有“内置延续单子”或“内置错误单子”这样的东西吗

内置错误monad是来自
Control.monad.error
MonadError
,而内置延续monad是来自
Control.monad.Cont的
MonadCont

这些不是实际的monad,而是类型类。在GHCi中使用Hoogle或
:i Control.Monad.Error
查找实例


MonadError
的一个突出实例是
控件。异常在IO monad中提供try/catch/finally。这使得它们也可以在ST monad中使用(假设你很小心的话)。抛出方程可以在纯代码中使用。我怀疑(尽管我没有验证)异常机制是有效的。虽然与使用monad transformer提供故障控制流不同,但有时例外情况是正确的解决方案。

我已经成功地使用了一个相当可怕的手写monad,它使用了

newtype M r a = M { runM :: r -> (# Bool, a #) }
我把Bool当作Maybe构造函数,在Nothing的情况下为'a'加上一个错误。当我有更多的结构(环境、状态、日志等)时,我通常会使用它,所以我不确定当它这么简单时,它会有多好的效果,但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 #))
这样做的好处是,我们不在堆上构造任何东西,只在堆栈上构造

然而,你需要小心,在所有正确的地方都要严格。很容易在你的状态下意外地制造出一个thunk,这会破坏你的表现

如果你有胆量,你可以在失败时将
不安全的错误
d偷偷带到“a”槽中,并在最后提取出来,或者你可以将
Bool
翻译成
可能是e
,但你需要小心,因为你不想建立一座不安全的塔,击败你为达到这一目标所做的所有工作


这种方法的有效性取决于构建和拆除Maybe框架的开销与在代码中的许多不同位置分发处理失败的代码的精神和执行时间成本。请注意>>=必须如何有效地手动解除故障案例。

您能否给出一些示例,说明/Maybe/或/Maybe如何显著降低速度?背景是什么?(是性能还是开发)“Maybe/other monad会显著减慢速度”[需要引证]很抱歉这么晚才回答,我以为我会收到邮件通知。我认为以下几点表明使用maybe或continuation是有成本的。直观地说,跳100个堆栈帧(延续)的成本确实比执行100个测试(可能)的成本要低,但使用CPS显然会有一些额外的成本。这就是为什么我要问关于建筑延续的问题。或者我忽略了什么?请记住,使用maybe和other进行错误处理的成本来自通过绑定传播成功状态。通过单独测试一个计算,你不会学到任何东西。你试过优化基准测试吗?在我的笔记本电脑上,使用-O2编译使test2和test3花费的时间约为test1的2倍,我认为这并不是很糟糕……它们并不像
ST
那样真正内置在monad中。
ST
monad有编译器支持,而你提到的monad只是普通的Haskell代码。这正是我的意思。我注意到在没有强制的情况下(我想,如果我错了,请告诉我,也许nf在这里做得“太多”)会变慢(请参阅)。我应该试试。。。但正如你所说,这是一个有点恼人的是,它在IO单子。我总是可以把它藏在新的字体后面。但是,如果它恰好是快速的,那么将功能隔离在它自己的monad中,与IO分离,这将是非常棒的,比如ST for IORefs。谢谢,这就是我一直在寻找的答案!尽管正如您所注意到的,这是一种黑客行为(尤其是不变量“not(fstp)=>(sndp)未定义”没有被强制执行)。堆上不是构建了
\r->
闭包和
未定义的
thunks吗?或者你的意思是,在任何给定的时间,它们只有O(1)个?后者。事实上,它不会把它们拴起来,也不会把它们积攒起来,也不会马上把它们撕下来,这正是我所追求的。